mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
714 lines
28 KiB
Python
714 lines
28 KiB
Python
import logging
|
|
|
|
from jsonschema import ValidationError, validate
|
|
import orjson
|
|
from app.classes.models.crafty_permissions import EnumPermissionsCrafty
|
|
from app.classes.web.base_api_handler import BaseApiHandler
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
new_server_schema = {
|
|
"definitions": {},
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"title": "Root",
|
|
"type": "object",
|
|
"required": [
|
|
"name",
|
|
"monitoring_type",
|
|
"create_type",
|
|
],
|
|
"examples": [
|
|
{
|
|
"name": "My Server",
|
|
"monitoring_type": "minecraft_java",
|
|
"minecraft_java_monitoring_data": {"host": "127.0.0.1", "port": 25565},
|
|
"create_type": "minecraft_java",
|
|
"minecraft_java_create_data": {
|
|
"create_type": "download_jar",
|
|
"download_jar_create_data": {
|
|
"type": "Paper",
|
|
"version": "1.18.2",
|
|
"mem_min": 1,
|
|
"mem_max": 2,
|
|
"server_properties_port": 25565,
|
|
},
|
|
},
|
|
}
|
|
],
|
|
"properties": {
|
|
"name": {
|
|
"title": "Name",
|
|
"type": "string",
|
|
"examples": ["My Server"],
|
|
"minLength": 2,
|
|
},
|
|
"stop_command": {
|
|
"title": "Stop command",
|
|
"description": '"" means the default for the server creation type.',
|
|
"type": "string",
|
|
"default": "",
|
|
"examples": ["stop", "end"],
|
|
},
|
|
"log_location": {
|
|
"title": "Log file",
|
|
"description": '"" means the default for the server creation type.',
|
|
"type": "string",
|
|
"default": "",
|
|
"examples": ["./logs/latest.log", "./proxy.log.0"],
|
|
},
|
|
"crashdetection": {
|
|
"title": "Crash detection",
|
|
"type": "boolean",
|
|
"default": False,
|
|
},
|
|
"autostart": {
|
|
"title": "Autostart",
|
|
"description": "If true, the server will be started"
|
|
+ " automatically when Crafty is launched.",
|
|
"type": "boolean",
|
|
"default": False,
|
|
},
|
|
"autostart_delay": {
|
|
"title": "Autostart delay",
|
|
"description": "Delay in seconds before autostarting. (If enabled)",
|
|
"type": "number",
|
|
"default": 10,
|
|
"minimum": 0,
|
|
},
|
|
"monitoring_type": {
|
|
"title": "Server monitoring type",
|
|
"type": "string",
|
|
"default": "minecraft_java",
|
|
"enum": ["minecraft_java", "minecraft_bedrock", "none"],
|
|
# TODO: SteamCMD, RakNet, etc.
|
|
},
|
|
"minecraft_java_monitoring_data": {
|
|
"title": "Minecraft Java monitoring data",
|
|
"type": "object",
|
|
"required": ["host", "port"],
|
|
"properties": {
|
|
"host": {
|
|
"title": "Host",
|
|
"type": "string",
|
|
"default": "127.0.0.1",
|
|
"examples": ["127.0.0.1"],
|
|
"minLength": 1,
|
|
},
|
|
"port": {
|
|
"title": "Port",
|
|
"type": "integer",
|
|
"examples": [25565],
|
|
"default": 25565,
|
|
"minimum": 0,
|
|
},
|
|
},
|
|
},
|
|
"minecraft_bedrock_monitoring_data": {
|
|
"title": "Minecraft Bedrock monitoring data",
|
|
"type": "object",
|
|
"required": ["host", "port"],
|
|
"properties": {
|
|
"host": {
|
|
"title": "Host",
|
|
"type": "string",
|
|
"default": "127.0.0.1",
|
|
"examples": ["127.0.0.1"],
|
|
"minLength": 1,
|
|
},
|
|
"port": {
|
|
"title": "Port",
|
|
"type": "integer",
|
|
"examples": [19132],
|
|
"default": 19132,
|
|
"minimum": 0,
|
|
},
|
|
},
|
|
},
|
|
"create_type": {
|
|
# This is only used for creation, this is not saved in the db
|
|
"title": "Server creation type",
|
|
"type": "string",
|
|
"default": "minecraft_java",
|
|
"enum": ["minecraft_java", "minecraft_bedrock", "custom"],
|
|
},
|
|
"minecraft_java_create_data": {
|
|
"title": "Java creation data",
|
|
"type": "object",
|
|
"required": ["create_type"],
|
|
"properties": {
|
|
"create_type": {
|
|
"title": "Creation type",
|
|
"type": "string",
|
|
"default": "download_jar",
|
|
"enum": ["download_jar", "import_server", "import_zip"],
|
|
},
|
|
"download_jar_create_data": {
|
|
"title": "JAR download data",
|
|
"type": "object",
|
|
"required": [
|
|
"type",
|
|
"version",
|
|
"mem_min",
|
|
"mem_max",
|
|
"server_properties_port",
|
|
"agree_to_eula",
|
|
],
|
|
"properties": {
|
|
"type": {
|
|
"title": "Server JAR Type",
|
|
"type": "string",
|
|
"examples": ["Paper"],
|
|
"minLength": 1,
|
|
},
|
|
"version": {
|
|
"title": "Server JAR Version",
|
|
"type": "string",
|
|
"examples": ["1.18.2"],
|
|
"minLength": 1,
|
|
},
|
|
"mem_min": {
|
|
"title": "Minimum JVM memory (in GiBs)",
|
|
"type": "number",
|
|
"examples": [1],
|
|
"default": 1,
|
|
"exclusiveMinimum": 0,
|
|
},
|
|
"mem_max": {
|
|
"title": "Maximum JVM memory (in GiBs)",
|
|
"type": "number",
|
|
"examples": [2],
|
|
"default": 2,
|
|
"exclusiveMinimum": 0,
|
|
},
|
|
"server_properties_port": {
|
|
"title": "Port",
|
|
"type": "integer",
|
|
"examples": [25565],
|
|
"default": 25565,
|
|
"minimum": 0,
|
|
},
|
|
"agree_to_eula": {
|
|
"title": "Agree to the EULA",
|
|
"type": "boolean",
|
|
"default": False,
|
|
},
|
|
},
|
|
},
|
|
"import_server_create_data": {
|
|
"title": "Import server data",
|
|
"type": "object",
|
|
"required": [
|
|
"existing_server_path",
|
|
"jarfile",
|
|
"mem_min",
|
|
"mem_max",
|
|
"server_properties_port",
|
|
"agree_to_eula",
|
|
],
|
|
"properties": {
|
|
"existing_server_path": {
|
|
"title": "Server path",
|
|
"description": "Absolute path to the old server",
|
|
"type": "string",
|
|
"examples": ["/var/opt/server"],
|
|
"minLength": 1,
|
|
},
|
|
"jarfile": {
|
|
"title": "JAR file",
|
|
"description": "The JAR file relative to the previous path",
|
|
"type": "string",
|
|
"examples": ["paper.jar", "jars/vanilla-1.12.jar"],
|
|
"minLength": 1,
|
|
},
|
|
"mem_min": {
|
|
"title": "Minimum JVM memory (in GiBs)",
|
|
"type": "number",
|
|
"examples": [1],
|
|
"default": 1,
|
|
"exclusiveMinimum": 0,
|
|
},
|
|
"mem_max": {
|
|
"title": "Maximum JVM memory (in GiBs)",
|
|
"type": "number",
|
|
"examples": [2],
|
|
"default": 2,
|
|
"exclusiveMinimum": 0,
|
|
},
|
|
"server_properties_port": {
|
|
"title": "Port",
|
|
"type": "integer",
|
|
"examples": [25565],
|
|
"default": 25565,
|
|
"minimum": 0,
|
|
},
|
|
"agree_to_eula": {
|
|
"title": "Agree to the EULA",
|
|
"type": "boolean",
|
|
"default": False,
|
|
},
|
|
},
|
|
},
|
|
"import_zip_create_data": {
|
|
"title": "Import ZIP server data",
|
|
"type": "object",
|
|
"required": [
|
|
"zip_path",
|
|
"zip_root",
|
|
"jarfile",
|
|
"mem_min",
|
|
"mem_max",
|
|
"server_properties_port",
|
|
"agree_to_eula",
|
|
],
|
|
"properties": {
|
|
"zip_path": {
|
|
"title": "ZIP path",
|
|
"description": "Absolute path to the ZIP archive",
|
|
"type": "string",
|
|
"examples": ["/var/opt/server.zip"],
|
|
"minLength": 1,
|
|
},
|
|
"zip_root": {
|
|
"title": "Server root directory",
|
|
"description": "The server root in the ZIP archive",
|
|
"type": "string",
|
|
"examples": ["/", "/paper-server/", "server-1"],
|
|
"minLength": 1,
|
|
},
|
|
"jarfile": {
|
|
"title": "JAR file",
|
|
"description": "The JAR relative to the configured root",
|
|
"type": "string",
|
|
"examples": ["paper.jar", "jars/vanilla-1.12.jar"],
|
|
"minLength": 1,
|
|
},
|
|
"mem_min": {
|
|
"title": "Minimum JVM memory (in GiBs)",
|
|
"type": "number",
|
|
"examples": [1],
|
|
"default": 1,
|
|
"exclusiveMinimum": 0,
|
|
},
|
|
"mem_max": {
|
|
"title": "Maximum JVM memory (in GiBs)",
|
|
"type": "number",
|
|
"examples": [2],
|
|
"default": 2,
|
|
"exclusiveMinimum": 0,
|
|
},
|
|
"server_properties_port": {
|
|
"title": "Port",
|
|
"type": "integer",
|
|
"examples": [25565],
|
|
"default": 25565,
|
|
"minimum": 0,
|
|
},
|
|
"agree_to_eula": {
|
|
"title": "Agree to the EULA",
|
|
"type": "boolean",
|
|
"default": False,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"allOf": [
|
|
{
|
|
"$comment": "If..then section",
|
|
"allOf": [
|
|
{
|
|
"if": {
|
|
"properties": {"create_type": {"const": "download_jar"}}
|
|
},
|
|
"then": {"required": ["download_jar_create_data"]},
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {"create_type": {"const": "import_exec"}}
|
|
},
|
|
"then": {"required": ["import_server_create_data"]},
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {"create_type": {"const": "import_zip"}}
|
|
},
|
|
"then": {"required": ["import_zip_create_data"]},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"title": "Only one creation data",
|
|
"oneOf": [
|
|
{"required": ["download_jar_create_data"]},
|
|
{"required": ["import_server_create_data"]},
|
|
{"required": ["import_zip_create_data"]},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
"minecraft_bedrock_create_data": {
|
|
"title": "Minecraft Bedrock creation data",
|
|
"type": "object",
|
|
"required": ["create_type"],
|
|
"properties": {
|
|
"create_type": {
|
|
"title": "Creation type",
|
|
"type": "string",
|
|
"default": "import_server",
|
|
"enum": ["import_server", "import_zip"],
|
|
},
|
|
"import_server_create_data": {
|
|
"title": "Import server data",
|
|
"type": "object",
|
|
"required": ["existing_server_path", "command"],
|
|
"properties": {
|
|
"existing_server_path": {
|
|
"title": "Server path",
|
|
"description": "Absolute path to the old server",
|
|
"type": "string",
|
|
"examples": ["/var/opt/server"],
|
|
"minLength": 1,
|
|
},
|
|
"command": {
|
|
"title": "Command",
|
|
"type": "string",
|
|
"default": "echo foo bar baz",
|
|
"examples": ["LD_LIBRARY_PATH=. ./bedrock_server"],
|
|
"minLength": 1,
|
|
},
|
|
},
|
|
},
|
|
"import_zip_create_data": {
|
|
"title": "Import ZIP server data",
|
|
"type": "object",
|
|
"required": ["zip_path", "zip_root", "command"],
|
|
"properties": {
|
|
"zip_path": {
|
|
"title": "ZIP path",
|
|
"description": "Absolute path to the ZIP archive",
|
|
"type": "string",
|
|
"examples": ["/var/opt/server.zip"],
|
|
"minLength": 1,
|
|
},
|
|
"zip_root": {
|
|
"title": "Server root directory",
|
|
"description": "The server root in the ZIP archive",
|
|
"type": "string",
|
|
"examples": ["/", "/paper-server/", "server-1"],
|
|
"minLength": 1,
|
|
},
|
|
"command": {
|
|
"title": "Command",
|
|
"type": "string",
|
|
"default": "echo foo bar baz",
|
|
"examples": ["LD_LIBRARY_PATH=. ./bedrock_server"],
|
|
"minLength": 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"allOf": [
|
|
{
|
|
"$comment": "If..then section",
|
|
"allOf": [
|
|
{
|
|
"if": {
|
|
"properties": {"create_type": {"const": "import_exec"}}
|
|
},
|
|
"then": {"required": ["import_server_create_data"]},
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {"create_type": {"const": "import_zip"}}
|
|
},
|
|
"then": {"required": ["import_zip_create_data"]},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"title": "Only one creation data",
|
|
"oneOf": [
|
|
{"required": ["import_server_create_data"]},
|
|
{"required": ["import_zip_create_data"]},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
"custom_create_data": {
|
|
"title": "Custom creation data",
|
|
"type": "object",
|
|
"required": [
|
|
"working_directory",
|
|
"executable_update",
|
|
"create_type",
|
|
],
|
|
"properties": {
|
|
"working_directory": {
|
|
"title": "Working directory",
|
|
"description": '"" means the default',
|
|
"type": "string",
|
|
"default": "",
|
|
"examples": ["/mnt/mydrive/server-configs/", "./subdirectory", ""],
|
|
},
|
|
"executable_update": {
|
|
"title": "Executable Updation",
|
|
"description": "Also configurable later on and for other servers",
|
|
"type": "object",
|
|
"required": ["enabled", "file", "url"],
|
|
"properties": {
|
|
"enabled": {
|
|
"title": "Enabled",
|
|
"type": "boolean",
|
|
"default": False,
|
|
},
|
|
"file": {
|
|
"title": "Executable to update",
|
|
"type": "string",
|
|
"default": "",
|
|
"examples": ["./paper.jar"],
|
|
},
|
|
"url": {
|
|
"title": "URL to download the executable from",
|
|
"type": "string",
|
|
"default": "",
|
|
},
|
|
},
|
|
},
|
|
"create_type": {
|
|
"title": "Creation type",
|
|
"type": "string",
|
|
"default": "raw_exec",
|
|
"enum": ["raw_exec", "import_server", "import_zip"],
|
|
},
|
|
"raw_exec_create_data": {
|
|
"title": "Raw execution command create data",
|
|
"type": "object",
|
|
"required": ["command"],
|
|
"properties": {
|
|
"command": {
|
|
"title": "Command",
|
|
"type": "string",
|
|
"default": "echo foo bar baz",
|
|
"examples": ["caddy start"],
|
|
"minLength": 1,
|
|
}
|
|
},
|
|
},
|
|
"import_server_create_data": {
|
|
"title": "Import server data",
|
|
"type": "object",
|
|
"required": ["existing_server_path", "command"],
|
|
"properties": {
|
|
"existing_server_path": {
|
|
"title": "Server path",
|
|
"description": "Absolute path to the old server",
|
|
"type": "string",
|
|
"examples": ["/var/opt/server"],
|
|
"minLength": 1,
|
|
},
|
|
"command": {
|
|
"title": "Command",
|
|
"type": "string",
|
|
"default": "echo foo bar baz",
|
|
"examples": ["caddy start"],
|
|
"minLength": 1,
|
|
},
|
|
},
|
|
},
|
|
"import_zip_create_data": {
|
|
"title": "Import ZIP server data",
|
|
"type": "object",
|
|
"required": ["zip_path", "zip_root", "command"],
|
|
"properties": {
|
|
"zip_path": {
|
|
"title": "ZIP path",
|
|
"description": "Absolute path to the ZIP archive",
|
|
"type": "string",
|
|
"examples": ["/var/opt/server.zip"],
|
|
"minLength": 1,
|
|
},
|
|
"zip_root": {
|
|
"title": "Server root directory",
|
|
"description": "The server root in the ZIP archive",
|
|
"type": "string",
|
|
"examples": ["/", "/paper-server/", "server-1"],
|
|
"minLength": 1,
|
|
},
|
|
"command": {
|
|
"title": "Command",
|
|
"type": "string",
|
|
"default": "echo foo bar baz",
|
|
"examples": ["caddy start"],
|
|
"minLength": 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"allOf": [
|
|
{
|
|
"$comment": "If..then section",
|
|
"allOf": [
|
|
{
|
|
"if": {
|
|
"properties": {"create_type": {"const": "raw_exec"}}
|
|
},
|
|
"then": {"required": ["raw_exec_create_data"]},
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"create_type": {"const": "import_server"}
|
|
}
|
|
},
|
|
"then": {"required": ["import_server_create_data"]},
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {"create_type": {"const": "import_zip"}}
|
|
},
|
|
"then": {"required": ["import_zip_create_data"]},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"title": "Only one creation data",
|
|
"oneOf": [
|
|
{"required": ["raw_exec_create_data"]},
|
|
{"required": ["import_server_create_data"]},
|
|
{"required": ["import_zip_create_data"]},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
"allOf": [
|
|
{
|
|
"$comment": "If..then section",
|
|
"allOf": [
|
|
# start require creation data
|
|
{
|
|
"if": {"properties": {"create_type": {"const": "minecraft_java"}}},
|
|
"then": {"required": ["minecraft_java_create_data"]},
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {"create_type": {"const": "minecraft_bedrock"}}
|
|
},
|
|
"then": {"required": ["minecraft_bedrock_create_data"]},
|
|
},
|
|
{
|
|
"if": {"properties": {"create_type": {"const": "custom"}}},
|
|
"then": {"required": ["custom_create_data"]},
|
|
},
|
|
# end require creation data
|
|
# start require monitoring data
|
|
{
|
|
"if": {
|
|
"properties": {"monitoring_type": {"const": "minecraft_java"}}
|
|
},
|
|
"then": {"required": ["minecraft_java_monitoring_data"]},
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": {
|
|
"monitoring_type": {"const": "minecraft_bedrock"}
|
|
}
|
|
},
|
|
"then": {"required": ["minecraft_bedrock_monitoring_data"]},
|
|
},
|
|
# end require monitoring data
|
|
],
|
|
},
|
|
{
|
|
"title": "Only one creation data",
|
|
"oneOf": [
|
|
{"required": ["minecraft_java_create_data"]},
|
|
{"required": ["minecraft_bedrock_create_data"]},
|
|
{"required": ["custom_create_data"]},
|
|
],
|
|
},
|
|
{
|
|
"title": "Only one monitoring data",
|
|
"oneOf": [
|
|
{"required": ["minecraft_java_monitoring_data"]},
|
|
{"required": ["minecraft_bedrock_monitoring_data"]},
|
|
{"properties": {"monitoring_type": {"const": "none"}}},
|
|
],
|
|
},
|
|
],
|
|
}
|
|
|
|
|
|
class ApiServersIndexHandler(BaseApiHandler):
|
|
def get(self):
|
|
auth_data = self.authenticate_user()
|
|
if not auth_data:
|
|
return
|
|
|
|
# TODO: limit some columns for specific permissions
|
|
|
|
self.finish_json(200, {"status": "ok", "data": auth_data[0]})
|
|
|
|
def post(self):
|
|
|
|
auth_data = self.authenticate_user()
|
|
if not auth_data:
|
|
return
|
|
(
|
|
_,
|
|
exec_user_crafty_permissions,
|
|
_,
|
|
_superuser,
|
|
user,
|
|
) = auth_data
|
|
|
|
if EnumPermissionsCrafty.SERVER_CREATION not in exec_user_crafty_permissions:
|
|
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
|
|
|
|
try:
|
|
data = orjson.loads(self.request.body) # pylint: disable=no-member
|
|
except orjson.decoder.JSONDecodeError as e: # pylint: disable=no-member
|
|
return self.finish_json(
|
|
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
|
|
)
|
|
|
|
try:
|
|
validate(data, new_server_schema)
|
|
except ValidationError as e:
|
|
return self.finish_json(
|
|
400,
|
|
{
|
|
"status": "error",
|
|
"error": "INVALID_JSON_SCHEMA",
|
|
"error_data": str(e),
|
|
},
|
|
)
|
|
|
|
new_server_id, new_server_uuid = self.controller.create_api_server(data)
|
|
|
|
# Increase the server creation counter
|
|
self.controller.crafty_perms.add_server_creation(user["user_id"])
|
|
|
|
self.controller.stats.record_stats()
|
|
|
|
self.controller.management.add_to_audit_log(
|
|
user["user_id"],
|
|
(
|
|
f"created server {data['name']}"
|
|
f" (ID: {new_server_id})"
|
|
f" (UUID: {new_server_uuid})"
|
|
),
|
|
server_id=new_server_id,
|
|
source_ip=self.get_remote_ip(),
|
|
)
|
|
|
|
self.finish_json(
|
|
201,
|
|
{
|
|
"status": "ok",
|
|
"data": {
|
|
"new_server_id": str(new_server_id),
|
|
"new_server_uuid": new_server_uuid,
|
|
},
|
|
},
|
|
)
|