From c08751c7f8a13b7182dd6b3f8a756e4a9844d6e4 Mon Sep 17 00:00:00 2001 From: LukasDoesDev Date: Fri, 15 Jan 2021 00:55:14 +0200 Subject: [PATCH 1/6] FILES: Got everything working except Tornado seems to escape my HTML output, works if you set the output to the DOM and run the script below it. --- app/classes/shared/helpers.py | 12 ++++ app/classes/web/panel_handler.py | 19 ++++- app/frontend/templates/main_menu.html | 8 +++ .../panel/{files_menu.html => files.html} | 69 +++++++++++++++++-- 4 files changed, 102 insertions(+), 6 deletions(-) rename app/frontend/templates/panel/{files_menu.html => files.html} (74%) diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index 89b7ad5d..d415ae71 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -454,6 +454,18 @@ class Helpers: return data + @staticmethod + def generate_tree(folder, html=""): + for filename in os.listdir(folder): + print(filename) + rel = os.path.join(folder, filename) + if os.path.isdir(rel): + html += '
  • \n{}\n' + else: + html += '
  • {}
  • '.format(filename) + return html helper = Helpers() diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index fcf5c192..d9ca5408 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -62,8 +62,23 @@ class PanelHandler(BaseHandler): elif page == 'file_edit': template = "panel/file_edit.html" - elif page == 'files_menu': - template = "panel/files_menu.html" + elif page == 'files': + server_id = self.get_argument('id', None) + + if server_id is None: + self.redirect("/panel/error?error=Invalid Server ID") + return False + else: + server_id = bleach.clean(server_id) + + # does this server id exist? + if not db_helper.server_id_exists(server_id): + self.redirect("/panel/error?error=Invalid Server ID") + return False + + page_data['tree_html'] = helper.generate_tree(db_helper.get_server_data_by_id(server_id)['path']) + + template = "panel/files.html" elif page == "remove_server": server_id = self.get_argument('id', None) diff --git a/app/frontend/templates/main_menu.html b/app/frontend/templates/main_menu.html index 8e6b6d97..3745a667 100644 --- a/app/frontend/templates/main_menu.html +++ b/app/frontend/templates/main_menu.html @@ -64,6 +64,14 @@ {% end %} + + diff --git a/app/frontend/templates/panel/files_menu.html b/app/frontend/templates/panel/files.html similarity index 74% rename from app/frontend/templates/panel/files_menu.html rename to app/frontend/templates/panel/files.html index 0f883903..1d8e18b8 100644 --- a/app/frontend/templates/panel/files_menu.html +++ b/app/frontend/templates/panel/files.html @@ -27,7 +27,68 @@
    -
    +
    + +
      +
    • + Files +
        + {{ data['tree_html'] }} + +
      +
    • +
    +
    + +
    +
    + + + + + --a>
    - + --> From eba7bff050d4bd4c85b1ffbb58fe830a4383ab55 Mon Sep 17 00:00:00 2001 From: LukasDoesDev Date: Fri, 15 Jan 2021 14:13:06 +0200 Subject: [PATCH 2/6] Now can see a tree view of the directory the server is in. Will do file editing now. --- app/classes/shared/helpers.py | 2 +- app/classes/web/panel_handler.py | 25 +- app/frontend/templates/panel/files.html | 173 ---------- .../templates/panel/server_files.html | 296 ++++++++++++++++++ 4 files changed, 303 insertions(+), 193 deletions(-) delete mode 100644 app/frontend/templates/panel/files.html create mode 100644 app/frontend/templates/panel/server_files.html diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index d415ae71..24256081 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -462,7 +462,7 @@ class Helpers: if os.path.isdir(rel): html += '
  • \n{}\n
      '.format(filename) html += helper.generate_tree(rel) - html += '
    ' + html += '\n
  • ' else: html += '
  • {}
  • '.format(filename) return html diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index d9ca5408..d284facc 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -62,24 +62,6 @@ class PanelHandler(BaseHandler): elif page == 'file_edit': template = "panel/file_edit.html" - elif page == 'files': - server_id = self.get_argument('id', None) - - if server_id is None: - self.redirect("/panel/error?error=Invalid Server ID") - return False - else: - server_id = bleach.clean(server_id) - - # does this server id exist? - if not db_helper.server_id_exists(server_id): - self.redirect("/panel/error?error=Invalid Server ID") - return False - - page_data['tree_html'] = helper.generate_tree(db_helper.get_server_data_by_id(server_id)['path']) - - template = "panel/files.html" - elif page == "remove_server": server_id = self.get_argument('id', None) server_data = controller.get_server_data(server_id) @@ -121,10 +103,15 @@ class PanelHandler(BaseHandler): self.redirect("/panel/error?error=Invalid Server ID") return False - valid_subpages = ['term', 'logs', 'config'] + valid_subpages = ['term', 'logs', 'config', 'files'] if subpage not in valid_subpages: + console.debug('not a valid subpage') subpage = 'term' + console.debug('Subpage: "{}"'.format(subpage)) + if subpage == 'files': + console.debug('Subpage is "files"') + page_data['tree_html'] = helper.generate_tree(db_helper.get_server_data_by_id(server_id)['path']) # server_data isn't needed since the server_stats also pulls server data # page_data['server_data'] = db_helper.get_server_data_by_id(server_id) diff --git a/app/frontend/templates/panel/files.html b/app/frontend/templates/panel/files.html deleted file mode 100644 index 1d8e18b8..00000000 --- a/app/frontend/templates/panel/files.html +++ /dev/null @@ -1,173 +0,0 @@ -{% extends ../base.html %} - -{% block meta %} - -{% end %} - -{% block title %}Crafty Controller - Looking at files in server -< server name >- (-< server path id >-){% end %} - -{% block content %} - -
    - - -
    -
    - -
    - -
    - - -
    - -
    - -
      -
    • - Files -
        - {{ data['tree_html'] }} - -
      -
    • -
    -
    - -
    -
    - - - - -
    - - -
    - - -{% end %} - -{% block js %} - - - -{% end %} \ No newline at end of file diff --git a/app/frontend/templates/panel/server_files.html b/app/frontend/templates/panel/server_files.html new file mode 100644 index 00000000..3d54a248 --- /dev/null +++ b/app/frontend/templates/panel/server_files.html @@ -0,0 +1,296 @@ +{% extends ../base.html %} + +{% block meta %} + +{% end %} + +{% block title %}Crafty Controller - Server Details{% end %} + +{% block content %} + +
    + + +
    +
    + +
    + +
    + + + {% include "parts/details_stats.html %} + +
    + +
    +
    +
    + + +
    +
    + +
      +
    • + Files +
        +
      • Error while getting files
      • + +
      +
    • +
    +
    + +
    + TODO: edit files

    + Editing file +
    file_contents
    +

    + +
    + + +
    + +
    +
    +
    +
    + + + +
    + + +{% end %} + +{% block js %} + + + + +{% end %} \ No newline at end of file From 75fb8fc9201c3bd67995a8236e8d0cca961d8ed8 Mon Sep 17 00:00:00 2001 From: LukasDoesDev Date: Fri, 15 Jan 2021 14:33:17 +0200 Subject: [PATCH 3/6] (Maybe) fix potential code injection attack --- app/classes/shared/helpers.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index 24256081..f1f81bae 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -9,6 +9,7 @@ import base64 import socket import random import logging +import html from datetime import datetime from socket import gethostname @@ -455,17 +456,19 @@ class Helpers: return data @staticmethod - def generate_tree(folder, html=""): + def generate_tree(folder, output=""): for filename in os.listdir(folder): + print(filename) + filename = html.escape(filename) print(filename) rel = os.path.join(folder, filename) if os.path.isdir(rel): - html += '
  • \n{}\n
      '.format(filename) - html += helper.generate_tree(rel) - html += '
    \n
  • ' + output += '
  • \n{}\n
      '.format(filename) + output += helper.generate_tree(rel) + output += '
    \n
  • ' else: - html += '
  • {}
  • '.format(filename) - return html + output += '
  • {}
  • '.format(filename) + return output helper = Helpers() From eb06f1b33bab49fa7421bca6bbd6ba103eced323 Mon Sep 17 00:00:00 2001 From: LukasDoesDev Date: Fri, 15 Jan 2021 21:59:58 +0200 Subject: [PATCH 4/6] Now can edit files. Also fixed a bunch of bugs. --- app/classes/shared/helpers.py | 16 +++-- app/classes/web/ajax_handler.py | 68 +++++++++++++++++++ .../templates/panel/server_files.html | 45 +++++++++++- 3 files changed, 121 insertions(+), 8 deletions(-) diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index f1f81bae..46e2e4e4 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -457,18 +457,24 @@ class Helpers: @staticmethod def generate_tree(folder, output=""): - for filename in os.listdir(folder): + for raw_filename in os.listdir(folder): + print(raw_filename) + filename = html.escape(raw_filename) print(filename) - filename = html.escape(filename) - print(filename) - rel = os.path.join(folder, filename) + rel = os.path.join(folder, raw_filename) if os.path.isdir(rel): output += '
  • \n{}\n
      '.format(filename) output += helper.generate_tree(rel) output += '
    \n
  • ' else: - output += '
  • {}
  • '.format(filename) + console.debug('os.path.isdir(rel): "{}", rel: "{}"'.format(os.path.isdir(rel), rel)) + output += '
  • {}
  • '\ + .format(os.path.join(folder, filename), filename) return output + @staticmethod + def in_path(x, y): + return os.path.abspath(y).__contains__(os.path.abspath(x)) + helper = Helpers() diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index 03641140..f7f75190 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -3,6 +3,7 @@ import logging import tornado.web import tornado.escape import bleach +import os from app.classes.shared.console import console from app.classes.shared.models import Users, installer @@ -79,6 +80,42 @@ class AjaxHandler(BaseHandler): page_data['notify_data'] = data self.render_page('ajax/notify.html', page_data) + elif page == "get_file": + file_path = self.get_argument('file_path', None) + server_id = self.get_argument('id', None) + + if server_id is None: + logger.warning("Server ID not found in get_file ajax call") + console.warning("Server ID not found in get_file ajax call") + return False + else: + server_id = bleach.clean(server_id) + + # does this server id exist? + if not db_helper.server_id_exists(server_id): + logger.warning("Server ID not found in get_file ajax call") + console.warning("Server ID not found in get_file ajax call") + return False + + if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], file_path)\ + or not helper.check_file_exists(os.path.abspath(file_path)): + logger.warning("Invalid path in get_file ajax call") + console.warning("Invalid path in get_file ajax call") + if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], file_path): + console.warning('1') + elif not helper.check_file_exists(os.path.abspath(file_path)): + console.warning('2') + else: + console.warning('3') + return False + + file = open(file_path) + file_contents = file.read() + file.close() + + console.debug("Send file contents") + self.write(file_contents) + self.finish() def post(self, page): user_data = json.loads(self.get_secure_cookie("user_data")) @@ -95,6 +132,7 @@ class AjaxHandler(BaseHandler): if server_id is None: logger.warning("Server ID not found in send_command ajax call") + console.warning("Server ID not found in send_command ajax call") srv_obj = controller.get_server_obj(server_id) @@ -102,3 +140,33 @@ class AjaxHandler(BaseHandler): if srv_obj.check_running(): srv_obj.send_command(command) + elif page == "save_file": + file_contents = bleach.clean(self.get_body_argument('file_contents', default=None, strip=True)) + file_path = bleach.clean(self.get_body_argument('file_path', default=None, strip=True)) + server_id = self.get_argument('id', None) + print(file_contents) + print(file_path) + print(server_id) + + if server_id is None: + logger.warning("Server ID not found in save_file ajax call") + console.warning("Server ID not found in save_file ajax call") + return False + else: + server_id = bleach.clean(server_id) + + # does this server id exist? + if not db_helper.server_id_exists(server_id): + logger.warning("Server ID not found in save_file ajax call") + console.warning("Server ID not found in save_file ajax call") + return False + + if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], file_path)\ + or not helper.check_file_exists(os.path.abspath(file_path)): + logger.warning("Invalid path in save_file ajax call") + console.warning("Invalid path in save_file ajax call") + return False + + # Open the file in write mode and store the content in file_object + with open(file_path, 'w') as file_object: + file_object.write(file_contents) \ No newline at end of file diff --git a/app/frontend/templates/panel/server_files.html b/app/frontend/templates/panel/server_files.html index 3d54a248..e3267cb6 100644 --- a/app/frontend/templates/panel/server_files.html +++ b/app/frontend/templates/panel/server_files.html @@ -108,7 +108,6 @@ }
    - TODO: edit files

    Editing file
    file_contents

    @@ -155,8 +154,17 @@ From e3a359bbc6c5282597cea8cd10ca70f413366813 Mon Sep 17 00:00:00 2001 From: LukasDoesDev Date: Sun, 17 Jan 2021 19:20:28 +0200 Subject: [PATCH 5/6] File Manager: DONE --- app/classes/shared/controller.py | 2 +- app/classes/shared/helpers.py | 16 +- app/classes/shared/server.py | 2 +- app/classes/web/ajax_handler.py | 196 +++++++++- app/classes/web/panel_handler.py | 3 - .../templates/panel/server_files.html | 370 ++++++++++++++++-- 6 files changed, 544 insertions(+), 45 deletions(-) diff --git a/app/classes/shared/controller.py b/app/classes/shared/controller.py index 805abe5d..54c858eb 100644 --- a/app/classes/shared/controller.py +++ b/app/classes/shared/controller.py @@ -49,7 +49,7 @@ class Controller: continue # if this server path no longer exists - let's warn and bomb out - if not helper.check_path_exits(s['path']): + if not helper.check_path_exists(s['path']): logger.warning("Unable to find server {} at path {}. Skipping this server".format(s['server_name'], s['path'])) diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py index 46e2e4e4..3cba2eea 100644 --- a/app/classes/shared/helpers.py +++ b/app/classes/shared/helpers.py @@ -272,7 +272,7 @@ class Helpers: return "%.1f%s%s" % (num, 'Y', suffix) @staticmethod - def check_path_exits(path: str): + def check_path_exists(path: str): logger.debug('Looking for path: {}'.format(path)) if os.path.exists(path): @@ -463,13 +463,21 @@ class Helpers: print(filename) rel = os.path.join(folder, raw_filename) if os.path.isdir(rel): - output += '
  • \n{}\n
      '.format(filename) + output += \ + """
    • + \n
      {}
      + \n
        """\ + .format(os.path.join(folder, filename), os.path.join(folder, filename), filename, filename) + output += helper.generate_tree(rel) output += '
      \n
    • ' else: console.debug('os.path.isdir(rel): "{}", rel: "{}"'.format(os.path.isdir(rel), rel)) - output += '
    • {}
    • '\ - .format(os.path.join(folder, filename), filename) + output += """
    • {}
    • """.format(os.path.join(folder, filename), filename, filename) return output @staticmethod diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index a52cb73a..54d3b618 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -96,7 +96,7 @@ class Server: console.critical("Server executable path: {} does not seem to exist".format(full_path)) helper.do_exit() - if not helper.check_path_exits(self.server_path): + if not helper.check_path_exists(self.server_path): logger.critical("Server path: {} does not seem to exits".format(self.server_path)) console.critical("Server path: {} does not seem to exits".format(self.server_path)) helper.do_exit() diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index f7f75190..13331e71 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -4,6 +4,7 @@ import tornado.web import tornado.escape import bleach import os +import shutil from app.classes.shared.console import console from app.classes.shared.models import Users, installer @@ -101,12 +102,6 @@ class AjaxHandler(BaseHandler): or not helper.check_file_exists(os.path.abspath(file_path)): logger.warning("Invalid path in get_file ajax call") console.warning("Invalid path in get_file ajax call") - if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], file_path): - console.warning('1') - elif not helper.check_file_exists(os.path.abspath(file_path)): - console.warning('2') - else: - console.warning('3') return False file = open(file_path) @@ -117,6 +112,26 @@ class AjaxHandler(BaseHandler): self.write(file_contents) self.finish() + elif page == "get_tree": + server_id = self.get_argument('id', None) + + if server_id is None: + logger.warning("Server ID not found in get_file ajax call") + console.warning("Server ID not found in get_file ajax call") + return False + else: + server_id = bleach.clean(server_id) + + # does this server id exist? + if not db_helper.server_id_exists(server_id): + logger.warning("Server ID not found in get_file ajax call") + console.warning("Server ID not found in get_file ajax call") + return False + + self.write(db_helper.get_server_data_by_id(server_id)['path'] + '\n' + + helper.generate_tree(db_helper.get_server_data_by_id(server_id)['path'])) + self.finish() + def post(self, page): user_data = json.loads(self.get_secure_cookie("user_data")) error = bleach.clean(self.get_argument('error', "WTF Error!")) @@ -127,8 +142,8 @@ class AjaxHandler(BaseHandler): } if page == "send_command": - command = bleach.clean(self.get_body_argument('command', default=None, strip=True)) - server_id = bleach.clean(self.get_argument('id')) + command = self.get_body_argument('command', default=None, strip=True) + server_id = self.get_argument('id') if server_id is None: logger.warning("Server ID not found in send_command ajax call") @@ -140,9 +155,125 @@ class AjaxHandler(BaseHandler): if srv_obj.check_running(): srv_obj.send_command(command) - elif page == "save_file": - file_contents = bleach.clean(self.get_body_argument('file_contents', default=None, strip=True)) - file_path = bleach.clean(self.get_body_argument('file_path', default=None, strip=True)) + elif page == "create_file": + file_parent = self.get_body_argument('file_parent', default=None, strip=True) + file_name = self.get_body_argument('file_name', default=None, strip=True) + file_path = os.path.join(file_parent, file_name) + server_id = self.get_argument('id', None) + print(server_id) + + if server_id is None: + logger.warning("Server ID not found in create_file ajax call") + console.warning("Server ID not found in create_file ajax call") + return False + else: + server_id = bleach.clean(server_id) + + # does this server id exist? + if not db_helper.server_id_exists(server_id): + logger.warning("Server ID not found in create_file ajax call") + console.warning("Server ID not found in create_file ajax call") + return False + + if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], file_path) \ + or helper.check_file_exists(os.path.abspath(file_path)): + logger.warning("Invalid path in create_file ajax call") + console.warning("Invalid path in create_file ajax call") + return False + + # Create the file by opening it + with open(file_path, 'w') as file_object: + file_object.close() + + elif page == "create_dir": + dir_parent = self.get_body_argument('dir_parent', default=None, strip=True) + dir_name = self.get_body_argument('dir_name', default=None, strip=True) + dir_path = os.path.join(dir_parent, dir_name) + server_id = self.get_argument('id', None) + print(server_id) + + if server_id is None: + logger.warning("Server ID not found in create_dir ajax call") + console.warning("Server ID not found in create_dir ajax call") + return False + else: + server_id = bleach.clean(server_id) + + # does this server id exist? + if not db_helper.server_id_exists(server_id): + logger.warning("Server ID not found in create_dir ajax call") + console.warning("Server ID not found in create_dir ajax call") + return False + + if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], dir_path) \ + or helper.check_path_exists(os.path.abspath(dir_path)): + logger.warning("Invalid path in create_dir ajax call") + console.warning("Invalid path in create_dir ajax call") + return False + + # Create the directory + os.mkdir(dir_path) + + def delete(self, page): + if page == "del_file": + file_path = self.get_body_argument('file_path', default=None, strip=True) + server_id = self.get_argument('id', None) + print(server_id) + + if server_id is None: + logger.warning("Server ID not found in del_file ajax call") + console.warning("Server ID not found in del_file ajax call") + return False + else: + server_id = bleach.clean(server_id) + + # does this server id exist? + if not db_helper.server_id_exists(server_id): + logger.warning("Server ID not found in del_file ajax call") + console.warning("Server ID not found in del_file ajax call") + return False + + if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], file_path) \ + or not helper.check_file_exists(os.path.abspath(file_path)): + logger.warning("Invalid path in del_file ajax call") + console.warning("Invalid path in del_file ajax call") + return False + + # Delete the file + os.remove(file_path) + + elif page == "del_dir": + dir_path = self.get_body_argument('dir_path', default=None, strip=True) + server_id = self.get_argument('id', None) + print(server_id) + + if server_id is None: + logger.warning("Server ID not found in del_file ajax call") + console.warning("Server ID not found in del_file ajax call") + return False + else: + server_id = bleach.clean(server_id) + + # does this server id exist? + if not db_helper.server_id_exists(server_id): + logger.warning("Server ID not found in del_file ajax call") + console.warning("Server ID not found in del_file ajax call") + return False + + if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], dir_path) \ + or not helper.check_path_exists(os.path.abspath(dir_path)): + logger.warning("Invalid path in del_file ajax call") + console.warning("Invalid path in del_file ajax call") + return False + + # Delete the file + # os.rmdir(dir_path) + shutil.rmtree(dir_path) # Removes also when there are contents + + def put(self, page): + if page == "save_file": + file_contents = self.get_body_argument('file_contents', default=None, strip=True) + file_path = self.get_body_argument('file_path', default=None, strip=True) server_id = self.get_argument('id', None) print(file_contents) print(file_path) @@ -169,4 +300,45 @@ class AjaxHandler(BaseHandler): # Open the file in write mode and store the content in file_object with open(file_path, 'w') as file_object: - file_object.write(file_contents) \ No newline at end of file + file_object.write(file_contents) + + elif page == "rename_item": + item_path = self.get_body_argument('item_path', default=None, strip=True) + new_item_name = self.get_body_argument('new_item_name', default=None, strip=True) + server_id = self.get_argument('id', None) + print(server_id) + + if server_id is None: + logger.warning("Server ID not found in rename_item ajax call") + console.warning("Server ID not found in rename_item ajax call") + return False + else: + server_id = bleach.clean(server_id) + + # does this server id exist? + if not db_helper.server_id_exists(server_id): + logger.warning("Server ID not found in rename_item ajax call (1)") + console.warning("Server ID not found in rename_item ajax call (1)") + return False + + if item_path is None or new_item_name is None: + logger.warning("Invalid path in rename_item ajax call (2)") + console.warning("Invalid path in rename_item ajax call (2)") + return False + + if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], item_path) \ + or not helper.check_path_exists(os.path.abspath(item_path)): + logger.warning("Invalid path in rename_item ajax call (3)") + console.warning("Invalid path in rename_item ajax call (3)") + return False + + new_item_path = os.path.join(os.path.split(item_path)[0], new_item_name) + + if not helper.in_path(db_helper.get_server_data_by_id(server_id)['path'], new_item_path) \ + or helper.check_path_exists(os.path.abspath(new_item_path)): + logger.warning("Invalid path 2 in rename_item ajax call") + console.warning("Invalid path 2 in rename_item ajax call") + return False + + # RENAME + os.rename(item_path, new_item_path) diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index d284facc..8ebd1b19 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -109,9 +109,6 @@ class PanelHandler(BaseHandler): console.debug('not a valid subpage') subpage = 'term' console.debug('Subpage: "{}"'.format(subpage)) - if subpage == 'files': - console.debug('Subpage is "files"') - page_data['tree_html'] = helper.generate_tree(db_helper.get_server_data_by_id(server_id)['path']) # server_data isn't needed since the server_stats also pulls server data # page_data['server_data'] = db_helper.get_server_data_by_id(server_id) diff --git a/app/frontend/templates/panel/server_files.html b/app/frontend/templates/panel/server_files.html index e3267cb6..d08e11ac 100644 --- a/app/frontend/templates/panel/server_files.html +++ b/app/frontend/templates/panel/server_files.html @@ -65,9 +65,82 @@ +
      + + + × + + + + +
      +
      • - Files +
        Files
        • Error while getting files
        • @@ -113,28 +186,6 @@

  • - - @@ -316,7 +367,7 @@ var token = getCookie("_xsrf") $.ajax({ - type: "POST", + type: "PUT", headers: {'X-XSRFToken': token}, url: '/ajax/save_file?id={{ data['server_stats'][0]['server_id']['server_id'] }}', data: { @@ -330,6 +381,277 @@ }); } + function createFile(parent, name, callback) { + var token = getCookie("_xsrf") + $.ajax({ + type: "POST", + headers: {'X-XSRFToken': token}, + url: '/ajax/create_file?id={{ data['server_stats'][0]['server_id']['server_id'] }}', + data: { + file_parent: parent, + file_name: name + }, + success: function(data){ + console.log("got response:"); + console.log(data); + callback(); + }, + }); + } + + function createDir(parent, name, callback) { + var token = getCookie("_xsrf") + $.ajax({ + type: "POST", + headers: {'X-XSRFToken': token}, + url: '/ajax/create_dir?id={{ data['server_stats'][0]['server_id']['server_id'] }}', + data: { + dir_parent: parent, + dir_name: name + }, + success: function(data){ + console.log("got response:"); + console.log(data); + callback(); + }, + }); + } + + function renameItem(path, name, callback) { + var token = getCookie("_xsrf") + $.ajax({ + type: "PUT", + headers: {'X-XSRFToken': token}, + url: '/ajax/rename_item?id={{ data['server_stats'][0]['server_id']['server_id'] }}', + data: { + item_path: path, + new_item_name: name + }, + success: function(data){ + console.log("got response:"); + console.log(data); + callback(); + }, + }); + } + + function deleteFile(path, callback) { + console.log('Deleting: ' + path) + var token = getCookie("_xsrf") + $.ajax({ + type: "DELETE", + headers: {'X-XSRFToken': token}, + url: '/ajax/del_file?id={{ data['server_stats'][0]['server_id']['server_id'] }}', + data: { + file_path: path + }, + success: function(data){ + console.log("got response:"); + console.log(data); + callback(); + }, + }); + } + + function deleteDir(path, callback) { + var token = getCookie("_xsrf") + $.ajax({ + type: "DELETE", + headers: {'X-XSRFToken': token}, + url: '/ajax/del_dir?id={{ data['server_stats'][0]['server_id']['server_id'] }}', + data: { + dir_path: path + }, + success: function(data){ + console.log("got response:"); + console.log(data); + callback(); + }, + }); + } + + function getTreeView() { + $.ajax({ + type: "GET", + url: '/ajax/get_tree?id={{ data['server_stats'][0]['server_id']['server_id'] }}', + dataType: 'text', + success: function(data){ + console.log("got response:"); + console.log(data); + + dataArr = data.split('\n'); + serverDir = dataArr.shift(); // Remove & return first element (server directory) + text = dataArr.join('\n'); + + document.getElementById('files-tree').innerHTML = text; + + document.getElementsByClassName('files-tree-title')[0].setAttribute('data-path', serverDir); + document.getElementsByClassName('files-tree-title')[0].setAttribute('data-name', 'Files'); + + setTimeout(function () {setTreeViewContext()}, 1000); + + var toggler = document.getElementsByClassName("tree-caret"); + var i; + + for (i = 0; i < toggler.length; i++) { + if (toggler[i].classList.contains('files-tree-title')) continue; + toggler[i].addEventListener("click", function caretListener() { + this.parentElement.querySelector(".tree-nested").classList.toggle("d-block"); + this.classList.toggle("tree-caret-down"); + }); + } + }, + }); + } + + function setTreeViewContext() { + var treeItems = document.getElementsByClassName('tree-ctx-item'); + + for (var i = 0; i < treeItems.length; i++) { + var treeItem = treeItems[i]; + treeItem.addEventListener('contextmenu', function contextListener(event) { + event.preventDefault(); + var ctxmenuPath = event.target.getAttribute('data-path'); + var ctxmenuName = event.target.getAttribute('data-name'); + if (!ctxmenuPath) { + console.log({ 'event.target': event.target, ctxmenuPath }); + return; + } + $('#renameItem').show(); + + var isDir = event.target.classList.contains('tree-folder'); + $('#createFile').toggle(isDir); + $('#createDir').toggle(isDir); + $('#deleteDir').toggle(isDir); + + var isFile = event.target.classList.contains('tree-file'); + $('#deleteFile').toggle(isFile); + console.log({ 'event.target': event.target, isDir, isFile }); + + if(event.target.classList.contains('files-tree-title')) { + $('#createFile').show(); + $('#createDir').show(); + $('#renameItem').hide(); + $('#deleteDir').hide(); + $('#deleteFile').hide(); + } + + + document.getElementById('files-tree-nav-content') + .setAttribute('data-path', ctxmenuPath); + + document.getElementById('files-tree-nav-content') + .setAttribute('data-name', ctxmenuName); + + document.getElementById("files-tree-nav").style.height = "100%"; + }) + } + } + + + function createFileE(event) { + bootbox.prompt('What name do you want for the new file?', function(result) { + path = event.target.parentElement.getAttribute('data-path'); + name = event.target.parentElement.getAttribute('data-name'); + if (!result) return; + + createFile(path, result, function () { + getTreeView() + document.getElementById('files-tree-nav').style.height = '0%'; + }); + }) + } + + function createDirE(event) { + bootbox.prompt('What name do you want for the new directory?', function(result) { + path = event.target.parentElement.getAttribute('data-path'); + name = event.target.parentElement.getAttribute('data-name'); + if (!result) return; + + createDir(path, result, function () { + getTreeView() + document.getElementById('files-tree-nav').style.height = '0%'; + }); + }) + } + + function renameItemE(event) { + bootbox.prompt('What should the new name be?', function(result) { + path = event.target.parentElement.getAttribute('data-path'); + name = event.target.parentElement.getAttribute('data-name'); + if (!result) return; + + renameItem(path, result, function () { + getTreeView() + document.getElementById('files-tree-nav').style.height = '0%'; + }); + }) + } + + function deleteFileE(event) { + path = event.target.parentElement.getAttribute('data-path'); + name = event.target.parentElement.getAttribute('data-name'); + bootbox.confirm({ + size: "", + title: "Are you sure you want to delete " + name + "?", + closeButton: false, + message: "You are deleting \"" + path + "\"!

    This action will be irreversible and it'll be lost forever!", + buttons: { + confirm: { + label: 'Yes, I understand the consequences', + className: 'btn-danger' + }, + cancel: { + label: 'No', + className: 'btn-link' + } + }, + callback: function(result) { + if (!result) return; + deleteFile(path, function () { + getTreeView() + document.getElementById('files-tree-nav').style.height = '0%'; + }); + } + }); + } + + function deleteDirE(event) { + path = event.target.parentElement.getAttribute('data-path'); + name = event.target.parentElement.getAttribute('data-name'); + bootbox.confirm({ + size: "", + title: "Are you sure you want to delete " + name + "?", + closeButton: false, + message: "You are deleting \"" + path + "\"!

    This action will be irreversible and it'll be lost forever!", + buttons: { + confirm: { + label: 'Yes, I understand the consequences', + className: 'btn-danger' + }, + cancel: { + label: 'No', + className: 'btn-link' + } + }, + callback: function(result) { + if (!result) return; + deleteDir(path, function () { + getTreeView() + document.getElementById('files-tree-nav').style.height = '0%'; + }); + } + }); + } + + document.getElementsByClassName('files-tree-title')[0].addEventListener("click", function caretListener() { + this.parentElement.querySelector(".tree-nested").classList.toggle("d-block"); + this.classList.toggle("tree-caret-down"); + }); + + getTreeView(); + setTreeViewContext(); + {% end %} \ No newline at end of file From e9dc45eeda0eaf7acfb482fab7aded6b79e4f722 Mon Sep 17 00:00:00 2001 From: LukasDoesDev Date: Mon, 18 Jan 2021 17:02:38 +0200 Subject: [PATCH 6/6] Add auth requirement to AJAX handlers --- app/classes/web/ajax_handler.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py index 13331e71..5ec917a6 100644 --- a/app/classes/web/ajax_handler.py +++ b/app/classes/web/ajax_handler.py @@ -132,6 +132,7 @@ class AjaxHandler(BaseHandler): helper.generate_tree(db_helper.get_server_data_by_id(server_id)['path'])) self.finish() + @tornado.web.authenticated def post(self, page): user_data = json.loads(self.get_secure_cookie("user_data")) error = bleach.clean(self.get_argument('error', "WTF Error!")) @@ -214,6 +215,7 @@ class AjaxHandler(BaseHandler): # Create the directory os.mkdir(dir_path) + @tornado.web.authenticated def delete(self, page): if page == "del_file": file_path = self.get_body_argument('file_path', default=None, strip=True) @@ -270,6 +272,7 @@ class AjaxHandler(BaseHandler): # os.rmdir(dir_path) shutil.rmtree(dir_path) # Removes also when there are contents + @tornado.web.authenticated def put(self, page): if page == "save_file": file_contents = self.get_body_argument('file_contents', default=None, strip=True)