From b77aab954dffbddc847177b95fb69968753a7a6b Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 24 Aug 2021 21:33:29 -0400 Subject: [PATCH] Adds download options for files in file tree. This does not add ability to download directories. --- app/classes/web/http_handler_page.py | 49 +++++++++++++++++ app/classes/web/panel_handler.py | 52 +++++++++++++++++++ .../templates/panel/server_files.html | 12 ++++- app/translations/en_EN.json | 3 +- app/translations/fi_FI.json | 3 +- app/translations/fr_FR.json | 3 +- 6 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 app/classes/web/http_handler_page.py diff --git a/app/classes/web/http_handler_page.py b/app/classes/web/http_handler_page.py new file mode 100644 index 00000000..97871ae2 --- /dev/null +++ b/app/classes/web/http_handler_page.py @@ -0,0 +1,49 @@ +import sys +import json +import logging +import tornado.web +import tornado.escape +import requests + +from app.classes.shared.helpers import helper +from app.classes.web.base_handler import BaseHandler +from app.classes.shared.console import console +from app.classes.shared.models import Users, fn, db_helper + +logger = logging.getLogger(__name__) + +try: + import bleach + +except ModuleNotFoundError as e: + logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True) + console.critical("Import Error: Unable to load {} module".format(e.name)) + sys.exit(1) + + +class HTTPHandlerPage(BaseHandler): + def get(self, page): + url = self.request.full_url + port = 443 + print(url) + if url[len(url)-1] == '/': + url = url.strip(url[len(url)-1]) + url_list = url.split('/') + print(url_list) + if url_list[0] != "": + primary_url = url_list[0] + ":"+str(port)+"/" + backup_url = url_list[0] + ":" +str(helper.get_setting["https_port"]) +"/" + for i in range(len(url_list)-1): + primary_url += url_list[i+1] + backup_url += url_list[i+1] + else: + primary_url = url + str(port) + backup_url = url + str(helper.get_setting['https_port']) + + try: + resp = requests.get(primary_url) + resp.raise_for_status() + url = primary_url + except Exception as err: + url = backup_url + self.redirect('https://'+url+':'+ str(port)) \ No newline at end of file diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index eded766f..930b9ce3 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -494,6 +494,58 @@ class PanelHandler(BaseHandler): template = "panel/activity_logs.html" + elif page == 'download_file': + server_id = self.get_argument('id', None) + file = self.get_argument('path', "") + name = self.get_argument('name', "") + + if server_id is None: + self.redirect("/panel/error?error=Invalid Server ID") + return + else: + # does this server id exist? + if not db_helper.server_id_exists(server_id): + self.redirect("/panel/error?error=Invalid Server ID") + return + + if exec_user['superuser'] != 1: + #if not db_helper.server_id_authorized(server_id, exec_user_id): + if not db_helper.server_id_authorized(int(server_id), exec_user_id): + self.redirect("/panel/error?error=Invalid Server ID") + return + + server_info = db_helper.get_server_data_by_id(server_id) + + if not helper.in_path(server_info["path"], file) \ + or not os.path.isfile(file): + self.redirect("/panel/error?error=Invalid path detected") + return + + self.set_header('Content-Type', 'application/octet-stream') + self.set_header('Content-Disposition', 'attachment; filename=' + name) + chunk_size = 1024 * 1024 * 4 # 4 MiB + + with open(file, 'rb') as f: + while True: + chunk = f.read(chunk_size) + if not chunk: + break + try: + self.write(chunk) # write the chunk to response + self.flush() # send the chunk to client + except iostream.StreamClosedError: + # this means the client has closed the connection + # so break the loop + break + finally: + # deleting the chunk is very important because + # if many clients are downloading files at the + # same time, the chunks in memory will keep + # increasing and will eat up the RAM + del chunk + self.redirect("/panel/server_detail?id={}&subpage=files".format(server_id)) + + self.render( template, data=page_data, diff --git a/app/frontend/templates/panel/server_files.html b/app/frontend/templates/panel/server_files.html index c055b6ff..cc3f43a2 100644 --- a/app/frontend/templates/panel/server_files.html +++ b/app/frontend/templates/panel/server_files.html @@ -48,10 +48,11 @@ {{ translate('serverFiles', 'createFile') }} {{ translate('serverFiles', 'createDir') }} {{ translate('serverFiles', 'rename') }} - {{ translate('serverFiles', 'delete') }} - {{ translate('serverFiles', 'delete') }} {{ translate('serverFiles', 'upload') }} {{ translate('serverFiles', 'unzip') }} + {{ translate('serverFiles', 'delete') }} + {{ translate('serverFiles', 'delete') }} + {{ translate('serverFiles', 'download') }} {{ translate('serverFiles', 'close') }} @@ -704,6 +705,7 @@ var isFile = event.target.classList.contains('tree-file'); $('#deleteFile').toggle(isFile); + $('#downloadFile').toggle(isFile); console.log({ 'event.target': event.target, isDir, isFile }); if(event.target.classList.contains('files-tree-title')) { @@ -712,6 +714,7 @@ $('#renameItem').hide(); $('#deleteDir').hide(); $('#deleteFile').hide(); + $('#downloadFile').hide(); $('#upload').show(); } if(event.target.textContent.endsWith('.zip')){ @@ -790,6 +793,11 @@ }); }) } + function downloadFileE(event) { + path = event.target.parentElement.getAttribute('data-path'); + name = event.target.parentElement.getAttribute('data-name'); + window.location.href = '/panel/download_file?id={{ data['server_stats']['server_id']['server_id'] }}&path='+path+'&name='+name; + } function renameItemE(event) { bootbox.prompt("{% raw translate('serverFiles', 'renameItemQuestion') %}", function(result) { diff --git a/app/translations/en_EN.json b/app/translations/en_EN.json index 6c3314a4..ca50b6cc 100644 --- a/app/translations/en_EN.json +++ b/app/translations/en_EN.json @@ -180,7 +180,8 @@ "uploadTitle": "Upload Files to: ", "waitUpload": "Please wait while we upload your files... This may take a while.", "stayHere": "DO NOT LEAVE THIS PAGE!", - "close": "Close" + "close": "Close", + "download": "Download" }, "serverConfig": { "serverName": "Server Name", diff --git a/app/translations/fi_FI.json b/app/translations/fi_FI.json index 348b258b..1b07ddec 100644 --- a/app/translations/fi_FI.json +++ b/app/translations/fi_FI.json @@ -179,7 +179,8 @@ "uploadTitle": "Lähetä tiedostot: ", "waitUpload": "Odota, kunnes lataamme tiedostosi ... Tämä voi kestää hetken.", "stayHere": "ÄLÄ JÄTÄ SIVUTA!", - "close": "Kiinni" + "close": "Kiinni", + "download": "Ladata" }, "serverConfig": { "serverName": "Palvelimen nimi", diff --git a/app/translations/fr_FR.json b/app/translations/fr_FR.json index 83cfafad..7329c48d 100644 --- a/app/translations/fr_FR.json +++ b/app/translations/fr_FR.json @@ -180,7 +180,8 @@ "uploadTitle": "Téléverser les fichiers vers : ", "waitUpload": "Merci de patienter pendant que nous téléversons tes fichiers... Cela peut prendre un certain temps.", "stayHere": "NE FERME PAS CETTE PAGE!", - "close": "Presque" + "close": "Presque", + "download": "Télécharger" }, "serverConfig": { "serverName": "Nom du Serveur",