crafty-4/app/classes/web/ajax_handler.py

480 lines
23 KiB
Python
Raw Normal View History

import json
import logging
import tempfile
import threading
2021-09-13 19:03:47 +00:00
from typing import Container
import zipfile
import tornado.web
import tornado.escape
import bleach
import os
2021-01-17 17:20:28 +00:00
import shutil
import html
import re
2021-11-30 19:37:45 +00:00
from app.classes.models.users import helper_users
from app.classes.shared.console import console
2021-09-08 22:01:10 +00:00
from app.classes.shared.main_models import Users, installer
from app.classes.web.base_handler import BaseHandler
from app.classes.shared.helpers import helper
from app.classes.shared.server import ServerOutBuf
2021-11-30 19:37:45 +00:00
from app.classes.models.server_permissions import Enum_Permissions_Server
logger = logging.getLogger(__name__)
class AjaxHandler(BaseHandler):
def render_page(self, template, page_data):
self.render(
template,
data=page_data,
translate=self.translator.translate,
)
@tornado.web.authenticated
def get(self, page):
user_data = json.loads(self.get_secure_cookie("user_data"))
error = bleach.clean(self.get_argument('error', "WTF Error!"))
template = "panel/denied.html"
page_data = {
'user_data': user_data,
'error': error
}
if page == "error":
template = "public/error.html"
self.render_page(template, page_data)
elif page == 'server_log':
server_id = self.get_argument('id', None)
full_log = self.get_argument('full', False)
if server_id is None:
logger.warning("Server ID not found in server_log ajax call")
self.redirect("/panel/error?error=Server ID Not Found")
return
server_id = bleach.clean(server_id)
server_data = self.controller.servers.get_server_data_by_id(server_id)
if not server_data:
logger.warning("Server Data not found in server_log ajax call")
self.redirect("/panel/error?error=Server ID Not Found")
return
if not server_data['log_path']:
logger.warning("Log path not found in server_log ajax call ({})".format(server_id))
if full_log:
log_lines = helper.get_setting('max_log_lines')
data = helper.tail_file(helper.get_os_understandable_path(server_data['log_path']), log_lines)
else:
data = ServerOutBuf.lines.get(server_id, [])
for d in data:
try:
d = re.sub('(\033\\[(0;)?[0-9]*[A-z]?(;[0-9])?m?)|(> )', '', d)
d = re.sub('[A-z]{2}\b\b', '', d)
line = helper.log_colors(html.escape(d))
self.write('{}<br />'.format(line))
# self.write(d.encode("utf-8"))
except Exception as e:
logger.warning("Skipping Log Line due to error: {}".format(e))
pass
elif page == "announcements":
data = helper.get_announcements()
page_data['notify_data'] = data
self.render_page('ajax/notify.html', page_data)
elif page == "get_file":
file_path = helper.get_os_understandable_path(self.get_argument('file_path', None))
server_id = self.get_argument('id', None)
if not self.check_server_id(server_id, 'get_file'): return
else: server_id = bleach.clean(server_id)
if not helper.in_path(helper.get_os_understandable_path(self.controller.servers.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 ({})".format(file_path))
console.warning("Invalid path in get_file ajax call ({})".format(file_path))
return
error = None
try:
with open(file_path) as file:
file_contents = file.read()
except UnicodeDecodeError:
file_contents = ''
error = 'UnicodeDecodeError'
self.write({
'content': file_contents,
'error': error
})
self.finish()
2021-01-17 17:20:28 +00:00
elif page == "get_tree":
server_id = self.get_argument('id', None)
path = self.get_argument('path', None)
2021-01-17 17:20:28 +00:00
if not self.check_server_id(server_id, 'get_tree'): return
else: server_id = bleach.clean(server_id)
2021-01-17 17:20:28 +00:00
if helper.validate_traversal(self.controller.servers.get_server_data_by_id(server_id)['path'], path):
self.write(helper.get_os_understandable_path(path) + '\n' +
helper.generate_tree(path))
self.finish()
elif page == "get_dir":
server_id = self.get_argument('id', None)
path = self.get_argument('path', None)
if not self.check_server_id(server_id, 'get_tree'): return
else: server_id = bleach.clean(server_id)
if helper.validate_traversal(self.controller.servers.get_server_data_by_id(server_id)['path'], path):
self.write(helper.get_os_understandable_path(path) + '\n' +
helper.generate_dir(path))
2021-01-17 17:20:28 +00:00
self.finish()
2021-01-18 15:02:38 +00:00
@tornado.web.authenticated
def post(self, page):
user_data = json.loads(self.get_secure_cookie("user_data"))
2021-11-30 19:37:45 +00:00
server_id = self.get_argument('id', None)
exec_user_id = user_data['user_id']
exec_user = helper_users.get_user(exec_user_id)
permissions = {
'Commands': Enum_Permissions_Server.Commands,
'Terminal': Enum_Permissions_Server.Terminal,
'Logs': Enum_Permissions_Server.Logs,
'Schedule': Enum_Permissions_Server.Schedule,
'Backup': Enum_Permissions_Server.Backup,
'Files': Enum_Permissions_Server.Files,
'Config': Enum_Permissions_Server.Config,
'Players': Enum_Permissions_Server.Players,
}
user_perms = self.controller.server_perms.get_server_permissions_foruser(exec_user_id, server_id)
error = bleach.clean(self.get_argument('error', "WTF Error!"))
page_data = {
'user_data': user_data,
'error': error
}
if page == "send_command":
2021-01-17 17:20:28 +00:00
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")
console.warning("Server ID not found in send_command ajax call")
srv_obj = self.controller.get_server_obj(server_id)
if command:
if srv_obj.check_running():
srv_obj.send_command(command)
self.controller.management.add_to_audit_log(user_data['user_id'], "Sent command to {} terminal: {}".format(self.controller.servers.get_server_friendly_name(server_id), command), server_id, self.get_remote_ip())
2021-01-17 17:20:28 +00:00
elif page == "create_file":
2021-11-30 19:37:45 +00:00
if not permissions['Files'] in user_perms:
if not exec_user['superuser']:
self.redirect("/panel/error?error=Unauthorized access to Files")
return
file_parent = helper.get_os_understandable_path(self.get_body_argument('file_parent', default=None, strip=True))
2021-01-17 17:20:28 +00:00
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)
if not self.check_server_id(server_id, 'create_file'): return
else: server_id = bleach.clean(server_id)
2021-01-17 17:20:28 +00:00
if not helper.in_path(helper.get_os_understandable_path(self.controller.servers.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 ({})".format(file_path))
console.warning("Invalid path in create_file ajax call ({})".format(file_path))
return
2021-01-17 17:20:28 +00:00
# Create the file by opening it
with open(file_path, 'w') as file_object:
file_object.close()
elif page == "create_dir":
2021-11-30 19:37:45 +00:00
if not permissions['Files'] in user_perms:
if not exec_user['superuser']:
self.redirect("/panel/error?error=Unauthorized access to Files")
return
dir_parent = helper.get_os_understandable_path(self.get_body_argument('dir_parent', default=None, strip=True))
2021-01-17 17:20:28 +00:00
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)
if not self.check_server_id(server_id, 'create_dir'): return
else: server_id = bleach.clean(server_id)
2021-01-17 17:20:28 +00:00
if not helper.in_path(helper.get_os_understandable_path(self.controller.servers.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 ({})".format(dir_path))
console.warning("Invalid path in create_dir ajax call ({})".format(dir_path))
return
2021-01-17 17:20:28 +00:00
# Create the directory
os.mkdir(dir_path)
elif page == "unzip_file":
2021-11-30 19:37:45 +00:00
if not permissions['Files'] in user_perms:
if not exec_user['superuser']:
self.redirect("/panel/error?error=Unauthorized access to Files")
return
server_id = self.get_argument('id', None)
path = helper.get_os_understandable_path(self.get_argument('path', None))
helper.unzipFile(path)
self.redirect("/panel/server_detail?id={}&subpage=files".format(server_id))
return
2021-09-13 19:03:47 +00:00
elif page == "kill":
2021-11-30 19:37:45 +00:00
if not permissions['Commands'] in user_perms:
if not exec_user['superuser']:
self.redirect("/panel/error?error=Unauthorized access to Commands")
return
2021-09-13 19:03:47 +00:00
server_id = self.get_argument('id', None)
svr = self.controller.get_server_obj(server_id)
2021-09-25 19:29:28 +00:00
try:
svr.kill()
except Exception as e:
2021-09-13 19:03:47 +00:00
logger.error("Could not find PID for requested termsig. Full error: {}".format(e))
return
elif page == "eula":
server_id = self.get_argument('id', None)
svr = self.controller.get_server_obj(server_id)
svr.agree_eula(user_data['user_id'])
2021-09-13 19:03:47 +00:00
2021-11-29 21:22:46 +00:00
elif page == "restore_backup":
2021-11-30 19:37:45 +00:00
if not permissions['Backup'] in user_perms:
if not exec_user['superuser']:
self.redirect("/panel/error?error=Unauthorized access to Backups")
return
2021-11-29 21:22:46 +00:00
server_id = bleach.clean(self.get_argument('id', None))
zip_name = bleach.clean(self.get_argument('zip_file', None))
svr_obj = self.controller.servers.get_server_obj(server_id)
server_data = self.controller.servers.get_server_data_by_id(server_id)
backup_path = svr_obj.backup_path
if helper.validate_traversal(backup_path, zip_name):
new_server = self.controller.import_zip_server(svr_obj.server_name, os.path.join(backup_path, zip_name), server_data['executable'], '1', '2', server_data['server_port'])
new_server_id = new_server
new_server = self.controller.get_server_data(new_server)
self.controller.rename_backup_dir(server_id, new_server_id, new_server['server_uuid'])
self.controller.remove_server(server_id, True)
self.redirect('/panel/dashboard')
2021-01-18 15:02:38 +00:00
@tornado.web.authenticated
2021-01-17 17:20:28 +00:00
def delete(self, page):
2021-11-30 19:37:45 +00:00
user_data = json.loads(self.get_secure_cookie("user_data"))
server_id = self.get_argument('id', None)
exec_user_id = user_data['user_id']
exec_user = helper_users.get_user(exec_user_id)
permissions = {
'Commands': Enum_Permissions_Server.Commands,
'Terminal': Enum_Permissions_Server.Terminal,
'Logs': Enum_Permissions_Server.Logs,
'Schedule': Enum_Permissions_Server.Schedule,
'Backup': Enum_Permissions_Server.Backup,
'Files': Enum_Permissions_Server.Files,
'Config': Enum_Permissions_Server.Config,
'Players': Enum_Permissions_Server.Players,
}
user_perms = self.controller.server_perms.get_server_permissions_foruser(exec_user_id, server_id)
2021-01-17 17:20:28 +00:00
if page == "del_file":
2021-11-30 19:37:45 +00:00
if not permissions['Files'] in user_perms:
if not exec_user['superuser']:
self.redirect("/panel/error?error=Unauthorized access to Files")
return
file_path = helper.get_os_understandable_path(self.get_body_argument('file_path', default=None, strip=True))
server_id = self.get_argument('id', None)
console.warning("delete {} for server {}".format(file_path, server_id))
if not self.check_server_id(server_id, 'del_file'):
return
else: server_id = bleach.clean(server_id)
server_info = self.controller.servers.get_server_data_by_id(server_id)
if not (helper.in_path(helper.get_os_understandable_path(server_info['path']), file_path) \
or helper.in_path(helper.get_os_understandable_path(server_info['backup_path']), file_path)) \
or not helper.check_file_exists(os.path.abspath(file_path)):
logger.warning("Invalid path in del_file ajax call ({})".format(file_path))
console.warning("Invalid path in del_file ajax call ({})".format(file_path))
return
# Delete the file
os.remove(file_path)
if page == "del_backup":
if not permissions['Backup'] in user_perms:
if not exec_user['superuser']:
self.redirect("/panel/error?error=Unauthorized access to Backups")
return
file_path = helper.get_os_understandable_path(self.get_body_argument('file_path', default=None, strip=True))
2021-01-17 17:20:28 +00:00
server_id = self.get_argument('id', None)
console.warning("delete {} for server {}".format(file_path, server_id))
2021-01-17 17:20:28 +00:00
if not self.check_server_id(server_id, 'del_file'):
return
else: server_id = bleach.clean(server_id)
2021-01-17 17:20:28 +00:00
2021-09-08 22:01:10 +00:00
server_info = self.controller.servers.get_server_data_by_id(server_id)
if not (helper.in_path(helper.get_os_understandable_path(server_info['path']), file_path) \
or helper.in_path(helper.get_os_understandable_path(server_info['backup_path']), file_path)) \
or not helper.check_file_exists(os.path.abspath(file_path)):
logger.warning("Invalid path in del_file ajax call ({})".format(file_path))
console.warning("Invalid path in del_file ajax call ({})".format(file_path))
return
2021-01-17 17:20:28 +00:00
# Delete the file
if helper.validate_traversal(helper.get_os_understandable_path(server_info['path']), file_path):
os.remove(file_path)
2021-01-17 17:20:28 +00:00
elif page == "del_dir":
2021-11-30 19:37:45 +00:00
if not permissions['Files'] in user_perms:
if not exec_user['superuser']:
self.redirect("/panel/error?error=Unauthorized access to Files")
return
dir_path = helper.get_os_understandable_path(self.get_body_argument('dir_path', default=None, strip=True))
2021-01-17 17:20:28 +00:00
server_id = self.get_argument('id', None)
console.warning("delete {} for server {}".format(dir_path, server_id))
2021-01-17 17:20:28 +00:00
if not self.check_server_id(server_id, 'del_dir'): return
else: server_id = bleach.clean(server_id)
2021-01-17 17:20:28 +00:00
2021-09-08 22:01:10 +00:00
server_info = self.controller.servers.get_server_data_by_id(server_id)
if not helper.in_path(helper.get_os_understandable_path(server_info['path']), dir_path) \
or not helper.check_path_exists(os.path.abspath(dir_path)):
logger.warning("Invalid path in del_file ajax call ({})".format(dir_path))
console.warning("Invalid path in del_file ajax call ({})".format(dir_path))
return
2021-01-17 17:20:28 +00:00
# Delete the directory
# os.rmdir(dir_path) # Would only remove empty directories
if helper.validate_traversal(helper.get_os_understandable_path(server_info['path']), dir_path):
shutil.rmtree(dir_path) # Removes also when there are contents
2021-01-17 17:20:28 +00:00
elif page == "delete_server":
2021-11-30 19:37:45 +00:00
if not permissions['Config'] in user_perms:
if not exec_user['superuser']:
self.redirect("/panel/error?error=Unauthorized access to Config")
return
server_id = self.get_argument('id', None)
logger.info(
2021-09-08 22:01:10 +00:00
"Removing server from panel for server: {}".format(self.controller.servers.get_server_friendly_name(server_id)))
self.controller.remove_server(server_id, False)
elif page == "delete_server_files":
2021-11-30 19:37:45 +00:00
if not permissions['Config'] in user_perms:
if not exec_user['superuser']:
self.redirect("/panel/error?error=Unauthorized access to Config")
return
server_id = self.get_argument('id', None)
logger.info(
2021-09-08 22:01:10 +00:00
"Removing server and all associated files for server: {}".format(self.controller.servers.get_server_friendly_name(server_id)))
self.controller.remove_server(server_id, True)
2021-01-18 15:02:38 +00:00
@tornado.web.authenticated
2021-01-17 17:20:28 +00:00
def put(self, page):
2021-11-30 19:37:45 +00:00
user_data = json.loads(self.get_secure_cookie("user_data"))
server_id = self.get_argument('id', None)
exec_user_id = user_data['user_id']
exec_user = helper_users.get_user(exec_user_id)
permissions = {
'Commands': Enum_Permissions_Server.Commands,
'Terminal': Enum_Permissions_Server.Terminal,
'Logs': Enum_Permissions_Server.Logs,
'Schedule': Enum_Permissions_Server.Schedule,
'Backup': Enum_Permissions_Server.Backup,
'Files': Enum_Permissions_Server.Files,
'Config': Enum_Permissions_Server.Config,
'Players': Enum_Permissions_Server.Players,
}
user_perms = self.controller.server_perms.get_server_permissions_foruser(exec_user_id, server_id)
2021-01-17 17:20:28 +00:00
if page == "save_file":
2021-11-30 19:37:45 +00:00
if not permissions['Files'] in user_perms:
if not exec_user['superuser']:
self.redirect("/panel/error?error=Unauthorized access to Files")
return
2021-01-17 17:20:28 +00:00
file_contents = self.get_body_argument('file_contents', default=None, strip=True)
file_path = helper.get_os_understandable_path(self.get_body_argument('file_path', default=None, strip=True))
server_id = self.get_argument('id', None)
if not self.check_server_id(server_id, 'save_file'): return
else: server_id = bleach.clean(server_id)
if not helper.in_path(helper.get_os_understandable_path(self.controller.servers.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 ({})".format(file_path))
console.warning("Invalid path in save_file ajax call ({})".format(file_path))
return
# Open the file in write mode and store the content in file_object
with open(file_path, 'w') as file_object:
2021-01-17 17:20:28 +00:00
file_object.write(file_contents)
elif page == "rename_item":
2021-11-30 19:37:45 +00:00
if not permissions['Files'] in user_perms:
if not exec_user['superuser']:
self.redirect("/panel/error?error=Unauthorized access to Files")
return
item_path = helper.get_os_understandable_path(self.get_body_argument('item_path', default=None, strip=True))
2021-01-17 17:20:28 +00:00
new_item_name = self.get_body_argument('new_item_name', default=None, strip=True)
server_id = self.get_argument('id', None)
if not self.check_server_id(server_id, 'rename_item'): return
else: server_id = bleach.clean(server_id)
2021-01-17 17:20:28 +00:00
if item_path is None or new_item_name is None:
logger.warning("Invalid path(s) in rename_item ajax call")
console.warning("Invalid path(s) in rename_item ajax call")
return
2021-01-17 17:20:28 +00:00
if not helper.in_path(helper.get_os_understandable_path(self.controller.servers.get_server_data_by_id(server_id)['path']), item_path) \
or not helper.check_path_exists(os.path.abspath(item_path)):
logger.warning("Invalid old name path in rename_item ajax call ({})".format(server_id))
console.warning("Invalid old name path in rename_item ajax call ({})".format(server_id))
return
2021-01-17 17:20:28 +00:00
new_item_path = os.path.join(os.path.split(item_path)[0], new_item_name)
if not helper.in_path(helper.get_os_understandable_path(self.controller.servers.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 new name path in rename_item ajax call ({})".format(server_id))
console.warning("Invalid new name path in rename_item ajax call ({})".format(server_id))
return
2021-01-17 17:20:28 +00:00
# RENAME
os.rename(item_path, new_item_path)
def check_server_id(self, server_id, page_name):
if server_id is None:
logger.warning("Server ID not defined in {} ajax call ({})".format(page_name, server_id))
console.warning("Server ID not defined in {} ajax call ({})".format(page_name, server_id))
return
else:
server_id = bleach.clean(server_id)
# does this server id exist?
2021-09-08 22:01:10 +00:00
if not self.controller.servers.server_id_exists(server_id):
logger.warning("Server ID not found in {} ajax call ({})".format(page_name, server_id))
console.warning("Server ID not found in {} ajax call ({})".format(page_name, server_id))
return
return True