Merge branch 'lukas-noinjection' into 'dev'

Reduced the amount of injection in JavaScript.

See merge request crafty-controller/crafty-commander!170
This commit is contained in:
Lukas ‎‎‎‎ 2022-02-27 18:17:06 +00:00
commit 67c76f1d1c
16 changed files with 1384 additions and 1099 deletions

View File

@ -1,5 +1,4 @@
import os
import shutil
import html
import re
import logging
@ -85,53 +84,8 @@ class AjaxHandler(BaseHandler):
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(f"Invalid path in get_file ajax call ({file_path})")
console.warning(f"Invalid path in get_file ajax call ({file_path})")
return
error = None
try:
with open(file_path, encoding='utf-8') as file:
file_contents = file.read()
except UnicodeDecodeError:
file_contents = ''
error = 'UnicodeDecodeError'
self.write({
'content': file_contents,
'error': error
})
self.finish()
elif page == "get_tree":
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_tree(path))
self.finish()
elif page == "get_zip_tree":
server_id = self.get_argument('id', None)
path = self.get_argument('path', None)
self.write(helper.get_os_understandable_path(path) + '\n' +
@ -139,26 +93,12 @@ class AjaxHandler(BaseHandler):
self.finish()
elif page == "get_zip_dir":
server_id = self.get_argument('id', None)
path = self.get_argument('path', None)
self.write(helper.get_os_understandable_path(path) + '\n' +
helper.generate_zip_dir(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))
self.finish()
@tornado.web.authenticated
def post(self, page):
@ -210,69 +150,10 @@ class AjaxHandler(BaseHandler):
server_id,
self.get_remote_ip())
elif page == "create_file":
if not permissions['Files'] in user_perms:
if not 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))
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)
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(f"Invalid path in create_file ajax call ({file_path})")
console.warning(f"Invalid path in create_file ajax call ({file_path})")
return
# Create the file by opening it
with open(file_path, 'w', encoding='utf-8') as file_object:
file_object.close()
elif page == "create_dir":
if not permissions['Files'] in user_perms:
if not 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))
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)
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(f"Invalid path in create_dir ajax call ({dir_path})")
console.warning(f"Invalid path in create_dir ajax call ({dir_path})")
return
# Create the directory
os.mkdir(dir_path)
elif page == "send_order":
self.controller.users.update_server_order(exec_user['user_id'], bleach.clean(self.get_argument('order')))
return
elif page == "unzip_file":
if not permissions['Files'] in user_perms:
if not 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(f"/panel/server_detail?id={server_id}&subpage=files")
return
elif page == "kill":
if not permissions['Commands'] in user_perms:
if not superuser:
@ -341,31 +222,6 @@ class AjaxHandler(BaseHandler):
'Players': Enum_Permissions_Server.Players,
}
user_perms = self.controller.server_perms.get_user_id_permissions_list(exec_user['user_id'], server_id)
if page == "del_file":
if not permissions['Files'] in user_perms:
if not 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(f"Delete {file_path} for server {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(f"Invalid path in del_file ajax call ({file_path})")
console.warning(f"Invalid path in del_file ajax call ({file_path})")
return
# Delete the file
os.remove(file_path)
if page == "del_task":
if not permissions['Schedule'] in user_perms:
self.redirect("/panel/error?error=Unauthorized access to Tasks")
@ -383,7 +239,7 @@ class AjaxHandler(BaseHandler):
console.warning(f"Delete {file_path} for server {server_id}")
if not self.check_server_id(server_id, 'del_file'):
if not self.check_server_id(server_id, 'del_backup'):
return
else: server_id = bleach.clean(server_id)
@ -391,41 +247,14 @@ class AjaxHandler(BaseHandler):
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(f"Invalid path in del_file ajax call ({file_path})")
console.warning(f"Invalid path in del_file ajax call ({file_path})")
logger.warning(f"Invalid path in del_backup ajax call ({file_path})")
console.warning(f"Invalid path in del_backup ajax call ({file_path})")
return
# Delete the file
if helper.validate_traversal(helper.get_os_understandable_path(server_info['backup_path']), file_path):
os.remove(file_path)
elif page == "del_dir":
if not permissions['Files'] in user_perms:
if not 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))
server_id = self.get_argument('id', None)
console.warning(f"Delete {dir_path} for server {server_id}")
if not self.check_server_id(server_id, 'del_dir'):
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']), dir_path) \
or not helper.check_path_exists(os.path.abspath(dir_path)):
logger.warning(f"Invalid path in del_file ajax call ({dir_path})")
console.warning(f"Invalid path in del_file ajax call ({dir_path})")
return
# 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
elif page == "delete_server":
if not permissions['Config'] in user_perms:
if not superuser:
@ -464,86 +293,6 @@ class AjaxHandler(BaseHandler):
self.tasks_manager.remove_all_server_tasks(server_id)
self.controller.remove_server(server_id, True)
@tornado.web.authenticated
def put(self, page):
api_key, _, exec_user = self.current_user
superuser = exec_user['superuser']
if api_key is not None:
superuser = superuser and api_key.superuser
server_id = self.get_argument('id', None)
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_user_id_permissions_list(exec_user['user_id'], server_id)
if page == "save_file":
if not permissions['Files'] in user_perms:
if not superuser:
self.redirect("/panel/error?error=Unauthorized access to Files")
return
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(f"Invalid path in save_file ajax call ({file_path})")
console.warning(f"Invalid path in save_file ajax call ({file_path})")
return
# Open the file in write mode and store the content in file_object
with open(file_path, 'w', encoding='utf-8') as file_object:
file_object.write(file_contents)
elif page == "rename_item":
if not permissions['Files'] in user_perms:
if not 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))
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)
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
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(f"Invalid old name path in rename_item ajax call ({server_id})")
console.warning(f"Invalid old name path in rename_item ajax call ({server_id})")
return
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(f"Invalid new name path in rename_item ajax call ({server_id})")
console.warning(f"Invalid new name path in rename_item ajax call ({server_id})")
return
# RENAME
os.rename(item_path, new_item_path)
def check_server_id(self, server_id, page_name):
if server_id is None:
logger.warning(f"Server ID not defined in {page_name} ajax call ({server_id})")

View File

@ -0,0 +1,410 @@
import os
import shutil
import logging
import tornado.web
import tornado.escape
import bleach
from app.classes.shared.console import console
from app.classes.shared.helpers import helper
from app.classes.web.base_handler import BaseHandler
from app.classes.models.server_permissions import Enum_Permissions_Server
logger = logging.getLogger(__name__)
class FileHandler(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):
api_key, _, exec_user = self.current_user
superuser = exec_user['superuser']
if api_key is not None:
superuser = superuser and api_key.superuser
server_id = self.get_argument('id', None)
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_user_id_permissions_list(exec_user['user_id'], server_id)
if page == "get_file":
if not permissions['Files'] in user_perms:
if not superuser:
self.redirect("/panel/error?error=Unauthorized access to Files")
return
file_path = helper.get_os_understandable_path(self.get_argument('file_path', 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(f"Invalid path in get_file file file ajax call ({file_path})")
console.warning(f"Invalid path in get_file file file ajax call ({file_path})")
return
error = None
try:
with open(file_path, encoding='utf-8') as file:
file_contents = file.read()
except UnicodeDecodeError:
file_contents = ''
error = 'UnicodeDecodeError'
self.write({
'content': file_contents,
'error': error
})
self.finish()
elif page == "get_tree":
if not permissions['Files'] in user_perms:
if not superuser:
self.redirect("/panel/error?error=Unauthorized access to Files")
return
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_tree(path))
self.finish()
elif page == "get_dir":
if not permissions['Files'] in user_perms:
if not superuser:
self.redirect("/panel/error?error=Unauthorized access to Files")
return
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))
self.finish()
@tornado.web.authenticated
def post(self, page):
api_key, _, exec_user = self.current_user
superuser = exec_user['superuser']
if api_key is not None:
superuser = superuser and api_key.superuser
server_id = self.get_argument('id', None)
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_user_id_permissions_list(exec_user['user_id'], server_id)
if page == "create_file":
if not permissions['Files'] in user_perms:
if not 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))
file_name = self.get_body_argument('file_name', default=None, strip=True)
file_path = os.path.join(file_parent, file_name)
if not self.check_server_id(server_id, 'create_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 helper.check_file_exists(os.path.abspath(file_path)):
logger.warning(f"Invalid path in create_file file ajax call ({file_path})")
console.warning(f"Invalid path in create_file file ajax call ({file_path})")
return
# Create the file by opening it
with open(file_path, 'w', encoding='utf-8') as file_object:
file_object.close()
elif page == "create_dir":
if not permissions['Files'] in user_perms:
if not 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))
dir_name = self.get_body_argument('dir_name', default=None, strip=True)
dir_path = os.path.join(dir_parent, dir_name)
if not self.check_server_id(server_id, 'create_dir'):
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']), dir_path) \
or helper.check_path_exists(os.path.abspath(dir_path)):
logger.warning(f"Invalid path in create_dir file ajax call ({dir_path})")
console.warning(f"Invalid path in create_dir file ajax call ({dir_path})")
return
# Create the directory
os.mkdir(dir_path)
elif page == "unzip_file":
if not permissions['Files'] in user_perms:
if not superuser:
self.redirect("/panel/error?error=Unauthorized access to Files")
return
path = helper.get_os_understandable_path(self.get_argument('path', None))
helper.unzipFile(path)
self.redirect(f"/panel/server_detail?id={server_id}&subpage=files")
return
@tornado.web.authenticated
def delete(self, page):
api_key, _, exec_user = self.current_user
superuser = exec_user['superuser']
if api_key is not None:
superuser = superuser and api_key.superuser
server_id = self.get_argument('id', None)
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_user_id_permissions_list(exec_user['user_id'], server_id)
if page == "del_file":
if not permissions['Files'] in user_perms:
if not 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))
console.warning(f"Delete {file_path} for server {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(f"Invalid path in del_file file ajax call ({file_path})")
console.warning(f"Invalid path in del_file file ajax call ({file_path})")
return
# Delete the file
os.remove(file_path)
elif page == "del_dir":
if not permissions['Files'] in user_perms:
if not 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))
console.warning(f"Delete {dir_path} for server {server_id}")
if not self.check_server_id(server_id, 'del_dir'):
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']), dir_path) \
or not helper.check_path_exists(os.path.abspath(dir_path)):
logger.warning(f"Invalid path in del_file file ajax call ({dir_path})")
console.warning(f"Invalid path in del_file file ajax call ({dir_path})")
return
# 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
@tornado.web.authenticated
def put(self, page):
api_key, _, exec_user = self.current_user
superuser = exec_user['superuser']
if api_key is not None:
superuser = superuser and api_key.superuser
server_id = self.get_argument('id', None)
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_user_id_permissions_list(exec_user['user_id'], server_id)
if page == "save_file":
if not permissions['Files'] in user_perms:
if not superuser:
self.redirect("/panel/error?error=Unauthorized access to Files")
return
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))
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(f"Invalid path in save_file file ajax call ({file_path})")
console.warning(f"Invalid path in save_file file ajax call ({file_path})")
return
# Open the file in write mode and store the content in file_object
with open(file_path, 'w', encoding='utf-8') as file_object:
file_object.write(file_contents)
elif page == "rename_file":
if not permissions['Files'] in user_perms:
if not 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))
new_item_name = self.get_body_argument('new_item_name', default=None, strip=True)
if not self.check_server_id(server_id, 'rename_file'):
return
else:
server_id = bleach.clean(server_id)
if item_path is None or new_item_name is None:
logger.warning("Invalid path(s) in rename_file file ajax call")
console.warning("Invalid path(s) in rename_file file ajax call")
return
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(f"Invalid old name path in rename_file file ajax call ({server_id})")
console.warning(f"Invalid old name path in rename_file file ajax call ({server_id})")
return
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(f"Invalid new name path in rename_file file ajax call ({server_id})")
console.warning(f"Invalid new name path in rename_file file ajax call ({server_id})")
return
# RENAME
os.rename(item_path, new_item_path)
@tornado.web.authenticated
def patch(self, page):
api_key, _, exec_user = self.current_user
superuser = exec_user['superuser']
if api_key is not None:
superuser = superuser and api_key.superuser
server_id = self.get_argument('id', None)
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_user_id_permissions_list(exec_user['user_id'], server_id)
if page == "rename_file":
if not permissions['Files'] in user_perms:
if not 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))
new_item_name = self.get_body_argument('new_item_name', default=None, strip=True)
if not self.check_server_id(server_id, 'rename_file'):
return
else:
server_id = bleach.clean(server_id)
if item_path is None or new_item_name is None:
logger.warning("Invalid path(s) in rename_file file ajax call")
console.warning("Invalid path(s) in rename_file file ajax call")
return
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(f"Invalid old name path in rename_file file ajax call ({server_id})")
console.warning(f"Invalid old name path in rename_file file ajax call ({server_id})")
return
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(f"Invalid new name path in rename_file file ajax call ({server_id})")
console.warning(f"Invalid new name path in rename_file file ajax call ({server_id})")
return
# RENAME
os.rename(item_path, new_item_path)
def check_server_id(self, server_id, page_name):
if server_id is None:
logger.warning(f"Server ID not defined in {page_name} file ajax call ({server_id})")
console.warning(f"Server ID not defined in {page_name} file ajax call ({server_id})")
return
else:
server_id = bleach.clean(server_id)
# does this server id exist?
if not self.controller.servers.server_id_exists(server_id):
logger.warning(f"Server ID not found in {page_name} file ajax call ({server_id})")
console.warning(f"Server ID not found in {page_name} file ajax call ({server_id})")
return
return True

View File

@ -14,6 +14,7 @@ try:
import tornado.escape
import tornado.locale
import tornado.httpserver
from app.classes.web.file_handler import FileHandler
from app.classes.web.public_handler import PublicHandler
from app.classes.web.panel_handler import PanelHandler
from app.classes.web.default_handler import DefaultHandler
@ -122,6 +123,7 @@ class Webserver:
(r'/panel/(.*)', PanelHandler, handler_args),
(r'/server/(.*)', ServerHandler, handler_args),
(r'/ajax/(.*)', AjaxHandler, handler_args),
(r'/files/(.*)', FileHandler, handler_args),
(r'/api/stats/servers', ServersStats, handler_args),
(r'/api/stats/node', NodeStats, handler_args),
(r'/ws', SocketHandler, handler_args),

View File

@ -34,6 +34,10 @@
<link rel="alternate icon" href="/static/assets/images/favicon.png" />
<link rel="stylesheet" href="/static/assets/css/crafty.css">
<!-- Alpine.js - The modern jQuery alternative -->
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
<!-- End Alpine.js -->
</head>
<body class="dark-theme">
@ -375,7 +379,7 @@
}
function notify(message) {
console.log(`notify(${message}})`);
console.log(`notify(${message})`);
var paragraphEl = document.createElement('p');
var closeEl = document.createElement('span');
@ -410,7 +414,15 @@
}
webSocket.on('notification', notify);
document.addEventListener('alpine:init', () => {
console.log('%c[Crafty Controller] %cAlpine.js pre-initialization!', 'font-weight: 900; color: #800080;', 'color: #eee;');
})
document.addEventListener('alpine:initialized', () => {
console.log('%c[Crafty Controller] %cAlpine.js initialized!', 'font-weight: 900; color: #800080;', 'color: #eee;');
})
$(document).ready(function () {
console.log('%c[Crafty Controller] %cReady for JS!', 'font-weight: 900; color: #800080;', 'font-weight: 900; color: #eee;');
$('#support_logs').click(function () {
var dialog = bootbox.dialog({
message: '<p class="text-center mb-0"><i class="fa fa-spin fa-cog"></i>{{ translate('notify', 'preparingLogs', data['lang']) }}</p>',

View File

@ -2,11 +2,11 @@
<footer class="footer">
<div class="container-fluid ">
<span class="text-muted d-block text-center text-sm-left d-sm-inline-block">{{ translate('footer', 'copyright', data['lang']) }} © 2021 - 2022 <a href="https://craftycontrol.com/" target="_blank">Crafty Controller</a>. {{ translate('footer', 'allRightsReserved', data['lang']) }}.</span>
<span class="text-muted d-block text-center text-sm-left d-sm-inline-block">{{ translate('footer', 'copyright', data['lang']) }} © 2021 - <span x-data x-text="new Date().getFullYear()"></span> <a href="https://craftycontrol.com/" target="_blank">Crafty Controller</a>. {{ translate('footer', 'allRightsReserved', data['lang']) }}.</span>
<span class="float-none float-sm-right d-block mt-1 mt-sm-0 text-center">{{ translate('footer', 'version', data['lang']) }}: {{ data['version_data'] }}
</span>
</div>
</footer>
<!-- partial -->
<!-- partial -->

View File

@ -134,29 +134,43 @@
<td id="controls{{server['server_data']['server_id']}}" class="actions_serverlist">
{% if server['user_command_permission'] %}
{% if server['stats']['running'] %}
<a class="stop_button" data-id="{{server['server_data']['server_id']}}" data-toggle="tooltip"
title={{ translate('dashboard', 'stop' , data['lang']) }}> <i class="fas fa-stop"></i></a> &nbsp;
<a class="restart_button" data-id="{{server['server_data']['server_id']}}" data-toggle="tooltip"
title={{ translate('dashboard', 'restart' , data['lang']) }}> <i class="fas fa-sync"></i></a>
&nbsp;
<a class="kill_button" data-id="{{server['server_data']['server_id']}}" class="kill_button"
data-toggle="tooltip" title={{ translate('dashboard', 'kill' , data['lang']) }}> <i
class="fas fa-skull"></i></a> &nbsp;
<a data-id="{{server['server_data']['server_id']}}" class="stop_button"
data-toggle="tooltip" title="{{ translate('dashboard', 'stop' , data['lang']) }}">
<i class="fas fa-stop"></i>
</a> &nbsp;
<a data-id="{{server['server_data']['server_id']}}" class="restart_button"
data-toggle="tooltip" title="{{ translate('dashboard', 'restart' , data['lang']) }}">
<i class="fas fa-sync"></i>
</a> &nbsp;
<a data-id="{{server['server_data']['server_id']}}" class="kill_button"
data-toggle="tooltip" title="{{ translate('dashboard', 'kill' , data['lang']) }}">
<i class="fas fa-skull"></i>
</a> &nbsp;
{% elif server['stats']['updating']%}
<!-- WHAT HAPPENED HERE -->
<a data-id="{{server['server_data']['server_id']}}" class="">{{ translate('serverTerm', 'updating',
data['lang']) }}</i></a>
{% elif server['stats']['waiting_start']%}
<!-- WHAT HAPPENED HERE -->
<a data-id="{{server['server_data']['server_id']}}" class="" title={{
translate('dashboard', 'delay-explained' , data['lang'])}}>{{ translate('dashboard', 'starting',
data['lang']) }}</i></a>
{% else %}
<a data-id="{{server['server_data']['server_id']}}" class="play_button"><i class="fas fa-play"
data-toggle="tooltip" title={{ translate('dashboard', 'start' , data['lang']) }}></i></a> &nbsp;
<a data-id="{{server['server_data']['server_id']}}" class="clone_button"> <i class="fas fa-clone"
data-toggle="tooltip" title={{ translate('dashboard', 'clone' , data['lang']) }}></i></a>&nbsp;
<a class="kill_button" data-id="{{server['server_data']['server_id']}}" class="kill_button"
data-toggle="tooltip" title={{ translate('dashboard', 'kill' , data['lang']) }}> <i
class="fas fa-skull"></i></a> &nbsp;
<a data-id="{{server['server_data']['server_id']}}" class="play_button"
data-toggle="tooltip" title="{{ translate('dashboard', 'start' , data['lang']) }}">
<i class="fas fa-play"></i>
</a> &nbsp;
<a data-id="{{server['server_data']['server_id']}}" class="clone_button"
data-toggle="tooltip" title="{{ translate('dashboard', 'clone' , data['lang']) }}">
<i class="fas fa-clone"></i>
</a> &nbsp;
<a data-id="{{server['server_data']['server_id']}}" class="kill_button"
data-toggle="tooltip" title="{{ translate('dashboard', 'kill' , data['lang']) }}">
<i class="fas fa-skull"></i>
</a> &nbsp;
{% end %}
{% end %}
</td>
@ -439,9 +453,9 @@
send_command(server_id, 'start_server');
bootbox.alert({
backdrop: true,
title: '{% raw translate("dashboard", "sendingCommand", data['lang']) %}',
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> &nbsp; {% raw translate("dashboard", "bePatientStart", data['lang']) %} </div>'
});
title: '{% raw translate("dashboard", "sendingCommand", data["lang"]) %}',
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> &nbsp; {% raw translate("dashboard", "bePatientStart", data["lang"]) %} </div>'
});
});
$(".stop_button").click(function () {
@ -450,9 +464,9 @@
send_command(server_id, 'stop_server');
bootbox.alert({
backdrop: true,
title: '{% raw translate("dashboard", "sendingCommand", data['lang']) %}',
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> &nbsp; {% raw translate("dashboard", "bePatientStop", data['lang']) %} </div>'
});
title: '{% raw translate("dashboard", "sendingCommand", data["lang"]) %}',
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> &nbsp; {% raw translate("dashboard", "bePatientStop", data["lang"]) %} </div>'
});
});
$(".restart_button").click(function () {
@ -460,9 +474,9 @@
send_command(server_id, 'restart_server');
bootbox.alert({
backdrop: true,
title: '{% raw translate("dashboard", "sendingCommand", data['lang']) %}',
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> &nbsp; {% raw translate("dashboard", "bePatientRestart", data['lang']) %} </div>'
});
title: '{% raw translate("dashboard", "sendingCommand", data["lang"]) %}',
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> &nbsp; {% raw translate("dashboard", "bePatientRestart", data["lang"]) %} </div>'
});
});
$(".kill_button").click(function () {
server_id = $(this).attr("data-id");
@ -470,11 +484,11 @@
message: "This will kill the server process and all it's subprocesses. Killing a process can potentially corrupt files. Only do this in extreme circumstances. Are you sure you would like to continue?",
buttons: {
confirm: {
label: '{% raw translate("dashboard", "kill", data['lang']) %}',
label: '{% raw translate("dashboard", "kill", data["lang"]) %}',
className: 'btn-danger'
},
cancel: {
label: '{% raw translate("panelConfig", "cancel", data['lang']) %}',
label: '{% raw translate("panelConfig", "cancel", data["lang"]) %}',
className: 'btn-secondary'
}
},
@ -482,7 +496,7 @@
if (result) {
send_kill(server_id);
var dialog = bootbox.dialog({
title: '{% raw translate("dashboard", "killing", data['lang']) %}',
title: '{% raw translate("dashboard", "killing", data["lang"]) %}',
message: '<p><i class="fa fa-spin fa-spinner"></i> Loading...</p>'
});
@ -524,13 +538,13 @@
if (webSocket) {
webSocket.on('update_button_status', function (updateButton) {
var id = 'controls';
var dataId = updateButton.server_id;
var string = updateButton.string
var id = id.concat(updateButton.server_id);
if (updateButton.isUpdating) {
console.log(updateButton.isUpdating)
document.getElementById(id).innerHTML = string;
let serverId = updateButton.server_id;
let message = updateButton.string;
let updating = updateButton.isUpdating;
let id = 'controls' + serverId;
if (updating) {
console.log(updating)
document.getElementById(id).innerHTML = message;
}
else {
window.location.reload()
@ -547,9 +561,9 @@
send_command(server_id, 'clone_server');
bootbox.alert({
backdrop: true,
title: '{% raw translate("dashboard", "sendingCommand", data['lang']) %}',
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> &nbsp; {% raw translate("dashboard", "bePatientClone", data['lang']) %} </div>'
});
title: '{% raw translate("dashboard", "sendingCommand", data["lang"]) %}',
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> &nbsp; {% raw translate("dashboard", "bePatientClone", data["lang"]) %} </div>'
});
});
});
@ -605,4 +619,4 @@
</script>
{% end %}
{% end %}

View File

@ -91,7 +91,7 @@
document.body.onload = (() => {
console.log('calculateTime');
startedUTC = '{{ data['server_stats']['started'] }}';
startedUTC = "{{ data['server_stats']['started'] }}";
if (startedUTC != 'False') {
console.log('started utc:', startedUTC);
startedUTC = moment.utc(startedUTC, 'YYYY-MM-DD HH:mm:ss');
@ -220,4 +220,4 @@
webSocket.on('update_server_details', update_server_details);
//}
});
</script>
</script>

View File

@ -123,136 +123,138 @@
{% block js %}
<script>
const serverId = new URLSearchParams(document.location.search).get('id')
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
function backup_started(time='5-10') {
bootbox.alert({
message: "{{ translate('serverBackups', 'backupTask', data['lang']) }}",
backdrop: true
});
}
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
function del_backup(filename, id){
var token = getCookie("_xsrf")
function backup_started(time='5-10') {
bootbox.alert({
message: "{{ translate('serverBackups', 'backupTask', data['lang']) }}",
backdrop: true
});
}
data_to_send = { file_name :filename}
function del_backup(filename, id){
var token = getCookie("_xsrf")
console.log('Sending Command to delete backup: ' + filename)
$.ajax({
type: "DELETE",
headers: {'X-XSRFToken': token},
url: '/ajax/del_backup?server_id='+id,
data: {
file_path: filename,
id: id
},
success: function(data) {
location.reload();
},
});
}
data_to_send = { file_name :filename}
function restore_backup(filename, id){
var token = getCookie("_xsrf")
console.log('Sending Command to delete backup: ' + filename)
$.ajax({
type: "DELETE",
headers: {'X-XSRFToken': token},
url: '/ajax/del_backup?server_id='+id,
data: {
file_path: filename,
id: id
},
success: function(data) {
location.reload();
},
});
}
console.log('Sending Command to restore backup: ' + filename)
$.ajax({
type: "POST",
headers: {'X-XSRFToken': token},
url: '/ajax/restore_backup?server_id='+id,
data: {
zip_file: filename,
id: id
},
success: function(data) {
var dialog = bootbox.dialog({
message: '<i class="fa fa-spin fa-spinner"></i> {{ translate('serverBackups', 'restoring', data['lang']) }}',
closeButton: false
});
setTimeout(function(){
location.href=('/panel/dashboard');
}, 15000);
},
function restore_backup(filename, id){
var token = getCookie("_xsrf")
console.log('Sending Command to restore backup: ' + filename)
$.ajax({
type: "POST",
headers: {'X-XSRFToken': token},
url: '/ajax/restore_backup?server_id='+id,
data: {
zip_file: filename,
id: id
},
success: function(data) {
var dialog = bootbox.dialog({
message: '<i class="fa fa-spin fa-spinner"></i> {{ translate('serverBackups', 'restoring', data['lang']) }}',
closeButton: false
});
setTimeout(function(){
location.href=('/panel/dashboard');
}, 15000);
},
});
}
$( document ).ready(function() {
console.log( "ready!" );
$("#backup_config_box").hide();
$("#backup_save_note").hide();
$( document ).ready(function() {
console.log( "ready!" );
$("#backup_config_box").hide();
$("#backup_save_note").hide();
$("#show_config").click(function () {
$("#backup_config_box").toggle();
$('#backup_button').hide();
$('#backup_save_note').show();
$('#backup_data').hide();
});
$("#show_config").click(function () {
$("#backup_config_box").toggle();
$('#backup_button').hide();
$('#backup_save_note').show();
$('#backup_data').hide();
});
$('#backup_table').DataTable({
"order": [[ 1, "desc" ]],
"paging":true,
"lengthChange": false,
"searching": true,
"ordering": true,
"info": true,
"autoWidth": false,
"responsive": true,
});
$('#backup_table').DataTable({
"order": [[ 1, "desc" ]],
"paging":true,
"lengthChange": false,
"searching": true,
"ordering": true,
"info": true,
"autoWidth": false,
"responsive": true,
});
$( ".del_button" ).click(function() {
var file_to_del = $(this).data("file");
$( ".del_button" ).click(function() {
var file_to_del = $(this).data("file");
console.log("file to delete is" + file_to_del);
console.log("file to delete is" + file_to_del);
bootbox.confirm({
title: "{% raw translate('serverBackups', 'destroyBackup', data['lang']) %}",
message: "{{ translate('serverBackups', 'confirmDelete', data['lang']) }}",
buttons: {
cancel: {
label: '<i class="fas fa-times"></i> {{ translate("serverBackups", "cancel", data['lang']) }}'
},
confirm: {
label: '<i class="fas fa-check"></i> {{ translate("serverBackups", "confirm", data['lang']) }}'
}
},
callback: function (result) {
console.log(result);
if (result == true) {
var full_path = '{{ data['backup_path'] }}' + '/' + file_to_del;
del_backup(full_path, {{ data['server_stats']['server_id']['server_id'] }} );
}
}
});
});
bootbox.confirm({
title: "{% raw translate('serverBackups', 'destroyBackup', data['lang']) %}",
message: "{{ translate('serverBackups', 'confirmDelete', data['lang']) }}",
buttons: {
cancel: {
label: '<i class="fas fa-times"></i> {{ translate("serverBackups", "cancel", data['lang']) }}'
},
confirm: {
label: '<i class="fas fa-check"></i> {{ translate("serverBackups", "confirm", data['lang']) }}'
}
},
callback: function (result) {
console.log(result);
if (result == true) {
var full_path = '{{ data['backup_path'] }}' + '/' + file_to_del;
del_backup(full_path, serverId);
}
}
});
});
$( ".restore_button" ).click(function() {
var file_to_restore = $(this).data("file");
$( ".restore_button" ).click(function() {
var file_to_restore = $(this).data("file");
bootbox.confirm({
title: "{{ translate('serverBackups', 'restore', data['lang']) }} "+file_to_restore,
message: "{{ translate('serverBackups', 'confirmRestore', data['lang']) }}",
buttons: {
cancel: {
label: '<i class="fas fa-times"></i> {{ translate("serverBackups", "cancel", data['lang']) }}'
},
confirm: {
label: '<i class="fas fa-check"></i> {{ translate("serverBackups", "restore", data['lang']) }}'
}
},
callback: function (result) {
console.log(result);
if (result == true) {
restore_backup(file_to_restore, {{ data['server_stats']['server_id']['server_id'] }} );
}
}
});
bootbox.confirm({
title: "{{ translate('serverBackups', 'restore', data['lang']) }} "+file_to_restore,
message: "{{ translate('serverBackups', 'confirmRestore', data['lang']) }}",
buttons: {
cancel: {
label: '<i class="fas fa-times"></i> {{ translate("serverBackups", "cancel", data['lang']) }}'
},
confirm: {
label: '<i class="fas fa-check"></i> {{ translate("serverBackups", "restore", data['lang']) }}'
}
},
callback: function (result) {
console.log(result);
if (result == true) {
restore_backup(file_to_restore, serverId);
}
}
});
});
});
@ -260,4 +262,4 @@
</script>
{% end %}
{% end %}

View File

@ -32,7 +32,7 @@
<div class="col-sm-12 grid-margin">
<div class="card">
<div class="card-body pt-0">
{% include "parts/server_controls_list.html %}
{% include "parts/server_controls_list.html" %}
<div class="row">
<div class="col-md-6 col-sm-12">
@ -188,14 +188,14 @@
</div>
<div class="text-center">
{% if data['server_stats']['running'] %}
<button onclick="send_command(server_id, 'update_executable');" id="update_executable"
<button onclick="send_command(serverId, 'update_executable');" id="update_executable"
style="max-width: 7rem;" class="btn btn-warning m-1 flex-grow-1 disabled">{{ translate('serverConfig',
'update', data['lang']) }}</button>
<a class="btn btn-sm btn-danger disabled">{{ translate('serverConfig', 'deleteServer', data['lang'])
}}</a><br />
<small>{{ translate('serverConfig', 'stopBeforeDeleting', data['lang']) }}</small>
{% else %}
<button onclick="send_command(server_id, 'update_executable');" id="update_executable"
<button onclick="send_command(serverId, 'update_executable');" id="update_executable"
style="max-width: 7rem;" class="btn btn-warning m-1 flex-grow-1">{{ translate('serverConfig',
'update', data['lang']) }}</button>
<button onclick="deleteConfirm()" class="btn btn-sm btn-danger">{{ translate('serverConfig',
@ -221,6 +221,8 @@
{% block js %}
<script>
const serverId = new URLSearchParams(document.location.search).get('id')
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
function getCookie(name) {
@ -238,7 +240,7 @@
$.ajax({
type: "DELETE",
headers: { 'X-XSRFToken': token },
url: '/ajax/delete_server?id={{ data['server_stats']['server_id']['server_id'] }}',
url: '/ajax/delete_server?id=' + serverId,
data: {
},
success: function (data) {
@ -252,7 +254,7 @@
$.ajax({
type: "DELETE",
headers: { 'X-XSRFToken': token },
url: '/ajax/delete_server_files?id={{ data['server_stats']['server_id']['server_id'] }}',
url: '/ajax/delete_server_files?id=' + serverId,
data: {
},
success: function (data) {
@ -262,16 +264,14 @@
});
}
let server_id = '{{ data['server_stats']['server_id']['server_id'] }}';
function send_command(server_id, command) {
function send_command(serverId, command) {
//<!-- this getCookie function is in base.html-->
var token = getCookie("_xsrf");
$.ajax({
type: "POST",
headers: { 'X-XSRFToken': token },
url: '/server/command?command=' + command + '&id=' + server_id,
url: '/server/command?command=' + command + '&id=' + serverId,
success: function (data) {
console.log("got response:");
console.log(data);
@ -373,4 +373,4 @@
</script>
{% end %}
{% end %}

File diff suppressed because it is too large Load Diff

View File

@ -24,14 +24,14 @@
</div>
<!-- Page Title Header Ends-->
{% include "parts/details_stats.html %}
{% include "parts/details_stats.html" %}
<div class="row">
<div class="col-sm-12 grid-margin">
<div class="card">
<div class="card-body pt-0">
{% include "parts/server_controls_list.html %}
{% include "parts/server_controls_list.html" %}
<div class="col-md-12">
<div class="input-group">
@ -55,42 +55,44 @@
{% block js %}
<script>
function get_server_log(){
if( !$("#stop_scroll").is(':checked')){
$.ajax({
type: 'GET',
url: '/ajax/server_log?id={{ data['server_stats']['server_id']['server_id'] }}&full=1',
dataType: 'text',
success: function (data) {
console.log('Got Log From Server')
$('#virt_console').html(data);
scroll();
},
});
}
const serverId = new URLSearchParams(document.location.search).get('id')
function get_server_log(){
if( !$("#stop_scroll").is(':checked')){
$.ajax({
type: 'GET',
url: '/ajax/server_log?id=' + serverId + '&full=1',
dataType: 'text',
success: function (data) {
console.log('Got Log From Server')
$('#virt_console').html(data);
scroll();
},
});
}
}
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
$( document ).ready(function() {
console.log( "ready!" );
get_server_log()
$( document ).ready(function() {
console.log( "ready!" );
get_server_log()
});
});
function scroll(){
var logview = $('#virt_console');
if(logview.length)
logview.scrollTop(logview[0].scrollHeight - logview.height());
}
function scroll(){
var logview = $('#virt_console');
if(logview.length)
logview.scrollTop(logview[0].scrollHeight - logview.height());
}
</script>
{% end %}
{% end %}

View File

@ -31,7 +31,7 @@
<div class="col-sm-12 grid-margin">
<div class="card">
<div class="card-body pt-0">
{% include "parts/server_controls_list.html %}
{% include "parts/server_controls_list.html" %}
<div class="row">
<div class="col-md-8 col-sm-8">
@ -264,4 +264,4 @@ try{
window.onload(startup())
</script>
{% end %}
{% end %}

View File

@ -233,6 +233,9 @@ td {
{% block js %}
<script>
const serverId = new URLSearchParams(document.location.search).get('id')
$( document ).ready(function() {
console.log('ready for JS!')
$('#schedule_table').DataTable({
@ -325,7 +328,6 @@ function ifDays(that) {
$( ".del_button" ).click(function() {
var sch_id = $(this).data('sch');
var server_id = {{ data['server_stats']['server_id']['server_id'] }};
console.log(sch_id)
@ -344,7 +346,7 @@ $( ".del_button" ).click(function() {
callback: function (result) {
console.log(result);
if (result == true) {
del_task(sch_id, server_id);
del_task(sch_id, serverId);
}
}
});
@ -369,4 +371,4 @@ function del_task(sch_id, id){
</script>
{% end %}
{% end %}

View File

@ -61,9 +61,9 @@
</div>
{% else %}
<div id="control_buttons" class="mt-4 flex-wrap d-flex justify-content-between justify-content-md-center align-items-center px-5 px-md-0" style="visibility: visible">
<button onclick="send_command(server_id, 'start_server');" id="start-btn" style="max-width: 7rem;" class="btn btn-primary m-1 flex-grow-1">{{ translate('serverTerm', 'start', data['lang']) }}</button>
<button onclick="send_command(server_id, 'restart_server');" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1">{% raw translate('serverTerm', 'restart', data['lang']) %}</button>
<button onclick="send_command(server_id, 'stop_server');" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1">{{ translate('serverTerm', 'stop', data['lang']) }}</button>
<button onclick="send_command(serverId, 'start_server');" id="start-btn" style="max-width: 7rem;" class="btn btn-primary m-1 flex-grow-1">{{ translate('serverTerm', 'start', data['lang']) }}</button>
<button onclick="send_command(serverId, 'restart_server');" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1">{% raw translate('serverTerm', 'restart', data['lang']) %}</button>
<button onclick="send_command(serverId, 'stop_server');" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1">{{ translate('serverTerm', 'stop', data['lang']) }}</button>
</div>
{% end %}
{% end %}
@ -93,7 +93,9 @@
{% block js %}
<script>
function send_command(server_id, command) {
const serverId = new URLSearchParams(document.location.search).get('id')
function send_command(serverId, command) {
if (command == 'start_server') {
startBtn.setAttribute('disabled', 'disabled');
restartBtn.removeAttribute('disabled');
@ -110,7 +112,7 @@
$.ajax({
type: "POST",
headers: { 'X-XSRFToken': token },
url: '/server/command?command=' + command + '&id=' + server_id,
url: '/server/command?command=' + command + '&id=' + serverId,
success: function (data) {
console.log("got response:");
console.log(data);
@ -120,28 +122,28 @@
if (webSocket) {
webSocket.on('update_button_status', function (updateButton) {
if (updateButton.isUpdating) {
if (updateButton.server_id == '{{ data['server_stats']['server_id']['server_id'] }}') {
if (updateButton.server_id == serverId) {
console.log(updateButton.isUpdating)
document.getElementById('control_buttons').innerHTML = '<button onclick="" id="start-btn" style="max-width: 7rem;" class="btn btn-primary m-1 flex-grow-1">{{ translate("serverTerm", "updating", data['lang']) }}</button><button onclick="" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1">{% raw translate("serverTerm", "restart", data['lang']) %}</button><button onclick="" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1 disabled">{{ translate("serverTerm", "stop", data['lang']) }}</button>';
document.getElementById('control_buttons').innerHTML = '<button onclick="" id="start-btn" style="max-width: 7rem;" class="btn btn-primary m-1 flex-grow-1">{{ translate("serverTerm", "updating", data["lang"]) }}</button><button onclick="" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1">{% raw translate("serverTerm", "restart", data["lang"]) %}</button><button onclick="" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1 disabled">{{ translate("serverTerm", "stop", data["lang"]) }}</button>';
}
}
else {
if (updateButton.server_id == '{{ data['server_stats']['server_id']['server_id'] }}') {
if (updateButton.server_id == serverId) {
window.location.reload()
document.getElementById('update_control_buttons').innerHTML = '<button onclick="send_command(server_id, "start_server");" id="start-btn" style="max-width: 7rem;" class="btn btn-primary m-1 flex-grow-1">{{ translate("serverTerm", "start", data['lang']) }}</button><button onclick="send_command(server_id, "restart_server");" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1">{% raw translate("serverTerm", "restart", data['lang']) %}</button><button onclick="" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1 disabled">{{ translate("serverTerm", "stop", data['lang']) }}</button>';
document.getElementById('update_control_buttons').innerHTML = '<button onclick="send_command(serverId, "start_server");" id="start-btn" style="max-width: 7rem;" class="btn btn-primary m-1 flex-grow-1">{{ translate("serverTerm", "start", data["lang"]) }}</button><button onclick="send_command(serverId, "restart_server");" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1">{% raw translate("serverTerm", "restart", data["lang"]) %}</button><button onclick="" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1 disabled">{{ translate("serverTerm", "stop", data["lang"]) }}</button>';
}
}
});
}
// Convert running to lower case (example: 'True' converts to 'true') and
// then to boolean via JSON.parse()
let online = JSON.parse('{{ data['server_stats']['running'] }}'.toLowerCase());
let online = JSON.parse("{{ data['server_stats']['running'] }}".toLowerCase());
let startBtn = document.querySelector('#start-btn');
let restartBtn = document.querySelector('#restart-btn');
let stopBtn = document.querySelector('#stop-btn');
{% if data['permissions']['Commands'] in data['user_permissions'] %}
//{% if data['permissions']['Commands'] in data['user_permissions'] %}
if (online) {
startBtn.setAttribute('disabled', 'disabled');
restartBtn.removeAttribute('disabled');
@ -151,14 +153,12 @@
restartBtn.setAttribute('disabled', 'disabled');
stopBtn.setAttribute('disabled', 'disabled');
}
{% end %}
let server_id = '{{ data['server_stats']['server_id']['server_id'] }}';
//{% end %}
function get_server_log() {
$.ajax({
type: 'GET',
url: '/ajax/server_log?id={{ data['server_stats']['server_id']['server_id'] }}',
url: '/ajax/server_log?id=' + serverId,
dataType: 'text',
success: function (data) {
console.log('Got Log From Server')
@ -195,7 +195,7 @@
$('#server_command').on('keydown', function (e) {
if (e.which == 13) {
$(this).attr("disabled", "disabled"); //Disable textbox to prevent multiple submit
send_command_to_server()
sendConsoleCommand()
$(this).removeAttr("disabled"); //Enable the textbox again if needed.
$(this).focus();
}
@ -211,7 +211,7 @@
$("#submit").click(function (e) {
e.preventDefault();
send_command_to_server();
sendConsoleCommand();
});
@ -222,28 +222,31 @@
}
function send_command_to_server() {
var server_command = $("#server_command").val()
console.log(server_command)
async function sendConsoleCommand() {
let serverCommand = $("#server_command").val()
console.log(serverCommand)
cmdHistory.push(server_command);
cmdHistory.push(serverCommand);
var token = getCookie("_xsrf")
let token = getCookie("_xsrf")
data_to_send = { command: server_command, }
let formdata = new FormData();
console.log('sending command: ' + server_command)
$.ajax({
type: "POST",
headers: { 'X-XSRFToken': token },
url: '/ajax/send_command?id={{ data['server_stats']['server_id']['server_id'] }}',
data: data_to_send,
success: function (data) {
console.log("got response:");
console.log(data);
$("#server_command").val('')
formdata.append('command', serverCommand)
console.log('sending command: ' + serverCommand)
let res = await fetch("/ajax/send_command?id=" + serverId, {
method: 'POST',
headers: {
'X-XSRFToken': token
},
body: formdata,
});
let responseData = await res.text();
console.log("got response:");
console.log(responseData);
$("#server_command").val('')
}
@ -272,4 +275,4 @@
}
</script>
{% end %}
{% end %}

View File

@ -426,7 +426,7 @@
document.getElementById("root_files_button").addEventListener("click", function(){
if(document.forms["zip"]["server_path"].value != ""){
if(document.getElementById('root_files_button').classList.contains('clicked')){
document.getElementById('main-tree-div').innerHTML = '<input type="radio" id="main-tree-input" name="root_path" value="" checked><span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path=""><i class="far fa-folder"></i><i class="far fa-folder-open"></i>{{ translate('serverFiles', 'files', data['lang']) }}</span></input>'
document.getElementById('main-tree-div').innerHTML = '<input type="radio" id="main-tree-input" name="root_path" value="" checked><span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path=""><i class="far fa-folder"></i><i class="far fa-folder-open"></i>{{ translate("serverFiles", "files", data["lang"]) }}</span></input>'
}else{
document.getElementById('root_files_button').classList.add('clicked')
}
@ -482,8 +482,8 @@ function hide(event) {
function wait_msg(importing){
bootbox.alert({
title: importing ? '{% raw translate("serverWizard", "importing", data['lang']) %}' : '{% raw translate("serverWizard", "downloading", data['lang']) %}',
message: '<i class="fas fa-cloud-download"></i> {% raw translate("serverWizard", "bePatient", data['lang']) %}',
title: importing ? '{% raw translate("serverWizard", "importing", data["lang"]) %}' : '{% raw translate("serverWizard", "downloading", data["lang"]) %}',
message: '<i class="fas fa-cloud-download"></i> {% raw translate("serverWizard", "bePatient", data["lang"]) %}',
});
}
@ -647,4 +647,4 @@ function hide(event) {
}
//]]>
</script>
{% end %}
{% end %}

View File

@ -76,10 +76,67 @@
"clickRoot": "Napsauta tästä valitaksesi juurihakemiston",
"explainRoot": "Napsauta alla olevaa painiketta valitaksesi palvelimesi juurihakemiston arkistosta"
},
"usersConfig":{
"userConfig":{
"pageTitle": "Muokkaa käyttäjää",
"pageTitleNew": "Luo käyttäjä",
"config": "Asetukset",
"apiKey": "API-avaimet",
"userSettings": "Käyttäjäasetukset",
"userName": "Käyttäjätunnus",
"userNameDesc": "Millä nimellä haluat kutsua tätä käyttäjää?",
"password": "Salasana",
"repeat": "Toista salasana",
"leaveBlank": "Jos haluat muokata käyttäjää vaihtamatta salasanaa, jätä se tyhjäksi.",
"craftyPermDesc": "Craftyn oikeuksia, joita tällä käyttäjällä on",
"gravEmail": "Gravatar™ Sähköposti",
"gravDesc": "Tämä shäköposti on vain Gravatar™-palvelun käyttöön. Crafty ei missään olosuhteissa käytä tätä sähköpostia muuhun kuin Gravatar™-tietojesi etsimiseen",
"userLang": "Käyttäjän kieli",
"userRoles": "Käyttäjän roolit",
"userRolesDesc": "Roolit, joissa tämä käyttäjä on",
"roleName": "Roolin nimi",
"member": "Jäsen?",
"craftyPerms": "Craftyn oikeudet: ",
"permName":"Oikeuden nimi",
"auth": "Valtuutettu? ",
"uses": "Sallittujen käyttäkertojen määtä (-1 == Ei rajaa)",
"super": "Järjestelmänvalvoja",
"enabled": "Päällä",
"configArea": "Käyttäjän Asetukset",
"configAreaDesc": "Tässä voi muokata kaikkia käyttäjän asetuksia",
"created": "Luotu: ",
"lastLogin": "Viimeinen Sisäänkirjautuminen: ",
"lastUpdate": "Viimeinen Muokkaus: ",
"lastIP": "Viimeinen IP: ",
"deleteUserB": "Poista käyttäjä",
"notExist": "Et voi poistaa mitään, joka ei ole olemassa!",
"delSuper": "Et voi poistaa järjestelmänvalvojaa!",
"deleteUser": "Poista käyttäjä: ",
"confirmDelete": "Oletko varma, että haluat poistaa tämän käyttäjän? Tätä ei voi peruuttaa."
},
"rolesConfig": {
"pageTitle": "Muokkaa roolia",
"pageTitleNew": "Luo rooli",
"config": "Asetukset",
"roleTitle": "Roolin asetukset",
"roleName": "Roolin nimi: ",
"roleDesc": "Millä nimellä haluaisit kutsua tätä roolia?",
"roleServers": "Sallitut palvelimet",
"serversDesc": "Palvelimet, joihin tällä roolilla on pääsy",
"serverName": "Server Name",
"serverAccess": "Pääsy?",
"rolePerms": "Roolin käyttöoikeudet",
"permsServer": "Tämän roolin käyttöoikeudet näille määritetyille palvelimille",
"permName": "Oikeuden nimi",
"permAccess": "Pääsy?",
"roleUsers": "Roolin käyttäjät: ",
"roleUserName": "Käyttäjätunnus",
"roleConfigArea": "Roolin asetukset",
"configDesc": "Täällä voit muuttaa roolin asetuksia",
"created": "Luotu: ",
"configUpdate": "Viimeinen muokkaus: ",
"delRole": "Poista rooli",
"doesNotExist": "Et voi poistaa mitään, joka ei ole olemassa!"
},
"dashboard": {
"dashboard": "Kojelauta",
"memUsage": "Muistin käyttö",
@ -113,16 +170,17 @@
"cpuCurFreq": "Nykyinen kellotaajuus",
"cpuMaxFreq": "Maksimi kellotaajuus",
"cpuCores": "Suorittimen ytimet",
"start": "Alkaa",
"stop": "Lopettaa",
"clone": "Klooni",
"start": "Käynnistä",
"stop": "Pysäytä",
"clone": "Kloonaa",
"kill": "Tapa prosessi",
"restart": "Uudelleenkäynnistää",
"killing": "Tappamisprosessi ...",
"starting": "Myöhästynyt lähtö",
"delay-explained": "Palvelu/agentti on äskettäin aloittanut ja viivästyttää minecraft -palvelimen ilmentymän alkua",
"killing": "Tapetaan prosessia...",
"starting": "Myöhästynyt käynnistys",
"delay-explained": "Palvelu/agentti on äskettäin aloittanut ja viivästyttää palvelimen käynnistämistä",
"no-servers": "Palvelimia ei tällä hetkellä ole. Aloita napsauttamalla",
"welcome": "Tervetuloa Crafty Controller"
"welcome": "Tervetuloa Crafty Controlleriin",
"crashed": "Kaatui"
},
"accessDenied": {
"accessDenied": "Käyttö estetty",
@ -133,7 +191,7 @@
"serverStats": {
"online": "Päällä",
"offline": "Pois päältä",
"starting": "Myöhästynyt lähtö",
"starting": "Myöhästynyt aloitus",
"serverStatus": "Palvelimen tila",
"serverStarted": "Palvelin käynnistyi",
"serverUptime": "Palvelimen käyttöaika",
@ -165,7 +223,7 @@
"restart": "Uudelleen&shy;käynnistä",
"stop": "Sammuta",
"updating": "Updating",
"starting": "Myöhästynyt lähtö",
"starting": "Myöhästynyt aloitus",
"delay-explained": "Palvelu/agentti on äskettäin aloittanut ja viivästyttää minecraft -palvelimen ilmentymän alkua"
},
"serverPlayerManagement": {
@ -277,7 +335,9 @@
"noDeleteFiles": "Ei, poista vain paneelista",
"sendingDelete": "Poistetaan palvelinta",
"bePatientDelete": "Ole kärsivällinen, kun poistamme palvelimesi Crafty-paneelista. Tämä näyttö sulkeutuu hetken kuluttua.",
"bePatientDeleteFiles" : "Ole kärsivällinen, kun poistamme palvelimesi Crafty-paneelista ja poistamme kaikki tiedostot. Tämä näyttö sulkeutuu hetken kuluttua."
"bePatientDeleteFiles" : "Ole kärsivällinen, kun poistamme palvelimesi Crafty-paneelista ja poistamme kaikki tiedostot. Tämä näyttö sulkeutuu hetken kuluttua.",
"crashTime": "Kaatumisen aikakatkaisu",
"crashTimeDesc": "Kuinka kauan meidän pitäisi odottaa, ennen kuin harkitsemme palvelimesi kaatuneen?"
},
"serverConfigHelp": {
"title": "Palvelimen asetukset",
@ -297,6 +357,18 @@
]
},
"panelConfig": {
"pageTitle": "Paneelin asetukset",
"users": "Käyttäjät",
"roles": "Roolit",
"newUser": "Luo uusi käyttäjä",
"newRole": "Luo uusi rooli",
"user": "Käyttäjä",
"enabled": "Käytössä",
"allowedServers": "Sallitut palvelimet",
"assignedRoles": "Määrätyt roolit",
"edit": "Muokkaa",
"role": "Rooli",
"roleUsers": "Roolin käyttäjät",
"save": "Tallenna",
"cancel": "Peruuta",
"delete": "Poista",
@ -395,6 +467,23 @@
"doesNotWorkWithoutJavascript": "<strong>Varoitus: </strong>Crafty ei toimi kunnolla ilman JavaScriptiä!"
},
"apiKeys": {
"pageTitle": "Muokkaa käyttäjän API-avaimia",
"config": "Asetukset",
"apiKeys": "API-avaimet",
"name": "Nimi",
"created": "Luotu",
"perms": "Käyttöoikeudet",
"buttons": "Painikkeet",
"yes": "Kyllä",
"no": "Ei",
"server": "Palvelin: ",
"crafty": "Crafty: ",
"getToken": "Hanki API-avain",
"createNew": "Luo uusi API-avain",
"nameDesc": "Millä nimellä haluat kutsua tätä API-avainta? ",
"permName": "Oikeuden nimi",
"auth":"Valtuutettu? ",
"superUser": "Järjestelmänvalvoja",
"deleteKeyConfirmation": "Haluatko varmasti poistaa tämän API-avaimen? Tämä on peruuttamaton toimenpide!",
"deleteKeyConfirmationTitle": "Poistetaanko API-avain ${keyId}?"
}