Continued implementation of new permissions systems and new table structures

This commit is contained in:
xevidos 2019-10-25 12:46:23 -04:00
parent a377b4dddd
commit 825154a4b3
9 changed files with 239 additions and 216 deletions

View File

@ -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() {

View File

@ -78,6 +78,8 @@ class Filemanager extends Common {
);
$path = self::formatPath( $path );
if( Permissions::has_create( $path ) ) {
// Create file
if( $type == "file" ) {
@ -116,6 +118,11 @@ class Filemanager extends Common {
$response["message"] = "Directory Already Exists";
}
}
} else {
$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 {

View File

@ -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 = $( '<ul></ul>' );

View File

@ -43,76 +43,68 @@ 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." ) );
}
$return["status"] = "error";
$return["message"] = "Error fetching projects.";
} else {
$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" );
$user = $sql->query( "SELECT * FROM access WHERE project = ? AND user = ? LIMIT 1", 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 );
$bind_variables = array( $access, $project["id"], $user_id );
$result = $sql->query( $query, $bind_variables, 0, "rowCount" );
if( $result > 0 ) {
echo formatJSEND( "success", "Successfully updated {$this->user}." );
$return["status"] = "success";
$return["message"] = "Successfully updated access.";
} else {
echo formatJSEND( "error", "Error setting access for project." );
$return["status"] = "error";
$return["message"] = "Error setting access for project.";
}
} 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" );
$bind_variables = array( $project["id"], $user_id, $access );
$result = $sql->query( $query, $bind_variables, 0, "rowCount", "exception" );
if( $result > 0 ) {
echo formatJSEND( "success", "Successfully added {$this->user}." );
$return["status"] = "success";
$return["message"] = "Successfully updated access.";
} else {
echo formatJSEND( "error", "Error setting access for project." );
$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,
);
$this->path = $this->cleanPath();
$this->name = htmlspecialchars( $this->name );
if ( ! $this->isAbsPath( $this->path ) ) {
if( $public === true ) {
$this->path = $this->SanitizePath();
$owner = -1;
} else {
$owner = $_SESSION["user_id"];
}
if ( $this->path != '' ) {
if ( $name != '' && $path != '' ) {
$path = $this->clean_path( $path );
$name = htmlspecialchars( $name );
if ( ! $this->isAbsPath( $path ) ) {
$path = $this->sanitize_path( $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() ) {
die( formatJSEND( "error", "Absolute Paths are only allowed for admins" ) );
}
if( is_admin() ) {
if ( defined( 'WHITEPATHS' ) ) {
$allowed = false;
foreach ( explode( ",", WHITEPATHS ) as $whitepath ) {
if ( strpos( $this->path, $whitepath ) === 0 ) {
if ( strpos( $path, $whitepath ) === 0 ) {
$allowed = true;
}
}
if ( ! $allowed ) {
die( formatJSEND( "error", "Absolute Path Only Allowed for " . WHITEPATHS ) );
$return["status"] = "error";
$return["message"] = "Absolute Path Only Allowed for " . WHITEPATHS;
}
}
if ( ! file_exists( $this->path ) ) {
if ( ! file_exists( $path ) ) {
if ( ! mkdir( $this->path . '/', 0755, true ) ) {
if ( ! mkdir( $path . '/', 0755, true ) ) {
die( formatJSEND( "error", "Unable to create Absolute Path" ) );
$return["status"] = "error";
$return["message"] = "Unable to create Absolute Path";
}
} else {
if ( ! is_writable( $this->path ) || ! is_readable( $this->path ) ) {
if ( ! is_writable( $path ) || ! is_readable( $path ) ) {
die( formatJSEND( "error", "No Read/Write Permission" ) );
$return["status"] = "error";
$return["message"] = "No Read/Write Permission";
}
}
}
$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 ) {
$this->gitbranch = $this->SanitizeGitBranch();
if ( ! $this->isAbsPath( $this->path ) ) {
$this->command_exec = "cd " . escapeshellarg( WORKSPACE . '/' . $this->path ) . " && git init && git remote add origin " . escapeshellarg( $this->gitrepo ) . " && git pull origin " . escapeshellarg( $this->gitbranch );
} else {
$this->command_exec = "cd " . escapeshellarg( $this->path ) . " && git init && git remote add origin " . escapeshellarg( $this->gitrepo ) . " && git pull origin " . escapeshellarg( $this->gitbranch );
}
$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" ) );
}
} else {
exit( formatJSEND( "error", "Project Name/Folder not allowed" ) );
$return["status"] = "error";
$return["message"] = "Absolute Paths are only allowed for admins";
}
}
if( $return["status"] == null ) {
$this->projects[] = array( "name" => $name, "path" => $path );
$result = $this->add_project( $name, $path, $owner );
if( $result > 0 ) {
$return["status"] = "success";
$return["message"] = "Created Project";
$return["data"] = array( "name" => $name, "path" => $path );
} else {
$return["status"] = "error";
$return["message"] = "A Project With the Same Name or Path Exists";
}
}
} else {
exit( formatJSEND( "error", "Project Name/Folder is empty" ) );
$return["status"] = "error";
$return["message"] = "A Project With the Same Name or Path Exists";
}
} else {
$return["status"] = "error";
$return["message"] = "Project Name/Folder not allowed";
}
} else {
$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 clean_path( $path ) {
public function ExecuteCMD() {
// prevent Poison Null Byte injections
$path = str_replace( chr( 0 ), '', $path );
if ( function_exists( 'system' ) ) {
// 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;
}
}

View File

@ -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 ) );
}
//////////////////////////////////////////////////////////////////

View File

@ -91,7 +91,7 @@ switch( $_GET['action'] ) {
<td width="250"><?php echo($data['path']);?></td>
<?php
$owner = $Project->get_owner( $data['path'] );
if( $owner == 'nobody' ) {
if( $owner == -1 ) {
?>
<td width="70"><a onclick="codiad.message.error(i18n('Public projects can not be managed'));" class="icon-block bigger-icon"></a></td>
@ -114,7 +114,7 @@ switch( $_GET['action'] ) {
?>
<td width="70"><a onclick="codiad.message.error(i18n('Active Project Cannot Be Removed'));" class="icon-block bigger-icon"></a></td>
<?php
} elseif( $owner !== $_SESSION["user"] && $owner != -1 ) {
} elseif( $owner !== $_SESSION["user_id"] && $owner != -1 ) {
?>
<td width="70"><a onclick="codiad.message.error(i18n('Projects owned by others can not be deleted'));" class="icon-block bigger-icon"></a></td>
@ -229,7 +229,7 @@ switch( $_GET['action'] ) {
foreach( $users as $user ) {
?>
<option value="<?php echo htmlentities( $user["username"] );?>"><?php echo htmlentities( $user["username"] );?></option>
<option value="<?php echo htmlentities( $user["id"] );?>"><?php echo htmlentities( $user["username"] );?></option>
<?php
}
?>
@ -281,7 +281,7 @@ switch( $_GET['action'] ) {
}
?>
</select>
<button class="btn-left" onclick="codiad.project.remove_user( '<?php echo htmlentities( $user["username"] );?>' );">Remove Access</button>
<button class="btn-left" onclick="codiad.project.remove_user( '<?php echo htmlentities( $user["id"] );?>' );">Remove Access</button>
</td>
</tr>
<?php

View File

@ -54,11 +54,11 @@
add_user: function() {
let _this = this;
let username = $( '#modal-content form select[name="user_list"]' ).val();
let id = $( '#modal-content form select[name="user_list"]' ).val();
let project_path = $( '#modal-content form input[name="project_path"]' ).val();
let project_id = $( '#modal-content form input[name="project_id"]' ).val();
$.get( _this.controller + '?action=add_user&project_path=' + encodeURIComponent( project_path ) + '&project_id=' + encodeURIComponent( project_id ) + '&username=' + encodeURIComponent( username ) + '&access=delete', function( data ) {
$.get( _this.controller + '?action=add_user&project_path=' + encodeURIComponent( project_path ) + '&project_id=' + encodeURIComponent( project_id ) + '&user_id=' + encodeURIComponent( id ) + '&access=delete', function( data ) {
response = codiad.jsend.parse( data );
console.log( response );
@ -72,14 +72,14 @@
change_access: function( e ) {
let _this = codiad.project;
let username = $( '#modal-content form select[name="user_list"]' ).val();
let id = $( '#modal-content form select[name="user_list"]' ).val();
let project_path = $( '#modal-content form input[name="project_path"]' ).val();
let project_id = $( '#modal-content form input[name="project_id"]' ).val();
let access = $( e.target ).children( "option:selected" ).val();
console.log( access, username, project_path, project_id );
console.log( access, id, project_path, project_id );
$.get( _this.controller + '?action=add_user&path=' + encodeURIComponent( project_path ) + '&id=' + encodeURIComponent( project_id ) + '&username=' + encodeURIComponent( username ) + '&access=' + encodeURIComponent( access ), function( data ) {
$.get( _this.controller + '?action=add_user&project_path=' + encodeURIComponent( project_path ) + '&id=' + encodeURIComponent( project_id ) + '&user_id=' + encodeURIComponent( id ) + '&access=' + encodeURIComponent( access ), function( data ) {
let response = codiad.jsend.parse( data );
console.log( response );

View File

@ -52,16 +52,13 @@ class User {
$return = $sql->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 );
}
//////////////////////////////////////////////////////////////////

View File

@ -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 ) );
}
}