diff --git a/components/active/init.js b/components/active/init.js index 357b1dd..2e8ea0b 100755 --- a/components/active/init.js +++ b/components/active/init.js @@ -113,8 +113,7 @@ }; // Assuming the mode file has no dependencies - $.loadScript( 'components/editor/ace-editor/mode-' + mode.name + '.js', - fn ); + $.loadScript( 'components/editor/ace-editor/mode-' + mode.name + '.js', fn ); }, init: function() { diff --git a/components/filemanager/class.filemanager.php b/components/filemanager/class.filemanager.php index e0fd0ec..a835879 100755 --- a/components/filemanager/class.filemanager.php +++ b/components/filemanager/class.filemanager.php @@ -78,43 +78,50 @@ class Filemanager extends Common { ); $path = self::formatPath( $path ); - // Create file - if( $type == "file" ) { + if( Permissions::has_create( $path ) ) { - if ( ! file_exists( $path ) ) { + // Create file + if( $type == "file" ) { - if ( $file = fopen( $path, 'w' ) ) { + if ( ! file_exists( $path ) ) { - // Write content - if ( $content ) { + if ( $file = fopen( $path, 'w' ) ) { - fwrite( $file, $content ); + // Write content + if ( $content ) { + + fwrite( $file, $content ); + } + fclose( $file ); + + $response["status"] = "success"; + $response["mtime"] = filemtime( $path ); + } else { + + $response["status"] = "error"; + $response["message"] = "Cannot Create File"; } - fclose( $file ); - - $response["status"] = "success"; - $response["mtime"] = filemtime( $path ); } else { $response["status"] = "error"; - $response["message"] = "Cannot Create File"; + $response["message"] = "File Already Exists"; } - } else { + } elseif( $type == "directory" ) { - $response["status"] = "error"; - $response["message"] = "File Already Exists"; + if ( ! is_dir( $path ) ) { + + mkdir( $path ); + $response["status"] = "success"; + } else { + + $response["status"] = "error"; + $response["message"] = "Directory Already Exists"; + } } - } elseif( $type == "directory" ) { + } else { - if ( ! is_dir( $path ) ) { - - mkdir( $path ); - $response["status"] = "success"; - } else { - - $response["status"] = "error"; - $response["message"] = "Directory Already Exists"; - } + $response["status"] = "error"; + $response["message"] = "You do not have permission to create files in this project"; } return $response; } @@ -354,13 +361,15 @@ class Filemanager extends Common { $paths[] = array( "basename" => $path_info["basename"], - "children" => $this->index_path( $p ), + //"children" => $this->index_path( $p ), + "children" => array(), "dirname" => str_replace( WORKSPACE . "/", "", $p ), "extension" => null, "filename" => $path_info["filename"], "full_dirname" => $path_info["dirname"], "full_path" => $p, "path" => str_replace( WORKSPACE . "/", "", $p ), + "type" => "directory", ); } else { @@ -370,6 +379,7 @@ class Filemanager extends Common { "extension" => isset( $path_info["extension"] ) ? $path_info["extension"] : null, "filename" => $path_info["filename"], "path" => str_replace( WORKSPACE . "/", "", $p ), + "type" => "file", ); } } @@ -377,9 +387,28 @@ class Filemanager extends Common { } closedir( $handle ); + usort( $paths, array( $this, "sorter" ) ); return $paths; } + function sorter( $a, $b ) { + + $basename = strnatcmp( $a["basename"], $b["basename"] ); + $type = strnatcmp( $a["type"], $b["type"] ); + $result = 0; + + if( $type == 0 ) { + + $result = $basename; + } else { + + $result = $type; + } + + return $result; + } + + ////////////////////////////////////////////////////////////////// // MODIFY (Modifies a file name/contents or directory name) ////////////////////////////////////////////////////////////////// @@ -398,6 +427,13 @@ class Filemanager extends Common { $content = ''; // Blank out file } + if( ! Permissions::has_write( $path ) ) { + + $response["status"] = "error"; + $response["message"] = "You do not have access to write to this file."; + return $response; + } + if( $patch && ! $mtime ) { $response["status"] = "error"; @@ -530,6 +566,7 @@ class Filemanager extends Common { $response["data"] = array( "content" => $output, "mtime" => filemtime( $path ), + "read_only" => ( ! Permissions::has_write( $path ) ), ); } else { diff --git a/components/filemanager/init.js b/components/filemanager/init.js index ac924f3..fd91055 100755 --- a/components/filemanager/init.js +++ b/components/filemanager/init.js @@ -193,10 +193,9 @@ console.log( data ); let response = codiad.jsend.parse( data ); console.log( response ); - /*parent = path.split( '/' ); + parent = path.split( '/' ); parent.pop(); _this.rescan( parent.join( '/' ) ); - */ }); }, @@ -446,6 +445,7 @@ ////////////////////////////////////////////////////////////////// opened_folders: [], + indexFiles: [], index: function( path, rescan ) { @@ -475,14 +475,16 @@ _this.opened_folders.push( path ); } - if( open && ! rescan ) { + if( node.hasClass( 'open' ) && ! rescan ) { node.parent( 'li' ) .children( 'ul' ) .slideUp( 300, function() { - $( this ) - .remove(); + + $( this ).remove(); node.removeClass( 'open' ); + node.parent().children( 'span' ).removeClass( 'minus' ).addClass( 'plus' ); + node.parent().children().find( 'span' ).removeClass( 'minus' ).addClass( 'plus' ); }); } else { @@ -491,6 +493,7 @@ node.addClass( 'open' ); let response = codiad.jsend.parse( data ); + console.log( response ); if( response != 'error' ) { @@ -504,13 +507,6 @@ if( Object.keys( files ).length > 0 ) { - let expanded = parentNode.children( 'span' ).hasClass( 'plus' ); - - if( expanded ) { - - parentNode.children( 'span' ).removeClass( 'plus' ).addClass( 'minus' ); - } - let display = 'display:none;'; let container = $( '' ); diff --git a/components/project/class.project.php b/components/project/class.project.php index 4138fb0..5fdbd24 100755 --- a/components/project/class.project.php +++ b/components/project/class.project.php @@ -43,75 +43,67 @@ class Project extends Common { // NEW METHODS ////////////////////////////////////////////////////////////////// - public function add_project( $project_name, $project_path, $owner = null ) { + public function add_project( $project_name, $project_path, $owner ) { global $sql; - if( $owner == null ) { - - $owner = -1; - } else { - - $owner = $_SESSION["user_id"]; - } - $query = "INSERT INTO projects( name, path, owner ) VALUES ( ?, ?, ? );"; $bind_variables = array( $project_name, $project_path, $owner ); $return = $sql->query( $query, $bind_variables, 0, "rowCount" ); - - if( ! ( $return > 0 ) ) { - - exit( formatJSEND( "error", "Error creating project $project_name" ) ); - } + return $return; } - public function add_user() { + public function add_user( $path, $user_id, $access ) { global $sql; + $return = array( + "status" => null, + "message" => null, + ); $query = "SELECT * FROM projects WHERE path=? AND owner=? LIMIT 1"; - $bind_variables = array( $this->path, $_SESSION["user_id"] ); + $bind_variables = array( $path, $_SESSION["user_id"] ); $project = $sql->query( $query, $bind_variables, array(), "fetch" ); if( empty( $project ) ) { - exit( formatJSEND( "error", "Error fetching projects." ) ); - } - - $user_id = get_user_id( $this->user ); - - if( $user_id === false ) { - - exit( formatJSEND( "error", "Error fetching user information." ) ); - } - - $user = $sql->query( "SELECT * FROM access WHERE project = ? AND user = ?", array( $project["id"], $user_id ), array(), "fetch" ); - - if( ! empty( $user ) ) { - - $query = "UPDATE access SET level=? WHERE project=? AND user=?;"; - $bind_variables = array( $this->access, $project["id"], $user_id ); - $result = $sql->query( $query, $bind_variables, 0, "rowCount" ); - - if( $result > 0 ) { - - echo formatJSEND( "success", "Successfully updated {$this->user}." ); - } else { - - echo formatJSEND( "error", "Error setting access for project." ); - } + $return["status"] = "error"; + $return["message"] = "Error fetching projects."; } else { - $query = "INSERT INTO access ( project, user, level ) VALUES ( ?,?,? );"; - $bind_variables = array( $project["id"], $user_id, $this->access ); - $result = $sql->query( $query, $bind_variables, 0, "rowCount" ); + $user = $sql->query( "SELECT * FROM access WHERE project = ? AND user = ? LIMIT 1", array( $project["id"], $user_id ), array(), "fetch" ); - if( $result > 0 ) { + if( ! empty( $user ) ) { - echo formatJSEND( "success", "Successfully added {$this->user}." ); + $query = "UPDATE access SET level=? WHERE project=? AND user=?;"; + $bind_variables = array( $access, $project["id"], $user_id ); + $result = $sql->query( $query, $bind_variables, 0, "rowCount" ); + + if( $result > 0 ) { + + $return["status"] = "success"; + $return["message"] = "Successfully updated access."; + } else { + + $return["status"] = "error"; + $return["message"] = "Error setting access for project."; + } } else { - echo formatJSEND( "error", "Error setting access for project." ); + $query = "INSERT INTO access ( project, user, level ) VALUES ( ?,?,? );"; + $bind_variables = array( $project["id"], $user_id, $access ); + $result = $sql->query( $query, $bind_variables, 0, "rowCount", "exception" ); + + if( $result > 0 ) { + + $return["status"] = "success"; + $return["message"] = "Successfully updated access."; + } else { + + $return["status"] = "error"; + $return["message"] = "Error setting access for project."; + } } } + return $return; } public function check_duplicate( $full_path ) { @@ -397,26 +389,39 @@ class Project extends Common { // Create ////////////////////////////////////////////////////////////////// - public function Create() { + public function Create( $path, $name, $public ) { - if ( $this->name != '' && $this->path != '' ) { + $return = array( + "status" => null, + "message" => null, + ); + + if( $public === true ) { - $this->path = $this->cleanPath(); - $this->name = htmlspecialchars( $this->name ); - if ( ! $this->isAbsPath( $this->path ) ) { + $owner = -1; + } else { + + $owner = $_SESSION["user_id"]; + } + + if ( $name != '' && $path != '' ) { + + $path = $this->clean_path( $path ); + $name = htmlspecialchars( $name ); + if ( ! $this->isAbsPath( $path ) ) { - $this->path = $this->SanitizePath(); + $path = $this->sanitize_path( $path ); } - if ( $this->path != '' ) { + if ( $path != '' ) { $user_path = WORKSPACE . '/' . preg_replace( '/[^\w-]/', '', strtolower( $_SESSION["user"] ) ); - if( ! $this->isAbsPath( $this->path ) ) { + if( ! $this->isAbsPath( $path ) ) { - $this->path = $_SESSION["user"] . '/' . $this->path; + $path = $_SESSION["user"] . '/' . $path; } - $pass = $this->check_duplicate( $this->path ); + $pass = $this->check_duplicate( $path ); if ( $pass ) { if( ! is_dir( $user_path ) ) { @@ -424,78 +429,87 @@ class Project extends Common { mkdir( $user_path, 0755, true ); } - if ( ! $this->isAbsPath( $this->path ) ) { + if ( ! $this->isAbsPath( $path ) ) { - if( ! is_dir( WORKSPACE . '/' . $this->path ) ) { + if( ! is_dir( WORKSPACE . '/' . $path ) ) { - mkdir( WORKSPACE . '/' . $this->path ); + mkdir( WORKSPACE . '/' . $path ); } } else { - if( ! is_admin() ) { + if( is_admin() ) { - die( formatJSEND( "error", "Absolute Paths are only allowed for admins" ) ); - } - - if ( defined( 'WHITEPATHS' ) ) { - - $allowed = false; - foreach ( explode( ",", WHITEPATHS ) as $whitepath ) { + if ( defined( 'WHITEPATHS' ) ) { - if ( strpos( $this->path, $whitepath ) === 0 ) { + $allowed = false; + foreach ( explode( ",", WHITEPATHS ) as $whitepath ) { - $allowed = true; + if ( strpos( $path, $whitepath ) === 0 ) { + + $allowed = true; + } + } + if ( ! $allowed ) { + + $return["status"] = "error"; + $return["message"] = "Absolute Path Only Allowed for " . WHITEPATHS; } } - if ( ! $allowed ) { + if ( ! file_exists( $path ) ) { - die( formatJSEND( "error", "Absolute Path Only Allowed for " . WHITEPATHS ) ); - } - } - if ( ! file_exists( $this->path ) ) { - - if ( ! mkdir( $this->path . '/', 0755, true ) ) { + if ( ! mkdir( $path . '/', 0755, true ) ) { + + $return["status"] = "error"; + $return["message"] = "Unable to create Absolute Path"; + } + } else { - die( formatJSEND( "error", "Unable to create Absolute Path" ) ); + if ( ! is_writable( $path ) || ! is_readable( $path ) ) { + + $return["status"] = "error"; + $return["message"] = "No Read/Write Permission"; + } } } else { - if ( ! is_writable( $this->path ) || ! is_readable( $this->path ) ) { - - die( formatJSEND( "error", "No Read/Write Permission" ) ); - } + $return["status"] = "error"; + $return["message"] = "Absolute Paths are only allowed for admins"; } } - $this->projects[] = array( "name" => $this->name, "path" => $this->path ); - $this->add_project( $this->name, $this->path ); - // Pull from Git Repo? - if ( $this->gitrepo && filter_var( $this->gitrepo, FILTER_VALIDATE_URL ) !== false ) { + if( $return["status"] == null ) { - $this->gitbranch = $this->SanitizeGitBranch(); - if ( ! $this->isAbsPath( $this->path ) ) { + $this->projects[] = array( "name" => $name, "path" => $path ); + $result = $this->add_project( $name, $path, $owner ); + + if( $result > 0 ) { - $this->command_exec = "cd " . escapeshellarg( WORKSPACE . '/' . $this->path ) . " && git init && git remote add origin " . escapeshellarg( $this->gitrepo ) . " && git pull origin " . escapeshellarg( $this->gitbranch ); + $return["status"] = "success"; + $return["message"] = "Created Project"; + $return["data"] = array( "name" => $name, "path" => $path ); } else { - $this->command_exec = "cd " . escapeshellarg( $this->path ) . " && git init && git remote add origin " . escapeshellarg( $this->gitrepo ) . " && git pull origin " . escapeshellarg( $this->gitbranch ); + $return["status"] = "error"; + $return["message"] = "A Project With the Same Name or Path Exists"; } - $this->ExecuteCMD(); } - - exit( formatJSEND( "success", array( "name" => $this->name, "path" => $this->path ) ) ); } else { - exit( formatJSEND( "error", "A Project With the Same Name or Path Exists" ) ); + $return["status"] = "error"; + $return["message"] = "A Project With the Same Name or Path Exists"; } } else { - exit( formatJSEND( "error", "Project Name/Folder not allowed" ) ); + $return["status"] = "error"; + $return["message"] = "Project Name/Folder not allowed"; } } else { - exit( formatJSEND( "error", "Project Name/Folder is empty" ) ); + $return["status"] = "error"; + $return["message"] = "Project Name/Folder is empty"; } + + return $return; } ////////////////////////////////////////////////////////////////// @@ -565,6 +579,12 @@ class Project extends Common { return preg_replace( '/[^\w-]/', '', strtolower( $sanitized ) ); } + public function sanitize_path( $path ) { + + $sanitized = str_replace( " ", "_", $path ); + return preg_replace( '/[^\w-]/', '', strtolower( $sanitized ) ); + } + ////////////////////////////////////////////////////////////////// // Clean Path ////////////////////////////////////////////////////////////////// @@ -583,31 +603,16 @@ class Project extends Common { return $path; } - ////////////////////////////////////////////////////////////////// - // Execute Command - ////////////////////////////////////////////////////////////////// - - public function ExecuteCMD() { + public function clean_path( $path ) { - if ( function_exists( 'system' ) ) { + // prevent Poison Null Byte injections + $path = str_replace( chr( 0 ), '', $path ); + + // prevent go out of the workspace + while( strpos( $path, '../' ) !== false ) { - ob_start(); - system( $this->command_exec ); - ob_end_clean(); - } elseif( function_exists( 'passthru' ) ) { - - //passthru - ob_start(); - passthru($this->command_exec); - ob_end_clean(); - } elseif ( function_exists( 'exec' ) ) { - - //exec - exec( $this->command_exec, $this->output ); - } elseif ( function_exists( 'shell_exec' ) ) { - - //shell_exec - shell_exec( $this->command_exec ); + $path = str_replace( '../', '', $path ); } + return $path; } } \ No newline at end of file diff --git a/components/project/controller.php b/components/project/controller.php index 40b450c..60f0528 100755 --- a/components/project/controller.php +++ b/components/project/controller.php @@ -37,33 +37,31 @@ if( $_GET['action'] == 'add_user' ) { exit( formatJSEND( "error", "No access set." ) ); } else { - $Project->access = Permissions::LEVELS[$_GET['access']]; + $access = Permissions::LEVELS[$_GET['access']]; } - if( isset( $_GET['username'] ) && ! in_array( $_GET['username'], $invalid_users ) ) { + if( isset( $_GET['user_id'] ) && ! in_array( $_GET['user_id'], $invalid_users ) ) { - $Project->user = $_GET['username']; + $user = $_GET['user_id']; } else { - echo formatJSEND( "error", "No username set." ); - return; + exit( formatJSEND( "error", "No user id set." ) ); } - if( $_GET['project_path'] != '' ) { + if( isset( $_GET['project_path'] ) && $_GET['project_path'] != '' ) { - $Project->path = $_GET['project_path']; + $project = $_GET['project_path']; } else { - echo formatJSEND( "error", "No project path set." ); - return; + exit( formatJSEND( "error", "No project path set." ) ); } - if( $Project->check_owner( $_GET["project_path"], true ) ) { + if( $Project->check_owner( $_GET['project_path'], true ) ) { - $Project->add_user(); + return $Project->add_user( $project, $user, $access ); } else { - echo formatJSEND( "error", "You can not manage this project." ); + exit( formatJSEND( "error", "You can not manage this project." ) ); } } @@ -74,27 +72,11 @@ if( $_GET['action'] == 'add_user' ) { if( $_GET['action'] == 'create' ) { - $Project->name = $_GET['project_name']; - - if( $_GET['public_project'] == 'true' ) { - - $Project->public_project = true; - } - - if( $_GET['project_path'] != '' ) { - - $Project->path = $_GET['project_path']; - } else { - - $Project->path = $_GET['project_name']; - } - // Git Clone? - if( ! empty( $_GET['git_repo'] ) ) { - - $Project->gitrepo = $_GET['git_repo']; - $Project->gitbranch = $_GET['git_branch']; - } - $Project->Create(); + $name = $_GET['project_name']; + $public = ( $_GET['public_project'] != 'true' ) ? false : true; + $path = ( $_GET['project_path'] != '' ) ? $_GET['project_path'] : $_GET['project_name']; + $return = $Project->Create( $path, $name, $public ); + exit( json_encode( $return ) ); } ////////////////////////////////////////////////////////////////// diff --git a/components/project/dialog.php b/components/project/dialog.php index 38b2a13..a87fb32 100755 --- a/components/project/dialog.php +++ b/components/project/dialog.php @@ -91,7 +91,7 @@ switch( $_GET['action'] ) { get_owner( $data['path'] ); - if( $owner == 'nobody' ) { + if( $owner == -1 ) { ?> @@ -114,7 +114,7 @@ switch( $_GET['action'] ) { ?> @@ -229,7 +229,7 @@ switch( $_GET['action'] ) { foreach( $users as $user ) { ?> - + @@ -281,7 +281,7 @@ switch( $_GET['action'] ) { } ?> - + query( $query, $bind_variables, -1, "rowCount" ); if( $return > -1 ) { - //TODO: add new permissions system to delete cleanup - - $query = "DELETE FROM projects WHERE owner=? AND access IN ( ?,?,?,?,? );"; + $query = " + DELETE FROM projects + WHERE owner=( SELECT id FROM users WHERE username=? ) + AND ( SELECT COUNT(*) FROM access WHERE project = projects.id AND WHERE user <> ( SELECT id FROM users WHERE username=? ) );"; $bind_variables = array( $username, - "null", - null, - "[]", - "", - json_encode( array( $username ) ) + $username ); $return = $sql->query( $query, $bind_variables, -1, "rowCount" ); @@ -296,16 +293,18 @@ class User { $username = self::CleanUsername( $username ); $password = $this->encrypt_password( $password ); - $this->add_user( $username, $password ); + $result = $this->add_user( $username, $password, Permissions::SYSTEM_LEVELS["user"] ); + return $result; } ////////////////////////////////////////////////////////////////// // Delete Account ////////////////////////////////////////////////////////////////// - public function Delete() { + public function Delete( $username ) { - $this->delete_user(); + $username = self::CleanUsername( $username ); + return $this->delete_user( $username ); } ////////////////////////////////////////////////////////////////// diff --git a/components/user/controller.php b/components/user/controller.php index f60306b..37891d8 100755 --- a/components/user/controller.php +++ b/components/user/controller.php @@ -137,7 +137,12 @@ if( $_GET['action'] == 'create' ) { exit( formatJSEND( "error", "Invalid characters in username" ) ); } - $User->Create( $_POST['username'], $_POST['password'] ); + $result = $User->Create( $_POST['username'], $_POST['password'] ); + + if( $result ) { + + exit( formatJSEND( "success", "User successfully created." ) ); + } } } @@ -151,11 +156,11 @@ if( $_GET['action'] == 'delete' ) { if( ! isset( $_GET['username'] ) ) { - die( formatJSEND( "error", "Missing username" ) ); + exit( formatJSEND( "error", "Missing username" ) ); } - $User->username = User::CleanUsername( $_GET['username'] ); - $User->Delete(); + $return = $User->Delete( $_GET['username'] ); + exit( json_encode( $return ) ); } }