Continued work on new permissions system, Fixed active file listings bug

This commit is contained in:
xevidos 2019-07-02 16:46:32 -04:00
parent d3d96e66f6
commit 492e372c5d
14 changed files with 447 additions and 399 deletions

View File

@ -157,10 +157,25 @@ class Common {
self::return( $return, $action ); self::return( $return, $action );
} }
public static function get_user_id( $username ) {
global $sql;
$user_id = false;
$query = "SELECT id FROM users WHERE username = ? LIMIT 1;";
$bind_variables = array( $username );
$return = $sql->query( $query, $bind_variables, array(), "fetch" );
if( ! empty( $return ) ) {
$user_id = $return["id"];
}
return $user_id;
}
public static function get_users( $return = "return", $exclude_current = false ) { public static function get_users( $return = "return", $exclude_current = false ) {
global $sql; global $sql;
$query = "SELECT username FROM users"; $query = "SELECT * FROM users";
$bind = ""; $bind = "";
$bind_variables = array(); $bind_variables = array();
@ -172,12 +187,6 @@ class Common {
} }
$result = $sql->query( $query, $bind_variables, formatJSEND( "error", "Error checking users." ) ); $result = $sql->query( $query, $bind_variables, formatJSEND( "error", "Error checking users." ) );
$user_list = array();
foreach( $result as $row ) {
array_push( $user_list, $row["username"] );
}
if( ! empty( $result ) ) { if( ! empty( $result ) ) {
@ -185,12 +194,12 @@ class Common {
case( "json" ): case( "json" ):
$return = json_encode( $user_list ); $return = json_encode( $result );
break; break;
case( "return" ): case( "return" ):
$return = $user_list; $return = $result;
break; break;
} }
} else { } else {
@ -615,19 +624,20 @@ class Common {
// Wrapper for old method names // Wrapper for old method names
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
function is_admin() { return Common::is_admin(); }
function debug($message) { Common::debug($message); }
function i18n($key, $args = array()) { echo Common::i18n($key, $args); }
function get_i18n($key, $args = array()) { return Common::get_i18n($key, $args); }
function checkSession(){ Common::checkSession(); }
function getJSON($file,$namespace=""){ return Common::getJSON($file,$namespace); }
function saveJSON($file,$data,$namespace=""){ Common::saveJSON($file,$data,$namespace); }
function formatJSEND($status,$data=false){ return Common::formatJSEND($status,$data); }
function checkAccess() { return Common::checkAccess(); } function checkAccess() { return Common::checkAccess(); }
function checkPath($path) { return Common::checkPath($path); } function checkPath( $path ) { return Common::checkPath($path); }
function isAvailable($func) { return Common::isAvailable($func); } function checkSession() { Common::checkSession(); }
function logout() { return Common::logout(); } function debug( $message ) { Common::debug( $message ); }
function formatJSEND( $status, $data=false ){ return Common::formatJSEND($status,$data); }
function get_i18n( $key, $args = array() ) { return Common::get_i18n($key, $args); }
function get_user_id( $username ) { return Common::get_user_id( $username ); }
function get_users( $return = "return", $exclude_current = false ) { return Common::get_users( $return, $exclude_current ); } function get_users( $return = "return", $exclude_current = false ) { return Common::get_users( $return, $exclude_current ); }
function search_users( $username, $return = "return", $exclude_current = false ) { return Common::search_users( $username, $return, $exclude_current ); }
function get_version() { return Common::get_version(); } function get_version() { return Common::get_version(); }
function getJSON( $file,$namespace=""){ return Common::getJSON( $file, $namespace ); }
function i18n( $key, $args = array() ) { echo Common::i18n( $key, $args ); }
function is_admin() { return Common::is_admin(); }
function isAvailable( $func ) { return Common::isAvailable( $func ); }
function logout() { return Common::logout(); }
function saveJSON( $file, $data, $namespace="" ){ Common::saveJSON( $file, $data, $namespace ); }
function search_users( $username, $return = "return", $exclude_current = false ) { return Common::search_users( $username, $return, $exclude_current ); }
?> ?>

View File

@ -31,6 +31,14 @@ class Active extends Common {
public function __construct() { public function __construct() {
} }
public static function remove( $path ) {
global $sql;
$query = "DELETE FROM active WHERE path=? AND username=?;";
$bind_variables = array( $path, $_SESSION["user"] );
$return = $sql->query( $query, $bind_variables, 0, "rowCount" );
}
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// List User's Active Files // List User's Active Files
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
@ -38,14 +46,14 @@ class Active extends Common {
public function ListActive() { public function ListActive() {
global $sql; global $sql;
$query = "SELECT path,position,focused FROM active WHERE username=?"; $query = "SELECT path, position, focused FROM active WHERE username=?";
$bind_variables = array( $this->username ); $bind_variables = array( $this->username );
$result = $sql->query( $query, $bind_variables, array() ); $result = $sql->query( $query, $bind_variables, array() );
$tainted = false; $tainted = false;
$root = WORKSPACE; $root = WORKSPACE;
$active_list = $result; $active_list = $result;
if( ! empty( $return ) ) { if( ! empty( $result ) ) {
foreach ( $result as $id => $data ) { foreach ( $result as $id => $data ) {
@ -57,20 +65,14 @@ class Active extends Common {
$root = $root.'/'; $root = $root.'/';
} }
if ( ! file_exists( $root . $data['path'] ) ) { if ( ! is_file( $root . $data['path'] ) ) {
$tainted = true; self::remove( $data['path'] );
unset( $active_list[$id] ); unset( $active_list[$id] );
} }
} }
} }
exit( formatJSEND( "success", $active_list ) );
if( $tainted ) {
$this->update_active( $active_list );
}
echo formatJSEND( "success", $active_list );
} }
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
@ -140,23 +142,6 @@ class Active extends Common {
} }
} }
//////////////////////////////////////////////////////////////////
// Remove File
//////////////////////////////////////////////////////////////////
public function Remove() {
global $sql;
$query = "DELETE FROM active WHERE path=? AND username=?;";
$bind_variables = array( $this->path, $this->username );
$return = $sql->query( $query, $bind_variables, 0, "rowCount" );
if( $return > 0 ) {
echo formatJSEND( "success" );
}
}
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// Remove All Files // Remove All Files
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////

View File

@ -1,94 +1,101 @@
<?php <?php
/* /*
* Copyright (c) Codiad & Kent Safranski (codiad.com), distributed * Copyright (c) Codiad & Kent Safranski (codiad.com), distributed
* as-is and without warranty under the MIT License. See * as-is and without warranty under the MIT License. See
* [root]/license.txt for more. This information must remain intact. * [root]/license.txt for more. This information must remain intact.
*/ */
require_once('../../common.php'); require_once('../../common.php');
require_once('class.active.php'); require_once('class.active.php');
$Active = new Active(); $Active = new Active();
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// Verify Session or Key // Verify Session or Key
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
checkSession(); checkSession();
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// Get user's active files // Get user's active files
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
if ($_GET['action']=='list') { if( $_GET['action'] == 'list' ) {
$Active->username = $_SESSION['user'];
$Active->ListActive(); $Active->username = $_SESSION['user'];
$Active->ListActive();
} }
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// Add active record // Add active record
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
if ($_GET['action']=='add') { if ( $_GET['action'] == 'add' ) {
$Active->username = $_SESSION['user'];
$Active->path = $_GET['path']; $Active->username = $_SESSION['user'];
$Active->Add(); $Active->path = $_GET['path'];
$Active->Add();
} }
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// Rename // Rename
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
if ($_GET['action']=='rename') { if ( $_GET['action'] == 'rename' ) {
$Active->username = $_SESSION['user'];
$Active->path = $_GET['old_path']; $Active->username = $_SESSION['user'];
$Active->new_path = $_GET['new_path']; $Active->path = $_GET['old_path'];
$Active->Rename(); $Active->new_path = $_GET['new_path'];
$Active->Rename();
} }
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// Check if file is active // Check if file is active
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
if ($_GET['action']=='check') { if ( $_GET['action'] == 'check' ) {
$Active->username = $_SESSION['user'];
$Active->path = $_GET['path']; $Active->username = $_SESSION['user'];
$Active->Check(); $Active->path = $_GET['path'];
$Active->Check();
} }
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// Remove active record // Remove active record
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
if ($_GET['action']=='remove') { if ( $_GET['action'] == 'remove' ) {
$Active->username = $_SESSION['user'];
$Active->path = $_GET['path']; $Active->username = $_SESSION['user'];
$Active->Remove(); $Active->path = $_GET['path'];
$Active->remove( $Active->path );
} }
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// Remove all active record // Remove all active record
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
if ($_GET['action']=='removeall') { if( $_GET['action'] == 'removeall' ) {
$Active->username = $_SESSION['user'];
$Active->RemoveAll(); $Active->username = $_SESSION['user'];
$Active->RemoveAll();
} }
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// Mark file as focused // Mark file as focused
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
if ($_GET['action']=='focused') { if( $_GET['action'] == 'focused' ) {
$Active->username = $_SESSION['user'];
$Active->path = $_GET['path']; $Active->username = $_SESSION['user'];
$Active->MarkFileAsFocused(); $Active->path = $_GET['path'];
$Active->MarkFileAsFocused();
} }
if ($_GET['action']=='save_positions') { if( $_GET['action'] == 'save_positions' ) {
ignore_user_abort( true ); ignore_user_abort( true );
$Active->username = $_SESSION['user']; $Active->username = $_SESSION['user'];
$Active->savePositions( $_POST["positions"] ); $Active->savePositions( $_POST["positions"] );
} }

View File

@ -51,12 +51,8 @@
return !!this.sessions[path]; return !!this.sessions[path];
}, },
open: function( path, content, mtime, inBackground, focus ) { open: function( path, content, mtime, inBackground, focus, read_only=false ) {
//if( this. ) {
//}
/* Notify listeners. */ /* Notify listeners. */
amplify.publish( 'active.onFileWillOpen', { amplify.publish( 'active.onFileWillOpen', {
path: path, path: path,
@ -64,12 +60,14 @@
}); });
if( focus === undefined ) { if( focus === undefined ) {
focus = true; focus = true;
} }
var _this = this; var _this = this;
if( this.isOpen( path ) ) { if( this.isOpen( path ) ) {
if( focus ) this.focus( path ); if( focus ) this.focus( path );
return; return;
} }
@ -98,6 +96,8 @@
session.serverMTime = mtime; session.serverMTime = mtime;
_this.sessions[path] = session; _this.sessions[path] = session;
session.untainted = content.slice( 0 ); session.untainted = content.slice( 0 );
session.read_only = read_only;
if( !inBackground && focus ) { if( !inBackground && focus ) {
codiad.editor.setSession( session ); codiad.editor.setSession( session );
} }
@ -275,6 +275,7 @@
// Open saved-state active files on load // Open saved-state active files on load
$.get( _this.controller + '?action=list', function( data ) { $.get( _this.controller + '?action=list', function( data ) {
console.log( data );
var listResponse = codiad.jsend.parse( data ); var listResponse = codiad.jsend.parse( data );
if( listResponse !== null ) { if( listResponse !== null ) {
$.each( listResponse, function( index, data ) { $.each( listResponse, function( index, data ) {

View File

@ -390,11 +390,16 @@
this.setTabSize( this.settings.tabSize, i ); this.setTabSize( this.settings.tabSize, i );
this.setSoftTabs( this.settings.softTabs, i ); this.setSoftTabs( this.settings.softTabs, i );
this.setOverScroll( this.settings.overScroll, i ); this.setOverScroll( this.settings.overScroll, i );
i.setOptions( { i.setOptions({
enableBasicAutocompletion: true, enableBasicAutocompletion: true,
enableSnippets: true, enableSnippets: true,
enableLiveAutocompletion: this.settings.autocomplete enableLiveAutocompletion: this.settings.autocomplete
}); });
if( i.getSession().read_only ) {
i.setReadOnly( true );
}
}, },
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
@ -718,11 +723,15 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
setSession: function( session, i ) { setSession: function( session, i ) {
i = i || this.getActive(); i = i || this.getActive();
if( !this.isOpen( session ) ) { if( !this.isOpen( session ) ) {
if( !i ) { if( !i ) {
i = this.addInstance( session ); i = this.addInstance( session );
} else { } else {
i.setSession( session ); i.setSession( session );
} }
} else { } else {

View File

@ -15,6 +15,7 @@ class Filemanager extends Common {
// PROPERTIES // PROPERTIES
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
public $access = 0;
public $root = ""; public $root = "";
public $project = ""; public $project = "";
public $rel_path = ""; public $rel_path = "";
@ -351,7 +352,7 @@ class Filemanager extends Common {
if ( is_file( $this->path ) ) { if ( is_file( $this->path ) ) {
$output = file_get_contents($this->path); $output = file_get_contents( $this->path );
if ( extension_loaded( 'mbstring' ) ) { if ( extension_loaded( 'mbstring' ) ) {
@ -371,6 +372,8 @@ class Filemanager extends Common {
$this->data = '"content":' . json_encode( $output ); $this->data = '"content":' . json_encode( $output );
$mtime = filemtime( $this->path ); $mtime = filemtime( $this->path );
$this->data .= ', "mtime":'.$mtime; $this->data .= ', "mtime":'.$mtime;
$this->data .= ', "access":'. $this->access;
$this->data .= ', "read_only":'. ( Permissions::check_access( "read", $this->access ) && ! Permissions::check_access( "write", $this->access ) );
} else { } else {
$this->status = "error"; $this->status = "error";
@ -562,60 +565,66 @@ class Filemanager extends Common {
$this->respond(); $this->respond();
return; return;
} }
echo var_dump( Permissions::has_write( $this->path ) );
if ( is_file( $this->path ) && Permissions::has_write( $this->path ) ) {
$serverMTime = filemtime( $this->path ); if ( is_file( $this->path ) ) {
$fileContents = file_get_contents( $this->path );
if ( $this->patch && $this->mtime != $serverMTime ) { if( Permissions::has_write( $this->path ) ) {
$this->status = "error"; $serverMTime = filemtime( $this->path );
$this->message = "Client is out of sync"; $fileContents = file_get_contents( $this->path );
//DEBUG : file_put_contents($this->path.".conflict", "SERVER MTIME :".$serverMTime.", CLIENT MTIME :".$this->mtime);
$this->respond();
return;
} elseif ( strlen( trim( $this->patch ) ) == 0 && ! $this->content ) {
// Do nothing if the patch is empty and there is no content if ( $this->patch && $this->mtime != $serverMTime ) {
$this->status = "success";
$this->data = '"mtime":' . $serverMTime;
$this->respond();
return;
}
if ( $file = fopen( $this->path, 'w' ) ) {
if ( $this->patch ) {
$dmp = new diff_match_patch();
$p = $dmp->patch_apply( $dmp->patch_fromText( $this->patch ), $fileContents );
$this->content = $p[0];
//DEBUG : file_put_contents($this->path.".orig",$fileContents );
//DEBUG : file_put_contents($this->path.".patch", $this->patch);
}
if ( fwrite( $file, $this->content ) === false ) {
$this->status = "error"; $this->status = "error";
$this->message = "could not write to file"; $this->message = "Client is out of sync";
} else { //DEBUG : file_put_contents($this->path.".conflict", "SERVER MTIME :".$serverMTime.", CLIENT MTIME :".$this->mtime);
$this->respond();
return;
} elseif ( strlen( trim( $this->patch ) ) == 0 && ! $this->content ) {
// Unless stat cache is cleared the pre-cached mtime will be // Do nothing if the patch is empty and there is no content
// returned instead of new modification time after editing
// the file.
clearstatcache();
$this->data = '"mtime":'.filemtime( $this->path );
$this->status = "success"; $this->status = "success";
$this->data = '"mtime":' . $serverMTime;
$this->respond();
return;
} }
fclose( $file ); if ( $file = fopen( $this->path, 'w' ) ) {
if ( $this->patch ) {
$dmp = new diff_match_patch();
$p = $dmp->patch_apply( $dmp->patch_fromText( $this->patch ), $fileContents );
$this->content = $p[0];
//DEBUG : file_put_contents($this->path.".orig",$fileContents );
//DEBUG : file_put_contents($this->path.".patch", $this->patch);
}
if ( fwrite( $file, $this->content ) === false ) {
$this->status = "error";
$this->message = "could not write to file";
} else {
// Unless stat cache is cleared the pre-cached mtime will be
// returned instead of new modification time after editing
// the file.
clearstatcache();
$this->data = '"mtime":'.filemtime( $this->path );
$this->status = "success";
}
fclose( $file );
} else {
$this->status = "error";
$this->message = "Cannot Write to File";
}
} else { } else {
$this->status = "error"; $this->status = "error";
$this->message = "Cannot Write to File"; $this->message = "Write access is denied.";
} }
} else { } else {
$this->status = "error"; $this->status = "error";

View File

@ -39,9 +39,11 @@ if (!isset($_SESSION['project'])) {
// Security Check // Security Check
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
if ( ! Permissions::has_read( $_GET['path'] ) ) { $access = Permissions::get_access( $_GET['path'] );
die('{"status":"error","message":"Invalid Path"}'); if ( ! Permissions::check_access( "read", $access ) ) {
die( '{"status":"error","message":"Invalid access to ' . $_GET['path'] . '."}' );
} }
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
@ -56,6 +58,7 @@ if ( ! Permissions::has_read( $_GET['path'] ) ) {
$Filemanager = new Filemanager($_GET, $_POST, $_FILES); $Filemanager = new Filemanager($_GET, $_POST, $_FILES);
$Filemanager->project = @$_SESSION['project']['path']; $Filemanager->project = @$_SESSION['project']['path'];
$Filemanager->access = $access;
switch ($action) { switch ($action) {
case 'index': case 'index':

View File

@ -459,35 +459,41 @@
// Open File // Open File
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
openFile: function( path, focus ) { openFile: function( path, focus=true ) {
/* Notify listeners. */ /* Notify listeners. */
amplify.publish( 'filemanager.onFileWillOpen', { amplify.publish( 'filemanager.onFileWillOpen', {
path: path path: path
}); });
if( focus === undefined ) {
focus = true;
}
var node = $( '#file-manager a[data-path="' + path + '"]' ); var node = $( '#file-manager a[data-path="' + path + '"]' );
var ext = this.getExtension( path ); var ext = this.getExtension( path );
if( $.inArray( ext.toLowerCase(), this.noOpen ) < 0 ) { if( $.inArray( ext.toLowerCase(), this.noOpen ) < 0 ) {
node.addClass( 'loading' ); node.addClass( 'loading' );
$.get( this.controller + '?action=open&path=' + encodeURIComponent( path ), function( data ) { $.get( this.controller + '?action=open&path=' + encodeURIComponent( path ), function( data ) {
var openResponse = codiad.jsend.parse( data ); var openResponse = codiad.jsend.parse( data );
if( openResponse != 'error' ) { if( openResponse != 'error' ) {
node.removeClass( 'loading' ); node.removeClass( 'loading' );
codiad.active.open( path, openResponse.content, openResponse.mtime, false, focus ); codiad.active.open( path, openResponse.content, openResponse.mtime, false, focus, openResponse.read_only );
} }
}); });
} else { } else {
if( !codiad.project.isAbsPath( path ) ) {
if( ! codiad.project.isAbsPath( path ) ) {
if( $.inArray( ext.toLowerCase(), this.noBrowser ) < 0 ) { if( $.inArray( ext.toLowerCase(), this.noBrowser ) < 0 ) {
this.download( path ); this.download( path );
} else { } else {
this.openInModal( path ); this.openInModal( path );
} }
} else { } else {
codiad.message.error( i18n( 'Unable to open file in Browser while using absolute path.' ) ); codiad.message.error( i18n( 'Unable to open file in Browser while using absolute path.' ) );
} }
} }
@ -583,21 +589,26 @@
path: path path: path
}); });
}, },
saveModifications: function( path, data, callbacks, save = true ) { saveModifications: function( path, data, callbacks, messages = true ) {
callbacks = callbacks || {}; callbacks = callbacks || {};
let _this = this, action; let _this = this, action;
var notifySaveErr = function() { var notifySaveErr = function() {
codiad.message.error( i18n( 'File could not be saved' ) ); codiad.message.error( i18n( 'File could not be saved' ) );
if( typeof callbacks.error === 'function' ) { if( typeof callbacks.error === 'function' ) {
var context = callbacks.context || _this; var context = callbacks.context || _this;
callbacks.error.apply( context, [data] ); callbacks.error.apply( context, [data] );
} }
} }
$.post( this.controller + '?action=modify&path=' + encodeURIComponent( path ), data, function( resp ) { $.post( this.controller + '?action=modify&path=' + encodeURIComponent( path ), data, function( resp ) {
console.log( resp );
resp = $.parseJSON( resp ); resp = $.parseJSON( resp );
if( resp.status == 'success' ) { if( resp.status == 'success' ) {
if( save === true ) { if( messages === true ) {
codiad.message.success( i18n( 'File saved' ) ); codiad.message.success( i18n( 'File saved' ) );
} }
if( typeof callbacks.success === 'function' ) { if( typeof callbacks.success === 'function' ) {
@ -621,8 +632,11 @@
session.serverMTime = null; session.serverMTime = null;
session.untainted = null; session.untainted = null;
} }
} else codiad.message.error( i18n( 'File could not be saved' ) ); //} else codiad.message.error( i18n( 'File could not be saved' ) );
} else codiad.message.error( i18n( resp.message ) );
if( typeof callbacks.error === 'function' ) { if( typeof callbacks.error === 'function' ) {
var context = callbacks.context || _this; var context = callbacks.context || _this;
callbacks.error.apply( context, [resp.data] ); callbacks.error.apply( context, [resp.data] );
} }
@ -633,10 +647,10 @@
// Save file // Save file
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
saveFile: function( path, content, callbacks, save = true ) { saveFile: function( path, content, callbacks, messages = true ) {
this.saveModifications( path, { this.saveModifications( path, {
content: content content: content
}, callbacks, save ); }, callbacks, messages );
}, },
savePatch: function( path, patch, mtime, callbacks, alerts ) { savePatch: function( path, patch, mtime, callbacks, alerts ) {

View File

@ -5,17 +5,22 @@
* [root]/license.txt for more. This information must remain intact. * [root]/license.txt for more. This information must remain intact.
*/ */
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
class Permissions { class Permissions {
const LEVELS = array( const LEVELS = array(
"admin" => 0, "none" => 0,
"owner" => 1, "read" => 1,
"manager" => 2, "write" => 2,
"delete" => 3,
"create" => 4, "create" => 4,
"write" => 5, "delete" => 8,
"read" => 6, "manager" => 16,
"owner" => 32,
"admin" => 64,
); );
function __construct() { function __construct() {
@ -23,75 +28,106 @@ class Permissions {
} }
public static function check_path( $level, $path ) { public static function check_access( $level, $user_level ) {
$project_path = $_SESSION["project"]; if( ! is_integer( $level ) ) {
$project_path = rtrim( $project_path, '/' ) . '/';
if( in_array( $level, array_keys( self::LEVELS ) ) ) {
$level = self::LEVELS[$level];
} else {
exit( formatJSEND( "error", "Access Level does not exist." ) );
}
}
return ( $user_level >= $level );
}
public static function check_path( $level, $path ) {
if( ! in_array( $level, array_keys( self::LEVELS ) ) ) { if( ! in_array( $level, array_keys( self::LEVELS ) ) ) {
exit( Common::formatJSEND( "error", "Access Level does not exist." ) ); exit( formatJSEND( "error", "Access Level does not exist." ) );
} }
if( strpos( $path, $project_path ) === 0 ) { $pass = false;
$user_level = self::get_access( $path );
exit( Common::formatJSEND( "error", "Error with path." ) ); if( $user_level >= self::LEVELS[$level] ) {
$pass = true;
} }
return( $pass );
}
public static function get_access( $path ) {
global $sql; global $sql;
$pass = false; $full_path = Common::isAbsPath( $path ) ? $path : WORKSPACE . "/{$path}";
//$query = "SELECT * FROM projects WHERE LOCATE( path, ? ) > 0 LIMIT 1;"; $access = 0;
//$bind_variables = array( $path ); //$query = "SELECT id, path, owner FROM projects WHERE path LIKE ?;";
//$result = $sql->query( $query, $bind_variables, array() )[0]; //$bind_variables = array( "{$path}%" );
/*$result = $sql->select( $query = "SELECT id, path, owner FROM projects;";
"projects", $bind_variables = array();
array(), $projects = $sql->query( $query, $bind_variables, array() );
array(
array(
"find",
$path,
array(
"more than",
0
)
),
array(
"limit",
1
)
)
);*/
$query = "SELECT * FROM projects WHERE path=? LIMIT 1;"; if( ! empty( $projects ) ) {
$bind_variables = array( $_SESSION["project"] );
$result = $sql->query( $query, $bind_variables, array() );
if( ! empty( $result ) ) { foreach( $projects as $row => $data ) {
$result = $result[0]; $full_project_path = Common::isAbsPath( $data["path"] ) ? $data["path"] : WORKSPACE . "/{$data["path"]}";
$users = $sql->query( "SELECT * FOM access WHERE project = ? AND user = ? LIMIT 1", array( $result["id"], $_SESSION["user_id"] ), array() ); $path_postition = strpos( $full_path, $full_project_path );
if( $result["owner"] == 'nobody' ) { if( $path_postition === false ) {
$pass = true; continue;
} elseif( $result["owner"] == $_SESSION["user"] ) {
$pass = true;
} elseif( ! empty( $users ) ) {
//Only allow the owner to delete the root dir / project
if( $path == $result["path"] && self::LEVELS[$level] == self::LEVELS["delete"] ) {
$level = "owner";
} }
if( self::LEVELS[$level] >= $users_access ) { if( $data["owner"] == 'nobody' ) {
$pass = true; $access = self::LEVELS["owner"];
} elseif( $data["owner"] == $_SESSION["user"] ) {
$access = self::LEVELS["owner"];
} else {
$user = $sql->query( "SELECT * FROM access WHERE project = ? AND user = ? LIMIT 1", array( $data["id"], $_SESSION["user_id"] ), array(), "fetch" );
if( ! empty( $user ) ) {
$access = $user["level"];
}
}
//echo var_dump( $full_path, $full_project_path, $path_postition, $user["level"], $pass );
if( $access > 0 ) {
break;
} }
} }
} }
return( $pass ); return $access;
}
public static function get_level( $i ) {
$level = 0;
if( is_integer( $i ) ) {
$level = array_search( $i, self::LEVELS );
} else {
if( in_array( $i, array_keys( self::LEVELS ) ) ) {
$level = self::LEVELS[$i];
} else {
exit( formatJSEND( "error", "Access Level does not exist." ) );
}
}
return $level;
} }
public static function has_owner( $path ) { public static function has_owner( $path ) {

View File

@ -14,7 +14,7 @@ class Project extends Common {
// PROPERTIES // PROPERTIES
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
public $access = 100; public $access = Permissions::LEVELS["read"];
public $name = ''; public $name = '';
public $path = ''; public $path = '';
public $gitrepo = false; public $gitrepo = false;
@ -68,53 +68,50 @@ class Project extends Common {
public function add_user() { public function add_user() {
global $sql; global $sql;
$query = "SELECT access FROM projects WHERE path=? AND owner=?"; $query = "SELECT * FROM projects WHERE path=? AND owner=? LIMIT 1";
$bind_variables = array( $this->path, $_SESSION["user"] ); $bind_variables = array( $this->path, $_SESSION["user"] );
$result = $sql->query( $query, $bind_variables, array() )[0]; $project = $sql->query( $query, $bind_variables, array(), "fetch" );
if( ! empty( $result ) ) { if( empty( $project ) ) {
$access = json_decode( $result["access"] ); exit( formatJSEND( "error", "Error fetching projects." ) );
}
if( is_array( $access ) && ! empty( $access ) ) { $user_id = get_user_id( $this->user );
$is_assoc = ( array_keys( $access ) !== range( 0, count( $access ) - 1 ) ); if( $user_id === false ) {
if( $is_assoc ) { exit( formatJSEND( "error", "Error fetching user information." ) );
}
$access[$this->user] = $this->access; $user = $sql->query( "SELECT * FROM access WHERE project = ? AND user = ?", array( $project["id"], $user_id ), array(), "fetch" );
} else {
$new_access = array(); if( ! empty( $user ) ) {
foreach( $access as $user ) {
$new_access[$user] = Permission::LEVELS["delete"]; $query = "UPDATE access SET level=? WHERE project=? AND user=?;";
} $bind_variables = array( $this->access, $project["id"], $user_id );
$access[$this->user] = $this->access; $result = $sql->query( $query, $bind_variables, 0, "rowCount" );
$access = $new_access;
}
} else {
$access = array(
$this->user => $this->access
);
}
$access = json_encode( $access );
$query = "UPDATE projects SET access=? WHERE path=? AND owner=?;";
$bind_variables = array( $access, $this->path, $_SESSION["user"] );
$return = $sql->query( $query, $bind_variables, 0, "rowCount" );
if( $result > 0 ) { if( $result > 0 ) {
echo( formatJSEND( "success", "Successfully added {$this->user}." ) ); echo formatJSEND( "success", "Successfully updated {$this->user}." );
} else { } else {
echo formatJSEND( "error", "Error setting access for project." ); echo formatJSEND( "error", "Error setting access for project." );
} }
} else { } else {
echo formatJSEND( "error", "Error fetching projects." ); $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" );
if( $result > 0 ) {
echo formatJSEND( "success", "Successfully added {$this->user}." );
} else {
echo formatJSEND( "error", "Error setting access for project." );
}
} }
} }
@ -127,7 +124,7 @@ class Project extends Common {
global $sql; global $sql;
$query = "SELECT owner FROM projects WHERE path=?"; $query = "SELECT owner FROM projects WHERE path=?";
$bind_variables = array( $path ); $bind_variables = array( $path );
$result = $sql->query( $query, $bind_variables, array() )[0]; $result = $sql->query( $query, $bind_variables, array(), "fetch" );
$return = false; $return = false;
if( ! empty( $result ) ) { if( ! empty( $result ) ) {
@ -150,25 +147,12 @@ class Project extends Common {
return( $return ); return( $return );
} }
public function get_access( $path = null ) { public function get_access( $project_id = null ) {
if( $path === null ) {
$path = $this->path;
}
global $sql; global $sql;
$query = "SELECT access FROM projects WHERE path=?"; $query = "SELECT * FROM access WHERE project=?";
$bind_variables = array( $path ); $bind_variables = array( $project_id );
$return = $sql->query( $query, $bind_variables, array() )[0]; $return = $sql->query( $query, $bind_variables, array() );
if( ! empty( $return ) ) {
$return = $return["access"];
} else {
$return = formatJSEND( "error", "Error fetching project info." );
}
return( $return ); return( $return );
} }
@ -181,7 +165,7 @@ class Project extends Common {
global $sql; global $sql;
$query = "SELECT owner FROM projects WHERE path=?"; $query = "SELECT owner FROM projects WHERE path=?";
$bind_variables = array( $path ); $bind_variables = array( $path );
$return = $sql->query( $query, $bind_variables, array() )[0]; $return = $sql->query( $query, $bind_variables, array(), "fetch" );
if( ! empty( $return ) ) { if( ! empty( $return ) ) {
@ -200,6 +184,7 @@ class Project extends Common {
$project = $this->path; $project = $this->path;
} }
global $sql; global $sql;
$query = " $query = "
SELECT * FROM projects SELECT * FROM projects
@ -212,7 +197,7 @@ class Project extends Common {
$bind_variables = array( $project, $_SESSION["user"], $_SESSION["user_id"] ); $bind_variables = array( $project, $_SESSION["user"], $_SESSION["user_id"] );
//$query = "SELECT * FROM projects WHERE path=? AND ( owner=? OR owner='nobody' ) ORDER BY name;"; //$query = "SELECT * FROM projects WHERE path=? AND ( owner=? OR owner='nobody' ) ORDER BY name;";
//$bind_variables = array( $project, $_SESSION["user"] ); //$bind_variables = array( $project, $_SESSION["user"] );
$return = $sql->query( $query, $bind_variables, array() )[0]; $return = $sql->query( $query, $bind_variables, array(), "fetch" );
if( ! empty( $return ) ) { if( ! empty( $return ) ) {
@ -231,7 +216,7 @@ class Project extends Common {
SELECT * FROM projects SELECT * FROM projects
WHERE owner=? WHERE owner=?
OR owner='nobody' OR owner='nobody'
OR path IN ( SELECT path FROM access WHERE user = ? );"; OR id IN ( SELECT project FROM access WHERE user = ? );";
$bind_variables = array( $_SESSION["user"], $_SESSION["user_id"] ); $bind_variables = array( $_SESSION["user"], $_SESSION["user_id"] );
$return = $sql->query( $query, $bind_variables, array() ); $return = $sql->query( $query, $bind_variables, array() );
@ -246,42 +231,24 @@ class Project extends Common {
public function remove_user() { public function remove_user() {
global $sql; global $sql;
$query = "SELECT access FROM projects WHERE path=? AND owner=?";
$bind_variables = array( $this->path, $_SESSION["user"] );
$result = $sql->query( $query, $bind_variables, array() )[0];
if( ! empty( $result ) ) { $user_id = get_user_id( $this->user );
$access = json_decode( $result["access"] ); if( $user_id === false ) {
if( is_array( $access ) ) { return formatJSEND( "error", "Error fetching user information." );
}
$key = array_search( $this->user, $access ); $query = "DELETE FROM access WHERE project=? AND user=?;";
$bind_variables = array( $this->project_id, $user_id );
$return = $sql->query( $query, $bind_variables, 0, "rowCount" );
if ( $key !== false ) { if( $return > 0 ) {
unset( $access[$key] ); echo( formatJSEND( "success", "Successfully removed {$this->user}." ) );
} else {
echo( formatJSEND( "error", "{$this->user} is not in the access list." ) );
}
}
$access = json_encode( $access );
$query = "UPDATE projects SET access=? WHERE path=? AND owner=?;";
$bind_variables = array( $access, $this->path, $_SESSION["user"] );
$return = $sql->query( $query, $bind_variables, 0, "rowCount" );
if( $return > 0 ) {
echo( formatJSEND( "success", "Successfully removed {$this->user}." ) );
} else {
echo formatJSEND( "error", "Error setting access for project." );
}
} else { } else {
echo formatJSEND( "error", "Error fetching projects." ); echo( formatJSEND( "error", "{$this->user} is not in the access list." ) );
} }
} }

View File

@ -34,13 +34,14 @@ if( $_GET['action'] == 'add_user' ) {
if( ! isset( $_GET['access'] ) || in_array( $_GET['access'], $invalid_users ) || ! in_array( $_GET['access'], array_keys( Permissions::LEVELS ) ) ) { if( ! isset( $_GET['access'] ) || in_array( $_GET['access'], $invalid_users ) || ! in_array( $_GET['access'], array_keys( Permissions::LEVELS ) ) ) {
echo formatJSEND( "error", "No access set." ); exit( formatJSEND( "error", "No access set." ) );
return; } else {
$Project->access = Permissions::LEVELS[$_GET['access']];
} }
if( isset( $_GET['username'] ) && ! in_array( $_GET['username'], $invalid_users ) ) { if( isset( $_GET['username'] ) && ! in_array( $_GET['username'], $invalid_users ) ) {
$Project->access = $_GET['access'];
$Project->user = $_GET['username']; $Project->user = $_GET['username'];
} else { } else {
@ -130,8 +131,7 @@ if( $_GET['action'] == 'delete' ) {
if( $_GET['action'] == 'get_access' ) { if( $_GET['action'] == 'get_access' ) {
$Project->path = $_GET['project_path']; $access = $Project->get_access( $_GET['project_id'] );
$access = $Project->get_access( $_GET['project_path'] );
echo formatJSEND( "success", $access ); echo formatJSEND( "success", $access );
} }
@ -191,7 +191,7 @@ if( $_GET['action'] == 'get_owner' ) {
if( $_GET['action'] == 'open' ) { if( $_GET['action'] == 'open' ) {
if( isset( $_GET['path'] ) && ! Permissions::has_read( $_GET['path'] ) ) { if( isset( $_GET['path'] ) && Permissions::has_read( $_GET['path'] ) ) {
die( formatJSEND( "error", "No Access to path " . $_GET['path'] ) ); die( formatJSEND( "error", "No Access to path " . $_GET['path'] ) );
} }
@ -212,8 +212,7 @@ if( $_GET['action'] == 'remove_user' ) {
$Project->user = $_GET['username']; $Project->user = $_GET['username'];
} else { } else {
echo formatJSEND( "error", "No username set." ); exit( formatJSEND( "error", "No username set." ) );
return;
} }
if( ! in_array( $_GET['project_path'], $invalid ) ) { if( ! in_array( $_GET['project_path'], $invalid ) ) {
@ -221,8 +220,15 @@ if( $_GET['action'] == 'remove_user' ) {
$Project->path = $_GET['project_path']; $Project->path = $_GET['project_path'];
} else { } else {
echo formatJSEND( "error", "No project path set." ); exit( formatJSEND( "error", "No project path set." ) );
return; }
if( ! in_array( $_GET['project_id'], $invalid ) ) {
$Project->project_id = $_GET['project_id'];
} else {
exit( formatJSEND( "error", "No project id set." ) );
} }
if( $Project->check_owner( $_GET["project_path"], true ) ) { if( $Project->check_owner( $_GET["project_path"], true ) ) {
@ -230,7 +236,7 @@ if( $_GET['action'] == 'remove_user' ) {
$Project->remove_user(); $Project->remove_user();
} else { } else {
echo formatJSEND( "error", "You can not manage this project." ); exit( formatJSEND( "error", "You can not manage this project." ) );
} }
} }

View File

@ -204,11 +204,12 @@ switch( $_GET['action'] ) {
// Get projects data // Get projects data
$path = $_GET['path']; $path = $_GET['path'];
$project = $Project->get_project( $path ); $project = $Project->get_project( $path );
$access = json_decode( $project["access"], true ); $access = $Project->get_access( $project["id"] );
$users = get_users( "return", true ); $users = get_users( "return", true );
?> ?>
<form> <form onSubmit="event.preventDefault();">
<input type="hidden" name="project_path" value="<?php echo( $path );?>"> <input type="hidden" name="project_path" value="<?php echo $path;?>">
<input type="hidden" name="project_id" value="<?php echo $project["id"];?>">
<label><span class="icon-pencil"></span><?php i18n( "Add Users" );?></label> <label><span class="icon-pencil"></span><?php i18n( "Add Users" );?></label>
<input id="search_users" type="text" onkeyup="codiad.project.search_users();" /> <input id="search_users" type="text" onkeyup="codiad.project.search_users();" />
<select id="user_list" name="user_list"> <select id="user_list" name="user_list">
@ -216,14 +217,14 @@ switch( $_GET['action'] ) {
foreach( $users as $user ) { foreach( $users as $user ) {
?> ?>
<option value="<?php echo htmlentities( $user );?>"><?php echo htmlentities( $user );?></option> <option value="<?php echo htmlentities( $user["username"] );?>"><?php echo htmlentities( $user["username"] );?></option>
<?php <?php
} }
?> ?>
</select> </select>
<button class="btn-left" onclick="codiad.project.add_user();">Add User</button> <button class="btn-left" onclick="codiad.project.add_user();">Add User</button>
<?php <?php
if( $access == null ) { if( $access == null || empty( $access ) ) {
?> ?>
<p>No users have been given access.</p> <p>No users have been given access.</p>
@ -234,30 +235,30 @@ switch( $_GET['action'] ) {
<table id="access_list"> <table id="access_list">
<?php <?php
$is_assoc = ( array_keys( $access ) !== range( 0, count( $access ) - 1 ) ); $user = null;
if( ! $is_assoc ) {
$temp = array(); foreach( $access as $row => $user_permissions ) {
foreach( $access as $user ) {
$temp[$user] = "delete"; foreach( $users as $row => $current_user ) {
if( $current_user["id"] == $user_permissions["user"] ) {
$user = $current_user;
break;
}
} }
$access = $temp;
}
foreach( $access as $user => $access_level ) {
?> ?>
<tr> <tr>
<td> <td>
<p><?php echo htmlentities( $user );?></p> <p><?php echo htmlentities( $user["username"] );?></p>
</td> </td>
<td> <td>
<select onchange="codiad.project.change_access( event );"> <select onchange="codiad.project.change_access( event );">
<?php <?php
foreach( Permissions::LEVELS as $level => $id ) { foreach( Permissions::LEVELS as $level => $id ) {
if( $level == $access_level ) { if( $id == $user_permissions["level"] ) {
$selected = "selected='selected'"; $selected = "selected='selected'";
} else { } else {
@ -268,7 +269,7 @@ switch( $_GET['action'] ) {
} }
?> ?>
</select> </select>
<button class="btn-left" onclick="codiad.project.remove_user( '<?php echo htmlentities( $user );?>' );">Remove Access</button> <button class="btn-left" onclick="codiad.project.remove_user( '<?php echo htmlentities( $user["username"] );?>' );">Remove Access</button>
</td> </td>
</tr> </tr>
<?php <?php

View File

@ -54,22 +54,18 @@
add_user: function() { add_user: function() {
let _this = this; let _this = this;
let username = $( '#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();
$( '#modal-content form' ).live( 'submit', function( e ) { $.get( _this.controller + '?action=add_user&project_path=' + encodeURIComponent( project_path ) + '&project_id=' + encodeURIComponent( project_id ) + '&username=' + encodeURIComponent( username ) + '&access=delete', function( data ) {
e.preventDefault(); response = codiad.jsend.parse( data );
let username = $( '#modal-content form select[name="user_list"]' ).val(); console.log( response );
let project_path = $( '#modal-content form input[name="project_path"]' ).val(); if ( response != 'error' ) {
$.get( _this.controller + '?action=add_user&project_path=' + encodeURIComponent( project_path ) + '&username=' + encodeURIComponent( username ) + '&access=delete', function( data ) { codiad.project.manage_access( project_path );
}
response = codiad.jsend.parse( data );
console.log( response );
if ( response != 'error' ) {
codiad.project.manage_access( project_path );
}
});
}); });
}, },
@ -78,11 +74,12 @@
let _this = codiad.project; let _this = codiad.project;
let username = $( '#modal-content form select[name="user_list"]' ).val(); let username = $( '#modal-content form select[name="user_list"]' ).val();
let project_path = $( '#modal-content form input[name="project_path"]' ).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(); let access = $( e.target ).children( "option:selected" ).val();
console.log( access, username, project_path ); console.log( access, username, project_path, project_id );
$.get( _this.controller + '?action=add_user&project_path=' + encodeURIComponent( project_path ) + '&username=' + encodeURIComponent( username ) + '&access=' + encodeURIComponent( access ), function( data ) { $.get( _this.controller + '?action=add_user&project_path=' + encodeURIComponent( project_path ) + '&project_id=' + encodeURIComponent( project_id ) + '&username=' + encodeURIComponent( username ) + '&access=' + encodeURIComponent( access ), function( data ) {
let response = codiad.jsend.parse( data ); let response = codiad.jsend.parse( data );
console.log( response ); console.log( response );
@ -327,6 +324,7 @@
codiad.finder.contractFinder(); codiad.finder.contractFinder();
$.get( this.controller + '?action=open&path=' + encodeURIComponent( path ), function( data ) { $.get( this.controller + '?action=open&path=' + encodeURIComponent( path ), function( data ) {
console.log( data );
var projectInfo = codiad.jsend.parse(data); var projectInfo = codiad.jsend.parse(data);
if ( projectInfo != 'error' ) { if ( projectInfo != 'error' ) {
@ -372,20 +370,17 @@
var _this = this; var _this = this;
$( '#modal-content form' ).live( 'submit', function( e ) { let project_path = $( '#modal-content form input[name="project_path"]' ).val();
let project_id = $( '#modal-content form input[name="project_id"]' ).val();
e.preventDefault(); $.get( _this.controller + '?action=remove_user&project_path=' + encodeURIComponent( project_path ) + '&project_id=' + encodeURIComponent( project_id ) + '&username=' + encodeURIComponent( user ), function( data ) {
project_path = $( '#modal-content form input[name="project_path"]' ).val()
$.get( _this.controller + '?action=remove_user&project_path=' + encodeURIComponent( project_path ) + '&username=' + encodeURIComponent( user ), function( data ) { response = codiad.jsend.parse( data );
console.log( response );
if ( response != 'error' ) {
response = codiad.jsend.parse( data ); codiad.project.manage_access( project_path );
console.log( response ); }
if ( response != 'error' ) {
codiad.project.manage_access( project_path );
}
});
}); });
}, },

View File

@ -342,6 +342,11 @@ class sql {
$return = $statement->rowCount(); $return = $statement->rowCount();
break; break;
case( 'fetch' ):
$return = $statement->fetch( \PDO::FETCH_ASSOC );
break;
case( 'fetchAll' ): case( 'fetchAll' ):
$return = $statement->fetchAll( \PDO::FETCH_ASSOC ); $return = $statement->fetchAll( \PDO::FETCH_ASSOC );