diff --git a/iwsy/index.html b/iwsy/index.html index 7edaf53..43c4aba 100644 --- a/iwsy/index.html +++ b/iwsy/index.html @@ -19,5 +19,6 @@ rest get Script from `/resources/ecs/iwsy.txt?v=` cat now run Script + diff --git a/iwsy/resources/ecs/fileman.txt b/iwsy/resources/ecs/fileman.txt index 696bc14..c53b413 100644 --- a/iwsy/resources/ecs/fileman.txt +++ b/iwsy/resources/ecs/fileman.txt @@ -32,6 +32,8 @@ variable Content variable Home variable UserRecord + variable Email + variable Password variable CurrentPath variable FilePath variable Path @@ -120,7 +122,7 @@ Show: ! Build the list Browser: - rest get Content from `list/` cat CurrentPath + rest get Content from `ulist/` cat Email can `/` cat Password cat `/` cat CurrentPath cat `?v=` cat now or begin alert `Failed to list files.` stop @@ -222,7 +224,7 @@ SelectFile: set style `display` of Scroller to `none` set style `display` of Image to `block` put CurrentPath cat `/` cat property `name` of File into FilePath - set attribute `src` of Image to `/resources/` cat FilePath + set attribute `src` of Image to `/resources/` cat FilePath cat `?v=` cat now on click CloseButton go to CloseMedia set the text of URL to `/resources/` cat FilePath ! highlight URL diff --git a/iwsy/resources/ecs/iwsy.txt b/iwsy/resources/ecs/iwsy.txt index 97af457..b7499df 100644 --- a/iwsy/resources/ecs/iwsy.txt +++ b/iwsy/resources/ecs/iwsy.txt @@ -44,7 +44,6 @@ variable Script variable Presentation variable Name - variable CurrentName variable ShowRun variable ReadOnly variable CallStack @@ -56,6 +55,8 @@ variable Running variable UserRecord variable UserHome + variable UserEmail + variable UserPassword variable N ! The browser @@ -68,7 +69,6 @@ button CloseButton a FileName variable Alpha - variable List variable FileList variable FileCount variable File @@ -77,7 +77,7 @@ ! Test if site is on a static host clear ReadOnly - rest get List from `list/scripts` + rest get Item from `test` or begin print `Static site` set ReadOnly @@ -257,7 +257,6 @@ L2: on click New begin -! gosub to StopTestModule if Presentation is not LastSavedState begin if confirm `Content has changed. Do you want to save it?` @@ -269,8 +268,8 @@ L2: set the content of Status to `No script name has been given` go to ResetStatus end - if UserRecord rest post Presentation to `save/` cat `users/` cat UserHome cat `/` cat Name - else put Presentation into storage as CurrentName + if UserRecord gosub to SavePresentation + else put Presentation into storage as Name end end clear FileIsOpen @@ -303,7 +302,7 @@ L2: begin put Presentation into Content json format Content - rest post Content to `save/` cat `users/` cat `users/` cat UserHome cat `/` cat Name + gosub to SavePresentation end else put Presentation into storage as Name put Presentation into LastSavedState @@ -331,7 +330,7 @@ L2: end if confirm `Are you sure you want to delete "` cat Name cat `"?` begin - if UserRecord rest post to `delete/` cat `users/` cat UserHome cat `/` cat Name + if UserRecord gosub to DeletePresentation else remove Name from storage gosub to SetStatusGreen set the content of Status to `Script "` cat Name cat `" deleted` @@ -417,9 +416,11 @@ L2: else if Action is `user` begin put property `user` of Message into UserRecord -print UserRecord put UserRecord into storage as `.user` put property `home` of UserRecord into UserHome + put UserHome cat `/` cat property `id` of UserRecord into UserHome + put property `email` of UserRecord into UserEmail + get UserPassword from storage as `password` set attribute `src` of User to `resources/icon/user-loggedin.png` set attribute `title` of User to `Logged in as ` cat property `name` of UserRecord gosub to SetStatusGreen @@ -429,6 +430,16 @@ print UserRecord end stop +SavePresentation: + rest post Content to `usave/` cat UserEmail cat `/` cat UserPassword cat `/` + cat `users/` cat UserHome cat `/scripts/` cat Name + return + +DeletePresentation: + rest post Content to `udelete/` cat UserEmail cat `/` cat UserPassword cat `/` + cat `users/` cat UserHome cat `/scripts/` cat Name + return + CreateNewPresentation: set Presentation to object set Item to array @@ -527,7 +538,8 @@ DoOpen: ! Fill the browser with content from the server if UserRecord begin - rest get Files from `list/` cat `users/` cat UserHome cat `/scripts` + rest get Files from `ulist/` cat UserEmail cat `/` cat UserPassword cat `/` + cat `users/` cat UserHome cat `/scripts` put the json count of Files into FileCount put empty into Content put 0 into N diff --git a/iwsy/resources/ecs/scripted.txt b/iwsy/resources/ecs/scripted.txt index afee677..b9e61ab 100644 --- a/iwsy/resources/ecs/scripted.txt +++ b/iwsy/resources/ecs/scripted.txt @@ -129,7 +129,7 @@ put the content of ContentEditor into Content if Content is not Current begin - rest post Content to `save/ecs/` cat Name + rest post Content to `save/` cat Password cat `/ecs/` cat Name put Content into Current set the content of Status to `Script '` cat Name cat `' saved` fork to ResetStatus @@ -155,7 +155,7 @@ if confirm `Are you sure you want to delete '` cat Name cat `'?` begin codemirror close ContentEditor - rest post to `delete/ecs/` cat Name + rest post to `delete/` cat Password cat `/ecs/` cat Name set the content of Status to `Script '` cat Name cat `' deleted` set the content of NameEditor to empty put empty into Content @@ -173,7 +173,7 @@ DoOpen: begin if confirm `Content has changed. Do you want to save it?` begin - rest post Content to `save/ecs/' cat CurrentName + rest post Content to `save/` cat Password cat `/ecs/' cat CurrentName codemirror attach to ContentEditor codemirror set content of ContentEditor to Content end @@ -201,7 +201,7 @@ DoOpen: set style `display` of FileListing to `inline-block` ! Fill the browser with content from the server - rest get Files from `list/ecs?v=` cat now + rest get Files from `list/` cat Password cat `/ecs?v=` cat now put the json count of Files into FileCount put empty into Content put 0 into N diff --git a/iwsy/resources/ecs/user.txt b/iwsy/resources/ecs/user.txt index ce42007..72646ec 100644 --- a/iwsy/resources/ecs/user.txt +++ b/iwsy/resources/ecs/user.txt @@ -171,7 +171,6 @@ ProcessLogin: if Record is empty go to NoRecord if property `email` of Record is not EmailInput go to NoRecord put property `password` of Record into Password - replace `/` with `~` in Password rest get Validated from `validate/` cat Password cat `/` cat PasswordInput if Validated is `yes` begin diff --git a/iwsy/rest.php b/iwsy/rest.php index d7276ba..039120a 100644 --- a/iwsy/rest.php +++ b/iwsy/rest.php @@ -30,9 +30,15 @@ switch ($method) { case 'GET': switch ($action) { + + case 'test': + exit; + case 'list': // List the contents of a directory, starting at 'resources' - // Endpoint: {site root}/rest.php/_list/[{path}] + // Endpoint: {site root}/rest.php/list/password/[{path}] + $password = array_shift($request); + checkAdminPassword($password, $props['password']); $path = getcwd() . '/'; if (count($request)) { $path .= 'resources/' . join('/', $request); @@ -97,99 +103,30 @@ case 'validate': // Validate a hash // Endpoint: {site root}/rest.php/validate/{encrypted-value}/{value-to-validate} - print password_verify($request[1],str_replace('~', '/', $request[0])) ? 'yes' : 'no'; - exit; - - case 'exists': - // Test if a file exists - // Endpoint: {site root}/rest.php/_exists/{{path} - $path = getcwd() . '/' . join('/', $request); - print file_exists($path) ? 'Y' : ''; - exit; - - case 'load': - // Load a file from the resources folder - // Endpoint: {site root}/rest.php/_load/{path} - $path = getcwd() . '/' . join('/', $request); - print file_get_contents($path); - exit; - - case 'loadall': - // Load all the files in the named folder - // Endpoint: {site root}/rest.php/_loadall/{path} - $path = getcwd() . '/'; - if (count($request)) { - $path .= join('/', $request); - } - $files = scandir($path); - print '['; - $flag = false; - foreach ($files as $file) { - if (strpos($file, '.') !== 0) { - if (!is_dir("$path/$file")) { - if ($flag) { - print ','; - } else { - $flag = true; - } - print file_get_contents("$path/$file"); - } - } - } - print ']'; - exit; - - case 'test': - // Test endpoint - // Endpoint: {site root}/rest.php/_test/ - print $_SERVER['HTTP_HOST']; + print password_verify($request[1], $request[0]) ? 'yes' : 'no'; exit; } break; + case 'POST': switch ($action) { case 'mkdir': // Create a directory - // Endpoint: {site root}/rest.php/_mkdir/{path} + // Endpoint: {site root}/rest.php/mkdir/{path} $path = getcwd() . '/' . join('/', $request); + $path = preg_replace('/[^0-9\-.\/A-Za-z]/', '', $path); logger("Create directory $path"); print("Create directory $path"); mkdir($path); exit; - case 'upload': - // Upload a file (an image) to the current directory - // Endpoint: {site root}/rest.php/_upload/{path} - $path = $_POST['path']; - $path = explode("/", $path); - array_shift($path); - $path = join('/', $path); - mkdir($path, 0777, true); - logger("path: $path"); - $fileName = $_FILES['source']['name']; - $tempName = $_FILES['source']['tmp_name']; - $fileType = $_FILES['source']['type']; - $fileSize = $_FILES['source']['size']; - $fileError = $_FILES['source']['error']; - if (!move_uploaded_file($tempName, "$path/$fileName")) { - unlink($tempName); - http_response_code(400); - logger("Failed to upload $tempName to $fileName.\ntempName: $tempName\nfileType: $fileType\nfileSize:$fileSize\nfileError: $fileError"); - } else { - logger("File $fileName uploaded successfully to $path/$fileName"); - $size = getimagesize("$path/$fileName"); - logger("$path/$fileName: width:".$size[0].", height:".$size[1]); - if ($size[0] > 1024) { - logger("mogrify -resize 1024x1024 $path/$fileName"); - system("mogrify -resize 1024x1024 $path/$fileName"); - } - } - exit; - case 'save': // Save data to a file in the resources folder - // Endpoint: {site root}/rest.php/save/{path} + // Endpoint: {site root}/rest.php/save/password/{path} + $password = array_shift($request); + checkAdminPassword($password, $props['password']); $path = getcwd() . '/resources/' . join('/', $request); + $path = preg_replace('/[^0-9\-.\/A-Za-z]/', '', $path); $p = strrpos($path, '/'); $dir = substr($path, 0, $p); mkdir($dir, 0777, true); @@ -203,8 +140,11 @@ case 'delete': // Delete a file in the resources folder - // Endpoint: {site root}/rest.php/_delete/{path} + // Endpoint: {site root}/rest.php/delete/password/{path} + $password = array_shift($request); + checkAdminPassword($password, $props['password']); $path = getcwd() . '/resources/' . join('/', $request); + $path = preg_replace('/[^0-9\-.\/A-Za-z]/', '', $path); if (is_dir($path)) { rmdir($path); } else { @@ -244,11 +184,11 @@ switch ($method) { case 'GET': - get($conn, $action, $request); + get($conn, $props, $action, $request); break; case 'POST': - post($conn, $action, $request); + post($conn, $props, $action, $request); break; default: @@ -260,11 +200,12 @@ exit; // Database GET - function get($conn, $action, $request) { + function get($conn, $props, $action, $request) { switch ($action) { case 'email': // Endpoint: {site root}/rest.php/email/{email} $email= $request[0]; + $email = preg_replace('/[^A-Za-z0-9@\-.\/]/', '', $email); if ($email) { logger("SELECT * from users WHERE email='$email'"); $result = query($conn, "SELECT * from users WHERE email='$email'"); @@ -284,9 +225,11 @@ function get($conn, $action, $request) { case 'name': // Endpoint: {site root}/rest.php/name/{name} - if ($request[0]) { + $name = $request[0]; + if ($name) { + $name = preg_replace("/[^A-Za-z0-9\-\'.\/]/", '', $name); logger("SELECT * from users WHERE name='" . $request[0] . "'"); - $result = query($conn, "SELECT * from users WHERE name='" . $request[0] . "'"); + $result = query($conn, "SELECT * from users WHERE name='$name'"); if ($row = mysqli_fetch_object($result)) { $response->id = $row->id; $response->email = $row->email; @@ -300,6 +243,61 @@ function get($conn, $action, $request) { print "{\"message\":\"REST: Name is empty.\"}"; } break; + + case 'ulist': + // List the contents of a directory, starting at 'resources' + // Endpoint: {site root}/rest.php/ulist/email/password/[{path}] + $email = array_shift($request); + $password = array_shift($request); + checkUserPassword($conn, $email, $password); + $path = getcwd() . '/'; + if (count($request)) { + $path .= 'resources/' . join('/', $request); + } + $files = scandir($path); + print '['; + // First list all the directories + $flag = false; + foreach ($files as $file) { + if (strpos($file, '.') !== 0) { + if (is_dir("$path/$file")) { + if ($flag) { + print ','; + } else { + $flag = true; + } + print "{\"name\":\"$file\",\"type\":\"dir\"}"; + } + } + } + // Now do the ordinary files + foreach ($files as $file) { + if (strpos($file, '.') !== 0) { + if (!is_dir("$path/$file")) { + if ($flag) { + print ','; + } else { + $flag = true; + } + $type = 'file'; + $p = strrpos($file, '.'); + if ($p > 0) { + $ext = substr($file, $p + 1); + $type = $ext; + switch (strtolower($ext)) { + case 'jpg': + case 'png': + case 'gif': + $type = 'img'; + break; + } + } + print "{\"name\":\"$file\",\"type\":\"$type\"}"; + } + } + } + print ']'; + exit; default: http_response_code(404); @@ -309,9 +307,10 @@ function get($conn, $action, $request) { } // POST - function post($conn, $action, $request) { + function post($conn, $props, $action, $request) { $ts = time(); switch ($action) { + case 'user': // Endpoint: {site root}/rest.php/user header("Content-Type: application/json"); @@ -321,6 +320,9 @@ function post($conn, $action, $request) { $password = $json->password; $name = $json->name; // Check if this user is already present + $email = preg_replace('/[^A-Za-z0-9@\-.\/]/', '', $email); + $password = preg_replace('/[^A-Za-z0-9$\/.]/', '', $password); + $name = preg_replace("/[^A-Za-z0-9\-.\'\/]/", '', $name); $result = query($conn, "SELECT id FROM users WHERE email='$email'"); if ($row = mysqli_fetch_object($result)) { // Yes, so update the record @@ -332,10 +334,74 @@ function post($conn, $action, $request) { $day = str_pad(date('z'), 3, '0', STR_PAD_LEFT); logger("INSERT INTO users (email,password,name,year,day,ts) VALUES ('$email','$password','$name','$year','$day','$ts')"); query($conn, "INSERT INTO users (email,password,name,year,day,ts) VALUES ('$email','$password','$name','$year','$day','$ts')"); - mkdir("resources/$year/$day", 0777, true); + $id = $conn->insert_id; + mkdir("resources/users/$year/$day/$id", 0777, true); } mysqli_free_result($result); break; + + case 'usave': + // Save a json script + // Endpoint: {site root}/rest.php/usave/email/password/{path} + $email = array_shift($request); + $password = array_shift($request); + checkUserPassword($conn, $email, $password); + $path = getcwd() . '/resources/' . join('/', $request); + $p = strrpos($path, '/'); + $dir = substr($path, 0, $p); + mkdir($dir, 0777, true); + header("Content-Type: application/text"); + $content = stripslashes(file_get_contents("php://input")); + $p = strrpos($path, '.'); + $root = substr($path, 0, $p); + $ext = substr($path, $p); + file_put_contents($path, $content); + exit; + + case 'udelete': + // Delete a file in the resources folder + // Endpoint: {site root}/rest.php/udelete/email/password/{path} + $email = array_shift($request); + $password = array_shift($request); + checkUserPassword($conn, $email, $password); + $path = getcwd() . '/resources/' . join('/', $request); + if (is_dir($path)) { + rmdir($path); + } else { + unlink($path); + } + exit; + + case 'upload': + // Upload a file (an image) to the current directory + // Endpoint: {site root}/rest.php/upload/email/password/{path} + $email = array_shift($request); + $password = array_shift($request); + checkUserPassword($conn, $email, $password); + $path = $_POST['path']; + $path = explode("/", $path); + array_shift($path); + $path = 'resources/' . join('/', $path); + mkdir($path, 0777, true); + logger("path: $path"); + $fileName = $_FILES['source']['name']; + $tempName = $_FILES['source']['tmp_name']; + $fileType = $_FILES['source']['type']; + $fileSize = $_FILES['source']['size']; + $fileError = $_FILES['source']['error']; + if (!move_uploaded_file($tempName, "$path/$fileName")) { + unlink($tempName); + http_response_code(400); + logger("Failed to upload $tempName to $path/$fileName.\ntempName: $tempName\nfileType: $fileType\nfileSize:$fileSize\nfileError: $fileError"); + } else { + logger("File $fileName uploaded successfully to $path/$fileName"); + $size = getimagesize("$path/$fileName"); + logger("$path/$fileName: width:".$size[0].", height:".$size[1]); + if ($size[0] > 1024) { + logger("mogrify -resize 1024x1024 $path/$fileName"); + system("mogrify -resize 1024x1024 $path/$fileName"); + } + } default: http_response_code(400); @@ -344,6 +410,34 @@ function post($conn, $action, $request) { } } + ///////////////////////////////////////////////////////////////////////// + // Check the admin password + function checkAdminPassword($password, $encrypted) + { + if (password_verify($password, $encrypted)) { + return; + } + http_response_code(403); + print "{\"message\":\"REST: Bad password.\"}"; + exit; + } + + ///////////////////////////////////////////////////////////////////////// + // Check a user password + function checkUserPassword($conn, $email, $password) + { + $result = query($conn, "SELECT password FROM users WHERE email='$email'"); + if ($row = mysqli_fetch_object($result)) { + $encrypted = $row->password; + if (password_verify($password, $encrypted)) { + return; + } + } + http_response_code(403); + print "{\"message\":\"REST: Bad password.\"}"; + exit; + } + ///////////////////////////////////////////////////////////////////////// // Do an SQL query function query($conn, $sql)