mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Improved File Loading, Fixed Port checking
This commit is contained in:
parent
abb7b8af08
commit
7dd24b6b15
@ -94,8 +94,8 @@ class Users_Controller:
|
|||||||
users_helper.update_user(user_id, up_data)
|
users_helper.update_user(user_id, up_data)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_user(username, password=None, api_token=None, enabled=True, superuser=False):
|
def add_user(username, password=None, email="default@example.com", api_token=None, enabled=True, superuser=False):
|
||||||
return users_helper.add_user(username, password=password, api_token=api_token, enabled=enabled, superuser=superuser)
|
return users_helper.add_user(username, password=password, email=email, api_token=api_token, enabled=enabled, superuser=superuser)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def remove_user(user_id):
|
def remove_user(user_id):
|
||||||
|
@ -38,6 +38,7 @@ class Users(Model):
|
|||||||
last_ip = CharField(default="")
|
last_ip = CharField(default="")
|
||||||
username = CharField(default="", unique=True, index=True)
|
username = CharField(default="", unique=True, index=True)
|
||||||
password = CharField(default="")
|
password = CharField(default="")
|
||||||
|
email = CharField(default="default@example.com")
|
||||||
enabled = BooleanField(default=True)
|
enabled = BooleanField(default=True)
|
||||||
superuser = BooleanField(default=False)
|
superuser = BooleanField(default=False)
|
||||||
api_token = CharField(default="", unique=True, index=True) # we may need to revisit this
|
api_token = CharField(default="", unique=True, index=True) # we may need to revisit this
|
||||||
@ -112,6 +113,7 @@ class helper_users:
|
|||||||
'last_ip': "127.27.23.89",
|
'last_ip': "127.27.23.89",
|
||||||
'username': "SYSTEM",
|
'username': "SYSTEM",
|
||||||
'password': None,
|
'password': None,
|
||||||
|
'email': "default@example.com",
|
||||||
'enabled': True,
|
'enabled': True,
|
||||||
'superuser': True,
|
'superuser': True,
|
||||||
'api_token': None,
|
'api_token': None,
|
||||||
@ -136,7 +138,7 @@ class helper_users:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_user(username, password=None, api_token=None, enabled=True, superuser=False):
|
def add_user(username, password=None, email=None, api_token=None, enabled=True, superuser=False):
|
||||||
if password is not None:
|
if password is not None:
|
||||||
pw_enc = helper.encode_pass(password)
|
pw_enc = helper.encode_pass(password)
|
||||||
else:
|
else:
|
||||||
@ -149,6 +151,7 @@ class helper_users:
|
|||||||
user_id = Users.insert({
|
user_id = Users.insert({
|
||||||
Users.username: username.lower(),
|
Users.username: username.lower(),
|
||||||
Users.password: pw_enc,
|
Users.password: pw_enc,
|
||||||
|
Users.email: email,
|
||||||
Users.api_token: api_token,
|
Users.api_token: api_token,
|
||||||
Users.enabled: enabled,
|
Users.enabled: enabled,
|
||||||
Users.superuser: superuser,
|
Users.superuser: superuser,
|
||||||
|
@ -97,13 +97,33 @@ class Helpers:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_port(server_port):
|
def check_port(server_port):
|
||||||
|
try:
|
||||||
|
ip = get('https://api.ipify.org').content.decode('utf8')
|
||||||
|
except:
|
||||||
|
ip = 'google.com'
|
||||||
a_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
a_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
a_socket.settimeout(20.0)
|
||||||
ip = get('https://api.ipify.org').content.decode('utf8')
|
|
||||||
|
|
||||||
location = (ip, server_port)
|
location = (ip, server_port)
|
||||||
result_of_check = a_socket.connect_ex(location)
|
result_of_check = a_socket.connect_ex(location)
|
||||||
|
|
||||||
|
a_socket.close()
|
||||||
|
|
||||||
|
if result_of_check == 0:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_server_conn(server_port):
|
||||||
|
a_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
a_socket.settimeout(10.0)
|
||||||
|
ip = '127.0.0.1'
|
||||||
|
|
||||||
|
location = (ip, server_port)
|
||||||
|
result_of_check = a_socket.connect_ex(location)
|
||||||
|
a_socket.close()
|
||||||
|
|
||||||
if result_of_check == 0:
|
if result_of_check == 0:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@ -654,29 +674,58 @@ class Helpers:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_tree(folder, output=""):
|
def generate_tree(folder, output=""):
|
||||||
file_list = os.listdir(folder)
|
file_list = os.listdir(folder)
|
||||||
file_list.sort()
|
file_list = sorted(file_list, key=str.casefold)
|
||||||
for raw_filename in file_list:
|
for raw_filename in file_list:
|
||||||
filename = html.escape(raw_filename)
|
filename = html.escape(raw_filename)
|
||||||
rel = os.path.join(folder, raw_filename)
|
rel = os.path.join(folder, raw_filename)
|
||||||
if os.path.isdir(rel):
|
if os.path.isdir(rel):
|
||||||
output += \
|
output += \
|
||||||
"""<li class="tree-item" data-path="{}">
|
"""<li class="tree-item" data-path="{}">
|
||||||
\n<div data-path="{}" data-name="{}" class="tree-caret tree-ctx-item tree-folder">
|
\n<div id="{}" data-path="{}" data-name="{}" class="tree-caret tree-ctx-item tree-folder">
|
||||||
|
<span id="{}span" class="files-tree-title" data-path="{}" onclick="getDirView(event)">
|
||||||
<i class="far fa-folder"></i>
|
<i class="far fa-folder"></i>
|
||||||
<i class="far fa-folder-open"></i>
|
<i class="far fa-folder-open"></i>
|
||||||
{}
|
{}
|
||||||
</div>
|
</span>
|
||||||
\n<ul class="tree-nested">"""\
|
</div><li>
|
||||||
.format(os.path.join(folder, filename), os.path.join(folder, filename), filename, filename)
|
\n"""\
|
||||||
|
.format(os.path.join(folder, filename), os.path.join(folder, filename), os.path.join(folder, filename), filename, os.path.join(folder, filename), os.path.join(folder, filename), filename)
|
||||||
|
else:
|
||||||
|
output += """<li
|
||||||
|
class="tree-item tree-ctx-item tree-file"
|
||||||
|
data-path="{}"
|
||||||
|
data-name="{}"
|
||||||
|
onclick="clickOnFile(event)"><span style="margin-right: 6px;"><i class="far fa-file"></i></span>{}</li>""".format(os.path.join(folder, filename), filename, filename)
|
||||||
|
return output
|
||||||
|
|
||||||
output += helper.generate_tree(rel)
|
@staticmethod
|
||||||
output += '</ul>\n</li>'
|
def generate_dir(folder, output=""):
|
||||||
|
file_list = os.listdir(folder)
|
||||||
|
file_list = sorted(file_list, key=str.casefold)
|
||||||
|
output += \
|
||||||
|
"""<ul class="tree-nested d-block" id="{}ul">"""\
|
||||||
|
.format(folder)
|
||||||
|
for raw_filename in file_list:
|
||||||
|
filename = html.escape(raw_filename)
|
||||||
|
rel = os.path.join(folder, raw_filename)
|
||||||
|
if os.path.isdir(rel):
|
||||||
|
output += \
|
||||||
|
"""<li class="tree-item" data-path="{}">
|
||||||
|
\n<div id="{}" data-path="{}" data-name="{}" class="tree-caret tree-ctx-item tree-folder">
|
||||||
|
<span id="{}span" class="files-tree-title" data-path="{}" onclick="getDirView(event)">
|
||||||
|
<i class="far fa-folder"></i>
|
||||||
|
<i class="far fa-folder-open"></i>
|
||||||
|
{}
|
||||||
|
</span>
|
||||||
|
</div><li>"""\
|
||||||
|
.format(os.path.join(folder, filename), os.path.join(folder, filename), os.path.join(folder, filename), filename, os.path.join(folder, filename), os.path.join(folder, filename), filename)
|
||||||
else:
|
else:
|
||||||
output += """<li
|
output += """<li
|
||||||
class="tree-item tree-ctx-item tree-file"
|
class="tree-item tree-ctx-item tree-file"
|
||||||
data-path="{}"
|
data-path="{}"
|
||||||
data-name="{}"
|
data-name="{}"
|
||||||
onclick="clickOnFile(event)"><span style="margin-right: 6px;"><i class="far fa-file"></i></span>{}</li>""".format(os.path.join(folder, filename), filename, filename)
|
onclick="clickOnFile(event)"><span style="margin-right: 6px;"><i class="far fa-file"></i></span>{}</li>""".format(os.path.join(folder, filename), filename, filename)
|
||||||
|
output += '</ul>\n'
|
||||||
return output
|
return output
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -130,7 +130,7 @@ class Controller:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_system_user():
|
def add_system_user():
|
||||||
helper_users.add_user("system", helper.random_string_generator(64), helper_users.new_api_token(), False, False)
|
helper_users.add_user("system", helper.random_string_generator(64), "default@example.com", helper_users.new_api_token(), False, False)
|
||||||
|
|
||||||
def get_server_settings(self, server_id):
|
def get_server_settings(self, server_id):
|
||||||
for s in self.servers_list:
|
for s in self.servers_list:
|
||||||
|
@ -48,7 +48,7 @@ class db_builder:
|
|||||||
# Users.enabled: True,
|
# Users.enabled: True,
|
||||||
# Users.superuser: True
|
# Users.superuser: True
|
||||||
#}).execute()
|
#}).execute()
|
||||||
user_id = users_helper.add_user(username=username, password=password, superuser=True)
|
user_id = users_helper.add_user(username=username, password=password, email="default@example.com", superuser=True)
|
||||||
#users_helper.update_user(user_id, user_crafty_data={"permissions_mask":"111", "server_quantity":[-1,-1,-1]} )
|
#users_helper.update_user(user_id, user_crafty_data={"permissions_mask":"111", "server_quantity":[-1,-1,-1]} )
|
||||||
|
|
||||||
#console.info("API token is {}".format(api_token))
|
#console.info("API token is {}".format(api_token))
|
||||||
|
@ -274,6 +274,8 @@ class Server:
|
|||||||
self.stats.record_stats()
|
self.stats.record_stats()
|
||||||
websocket_helper.broadcast_user(user_id, 'send_start_reload', {
|
websocket_helper.broadcast_user(user_id, 'send_start_reload', {
|
||||||
})
|
})
|
||||||
|
check_port_thread = threading.Thread(target=self.check_internet_thread, daemon=True, args=(user_id, user_lang, ), name=f"backup_{self.name}")
|
||||||
|
check_port_thread.start()
|
||||||
else:
|
else:
|
||||||
logger.warning("Server PID {} died right after starting - is this a server config issue?".format(self.process.pid))
|
logger.warning("Server PID {} died right after starting - is this a server config issue?".format(self.process.pid))
|
||||||
console.warning("Server PID {} died right after starting - is this a server config issue?".format(self.process.pid))
|
console.warning("Server PID {} died right after starting - is this a server config issue?".format(self.process.pid))
|
||||||
@ -284,27 +286,26 @@ class Server:
|
|||||||
|
|
||||||
self.crash_watcher_schedule = schedule.every(30).seconds.do(self.detect_crash).tag(self.name)
|
self.crash_watcher_schedule = schedule.every(30).seconds.do(self.detect_crash).tag(self.name)
|
||||||
|
|
||||||
check_port_thread = threading.Thread(target=self.check_internet_thread, daemon=True, args=(user_id, user_lang, ), name=f"backup_{self.name}")
|
|
||||||
check_port_thread.start()
|
|
||||||
|
|
||||||
def check_internet_thread(self, user_id, user_lang):
|
def check_internet_thread(self, user_id, user_lang):
|
||||||
if user_id:
|
if user_id:
|
||||||
if helper.check_internet():
|
if helper.check_internet():
|
||||||
loc_server_port = servers_helper.get_server_stats_by_id(self.server_id)['server_port']
|
loc_server_port = servers_helper.get_server_stats_by_id(self.server_id)['server_port']
|
||||||
port_status = False
|
port_status = False
|
||||||
|
|
||||||
for i in range(3):
|
checked = False
|
||||||
if helper.check_port(loc_server_port):
|
while not checked:
|
||||||
port_status = True
|
if helper.check_server_conn(loc_server_port):
|
||||||
return
|
checked = True
|
||||||
|
result_of_check = helper.check_port(loc_server_port)
|
||||||
|
|
||||||
|
if result_of_check == True:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
websocket_helper.broadcast_user(user_id, 'send_start_error', {
|
||||||
|
'error': translation.translate('error', 'closedPort', user_lang).format(loc_server_port)
|
||||||
|
})
|
||||||
else:
|
else:
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
|
|
||||||
if port_status == False:
|
|
||||||
websocket_helper.broadcast_user(user_id, 'send_start_error', {
|
|
||||||
'error': translation.translate('error', 'closedPort', user_lang).format(loc_server_port)
|
|
||||||
})
|
|
||||||
else:
|
else:
|
||||||
websocket_helper.broadcast_user(user_id, 'send_start_error', {
|
websocket_helper.broadcast_user(user_id, 'send_start_error', {
|
||||||
'error': translation.translate('error', 'internet', user_lang)
|
'error': translation.translate('error', 'internet', user_lang)
|
||||||
|
@ -124,12 +124,26 @@ class AjaxHandler(BaseHandler):
|
|||||||
|
|
||||||
elif page == "get_tree":
|
elif page == "get_tree":
|
||||||
server_id = self.get_argument('id', None)
|
server_id = self.get_argument('id', None)
|
||||||
|
path = self.get_argument('path', None)
|
||||||
|
|
||||||
if not self.check_server_id(server_id, 'get_tree'): return
|
if not self.check_server_id(server_id, 'get_tree'): return
|
||||||
else: server_id = bleach.clean(server_id)
|
else: server_id = bleach.clean(server_id)
|
||||||
|
|
||||||
self.write(helper.get_os_understandable_path(self.controller.servers.get_server_data_by_id(server_id)['path']) + '\n' +
|
if helper.validate_traversal(self.controller.servers.get_server_data_by_id(server_id)['path'], path):
|
||||||
helper.generate_tree(helper.get_os_understandable_path(self.controller.servers.get_server_data_by_id(server_id)['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))
|
||||||
self.finish()
|
self.finish()
|
||||||
|
|
||||||
@tornado.web.authenticated
|
@tornado.web.authenticated
|
||||||
@ -328,7 +342,8 @@ class AjaxHandler(BaseHandler):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Delete the file
|
# Delete the file
|
||||||
os.remove(file_path)
|
if helper.validate_traversal(helper.get_os_understandable_path(server_info['path']), file_path):
|
||||||
|
os.remove(file_path)
|
||||||
|
|
||||||
elif page == "del_dir":
|
elif page == "del_dir":
|
||||||
if not permissions['Files'] in user_perms:
|
if not permissions['Files'] in user_perms:
|
||||||
@ -352,7 +367,8 @@ class AjaxHandler(BaseHandler):
|
|||||||
|
|
||||||
# Delete the directory
|
# Delete the directory
|
||||||
# os.rmdir(dir_path) # Would only remove empty directories
|
# os.rmdir(dir_path) # Would only remove empty directories
|
||||||
shutil.rmtree(dir_path) # Removes also when there are contents
|
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":
|
elif page == "delete_server":
|
||||||
if not permissions['Config'] in user_perms:
|
if not permissions['Config'] in user_perms:
|
||||||
|
@ -422,6 +422,7 @@ class PanelHandler(BaseHandler):
|
|||||||
page_data['user'] = {}
|
page_data['user'] = {}
|
||||||
page_data['user']['username'] = ""
|
page_data['user']['username'] = ""
|
||||||
page_data['user']['user_id'] = -1
|
page_data['user']['user_id'] = -1
|
||||||
|
page_data['user']['email'] = ""
|
||||||
page_data['user']['enabled'] = True
|
page_data['user']['enabled'] = True
|
||||||
page_data['user']['superuser'] = False
|
page_data['user']['superuser'] = False
|
||||||
page_data['user']['api_token'] = "N/A"
|
page_data['user']['api_token'] = "N/A"
|
||||||
@ -489,6 +490,9 @@ class PanelHandler(BaseHandler):
|
|||||||
|
|
||||||
if exec_user['user_id'] != page_data['user']['user_id']:
|
if exec_user['user_id'] != page_data['user']['user_id']:
|
||||||
page_data['user']['api_token'] = "********"
|
page_data['user']['api_token'] = "********"
|
||||||
|
|
||||||
|
if exec_user['email'] == 'default@example.com':
|
||||||
|
page_data['user']['email'] = ""
|
||||||
template = "panel/panel_edit_user.html"
|
template = "panel/panel_edit_user.html"
|
||||||
|
|
||||||
elif page == "remove_user":
|
elif page == "remove_user":
|
||||||
@ -824,6 +828,7 @@ class PanelHandler(BaseHandler):
|
|||||||
username = bleach.clean(self.get_argument('username', None))
|
username = bleach.clean(self.get_argument('username', None))
|
||||||
password0 = bleach.clean(self.get_argument('password0', None))
|
password0 = bleach.clean(self.get_argument('password0', None))
|
||||||
password1 = bleach.clean(self.get_argument('password1', None))
|
password1 = bleach.clean(self.get_argument('password1', None))
|
||||||
|
email = bleach.clean(self.get_argument('email', "default@example.com"))
|
||||||
enabled = int(float(self.get_argument('enabled', '0')))
|
enabled = int(float(self.get_argument('enabled', '0')))
|
||||||
regen_api = int(float(self.get_argument('regen_api', '0')))
|
regen_api = int(float(self.get_argument('regen_api', '0')))
|
||||||
lang = bleach.clean(self.get_argument('language'), 'en_EN')
|
lang = bleach.clean(self.get_argument('language'), 'en_EN')
|
||||||
@ -894,9 +899,13 @@ class PanelHandler(BaseHandler):
|
|||||||
else:
|
else:
|
||||||
server_quantity[permission.name] = 0
|
server_quantity[permission.name] = 0
|
||||||
|
|
||||||
|
# if email is None or "":
|
||||||
|
# email = "default@example.com"
|
||||||
|
|
||||||
user_data = {
|
user_data = {
|
||||||
"username": username,
|
"username": username,
|
||||||
"password": password0,
|
"password": password0,
|
||||||
|
"email": email,
|
||||||
"enabled": enabled,
|
"enabled": enabled,
|
||||||
"regen_api": regen_api,
|
"regen_api": regen_api,
|
||||||
"roles": roles,
|
"roles": roles,
|
||||||
@ -922,6 +931,7 @@ class PanelHandler(BaseHandler):
|
|||||||
username = bleach.clean(self.get_argument('username', None))
|
username = bleach.clean(self.get_argument('username', None))
|
||||||
password0 = bleach.clean(self.get_argument('password0', None))
|
password0 = bleach.clean(self.get_argument('password0', None))
|
||||||
password1 = bleach.clean(self.get_argument('password1', None))
|
password1 = bleach.clean(self.get_argument('password1', None))
|
||||||
|
email = bleach.clean(self.get_argument('email', "default@example.com"))
|
||||||
enabled = int(float(self.get_argument('enabled', '0'))),
|
enabled = int(float(self.get_argument('enabled', '0'))),
|
||||||
lang = bleach.clean(self.get_argument('lang', 'en_EN'))
|
lang = bleach.clean(self.get_argument('lang', 'en_EN'))
|
||||||
|
|
||||||
@ -972,7 +982,7 @@ class PanelHandler(BaseHandler):
|
|||||||
else:
|
else:
|
||||||
server_quantity[permission.name] = 0
|
server_quantity[permission.name] = 0
|
||||||
|
|
||||||
user_id = self.controller.users.add_user(username, password=password0, enabled=enabled)
|
user_id = self.controller.users.add_user(username, password=password0, email=email, enabled=enabled)
|
||||||
user_data = {
|
user_data = {
|
||||||
"roles": roles,
|
"roles": roles,
|
||||||
'lang': lang
|
'lang': lang
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
|
from re import X
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
|
import libgravatar
|
||||||
import logging
|
import logging
|
||||||
|
import requests
|
||||||
import tornado.web
|
import tornado.web
|
||||||
import tornado.escape
|
import tornado.escape
|
||||||
|
|
||||||
from app.classes.shared.helpers import helper
|
from app.classes.shared.helpers import Helpers, helper
|
||||||
from app.classes.web.base_handler import BaseHandler
|
from app.classes.web.base_handler import BaseHandler
|
||||||
from app.classes.shared.console import console
|
from app.classes.shared.console import console
|
||||||
from app.classes.shared.main_models import fn
|
from app.classes.shared.main_models import fn
|
||||||
@ -121,9 +124,27 @@ class PublicHandler(BaseHandler):
|
|||||||
# log this login
|
# log this login
|
||||||
self.controller.management.add_to_audit_log(user_data.user_id, "Logged in", 0, self.get_remote_ip())
|
self.controller.management.add_to_audit_log(user_data.user_id, "Logged in", 0, self.get_remote_ip())
|
||||||
|
|
||||||
|
if helper.get_setting("allow_nsfw_profile_pictures"):
|
||||||
|
rating = "x"
|
||||||
|
else:
|
||||||
|
rating = "g"
|
||||||
|
|
||||||
|
|
||||||
|
#Get grvatar hash for profile pictures
|
||||||
|
if user_data.email != 'default@example.com' or "":
|
||||||
|
g = libgravatar.Gravatar(libgravatar.sanitize_email(user_data.email))
|
||||||
|
url = g.get_image(size=80, default="404", force_default=False, rating=rating, filetype_extension=False, use_ssl=True) # + "?d=404"
|
||||||
|
if requests.head(url).status_code != 404:
|
||||||
|
profile_url = url
|
||||||
|
else:
|
||||||
|
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||||
|
else:
|
||||||
|
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||||
cookie_data = {
|
cookie_data = {
|
||||||
"username": user_data.username,
|
"username": user_data.username,
|
||||||
"user_id": user_data.user_id,
|
"user_id": user_data.user_id,
|
||||||
|
"email": user_data.email,
|
||||||
|
"profile_url": profile_url,
|
||||||
"account_type": user_data.superuser,
|
"account_type": user_data.superuser,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,5 +12,6 @@
|
|||||||
"show_contribute_link": true,
|
"show_contribute_link": true,
|
||||||
"virtual_terminal_lines": 70,
|
"virtual_terminal_lines": 70,
|
||||||
"max_log_lines": 700,
|
"max_log_lines": 700,
|
||||||
"keywords": ["help", "chunk"]
|
"keywords": ["help", "chunk"],
|
||||||
|
"allow_nsfw_profile_pictures": false
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
<link rel="shortcut icon" href="/static/assets/images/favicon.png" />
|
<link rel="shortcut icon" href="/static/assets/images/favicon.png" />
|
||||||
<link rel="stylesheet" href="/static/assets/css/crafty.css">
|
<link rel="stylesheet" href="/static/assets/css/crafty.css">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="dark-theme">
|
<body class="dark-theme">
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<div class="container-fluid ">
|
<div class="container-fluid ">
|
||||||
|
|
||||||
|
<<<<<<< app/frontend/templates/footer.html
|
||||||
|
<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 - 2022 <a href="http://www.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 - 2022 <a href="http://www.craftycontrol.com/" target="_blank">Crafty Controller</a>. {{ translate('footer', 'allRightsReserved', data['lang']) }}.</span>
|
||||||
|
>>>>>>> app/frontend/templates/footer.html
|
||||||
<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 class="float-none float-sm-right d-block mt-1 mt-sm-0 text-center">{{ translate('footer', 'version', data['lang']) }}: {{ data['version_data'] }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,15 +18,16 @@
|
|||||||
|
|
||||||
<li class="nav-item dropdown user-dropdown">
|
<li class="nav-item dropdown user-dropdown">
|
||||||
<a class="nav-link dropdown-toggle" id="UserDropdown" href="#" data-toggle="dropdown" aria-expanded="false">
|
<a class="nav-link dropdown-toggle" id="UserDropdown" href="#" data-toggle="dropdown" aria-expanded="false">
|
||||||
<img class="img-xs rounded-circle" src="/static/assets/images/faces-clipart/pic-1.png" alt="Profile image"> </a>
|
<img class="img-xs rounded-circle profile-picture" src="{{ data['user_data']['profile_url'] }}" alt="Profile image"> </a>
|
||||||
<div class="dropdown-menu dropdown-menu-right navbar-dropdown" aria-labelledby="UserDropdown">
|
<div class="dropdown-menu dropdown-menu-right navbar-dropdown" aria-labelledby="UserDropdown">
|
||||||
<div class="dropdown-header text-center">
|
<div class="dropdown-header text-center">
|
||||||
<img class="img-md rounded-circle" src="/static/assets/images/faces-clipart/pic-1.png" alt="Profile image">
|
<img class="img-md rounded-circle profile-picture" src="{{ data['user_data']['profile_url'] }}" alt="Profile image">
|
||||||
<p class="mb-1 mt-3 font-weight-semibold">{{ data['user_data']['username'] }}</p>
|
<p class="mb-1 mt-3 font-weight-semibold">{{ data['user_data']['username'] }}</p>
|
||||||
<p class="font-weight-light text-muted mb-0">Roles: </p>
|
<p class="font-weight-light text-muted mb-0">Roles: </p>
|
||||||
{% for r in data['user_role'] %}
|
{% for r in data['user_role'] %}
|
||||||
<p class="font-weight-light text-muted mb-0">{{ r }}</p>
|
<p class="font-weight-light text-muted mb-0">{{ r }}</p>
|
||||||
{% end %}
|
{% end %}
|
||||||
|
<p class="font-weight-light text-muted mb-0">Email: {{ data['user_data']['email'] }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% if "Super User" in data['user_role'] %}
|
{% if "Super User" in data['user_role'] %}
|
||||||
<a class="dropdown-item" href="/panel/activity_logs"><i class="dropdown-item-icon mdi mdi-calendar-check-outline text-primary"></i> Activity</a>
|
<a class="dropdown-item" href="/panel/activity_logs"><i class="dropdown-item-icon mdi mdi-calendar-check-outline text-primary"></i> Activity</a>
|
||||||
|
@ -80,6 +80,10 @@
|
|||||||
<label class="form-label" for="password1">Repeat Password <small class="text-muted ml-1"> - leave blank to don't change</small> </label>
|
<label class="form-label" for="password1">Repeat Password <small class="text-muted ml-1"> - leave blank to don't change</small> </label>
|
||||||
<input type="password" class="form-control" name="password1" id="password1" value="" placeholder="Repeat Password" >
|
<input type="password" class="form-control" name="password1" id="password1" value="" placeholder="Repeat Password" >
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="email">Gravatar Email <small class="text-muted ml-1"> - for the profile picture. this is not required. crafty will never make use of user emails. User emails are strictly for Gravatar</small> </label>
|
||||||
|
<input type="email" class="form-control" name="email" id="email" value="{{ data['user']['email'] }}" placeholder="Gravatar Email" >
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label" for="language">User Language:</label>
|
<label class="form-label" for="language">User Language:</label>
|
||||||
<select class="form-select form-control form-control-lg select-css" id="language" name="language" form="user_form">
|
<select class="form-select form-control form-control-lg select-css" id="language" name="language" form="user_form">
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- Page Title Header Ends-->
|
<!-- Page Title Header Ends-->
|
||||||
|
|
||||||
{% include "parts/details_stats.html %}
|
{% include "parts/details_stats.html" %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- Page Title Header Ends-->
|
<!-- Page Title Header Ends-->
|
||||||
|
|
||||||
{% include "parts/details_stats.html %}
|
{% include "parts/details_stats.html" %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
@ -134,13 +134,15 @@
|
|||||||
</style>
|
</style>
|
||||||
<ul class="tree-view">
|
<ul class="tree-view">
|
||||||
<li>
|
<li>
|
||||||
<div class="tree-caret tree-ctx-item files-tree-title">
|
<div class="tree-ctx-item" data-path="{{ data['server_stats']['server_id']['path'] }}">
|
||||||
<i class="far fa-folder"></i>
|
<span id="{{ data['server_stats']['server_id']['path'] }}span" class="files-tree-title tree-caret-down" data-path="{{ data['server_stats']['server_id']['path'] }}" onclick="getToggleMain(event)">
|
||||||
<i class="far fa-folder-open"></i>
|
<i class="far fa-folder"></i>
|
||||||
{{ translate('serverFiles', 'files', data['lang']) }}
|
<i class="far fa-folder-open"></i>
|
||||||
|
{{ translate('serverFiles', 'files', data['lang']) }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<ul class="tree-nested d-block" id="files-tree">
|
<ul class="tree-nested d-block" id="files-tree">
|
||||||
<li>{{ translate('serverFiles', 'error', data['lang']) }}</li>
|
<li><i class="fa fa-spin fa-spinner"></i>{{ translate('serverFiles', 'loadingRecords', data['lang']) }}</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@ -648,10 +650,13 @@
|
|||||||
}, false);
|
}, false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function getTreeView() {
|
function getTreeView(event) {
|
||||||
|
|
||||||
|
path = '{{ data['server_stats']['server_id']['path'] }}'
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "GET",
|
type: "GET",
|
||||||
url: '/ajax/get_tree?id={{ data['server_stats']['server_id']['server_id'] }}',
|
url: '/ajax/get_tree?id={{ data['server_stats']['server_id']['server_id'] }}&path='+path,
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
success: function(data){
|
success: function(data){
|
||||||
console.log("got response:");
|
console.log("got response:");
|
||||||
@ -661,26 +666,75 @@
|
|||||||
serverDir = dataArr.shift(); // Remove & return first element (server directory)
|
serverDir = dataArr.shift(); // Remove & return first element (server directory)
|
||||||
text = dataArr.join('\n');
|
text = dataArr.join('\n');
|
||||||
|
|
||||||
document.getElementById('files-tree').innerHTML = text;
|
try{
|
||||||
|
document.getElementById(path).innerHTML += text;
|
||||||
|
event.target.parentElement.classList.add("clicked");
|
||||||
|
}catch{
|
||||||
|
document.getElementById('files-tree').innerHTML = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
document.getElementsByClassName('files-tree-title')[0].setAttribute('data-path', serverDir);
|
document.getElementsByClassName('files-tree-title')[0].setAttribute('data-path', serverDir);
|
||||||
document.getElementsByClassName('files-tree-title')[0].setAttribute('data-name', 'Files');
|
document.getElementsByClassName('files-tree-title')[0].setAttribute('data-name', 'Files');
|
||||||
|
|
||||||
setTimeout(function () {setTreeViewContext()}, 1000);
|
setTimeout(function () {setTreeViewContext()}, 1000);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var toggler = document.getElementsByClassName("tree-caret");
|
function getToggleMain(event) {
|
||||||
var i;
|
path = event.target.parentElement.getAttribute('data-path');
|
||||||
|
document.getElementById("files-tree").classList.toggle("d-block");
|
||||||
|
document.getElementById(path+"span").classList.toggle("tree-caret-down");
|
||||||
|
document.getElementById(path+"span").classList.toggle("tree-caret");
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < toggler.length; i++) {
|
function getDirView(event) {
|
||||||
if (toggler[i].classList.contains('files-tree-title')) continue;
|
path = event.target.parentElement.getAttribute('data-path');
|
||||||
toggler[i].addEventListener("click", function caretListener() {
|
|
||||||
this.parentElement.querySelector(".tree-nested").classList.toggle("d-block");
|
if (document.getElementById(path).classList.contains('clicked')){
|
||||||
this.classList.toggle("tree-caret-down");
|
|
||||||
|
var toggler = document.getElementById(path+"span");
|
||||||
|
|
||||||
|
if (toggler.classList.contains('files-tree-title')){
|
||||||
|
document.getElementById(path+"ul").classList.toggle("d-block");
|
||||||
|
document.getElementById(path+"span").classList.toggle("tree-caret-down");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: '/ajax/get_dir?id={{ data['server_stats']['server_id']['server_id'] }}&path='+path,
|
||||||
|
dataType: 'text',
|
||||||
|
success: function(data){
|
||||||
|
console.log("got response:");
|
||||||
|
|
||||||
|
dataArr = data.split('\n');
|
||||||
|
serverDir = dataArr.shift(); // Remove & return first element (server directory)
|
||||||
|
text = dataArr.join('\n');
|
||||||
|
|
||||||
|
try{
|
||||||
|
document.getElementById(path+"span").classList.add('tree-caret-down');
|
||||||
|
document.getElementById(path).innerHTML += text;
|
||||||
|
document.getElementById(path).classList.add("clicked");
|
||||||
|
}catch{
|
||||||
|
console.log("Bad")
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () {setTreeViewContext()}, 1000);
|
||||||
|
|
||||||
|
var toggler = document.getElementById(path);
|
||||||
|
|
||||||
|
if (toggler.classList.contains('files-tree-title')){
|
||||||
|
document.getElementById(path+"span").addEventListener("click", function caretListener() {
|
||||||
|
document.getElementById(path+"ul").classList.toggle("d-block");
|
||||||
|
document.getElementById(path+"span").classList.toggle("tree-caret-down");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function setTreeViewContext() {
|
function setTreeViewContext() {
|
||||||
var treeItems = document.getElementsByClassName('tree-ctx-item');
|
var treeItems = document.getElementsByClassName('tree-ctx-item');
|
||||||
@ -875,11 +929,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
getTreeView();
|
||||||
setTreeViewContext();
|
setTreeViewContext();
|
||||||
|
|
||||||
@ -898,7 +947,7 @@
|
|||||||
target.classList.add('btn-primary');
|
target.classList.add('btn-primary');
|
||||||
}
|
}
|
||||||
|
|
||||||
window.onload = getTreeView();
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -43,36 +43,51 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="server_name">Action<small class="text-muted ml-1"></small> </label><br>
|
<label for="server_name">Action<small class="text-muted ml-1"></small> </label><br>
|
||||||
<select id="action" name="action" onchange="yesnoCheck(this);" class="form-control form-control-lg select-css">
|
<select id="action" name="action" onchange="basicAdvanced(this);" class="form-control form-control-lg select-css">
|
||||||
<option value="start">Start Server</option>
|
<option value="basic">Basic</option>
|
||||||
<option value="restart">Restart Server</option>
|
<option value="advanced">Advanced</option>
|
||||||
<option value="shutdown">Shutdown Server</option>
|
|
||||||
<option value="command">Custon Command</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="ifBasic">
|
||||||
<div class="form-group">
|
|
||||||
<label for="server_path">Interval <small class="text-muted ml-1"> - How often you want this task to execute</small> </label>
|
|
||||||
<input type="number" class="form-control" name="server_path" id="server_path" value="{{ data['server_stats']['server_id']['path'] }}" placeholder="Interval" required>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
<select id="interval_type" name="interval_type" class="form-control form-control-lg select-css">
|
|
||||||
<option value="days">Days</option>
|
|
||||||
<option value="hours">Hours</option>
|
|
||||||
<option value="minutes">Minutes</option>
|
|
||||||
<option value="weeks">Weeks</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="time">Time <small class="text-muted ml-1"> - What time do you want your task to execute?</small> </label>
|
|
||||||
<input type="time" class="form-control" name="time" id="time" value="{{ data['server_stats']['server_id']['log_path'] }}" placeholder="Time" required>
|
|
||||||
</div>
|
|
||||||
<div id="ifYes" style="display: none;">
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="command">Command <small class="text-muted ml-1"> - What command do you want us to execute? Do not include the '/'</small> </label>
|
<label for="server_name">Action<small class="text-muted ml-1"></small> </label><br>
|
||||||
<input type="input" class="form-control" name="command" id="command" value="" placeholder="Command" required>
|
<select id="action" name="action" onchange="yesnoCheck(this);" class="form-control form-control-lg select-css">
|
||||||
|
<option value="start">Start Server</option>
|
||||||
|
<option value="restart">Restart Server</option>
|
||||||
|
<option value="shutdown">Shutdown Server</option>
|
||||||
|
<option value="command">Custon Command</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="server_path">Interval <small class="text-muted ml-1"> - How often you want this task to execute</small> </label>
|
||||||
|
<input type="number" class="form-control" name="server_path" id="server_path" value="{{ data['server_stats']['server_id']['path'] }}" placeholder="Interval" required>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<select id="interval_type" name="interval_type" class="form-control form-control-lg select-css">
|
||||||
|
<option value="days">Days</option>
|
||||||
|
<option value="hours">Hours</option>
|
||||||
|
<option value="minutes">Minutes</option>
|
||||||
|
<option value="weeks">Weeks</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="time">Time <small class="text-muted ml-1"> - What time do you want your task to execute?</small> </label>
|
||||||
|
<input type="time" class="form-control" name="time" id="time" value="{{ data['server_stats']['server_id']['log_path'] }}" placeholder="Time" required>
|
||||||
|
</div>
|
||||||
|
<div id="ifYes" style="display: none;">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="command">Command <small class="text-muted ml-1"> - What command do you want us to execute? Do not include the '/'</small> </label>
|
||||||
|
<input type="input" class="form-control" name="command" id="command" value="" placeholder="Command" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="ifAdvanced" style="display: none;">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="cron">Cron <small class="text-muted ml-1"> - Input your cron string</small> </label>
|
||||||
|
<input type="input" class="form-control" name="cron" id="cron" value="* * * * backup_server" placeholder="Cron" required>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check-flat">
|
<div class="form-check-flat">
|
||||||
@ -173,6 +188,15 @@
|
|||||||
document.getElementById("ifYes").style.display = "none";
|
document.getElementById("ifYes").style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function basicAdvanced(that) {
|
||||||
|
if (that.value == "advanced") {
|
||||||
|
document.getElementById("ifAdvanced").style.display = "block";
|
||||||
|
document.getElementById("ifBasic").style.display = "none";
|
||||||
|
} else {
|
||||||
|
document.getElementById("ifAdvanced").style.display = "none";
|
||||||
|
document.getElementById("ifBasic").style.display = "block";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
16
app/migrations/20210915205501_user_email.py
Normal file
16
app/migrations/20210915205501_user_email.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Generated by database migrator
|
||||||
|
import peewee
|
||||||
|
|
||||||
|
def migrate(migrator, database, **kwargs):
|
||||||
|
migrator.add_columns('users', email=peewee.CharField(default="default@example.com"))
|
||||||
|
"""
|
||||||
|
Write your migrations here.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def rollback(migrator, database, **kwargs):
|
||||||
|
migrator.drop_columns('users', ['email'])
|
||||||
|
"""
|
||||||
|
Write your rollback migrations here.
|
||||||
|
"""
|
@ -212,7 +212,8 @@
|
|||||||
"waitUpload": "Please wait while we upload your files... This may take a while.",
|
"waitUpload": "Please wait while we upload your files... This may take a while.",
|
||||||
"stayHere": "DO NOT LEAVE THIS PAGE!",
|
"stayHere": "DO NOT LEAVE THIS PAGE!",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
"download": "Download"
|
"download": "Download",
|
||||||
|
"loadingRecords": "Loading Files..."
|
||||||
},
|
},
|
||||||
"serverConfig": {
|
"serverConfig": {
|
||||||
"serverName": "Server Name",
|
"serverName": "Server Name",
|
||||||
|
22
main.py
22
main.py
@ -6,6 +6,7 @@ import time
|
|||||||
import argparse
|
import argparse
|
||||||
import logging.config
|
import logging.config
|
||||||
import signal
|
import signal
|
||||||
|
import threading
|
||||||
from app.classes.controllers.management_controller import Management_Controller
|
from app.classes.controllers.management_controller import Management_Controller
|
||||||
|
|
||||||
""" Our custom classes / pip packages """
|
""" Our custom classes / pip packages """
|
||||||
@ -36,6 +37,22 @@ def do_intro():
|
|||||||
|
|
||||||
console.magenta(intro)
|
console.magenta(intro)
|
||||||
|
|
||||||
|
def check_port_thread():
|
||||||
|
port = helper.get_setting('https_port')
|
||||||
|
checked = False
|
||||||
|
while not checked:
|
||||||
|
if helper.check_server_conn(port):
|
||||||
|
checked = True
|
||||||
|
result_of_check = helper.check_port(port)
|
||||||
|
if result_of_check == True:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
console.warning("We have detected Crafty's port, {} may not be open on the host network or a firewall is blocking it. Remote client connections to Crafty may be limited.".format(helper.get_setting('https_port')))
|
||||||
|
console.help("If you are not forwarding ports from your public IP or your router does not support hairpin NAT you can safely disregard the previous message.")
|
||||||
|
else:
|
||||||
|
time.sleep(5)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
def setup_logging(debug=True):
|
def setup_logging(debug=True):
|
||||||
logging_config_file = os.path.join(os.path.curdir,
|
logging_config_file = os.path.join(os.path.curdir,
|
||||||
@ -143,9 +160,8 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
if not helper.check_internet():
|
if not helper.check_internet():
|
||||||
console.warning("We have detected the machine running Crafty has no connection to the internet. Client connections to the server may be limited.")
|
console.warning("We have detected the machine running Crafty has no connection to the internet. Client connections to the server may be limited.")
|
||||||
elif not helper.check_port(helper.get_setting('https_port')):
|
check_port_thread = threading.Thread(target=check_port_thread, daemon=True, name="crafty_port_check")
|
||||||
console.warning("We have detected Crafty's port, {} may not be open on the host network or a firewall is blocking it. Remote client connections to Crafty may be limited.".format(helper.get_setting('https_port')))
|
check_port_thread.start()
|
||||||
console.help("If you are not forwarding ports from your public IP or your router does not support hairpin NAT you can safely disregard the previous message.")
|
|
||||||
|
|
||||||
if not controller.check_system_user():
|
if not controller.check_system_user():
|
||||||
controller.add_system_user()
|
controller.add_system_user()
|
||||||
|
@ -3,6 +3,7 @@ argon2-cffi~=20.1
|
|||||||
bleach~=3.1
|
bleach~=3.1
|
||||||
colorama~=0.4
|
colorama~=0.4
|
||||||
cryptography~=3.4
|
cryptography~=3.4
|
||||||
|
libgravatar~=1.0.0
|
||||||
peewee~=3.13
|
peewee~=3.13
|
||||||
pexpect~=4.8
|
pexpect~=4.8
|
||||||
psutil~=5.7
|
psutil~=5.7
|
||||||
|
Loading…
Reference in New Issue
Block a user