diff --git a/CHANGELOG.md b/CHANGELOG.md
index f90dd136..a61a3c7b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,25 @@
# Changelog
-## --- [4.0.17] - 2022/11/30
+## --- [4.0.19] - 2022/TBD
+### New features
+TBD
+### Bug fixes
+- Fix port tooltip not showing on dash while server online. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/503))
+- Fix '+' char in path causing any file operation to fail. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/502))
+- Fix colours on public pages. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/504))
+- Fix bug where public background was not sent to public pages...like the error page resulting in an error...ironic...I know. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/505))
+- Be sure a user cannot server import crafty dir. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/506))
+- Remove Pathlib from sub path check ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/507))
+- Fix root dir selection in Upload Zip Import ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/508))
+- Fix stats error on mac M1 chips ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/512))
+- Fix window path escape on java override ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/513))
+### Tweaks
+- Make server directories non-configurable ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/511))
+- Add popover to server port to detail it's purpose ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/514))
+### Lang
+TBD
+
+
+## --- [4.0.17/4.0.18] - 2022/11/30
### New features
- Automate forge install process through Crafty server creation for Forge server version 1.16 and greater. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/495))
- Tooltip for server port on dashboard. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/496))
@@ -7,8 +27,10 @@
### Bug fixes
- Fix no port on bedrock server creation. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/493))
### Tweaks
-- Docker🐋 | Update image base to Ubuntu 22.04 Jammy ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/497))
+- Docker🐋 | Update image base to Ubuntu 22.04 Jammy. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/497))
*(OpenJDK16 Removed, no jammy backport)*
+### Hotfix (4.0.18)
+- Apply custom login backgrounds on all public pages. ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/499))
## --- [4.0.16] - 2022/10/23
diff --git a/README.md b/README.md
index 5ae83d5f..93888c5c 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
[![Crafty Logo](app/frontend/static/assets/images/logo_long.svg)](https://craftycontrol.com)
-# Crafty Controller 4.0.17
+# Crafty Controller 4.0.19
> Python based Control Panel for your Minecraft Server
## What is Crafty Controller?
diff --git a/app/classes/minecraft/stats.py b/app/classes/minecraft/stats.py
index 5ef9550d..e3611509 100644
--- a/app/classes/minecraft/stats.py
+++ b/app/classes/minecraft/stats.py
@@ -86,7 +86,7 @@ class Stats:
def get_node_stats(self) -> NodeStatsReturnDict:
try:
cpu_freq = psutil.cpu_freq()
- except NotImplementedError:
+ except (NotImplementedError, FileNotFoundError):
cpu_freq = None
if cpu_freq is None:
cpu_freq = psutil._common.scpufreq(current=-1, min=-1, max=-1)
diff --git a/app/classes/shared/helpers.py b/app/classes/shared/helpers.py
index c7bef77b..f853286b 100644
--- a/app/classes/shared/helpers.py
+++ b/app/classes/shared/helpers.py
@@ -377,6 +377,17 @@ class Helpers:
return default_return
+ @staticmethod
+ def is_subdir(server_path, root_dir):
+ server_path = os.path.realpath(server_path)
+ root_dir = os.path.realpath(root_dir)
+
+ relative = os.path.relpath(server_path, root_dir)
+
+ if relative.startswith(os.pardir):
+ return False
+ return True
+
def set_setting(self, key, new_value):
try:
with open(self.settings_file, "r", encoding="utf-8") as f:
diff --git a/app/classes/web/ajax_handler.py b/app/classes/web/ajax_handler.py
index fe3fb14f..cdd67146 100644
--- a/app/classes/web/ajax_handler.py
+++ b/app/classes/web/ajax_handler.py
@@ -4,6 +4,7 @@ import pathlib
import re
import logging
import time
+import urllib.parse
import bleach
import tornado.web
import tornado.escape
@@ -507,12 +508,12 @@ class AjaxHandler(BaseHandler):
self.redirect("/panel/dashboard")
elif page == "unzip_server":
- path = self.get_argument("path", None)
+ path = urllib.parse.unquote(self.get_argument("path", ""))
if not path:
path = os.path.join(
self.controller.project_root,
"imports",
- self.get_argument("file", ""),
+ urllib.parse.unquote(self.get_argument("file", "")),
)
if Helpers.check_file_exists(path):
self.helper.unzip_server(path, exec_user["user_id"])
diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py
index d64774bd..020dee12 100644
--- a/app/classes/web/panel_handler.py
+++ b/app/classes/web/panel_handler.py
@@ -7,6 +7,7 @@ import json
import logging
import threading
import shlex
+import urllib.parse
import bleach
import requests
import tornado.web
@@ -289,6 +290,7 @@ class PanelHandler(BaseHandler):
page_data: t.Dict[str, t.Any] = {
# todo: make this actually pull and compare version data
"update_available": self.helper.update_available,
+ "background": self.controller.cached_login,
"serverTZ": tz,
"version_data": self.helper.get_version_string(),
"failed_servers": self.controller.servers.failed_servers,
@@ -806,9 +808,15 @@ class PanelHandler(BaseHandler):
user_roles_list = self.controller.users.get_user_roles_names(
user.user_id
)
- user_servers = self.controller.servers.get_authorized_servers(
- user.user_id
- )
+ try:
+ user_servers = self.controller.servers.get_authorized_servers(
+ user.user_id
+ )
+ except:
+ return self.redirect(
+ "/panel/error?error=Cannot load panel config"
+ " while servers are unloaded"
+ )
servers = []
for server in user_servers:
if server.name not in servers:
@@ -1386,9 +1394,10 @@ class PanelHandler(BaseHandler):
template = "panel/activity_logs.html"
elif page == "download_file":
- file = Helpers.get_os_understandable_path(self.get_argument("path", ""))
- name = self.get_argument("name", "")
-
+ file = Helpers.get_os_understandable_path(
+ urllib.parse.unquote(self.get_argument("path", ""))
+ )
+ name = urllib.parse.unquote(self.get_argument("name", ""))
server_id = self.check_server_id()
if server_id is None:
return
@@ -1551,7 +1560,10 @@ class PanelHandler(BaseHandler):
return
if java_selection:
try:
- execution_list = shlex.split(execution_command)
+ if self.helper.is_os_windows():
+ execution_list = shlex.split(execution_command, posix=False)
+ else:
+ execution_list = shlex.split(execution_command, posix=True)
except ValueError:
self.redirect(
"/panel/error?error=Invalid execution command. Java path"
@@ -1603,7 +1615,6 @@ class PanelHandler(BaseHandler):
if Helpers.validate_traversal(
self.helper.get_servers_root_dir(), server_path
):
- server_obj.path = server_path
server_obj.log_path = log_path
if Helpers.validate_traversal(
self.helper.get_servers_root_dir(), executable
@@ -1615,7 +1626,6 @@ class PanelHandler(BaseHandler):
server_obj.executable_update_url = executable_update_url
server_obj.show_status = show_status
else:
- server_obj.path = server_obj.path
server_obj.log_path = server_obj.log_path
server_obj.executable = server_obj.executable
server_obj.execution_command = execution_command
diff --git a/app/classes/web/public_handler.py b/app/classes/web/public_handler.py
index bb31248f..7f3f0c26 100644
--- a/app/classes/web/public_handler.py
+++ b/app/classes/web/public_handler.py
@@ -39,6 +39,7 @@ class PublicHandler(BaseHandler):
"lang": self.helper.get_setting("language"),
"lang_page": self.helper.get_lang_page(self.helper.get_setting("language")),
"query": "",
+ "background": self.controller.cached_login,
}
if self.request.query:
@@ -48,7 +49,6 @@ class PublicHandler(BaseHandler):
template = "public/404.html"
if page == "login":
- page_data["background"] = self.controller.cached_login
template = "public/login.html"
elif page == 404:
diff --git a/app/classes/web/routes/api/servers/server/index.py b/app/classes/web/routes/api/servers/server/index.py
index 11f8620b..3d5e3e2f 100644
--- a/app/classes/web/routes/api/servers/server/index.py
+++ b/app/classes/web/routes/api/servers/server/index.py
@@ -90,7 +90,8 @@ class ApiServersServerIndexHandler(BaseApiHandler):
server_obj = self.controller.servers.get_server_obj(server_id)
for key in data:
# If we don't validate the input there could be security issues
- setattr(server_obj, key, data[key])
+ if key != "path":
+ setattr(server_obj, key, data[key])
self.controller.servers.update_server(server_obj)
self.controller.management.add_to_audit_log(
diff --git a/app/classes/web/server_handler.py b/app/classes/web/server_handler.py
index 08162365..62c549e5 100644
--- a/app/classes/web/server_handler.py
+++ b/app/classes/web/server_handler.py
@@ -331,6 +331,15 @@ class ServerHandler(BaseHandler):
return
if import_type == "import_jar":
+ if not self.helper.is_subdir(
+ import_server_path, self.controller.project_root
+ ):
+ self.redirect(
+ "/panel/error?error=Loop Error: The selected path will cause"
+ " an infinite copy loop. Make sure Crafty's directory is not"
+ " in your server path."
+ )
+ return
good_path = self.controller.verify_jar_server(
import_server_path, import_server_jar
)
@@ -480,6 +489,15 @@ class ServerHandler(BaseHandler):
return
if import_type == "import_jar":
+ if self.helper.is_subdir(
+ import_server_path, self.controller.project_root
+ ):
+ self.redirect(
+ "/panel/error?error=Loop Error: The selected path will cause"
+ " an infinite copy loop. Make sure Crafty's directory is not"
+ " in your server path."
+ )
+ return
good_path = self.controller.verify_jar_server(
import_server_path, import_server_exe
)
diff --git a/app/classes/web/status_handler.py b/app/classes/web/status_handler.py
index 6e73cdcb..410e3a36 100644
--- a/app/classes/web/status_handler.py
+++ b/app/classes/web/status_handler.py
@@ -7,7 +7,7 @@ logger = logging.getLogger(__name__)
class StatusHandler(BaseHandler):
def get(self):
- page_data = {}
+ page_data = {"background": self.controller.cached_login}
page_data["lang"] = self.helper.get_setting("language")
page_data["lang_page"] = self.helper.get_lang_page(
self.helper.get_setting("language")
diff --git a/app/classes/web/upload_handler.py b/app/classes/web/upload_handler.py
index 2de4fe1f..785d5783 100644
--- a/app/classes/web/upload_handler.py
+++ b/app/classes/web/upload_handler.py
@@ -1,6 +1,7 @@
import logging
import os
import time
+import urllib.parse
import tornado.web
import tornado.options
import tornado.httpserver
@@ -108,7 +109,9 @@ class UploadHandler(BaseHandler):
logger.debug("Could not delete file on user server upload")
self.helper.ensure_dir_exists(path)
- filename = self.request.headers.get("X-FileName", None)
+ filename = urllib.parse.unquote(
+ self.request.headers.get("X-FileName", None)
+ )
if not str(filename).endswith(".zip"):
self.helper.websocket_helper.broadcast("close_upload_box", "error")
self.finish("error")
diff --git a/app/config/version.json b/app/config/version.json
index f97d9f2b..02ec3ae1 100644
--- a/app/config/version.json
+++ b/app/config/version.json
@@ -1,5 +1,5 @@
{
"major": 4,
"minor": 0,
- "sub": 17
+ "sub": 19
}
diff --git a/app/frontend/static/assets/css/dark/style.css b/app/frontend/static/assets/css/dark/style.css
index dbd6ea8b..c8ac5eb9 100755
--- a/app/frontend/static/assets/css/dark/style.css
+++ b/app/frontend/static/assets/css/dark/style.css
@@ -22155,7 +22155,7 @@ ul li {
}
.popover .popover-body {
- color: #000;
+ color: var(--base-text);
background: var(--card-banner-bg);
}
diff --git a/app/frontend/templates/panel/dashboard.html b/app/frontend/templates/panel/dashboard.html
index 1fac58cf..171f2b8a 100644
--- a/app/frontend/templates/panel/dashboard.html
+++ b/app/frontend/templates/panel/dashboard.html
@@ -278,9 +278,10 @@
{% end %}
-