mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'bugfix/api-v2-bugfixes' into 'dev'
API v2 bug fixes See merge request crafty-controller/crafty-4!267
This commit is contained in:
commit
54c81d6dd4
@ -443,7 +443,7 @@ ignored-classes=optparse.Values,thread._local,_thread._local
|
||||
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||
# and thus existing member attributes cannot be deduced by static analysis). It
|
||||
# supports qualified module names, as well as Unix pattern matching.
|
||||
ignored-modules=
|
||||
ignored-modules=jsonschema,orjson
|
||||
|
||||
# Show a hint with possible names when a member name was not found. The aspect
|
||||
# of finding the hint is based on edit distance.
|
||||
|
@ -11,6 +11,11 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UsersController:
|
||||
class ApiPermissionDict(t.TypedDict):
|
||||
name: str
|
||||
quantity: int
|
||||
enabled: bool
|
||||
|
||||
def __init__(self, helper, users_helper, authentication):
|
||||
self.helper = helper
|
||||
self.users_helper = users_helper
|
||||
|
@ -1,4 +1,5 @@
|
||||
import logging
|
||||
import typing as t
|
||||
from enum import Enum
|
||||
from peewee import (
|
||||
ForeignKeyField,
|
||||
@ -99,7 +100,7 @@ class PermissionsCrafty:
|
||||
try:
|
||||
user_crafty = UserCrafty.get(UserCrafty.user_id == user_id)
|
||||
except DoesNotExist:
|
||||
user_crafty = UserCrafty.insert(
|
||||
UserCrafty.insert(
|
||||
{
|
||||
UserCrafty.user_id: user_id,
|
||||
UserCrafty.permissions: "000",
|
||||
@ -114,6 +115,13 @@ class PermissionsCrafty:
|
||||
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
|
||||
return user_crafty
|
||||
|
||||
@staticmethod
|
||||
def get_user_crafty_optional(user_id) -> t.Optional[UserCrafty]:
|
||||
try:
|
||||
return UserCrafty.get(UserCrafty.user_id == user_id)
|
||||
except DoesNotExist:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def add_user_crafty(user_id, uc_permissions):
|
||||
user_crafty = UserCrafty.insert(
|
||||
|
@ -66,10 +66,9 @@ class HelperRoles:
|
||||
@staticmethod
|
||||
def get_role_column(role_id: t.Union[str, int], column_name: str) -> t.Any:
|
||||
column = getattr(Roles, column_name)
|
||||
return model_to_dict(
|
||||
Roles.select(column).where(Roles.role_id == role_id).get(),
|
||||
only=[column],
|
||||
)[column_name]
|
||||
return getattr(
|
||||
Roles.select(column).where(Roles.role_id == role_id).get(), column_name
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def add_role(role_name):
|
||||
|
@ -205,7 +205,7 @@ class PermissionsServers:
|
||||
@staticmethod
|
||||
def get_user_permissions_mask(user: Users, server_id: str):
|
||||
if user.superuser:
|
||||
permissions_mask = "1" * len(PermissionsServers.get_permissions_list())
|
||||
permissions_mask = "1" * len(EnumPermissionsServer)
|
||||
else:
|
||||
roles_list = HelperUsers.get_user_roles_id(user.user_id)
|
||||
role_server = (
|
||||
@ -217,7 +217,7 @@ class PermissionsServers:
|
||||
try:
|
||||
permissions_mask = role_server[0].permissions
|
||||
except IndexError:
|
||||
permissions_mask = "0" * len(PermissionsServers.get_permissions_list())
|
||||
permissions_mask = "0" * len(EnumPermissionsServer)
|
||||
return permissions_mask
|
||||
|
||||
@staticmethod
|
||||
|
@ -143,10 +143,10 @@ class HelperServers:
|
||||
@staticmethod
|
||||
def get_server_column(server_id: t.Union[str, int], column_name: str) -> t.Any:
|
||||
column = getattr(Servers, column_name)
|
||||
return model_to_dict(
|
||||
return getattr(
|
||||
Servers.select(column).where(Servers.server_id == server_id).get(),
|
||||
only=[column],
|
||||
)[column_name]
|
||||
column_name,
|
||||
)
|
||||
|
||||
# **********************************************************************************
|
||||
# Servers Methods
|
||||
|
@ -165,19 +165,10 @@ class HelperUsers:
|
||||
@staticmethod
|
||||
def get_user_column(user_id: t.Union[str, int], column_name: str) -> t.Any:
|
||||
column = getattr(Users, column_name)
|
||||
return model_to_dict(
|
||||
return getattr(
|
||||
Users.select(column).where(Users.user_id == user_id).get(),
|
||||
only=[column],
|
||||
)[column_name]
|
||||
|
||||
@staticmethod
|
||||
def check_system_user(user_id):
|
||||
try:
|
||||
result = Users.get(Users.user_id == user_id).user_id == user_id
|
||||
if result:
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
column_name,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_user_model(user_id: str) -> Users:
|
||||
|
@ -147,10 +147,7 @@ class Controller:
|
||||
|
||||
@staticmethod
|
||||
def check_system_user():
|
||||
if HelperUsers.get_user_id_by_name("system") is not None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return HelperUsers.get_user_id_by_name("system") is not None
|
||||
|
||||
def set_project_root(self, root_dir):
|
||||
self.project_root = root_dir
|
||||
@ -393,12 +390,12 @@ class Controller:
|
||||
+ ("" if empty else f"\nserver-port={port}")
|
||||
)
|
||||
|
||||
server_file = "server.jar" # HACK: Throw this horrible default out of here
|
||||
root_create_data = data[data["create_type"] + "_create_data"]
|
||||
create_data = root_create_data[root_create_data["create_type"] + "_create_data"]
|
||||
if data["create_type"] == "minecraft_java":
|
||||
if root_create_data["create_type"] == "download_jar":
|
||||
server_file = f"{create_data['type']}-{create_data['version']}.jar"
|
||||
full_jar_path = os.path.join(new_server_path, server_file)
|
||||
|
||||
# Create an EULA file
|
||||
with open(
|
||||
@ -409,16 +406,18 @@ class Controller:
|
||||
)
|
||||
elif root_create_data["create_type"] == "import_server":
|
||||
_copy_import_dir_files(create_data["existing_server_path"])
|
||||
full_jar_path = os.path.join(new_server_path, create_data["jarfile"])
|
||||
server_file = create_data["jarfile"]
|
||||
elif root_create_data["create_type"] == "import_zip":
|
||||
# TODO: Copy files from the zip file to the new server directory
|
||||
full_jar_path = os.path.join(new_server_path, create_data["jarfile"])
|
||||
server_file = create_data["jarfile"]
|
||||
raise Exception("Not yet implemented")
|
||||
_create_server_properties_if_needed(create_data["server_properties_port"])
|
||||
|
||||
min_mem = create_data["mem_min"]
|
||||
max_mem = create_data["mem_max"]
|
||||
|
||||
full_jar_path = os.path.join(new_server_path, server_file)
|
||||
|
||||
def _gibs_to_mibs(gibs: float) -> str:
|
||||
return str(int(gibs * 1024))
|
||||
|
||||
@ -448,7 +447,9 @@ class Controller:
|
||||
_create_server_properties_if_needed(0, True)
|
||||
|
||||
server_command = create_data["command"]
|
||||
server_file = ""
|
||||
server_file = (
|
||||
"./bedrock_server" # HACK: This is a hack to make the server start
|
||||
)
|
||||
elif data["create_type"] == "custom":
|
||||
# TODO: working_directory, executable_update
|
||||
if root_create_data["create_type"] == "raw_exec":
|
||||
@ -468,7 +469,11 @@ class Controller:
|
||||
_create_server_properties_if_needed(0, True)
|
||||
|
||||
server_command = create_data["command"]
|
||||
server_file = root_create_data["executable_update"].get("file", "")
|
||||
|
||||
server_file_new = root_create_data["executable_update"].get("file", "")
|
||||
if server_file_new != "":
|
||||
# HACK: Horrible hack to make the server start
|
||||
server_file = server_file_new
|
||||
|
||||
stop_command = data.get("stop_command", "")
|
||||
if stop_command == "":
|
||||
@ -478,7 +483,7 @@ class Controller:
|
||||
log_location = data.get("log_location", "")
|
||||
if log_location == "":
|
||||
# TODO: different default log locations for server creation types
|
||||
log_location = "/logs/latest.log"
|
||||
log_location = "./logs/latest.log"
|
||||
|
||||
if data["monitoring_type"] == "minecraft_java":
|
||||
monitoring_port = data["minecraft_java_monitoring_data"]["port"]
|
||||
@ -490,7 +495,7 @@ class Controller:
|
||||
monitoring_type = "minecraft-bedrock"
|
||||
elif data["monitoring_type"] == "none":
|
||||
# TODO: this needs to be NUKED..
|
||||
# There shouldn't be anything set if there are nothing to monitor
|
||||
# There shouldn't be anything set if there is nothing to monitor
|
||||
monitoring_port = 25565
|
||||
monitoring_host = "127.0.0.1"
|
||||
monitoring_type = "minecraft-java"
|
||||
|
@ -238,4 +238,4 @@ class BaseHandler(tornado.web.RequestHandler):
|
||||
def finish_json(self, status: int, data: t.Dict[str, t.Any]):
|
||||
self.set_status(status)
|
||||
self.set_header("Content-Type", "application/json")
|
||||
self.finish(orjson.dumps(data)) # pylint: disable=no-member
|
||||
self.finish(orjson.dumps(data))
|
||||
|
@ -16,12 +16,9 @@ from tornado import iostream
|
||||
# TZLocal is set as a hidden import on win pipeline
|
||||
from tzlocal import get_localzone
|
||||
from croniter import croniter
|
||||
from app.classes.controllers.roles_controller import RolesController
|
||||
|
||||
from app.classes.models.roles import HelperRoles
|
||||
from app.classes.models.server_permissions import (
|
||||
EnumPermissionsServer,
|
||||
PermissionsServers,
|
||||
)
|
||||
from app.classes.models.server_permissions import EnumPermissionsServer
|
||||
from app.classes.models.crafty_permissions import EnumPermissionsCrafty
|
||||
from app.classes.models.management import HelpersManagement
|
||||
from app.classes.shared.helpers import Helpers
|
||||
@ -40,8 +37,8 @@ class PanelHandler(BaseHandler):
|
||||
user_roles[user_id] = user_roles_list
|
||||
return user_roles
|
||||
|
||||
def get_role_servers(self) -> t.Set[int]:
|
||||
servers = set()
|
||||
def get_role_servers(self) -> t.List[RolesController.RoleServerJsonType]:
|
||||
servers = []
|
||||
for server in self.controller.list_defined_servers():
|
||||
argument = self.get_argument(f"server_{server['server_id']}_access", "0")
|
||||
if argument == "0":
|
||||
@ -57,7 +54,9 @@ class PanelHandler(BaseHandler):
|
||||
permission_mask, permission, "1"
|
||||
)
|
||||
|
||||
servers.add((server["server_id"], permission_mask))
|
||||
servers.append(
|
||||
{"server_id": server["server_id"], "permissions": permission_mask}
|
||||
)
|
||||
return servers
|
||||
|
||||
def get_perms_quantity(self) -> t.Tuple[str, dict]:
|
||||
@ -2016,35 +2015,7 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
servers = self.get_role_servers()
|
||||
|
||||
# TODO: use update_role_advanced when API v2 gets merged
|
||||
base_data = self.controller.roles.get_role_with_servers(role_id)
|
||||
|
||||
server_ids = {server[0] for server in servers}
|
||||
server_permissions_map = {server[0]: server[1] for server in servers}
|
||||
|
||||
added_servers = server_ids.difference(set(base_data["servers"]))
|
||||
removed_servers = set(base_data["servers"]).difference(server_ids)
|
||||
same_servers = server_ids.intersection(set(base_data["servers"]))
|
||||
logger.debug(
|
||||
f"role: {role_id} +server:{added_servers} -server{removed_servers}"
|
||||
)
|
||||
for server_id in added_servers:
|
||||
PermissionsServers.get_or_create(
|
||||
role_id, server_id, server_permissions_map[server_id]
|
||||
)
|
||||
for server_id in same_servers:
|
||||
PermissionsServers.update_role_permission(
|
||||
role_id, server_id, server_permissions_map[server_id]
|
||||
)
|
||||
if len(removed_servers) != 0:
|
||||
PermissionsServers.delete_roles_permissions(role_id, removed_servers)
|
||||
|
||||
up_data = {
|
||||
"role_name": role_name,
|
||||
"last_update": Helpers.get_time_as_string(),
|
||||
}
|
||||
# TODO: do the last_update on the db side
|
||||
HelperRoles.update_role(role_id, up_data)
|
||||
self.controller.roles.update_role_advanced(role_id, role_name, servers)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
exec_user["user_id"],
|
||||
@ -2081,10 +2052,7 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
servers = self.get_role_servers()
|
||||
|
||||
role_id = self.controller.roles.add_role(role_name)
|
||||
# TODO: use add_role_advanced when API v2 gets merged
|
||||
for server in servers:
|
||||
PermissionsServers.get_or_create(role_id, server[0], server[1])
|
||||
role_id = self.controller.roles.add_role_advanced(role_name, servers)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
exec_user["user_id"],
|
||||
|
@ -25,6 +25,9 @@ from app.classes.web.routes.api.servers.server.stats import ApiServersServerStat
|
||||
from app.classes.web.routes.api.servers.server.users import ApiServersServerUsersHandler
|
||||
from app.classes.web.routes.api.users.index import ApiUsersIndexHandler
|
||||
from app.classes.web.routes.api.users.user.index import ApiUsersUserIndexHandler
|
||||
from app.classes.web.routes.api.users.user.permissions import (
|
||||
ApiUsersUserPermissionsHandler,
|
||||
)
|
||||
from app.classes.web.routes.api.users.user.pfp import ApiUsersUserPfpHandler
|
||||
from app.classes.web.routes.api.users.user.public import ApiUsersUserPublicHandler
|
||||
|
||||
@ -58,6 +61,16 @@ def api_handlers(handler_args):
|
||||
ApiUsersUserIndexHandler,
|
||||
handler_args,
|
||||
),
|
||||
(
|
||||
r"/api/v2/users/([0-9]+)/permissions/?",
|
||||
ApiUsersUserPermissionsHandler,
|
||||
handler_args,
|
||||
),
|
||||
(
|
||||
r"/api/v2/users/(@me)/permissions/?",
|
||||
ApiUsersUserPermissionsHandler,
|
||||
handler_args,
|
||||
),
|
||||
(
|
||||
r"/api/v2/users/([0-9]+)/pfp/?",
|
||||
ApiUsersUserPfpHandler,
|
||||
|
@ -1,6 +1,5 @@
|
||||
import datetime
|
||||
import logging
|
||||
from app.classes.shared.console import Console
|
||||
from app.classes.web.base_api_handler import BaseApiHandler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -12,8 +11,7 @@ class ApiAuthInvalidateTokensHandler(BaseApiHandler):
|
||||
if not auth_data:
|
||||
return
|
||||
|
||||
# TODO: Invalidate tokens
|
||||
Console.info("invalidate_tokens")
|
||||
logger.debug(f"Invalidate tokens for user {auth_data[4]['user_id']}")
|
||||
self.controller.users.raw_update_user(
|
||||
auth_data[4]["user_id"], {"valid_tokens_from": datetime.datetime.now()}
|
||||
)
|
||||
|
@ -79,8 +79,8 @@ class ApiRolesIndexHandler(BaseApiHandler):
|
||||
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
|
||||
data = orjson.loads(self.request.body)
|
||||
except orjson.decoder.JSONDecodeError as e:
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
|
||||
)
|
||||
|
@ -105,8 +105,8 @@ class ApiRolesRoleIndexHandler(BaseApiHandler):
|
||||
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
|
||||
data = orjson.loads(self.request.body)
|
||||
except orjson.decoder.JSONDecodeError as e:
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
|
||||
)
|
||||
|
@ -17,24 +17,6 @@ new_server_schema = {
|
||||
"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",
|
||||
@ -665,8 +647,8 @@ class ApiServersIndexHandler(BaseApiHandler):
|
||||
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
|
||||
data = orjson.loads(self.request.body)
|
||||
except orjson.decoder.JSONDecodeError as e:
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
|
||||
)
|
||||
|
@ -110,7 +110,7 @@ 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(self, key, data[key])
|
||||
setattr(server_obj, key, data[key])
|
||||
self.controller.servers.update_server(server_obj)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
|
@ -99,7 +99,7 @@ class ApiUsersIndexHandler(BaseApiHandler):
|
||||
email = data.get("email", "default@example.com")
|
||||
enabled = data.get("enabled", True)
|
||||
lang = data.get("lang", self.helper.get_setting("language"))
|
||||
superuser = data.get("superuser", False)
|
||||
new_superuser = data.get("superuser", False)
|
||||
permissions = data.get("permissions", None)
|
||||
roles = data.get("roles", None)
|
||||
hints = data.get("hints", True)
|
||||
@ -134,13 +134,24 @@ class ApiUsersIndexHandler(BaseApiHandler):
|
||||
)
|
||||
permissions_mask = "".join(permissions_mask)
|
||||
|
||||
if new_superuser and not superuser:
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "INVALID_SUPERUSER_CREATE"}
|
||||
)
|
||||
|
||||
if len(roles) != 0 and not superuser:
|
||||
# HACK: This should check if the user has the roles or something
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "INVALID_ROLES_CREATE"}
|
||||
)
|
||||
|
||||
# TODO: do this in the most efficient way
|
||||
user_id = self.controller.users.add_user(
|
||||
username,
|
||||
password,
|
||||
email,
|
||||
enabled,
|
||||
superuser,
|
||||
new_superuser,
|
||||
)
|
||||
self.controller.users.update_user(
|
||||
user_id,
|
||||
|
@ -1,8 +1,13 @@
|
||||
import json
|
||||
import logging
|
||||
import typing as t
|
||||
|
||||
from jsonschema import ValidationError, validate
|
||||
from app.classes.models.crafty_permissions import EnumPermissionsCrafty
|
||||
from app.classes.controllers.users_controller import UsersController
|
||||
from app.classes.models.crafty_permissions import (
|
||||
EnumPermissionsCrafty,
|
||||
PermissionsCrafty,
|
||||
)
|
||||
from app.classes.models.roles import HelperRoles
|
||||
from app.classes.models.users import HelperUsers
|
||||
from app.classes.web.base_api_handler import BaseApiHandler
|
||||
@ -170,7 +175,7 @@ class ApiUsersUserIndexHandler(BaseApiHandler):
|
||||
},
|
||||
)
|
||||
|
||||
if data.get("username", None) is not None:
|
||||
if "username" in data:
|
||||
if data["username"].lower() in ["system", ""]:
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "INVALID_USERNAME"}
|
||||
@ -180,10 +185,10 @@ class ApiUsersUserIndexHandler(BaseApiHandler):
|
||||
400, {"status": "error", "error": "USER_EXISTS"}
|
||||
)
|
||||
|
||||
if data.get("superuser", None) is not None:
|
||||
if str(user["user_id"]) == str(user_id):
|
||||
# Checks if user is trying to change super user status of self.
|
||||
# We don't want that.
|
||||
if "superuser" in data:
|
||||
if str(user["user_id"]) == str(user_id) and not superuser:
|
||||
# Checks if user is trying to change super user status
|
||||
# of self without superuser. We don't want that.
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "INVALID_SUPERUSER_MODIFY"}
|
||||
)
|
||||
@ -191,10 +196,10 @@ class ApiUsersUserIndexHandler(BaseApiHandler):
|
||||
# The user is not superuser so they can't change the superuser status
|
||||
data.pop("superuser")
|
||||
|
||||
if data.get("permissions", None) is not None:
|
||||
if str(user["user_id"]) == str(user_id):
|
||||
# Checks if user is trying to change permissions of self.
|
||||
# We don't want that.
|
||||
if "permissions" in data:
|
||||
if str(user["user_id"]) == str(user_id) and not superuser:
|
||||
# Checks if user is trying to change permissions
|
||||
# of self without superuser. We don't want that.
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "INVALID_PERMISSIONS_MODIFY"}
|
||||
)
|
||||
@ -205,10 +210,10 @@ class ApiUsersUserIndexHandler(BaseApiHandler):
|
||||
400, {"status": "error", "error": "INVALID_PERMISSIONS_MODIFY"}
|
||||
)
|
||||
|
||||
if data.get("roles", None) is not None:
|
||||
if str(user["user_id"]) == str(user_id):
|
||||
# Checks if user is trying to change roles of self.
|
||||
# We don't want that.
|
||||
if "roles" in data:
|
||||
if str(user["user_id"]) == str(user_id) and not superuser:
|
||||
# Checks if user is trying to change roles of
|
||||
# self without superuser. We don't want that.
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "INVALID_ROLES_MODIFY"}
|
||||
)
|
||||
@ -219,10 +224,66 @@ class ApiUsersUserIndexHandler(BaseApiHandler):
|
||||
400, {"status": "error", "error": "INVALID_ROLES_MODIFY"}
|
||||
)
|
||||
|
||||
# TODO: make this more efficient
|
||||
# TODO: add permissions and roles because I forgot
|
||||
if "password" in data and str(user["user_id"] == str(user_id)):
|
||||
# TODO: edit your own password
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "INVALID_PASSWORD_MODIFY"}
|
||||
)
|
||||
|
||||
user_obj = HelperUsers.get_user_model(user_id)
|
||||
|
||||
if "roles" in data:
|
||||
roles: t.Set[str] = set(data.pop("roles"))
|
||||
base_roles: t.Set[str] = set(user_obj.roles)
|
||||
added_roles = roles.difference(base_roles)
|
||||
removed_roles = base_roles.difference(roles)
|
||||
logger.debug(
|
||||
f"updating user {user_id}'s roles: "
|
||||
f"+role:{added_roles} -role:{removed_roles}"
|
||||
)
|
||||
|
||||
for role_id in added_roles:
|
||||
HelperUsers.get_or_create(user_id, role_id)
|
||||
|
||||
if len(removed_roles) != 0:
|
||||
self.controller.users.users_helper.delete_user_roles(
|
||||
user_id, removed_roles
|
||||
)
|
||||
|
||||
if "permissions" in data:
|
||||
permissions: t.List[UsersController.ApiPermissionDict] = data.pop(
|
||||
"permissions"
|
||||
)
|
||||
permissions_mask = "0" * len(EnumPermissionsCrafty)
|
||||
limit_server_creation = 0
|
||||
limit_user_creation = 0
|
||||
limit_role_creation = 0
|
||||
|
||||
for permission in permissions:
|
||||
self.controller.crafty_perms.set_permission(
|
||||
permissions_mask,
|
||||
EnumPermissionsCrafty.__members__[permission["name"]],
|
||||
"1" if permission["enabled"] else "0",
|
||||
)
|
||||
|
||||
PermissionsCrafty.add_or_update_user(
|
||||
user_id,
|
||||
permissions_mask,
|
||||
limit_server_creation,
|
||||
limit_user_creation,
|
||||
limit_role_creation,
|
||||
)
|
||||
|
||||
# TODO: make this more efficient
|
||||
if len(data) != 0:
|
||||
for key in data:
|
||||
# If we don't validate the input there could be security issues
|
||||
value = data[key]
|
||||
if key == "password":
|
||||
value = self.helper.encode_pass(value)
|
||||
setattr(user_obj, key, value)
|
||||
user_obj.save()
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
user["user_id"],
|
||||
(
|
||||
@ -233,9 +294,4 @@ class ApiUsersUserIndexHandler(BaseApiHandler):
|
||||
source_ip=self.get_remote_ip(),
|
||||
)
|
||||
|
||||
for key in data:
|
||||
# If we don't validate the input there could be security issues
|
||||
setattr(user_obj, key, data[key])
|
||||
user_obj.save()
|
||||
|
||||
return self.finish_json(200, {"status": "ok"})
|
||||
|
73
app/classes/web/routes/api/users/user/permissions.py
Normal file
73
app/classes/web/routes/api/users/user/permissions.py
Normal file
@ -0,0 +1,73 @@
|
||||
import logging
|
||||
import typing as t
|
||||
|
||||
from app.classes.models.crafty_permissions import (
|
||||
EnumPermissionsCrafty,
|
||||
PermissionsCrafty,
|
||||
)
|
||||
from app.classes.web.base_api_handler import BaseApiHandler
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
SERVER_CREATION: t.Final[str] = EnumPermissionsCrafty.SERVER_CREATION.name
|
||||
USER_CONFIG: t.Final[str] = EnumPermissionsCrafty.USER_CONFIG.name
|
||||
ROLES_CONFIG: t.Final[str] = EnumPermissionsCrafty.ROLES_CONFIG.name
|
||||
|
||||
|
||||
class ApiUsersUserPermissionsHandler(BaseApiHandler):
|
||||
def get(self, user_id: str):
|
||||
auth_data = self.authenticate_user()
|
||||
if not auth_data:
|
||||
return
|
||||
(
|
||||
_,
|
||||
exec_user_crafty_permissions,
|
||||
_,
|
||||
_,
|
||||
user,
|
||||
) = auth_data
|
||||
|
||||
if user_id in ["@me", user["user_id"]]:
|
||||
user_id = user["user_id"]
|
||||
res_data = PermissionsCrafty.get_user_crafty(user_id)
|
||||
elif EnumPermissionsCrafty.USER_CONFIG not in exec_user_crafty_permissions:
|
||||
return self.finish_json(
|
||||
400,
|
||||
{
|
||||
"status": "error",
|
||||
"error": "NOT_AUTHORIZED",
|
||||
},
|
||||
)
|
||||
else:
|
||||
# has User_Config permission and isn't viewing self
|
||||
res_data = PermissionsCrafty.get_user_crafty_optional(user_id)
|
||||
if res_data is None:
|
||||
return self.finish_json(
|
||||
404,
|
||||
{
|
||||
"status": "error",
|
||||
"error": "USER_NOT_FOUND",
|
||||
},
|
||||
)
|
||||
|
||||
self.finish_json(
|
||||
200,
|
||||
{
|
||||
"status": "ok",
|
||||
"data": {
|
||||
"permissions": res_data.permissions,
|
||||
"counters": {
|
||||
SERVER_CREATION: res_data.created_server,
|
||||
USER_CONFIG: res_data.created_user,
|
||||
ROLES_CONFIG: res_data.created_role,
|
||||
},
|
||||
"limits": {
|
||||
SERVER_CREATION: res_data.limit_server_creation,
|
||||
USER_CONFIG: res_data.limit_user_creation,
|
||||
ROLES_CONFIG: res_data.limit_role_creation,
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
@ -17,5 +17,5 @@ requests==2.26
|
||||
termcolor==1.1
|
||||
tornado==6.0
|
||||
tzlocal==4.0
|
||||
jsonschema==4.4.0
|
||||
jsonschema==4.5.1
|
||||
orjson==3.6.7
|
||||
|
Loading…
Reference in New Issue
Block a user