F diff --git a/css/style.css b/css/style.css --- a/css/style.css +++ b/css/style.cssoverflow: hidden;}- .noselect {- user-select: none;- -webkit-user-select: none;- -ms-user-select: none;- }-#page {display: flex;flex: 1 0 0;}.window {- overflow: hidden;- box-sizing: border-box;margin: 0rem;padding: 0;box-shadow: 0 0.8rem 1.3rem rgba(0,0,0,0.2);flex-direction: column;}- .window.focus {- border-color: black;- }-.foldercontents, .filecontents {- background: rgba(250, 250, 250, .9);+ background: rgba(250, 250, 250, .8);flex: 1 0 0;}border-top-left-radius: 0.5rem;border-top-right-radius: 0.5rem;cursor: grab;-- user-select: none;- -webkit-user-select: none;- -ms-user-select: none;}.window h3 {}.file {- box-sizing: border-box;padding: 0.5rem;cursor: pointer;color: #333;background-image: url("/img/backdrop.jpg");background-size: cover;}-- .share_dialog_contents {- display: flex;- flex-direction: column;- background: white;- background: rgba(255,255,255, 0.9);- }F diff --git a/loggedin.js b/loggedin.js --- a/loggedin.js +++ b/loggedin.jsvar context_menu = null;var dragging = null;-- var dragging_candidate = null;- var dragging_candidate_x, dragging_candidate_y;-var dragging_fileview;var dragging_placeholder = null;var dragging_offset_x = 0, dragging_offset_y = 0;- var depth = 20;-class FileView {constructor(filename, visuals, mimetype, is_directory) {this.filename = filename;var d;if (i >= 0) {d = focus.pwd[i];- var separator_div = mk(the_path, 'div', 'separator');+ var separator_div = document.createElement('div');+ separator_div.classList.add('separator');+ the_path.appendChild(separator_div);separator_div.innerText = "ยป";}elsed = "Root";- var entry = mk(the_path, 'button', 'pathentry');++ var entry = document.createElement('button');+ entry.classList.add('pathentry');entry.innerText = d;+ the_path.appendChild(entry);add_link_functionality(entry, i + 1);}var folder = get_path();}- var wnd = make_share_window(folder, filename);- focus_window(wnd);+ var users = prompt("Enter comma separated list of users. empty = public", "");+ if (users === null)+ return;+ var password = prompt("Enter a passcode", "");+ if (password === null)+ return;+++ var data = new FormData();+ data.append('folder', folder);+ data.append('filename', filename);+ data.append('users', users);+ data.append('password', password);++ var xhr = new XMLHttpRequest();+ xhr.open('POST', '/php/share.php', true);+ xhr.onload = function () {+ }++ xhr.send(data);}function opendir() {if (dragging)end_drag();- // Inserted in place by begin_dragdragging_placeholder = document.createElement('div');dragging_fileview = fileview;dragging = fileview.visuals;- dragging.style.zIndex = 50000;- begin_drag(e, fileview.visuals);+ // document.body.appendChild(dragging);++ begin_drag(e, fileview.visuals,);}- function begin_drag(e, obj, dont_set_width) {+ function begin_drag(e, obj) {+dragging = obj;- dragging_candidate = null;dragging.classList.add("dragged");var elemRect = dragging.getBoundingClientRect();dragging_offset_x = e.clientX - elemRect.left;dragging_offset_y = -e.clientY + elemRect.top;+if (dragging_placeholder)obj.parentNode.insertBefore(dragging_placeholder, obj);dragging.style.left = (e.clientX - dragging_offset_x) + "px";dragging.style.top = (e.clientY + dragging_offset_y) + "px";- if (!dont_set_width) {- dragging.style.width = elemRect.width + "px";- dragging.style.height = elemRect.height + "px";- }+ dragging.style.width = elemRect.width + "px";+ dragging.style.height = elemRect.height + "px";dragging.style.position = "absolute";document.body.appendChild(dragging);}}- function focus_window(wnd) {- if (focus)- focus.visuals.classList.remove('focus');- focus = wnd;- if (wnd) {- wnd.visuals.classList.add('focus');- wnd.visuals.style.zIndex = depth ++;- }- }- function make_window_base(pwd, x, y, w, h) {+ function make_window(pwd) {var wnd = new Window(pwd);windows.push(wnd);- wnd.visuals = mk(document.body, 'div', 'window');-- wnd.visuals.style.width = w + "px";- wnd.visuals.style.height = h ? (h + "px") : "unset";- wnd.visuals.style.position = "absolute";- wnd.visuals.style.left = x + "px";- wnd.visuals.style.top = y + "px";-- wnd.h2 = mk(wnd.visuals, 'h2');-- wnd.visuals.onmousedown = (e) => {- focus_window(wnd);- }-- wnd.h2.onmousedown = (e) => {- if (!dragging) {- dragging_candidate = wnd.visuals;- dragging_candidate_x = e.clientX;- dragging_candidate_y = e.clientY;- }- };-- return wnd;- }-- function mk(parent, type, _class) {- var el = document.createElement(type);- parent.appendChild(el);- if (_class)- el.classList.add(_class);- return el;- }-- function mkhdiv(parent) {- var hdiv = mk(parent, 'div');- hdiv.style.display = "flex";- hdiv.style.alignItems = "center";- hdiv.style.padding = "0.3rem";- hdiv.style.gap = "0.3rem";- return hdiv;- }-- function mkcheckbox(parent, label, togglefn) {- var hdiv = mkhdiv(parent);-- var write_checkbox = mk(hdiv, 'input');- write_checkbox.type = 'checkbox';-- var write_checkbox_label = mk(hdiv, 'label');- write_checkbox_label.innerText = label;- write_checkbox_label.onclick = (e) => { write_checkbox.click(); }- write_checkbox_label.classList.add('noselect');-- write_checkbox.onchange = (_e) => {- togglefn(write_checkbox.checked);- };- }-- function make_share_window(folder, filename) {- var wnd = make_window_base(null, 400, 400, 400, 0);-- wnd.h2.innerText = "Share " + filename;- wnd.h2.style.padding = "0.2rem 0.4rem";-- wnd.foldercontents = mk(wnd.visuals, 'div', 'share_dialog_contents');- wnd.foldercontents.style.padding = "0.5rem";-- var data = {- write_permissions: false,- private: false,- has_password: false,- password: "",- userlist: [],- }-- var userlist, add_user;- mkcheckbox(wnd.foldercontents, "Private link", (toggled) => {- add_user.style.display = toggled ? "block" : "none";- userlist.style.display = toggled ? "block" : "none";- data.private = toggled;- });-- userlist = mk(wnd.foldercontents, 'div');- userlist.style.display = "none";- add_user = mk(wnd.foldercontents, 'button');- add_user.innerText = "Add user";- add_user.style.display = "none";-- add_user.onclick = (e) => {- var i = mk(userlist, 'input');- i.value = 'John Doe';-- let index = data.userlist.length;- data.userlist.push(i.value);-- i.onchange = (e) => {- data.userlist[index] = i.value;- }- }+ var wnd_html = document.createElement('div');+ wnd_html.classList.add('window');- // Click the add_user to add a default user- add_user.click();-- mkcheckbox(wnd.foldercontents, "Give write permissions", (toggled) => {- data.write_permissions = toggled;- });-- let password_container;- mkcheckbox(wnd.foldercontents, "Password protected", (toggled) => {- data.has_password = toggled;- password_container.style.display = toggled ? "flex" : "none";- });-- password_container = mkhdiv(wnd.foldercontents);- password_container.style.display = 'none'- var password_label = mk(password_container, 'label');- password_label.innerText = "Password";- var password_input = mk(password_container, 'input');- password_input.type = 'password';- password_input.style.flex = "1 0 0";- password_input.onchange = (_e) => {- data.password = password_input.value;- };+ var h2 = document.createElement('h2');+ wnd_html.appendChild(h2);- var generate_url_button = mk(wnd.foldercontents, 'button');- generate_url_button.innerText = "Generate link";+ //h2.onmousedown = (e) => {+ //begin_drag(e, wnd_html);+ // e.preventDefault();+ //};- generate_url_button.onclick = () => {- console.log(data);+ path = document.createElement('div');+ path.classList.add('path');+ h2.appendChild(path);- var users = "";- if (data.private) {- users = data.userlist.join(',');- }+ wnd_html.style.width = "900px";+ wnd_html.style.height = "600px";+ wnd_html.style.position = "absolute";+ wnd_html.style.left = "200px";+ wnd_html.style.top = "100px";- var form_data = new FormData();- form_data.append('folder', folder);- form_data.append('filename', filename);- form_data.append('users', users);- form_data.append('password', data.has_password ? data.password : "");-- var xhr = new XMLHttpRequest();- xhr.open('POST', '/php/share.php', true);- xhr.onload = function () {- alert(xhr.response);- }-- xhr.send(form_data);- delete_window();- }-- return wnd;- }-- function delete_window() {- var index = windows.indexOf(focus);- if (index >= 0) {- windows.splice(index, 1);- }- focus.visuals.parentNode.removeChild(focus.visuals);- fous = null;- }-- function make_window(pwd) {- var wnd = make_window_base(pwd, 100, 100, 800, 600);-- path = mk(wnd.h2, 'div', 'path');+ wnd.visuals = wnd_html;{- wnd.foldercontents = mk(wnd.visuals, 'div', 'foldercontents');- var h3 = mk(wnd.foldercontents, 'h3');+ wnd.foldercontents = document.createElement('div');+ wnd.foldercontents.classList.add('foldercontents');+ wnd_html.appendChild(wnd.foldercontents);++ var h3 = document.createElement('h3');+ wnd.foldercontents.appendChild(h3);- var upload_btn = mk(h3, 'button');+ var upload_btn = document.createElement('button');upload_btn.innerText = "Upload";upload_btn.onclick = () => { begin_upload(); }+ h3.appendChild(upload_btn);- mk(h3, 'div', 'separator');+ var separator = document.createElement('div');+ separator.classList.add('separator');+ h3.appendChild(separator);- var new_folder_btn = mk(h3, 'button');+ var new_folder_btn = document.createElement('button');new_folder_btn.innerText = "New Folder";new_folder_btn.onclick = () => { new_folder(); }+ h3.appendChild(new_folder_btn);- mk(h3, 'div', 'separator');+ separator = document.createElement('div');+ separator.classList.add('separator');+ h3.appendChild(separator);- wnd.filegrid = mk(wnd.foldercontents, 'div', 'files');+ wnd.filegrid = document.createElement('div');+ wnd.filegrid.classList.add('files');+ wnd.foldercontents.appendChild(wnd.filegrid);}{- wnd.filecontentsroot = mk(wnd.visuals, 'div');- var h3 = mk(wnd.filecontentsroot, 'h3');+ wnd.filecontentsroot = document.createElement('div');+ wnd_html.appendChild(wnd.filecontentsroot);++ var h3 = document.createElement('h3');+ wnd.filecontentsroot.appendChild(h3);- var download_btn = mk(h3, 'button');+ var download_btn = document.createElement('button');download_btn.innerText = "Download";download_btn.onclick = () => { download_file(); }+ h3.appendChild(download_btn);- mk(h3, 'div', 'separator');+ separator = document.createElement('div');+ separator.classList.add('separator');+ h3.appendChild(separator);- var download_btn = mk(h3, 'button');+ var download_btn = document.createElement('button');download_btn.innerText = "Share";download_btn.onclick = () => { share(true); }-- mk(h3, 'div', 'separator');+ h3.appendChild(download_btn);++ separator = document.createElement('div');+ separator.classList.add('separator');+ h3.appendChild(separator);++ wnd.filecontents = document.createElement('div');+ wnd.filecontents.classList.add('filecontents');+ wnd.filecontentsroot.appendChild(wnd.filecontents);- wnd.filecontents = mk(wnd.filecontentsroot, 'div', 'filecontents');}+ document.body.appendChild(wnd_html);return wnd;}// Is the current filewview the trash folder itselfvar is_trash = focus.pwd.length == 0 && fileview.filename == "trash";- var visuals = mk(focus.filegrid, 'div');+ var visuals = document.createElement('div');fileview.visuals = visuals;var img = document.createElement('img');img.src=`/mimeicons/${fileview.mimetype.replace("/", "-")}.png`;}- fileview.visuals.onclick = () => {+ visuals.onclick = () => {focus.pwd.push(fileview.filename);openfile(fileview.is_directory);}visuals.appendChild(img);visuals.appendChild(filename);+ focus.filegrid.appendChild(visuals);}function begin_upload() {if (context_menu)context_menu.remove();- context_menu = mk(document.body, 'ul', 'context');-- context_menu.onmousedown = (e) => {- e.stopPropagation();- }+ context_menu = document.createElement('ul');+ context_menu.classList.add('context');context_menu.style.left = e.clientX + "px";context_menu.style.top = e.clientY + "px";li.onclick = e[1];context_menu.appendChild(li);}++ document.body.appendChild(context_menu);}function get_path(max_length) {dragging.style.left = (e.clientX - dragging_offset_x) + "px";dragging.style.top = (e.clientY + dragging_offset_y) + "px";}- else if (dragging_candidate) {- var d = Math.abs(e.clientX - dragging_candidate_x) + Math.abs(e.clientY - dragging_candidate_y);- if (d > 15)- begin_drag(e, dragging_candidate, true);- }- }-- document.body.onmousedown = (_e) => {- if (context_menu)- context_menu.remove();}document.body.onmouseup = (_e) => {- if (dragging_candidate)- dragging_candidate = null;if (dragging)end_drag();}context_menu.remove();}+var root_window = make_window([]);- focus_window(root_window);+ focus = root_window;openfile(true);F diff --git a/php/.configuration.php.swp b/php/.configuration.php.swp deleted file mode 100644B Binary files a/php/.configuration.php.swp and /dev/null differF diff --git a/php/configuration.php b/php/configuration.php --- a/php/configuration.php +++ b/php/configuration.php<?php/*should be placed outside of document root*/- $domain_name="localhost";+ $use_https=true;if (file_exists("/home/alex")) {- $database_name="alex";- $database_username="alex";- $database_password="lol";- $database_location="127.0.0.1";+ $domain_name="localhost";+ $database_name="alex";+ $database_username="alex";+ $database_password="lol";+ $database_location="127.0.0.1";- $storage_root = "/home/alex/fileup_storage";+ $storage_root = "/home/alex/fileup_storage";}else {-- $database_name="fileup_testing";- $database_username="outsider";- $database_password="parola123";- $database_location="localhost";- /*storage root must be in the webroot*/- $storage_root = "/srv/apache/testing/project/files/";+ $domain_name="testing";+ $database_name="fileup_testing";+ $database_username="outsider";+ $database_password="parola123";+ $database_location="localhost";+ /*storage root must be in the webroot*/+ $storage_root = "/srv/apache/testing/project/files/";}/*if we save deleted files just in case of an error*/F diff --git a/php/database.php b/php/database.php --- a/php/database.php +++ b/php/database.phpwhere name=:name");$statement->bindParam(':name',$name);- if($statement->execute()==NULL)+ if($statement->execute()==false){error_log("there was a problem with the sql statement at get_nodes_with_name");- return [];+ return NULL;}return $statement->fetchAll(PDO::FETCH_ASSOC);}- /*returns assoc array*/+ /*returns id*/function get_node_with_code($code){$statement=$this->pdo->prepare(where code=:code");$statement->bindParam(':code',$code);- if($statement->execute()==NULL)+ if($statement->execute()==false){error_log("there was a problem with the sql statement at get_nodes_with_code");- return [];+ return NULL;}- return $statement->fetch(PDO::FETCH_ASSOC);+ $ret= $statement->fetch(PDO::FETCH_ASSOC);+ return $ret["id"];}/* I think this only makes sense if node is a dir*//* returns assoc array of nodes*//*give premissions*/$id=$this->get_node_with_code($code_name);- if(count($id)!=1)+ if($id!=NULL){error_log("created a dangling directory but couldn't find it afterward. Fatal error!");exit(1);}}+ function create_shared_node(string $password,int $node_id):bool+ {+ $prep=$this->pdo->prepare("insert into shared_nodes(node_id,passcode)+ values (:id,:pass)+ ");+ $prep->bindParam(':id',$node_id);+ $prep->bindParam(':pass',$password);+ if($prep->execute()==false)+ {+ error_log("could not create shared node in create_shared_node");+ return false;+ }+ return true;+ }+ function get_node(int $node_id)+ {+ $prep=$this->pdo->prepare("select * from nodes where node_id=:id");+ $prep->bindParam(':id',$node_id);+ if($prep->execute()==false)+ {+ error_log("sql statement at get_node failed");+ return NULL;+ }+ $nod=$prep->fetch(PDO::FETCH_ASSOC);+ $ret=new Node();+ $ret->node_id=$nod["node_id"];+ $ret->is_directory=$nod["is_directory"];+ $ret->relative_path=$nod["relative_path"];+ $ret->type=$nod["type"];+ $ret->code=$nod["code"];++ return $ret;++ }/*returns the file name as it must be in the filesystem relative to the storage root*/function create_file_node(string $filename,string $note,int $dir_id,string $mimetype,User $user): string{{error_log("could not exedude dir sql statement in create_file_node");return "error";- }+ }- $dir=$dir_prep->fetch(PDO::FETCH_ASSOC);+ $dir=$dir_prep->fetch(PDO::FETCH_ASSOC);if($dir == false){error_log("create_file_node dir isnt a directory");/*not so quiet error*/return "error";}- $new_id=$this->get_node_with_code($code)["id"];+ $new_id=$this->get_node_with_code($code);/*link the node to the directory*/$this->link_nodes($dir_id,$new_id,$filename,$note);/*give premissions to the creator*/F diff --git a/php/node.php b/php/node.php --- a/php/node.php +++ b/php/node.phprequire_once "database.php";require_once "user.php";+ class Node+ {+ public $node_id;+ public $is_directory;+ public $relative_path;+ public $type;+ public $code;+ }/*path is in terms of the simulated filesystem*/+ /*returns NULL on error*/function get_directory(string $abstract_path,User $user){$parent_dir_id=get_directory($abstract_path,$user);$database->unlink_nodes($parent_dir_id,$filename);}+ function create_share_link(string $abstract_path,string $filename,string $password,User $user,bool $can_read,bool $can_write)+ {+ global $database;+ global $domain_name;+ global $use_https;++ $dir_id=get_directory($abstract_path,$user);+ if($dir_id==NULL)+ {+ return NULL;+ }+ $node_id=get_node_id($filename,$dir_id);+ if($node_id==NULL)+ {+ return NULL;+ }+ if($database->create_shared_node($password,$node_id)==false)+ {+ return NULL;+ }++ $code=$database->get_code_of_node($node_id);+ if($code==NULL)+ {+ return NULL;+ }+ if($use_https)+ {+ return "https://".$domain_name."/share?file=".$code;+ }else+ {+ return "http://".$domain_name."/share?file=".$code;+ }+ }?>F diff --git a/php/readfile.php b/php/readfile.php --- a/php/readfile.php +++ b/php/readfile.php}header("Content-type: $file_node[mimetype]");-readfile("$storage_root/$file_node[code]");F diff --git a/php/share.php b/php/share.php new file mode 100644 --- /dev/null +++ b/php/share.php+ <?php+ require_once "configuration.php";+ require_once "database.php";+ require_once "user.php";+ session_start();++ $user=$_SESSION['user_object'];+++ if($_SERVER["REQUEST_METHOD"] == "POST")+ {+ $path=$_POST["folder"];+ /*this could be a directory as well*/+ $filename=$_POST["filename"];+ $users=$_POST["users"];+ $password=$_POST["password"];+ $premissions=$_POST["premissions"];++ if($premissions==1)+ {+ $can_read=true;+ $can_write=false;+ }else if($premissions==3)+ {+ $can_read=true;+ $can_write=true;+ }+ else+ {+ http_response_code(409);+ error_log("someone gave wrong premmissions =".$premissions."! This could be an attack");+ exit(1);+ }++ $share_link=create_share_link($path,$filename,$password,$user,$can_read,$can_write);++ if($share_link==NULL)+ {+ http_response_code(409);+ }+ echo $share_link;+ http_response_code(200);+ exit(0);+ }else if($_SERVER["REQUEST_METHOD"]== "GET")+ {+ $code=$_GET["code"];+ $file_id=$database->get_node_with_code($code);+ if($file_id==NULL)+ {+ http_response_code(409);+ exit(0);+ }+ $premissions=$database->get_premissions($file_id,$user->user_id);+ if($premissions["can_view"]==true)+ {+ $node=$database->get_node($file_id);+ if($node->is_directory)+ {+ /*spooky stuff here*/+ http_response_code(409);+ exit(1);+ }else+ {+ header("Content-type: $node[type]");+ readfile("$storage_root/$node[code]");+ }+ }++++ }else+ {+ http_response_code(409);+ exit(0);+ }+ ?>F diff --git a/sql/fileshare.sql b/sql/fileshare.sql --- a/sql/fileshare.sql +++ b/sql/fileshare.sqlforeign key (node_id) references nodes(node_id) on delete cascade);+ /*we store passwords for the shared links here, it doesn't really have anything to do with the filesystem*/+ create table shared_nodes (+ node_id int not null,+ passcode varchar(100) default "",+ foreign key (node_id) references nodes(node_id) on delete cascade+ );+create table trash (node_id int not null);