From bb1f43bc81eddfe2ce13da2ed53eeffc4e38aee4 Mon Sep 17 00:00:00 2001 From: Silversthorn Date: Tue, 24 Aug 2021 23:07:00 +0200 Subject: [PATCH] Adding Support for Crafty Permissions with limits --- app/classes/shared/controller.py | 49 ++++++-- app/classes/shared/models.py | 63 +++++++++- app/classes/web/panel_handler.py | 119 +++++++++++++----- app/classes/web/server_handler.py | 14 ++- app/frontend/templates/main_menu.html | 4 +- .../templates/panel/panel_edit_user.html | 36 ++++++ .../20210824205501_permissions_limits_1.py | 18 +++ 7 files changed, 258 insertions(+), 45 deletions(-) create mode 100644 app/migrations/20210824205501_permissions_limits_1.py diff --git a/app/classes/shared/controller.py b/app/classes/shared/controller.py index 207c8a53..94d3a24f 100644 --- a/app/classes/shared/controller.py +++ b/app/classes/shared/controller.py @@ -12,7 +12,7 @@ from distutils import dir_util from app.classes.shared.helpers import helper from app.classes.shared.console import console -from app.classes.shared.models import db_helper, server_permissions +from app.classes.shared.models import db_helper, server_permissions, Enum_Permissions_Server, crafty_permissions, Enum_Permissions_Crafty from app.classes.shared.server import Server from app.classes.minecraft.server_props import ServerProps @@ -115,6 +115,11 @@ class Controller: permissions_list = server_permissions.get_permissions_list() return permissions_list + @staticmethod + def list_defined_crafty_permissions(): + permissions_list = crafty_permissions.get_permissions_list() + return permissions_list + @staticmethod def get_mask_permissions(role_id, server_id): permissions_mask = db_helper.get_permissions_mask(role_id, server_id) @@ -128,18 +133,44 @@ class Controller: @staticmethod def get_server_permissions_foruser(user_id, server_id): permissions_list = db_helper.get_user_permissions_list(user_id, server_id) + return permissions_list + + @staticmethod + def get_mask_crafty_permissions(user_id): + permissions_mask = db_helper.get_crafty_permissions_mask(user_id) + return permissions_mask + + @staticmethod + def get_crafty_permissions(user_id): + permissions_list = db_helper.get_crafty_permissions_list(user_id) return permissions_list + @staticmethod + def can_create_server(user_id): + permissions_mask = db_helper.get_crafty_permissions_mask(user_id) + return crafty_permissions.has_permission(permissions_mask, Enum_Permissions_Crafty.Server_Creation) + + @staticmethod + def list_all_crafty_permissions_quantity_limits(): + return db_helper.get_all_permission_quantity_list() + + @staticmethod + def list_crafty_permissions_quantity_limits(user_id): + return db_helper.get_permission_quantity_list(user_id) + + @staticmethod + def get_crafty_permissions(user_id): + permissions_list = db_helper.get_crafty_permissions_list(user_id) + return permissions_list + + @staticmethod + def get_crafty_permissions(user_id): + permissions_list = db_helper.get_crafty_permissions_list(user_id) + return permissions_list + @staticmethod def list_authorized_servers(userId): - servers = db_helper.get_authorized_servers(userId) - server_list = [] - for item in servers: - server_list.append(item) - role_servers = db_helper.get_authorized_servers(userId) - for item in role_servers: - server_list.append(item) - logger.debug("servers list = {}".format(servers)) + server_list = db_helper.get_authorized_servers(userId) return server_list def get_server_data(self, server_id): diff --git a/app/classes/shared/models.py b/app/classes/shared/models.py index 6a1d4809..23dbb981 100644 --- a/app/classes/shared/models.py +++ b/app/classes/shared/models.py @@ -133,6 +133,8 @@ class User_Crafty(Model): user_id = ForeignKeyField(Users, backref='users_crafty') permissions = CharField(default="00000000") limit_server_creation = IntegerField(default=-1) + limit_user_creation = IntegerField(default=0) + limit_role_creation = IntegerField(default=0) class Meta: table_name = 'user_crafty' @@ -432,6 +434,40 @@ class db_shortcuts: if authorized.count() == 0: return False return True + + @staticmethod + def get_crafty_permissions_mask(user_id): + permissions_mask = '' + user_crafty = User_Crafty.select().where(User_Crafty.user_id == user_id).get() + permissions_mask = user_crafty.permissions + return permissions_mask + + @staticmethod + def get_crafty_permissions_list(user_id): + permissions_mask = '' + user_crafty = User_Crafty.select().where(User_Crafty.user_id == user_id).get() + permissions_mask = user_crafty.permissions + permissions_list = crafty_permissions.get_permissions(permissions_mask) + return permissions_list + + @staticmethod + def get_all_permission_quantity_list(): + quantity_list = { + Enum_Permissions_Crafty.Server_Creation.name: -1, + Enum_Permissions_Crafty.User_Config.name: -1, + Enum_Permissions_Crafty.Roles_Config.name: -1, + } + return quantity_list + + @staticmethod + def get_permission_quantity_list(user_id): + user_crafty = User_Crafty.select().where(User_Crafty.user_id == user_id).get() + quantity_list = { + Enum_Permissions_Crafty.Server_Creation.name: user_crafty.limit_server_creation, + Enum_Permissions_Crafty.User_Config.name: user_crafty.limit_user_creation, + Enum_Permissions_Crafty.Roles_Config.name: user_crafty.limit_role_creation, + } + return quantity_list @staticmethod def get_latest_hosts_stats(): @@ -555,7 +591,7 @@ class db_shortcuts: return {} @staticmethod - def update_user(user_id, user_data={}): + def update_user(user_id, user_data={}, user_crafty_data={}): base_data = db_helper.get_user(user_id) up_data = {} added_roles = set() @@ -581,6 +617,31 @@ class db_shortcuts: for role in added_roles: User_Roles.get_or_create(user_id=user_id, role_id=role) # TODO: This is horribly inefficient and we should be using bulk queries but im going for functionality at this point + + for key in user_crafty_data: + if key == "permissions_mask": + permissions_mask = user_crafty_data['permissions_mask'] + if key == "server_quantity": + limit_server_creation = user_crafty_data['server_quantity'][Enum_Permissions_Crafty.Server_Creation.name] + limit_user_creation = user_crafty_data['server_quantity'][Enum_Permissions_Crafty.User_Config.name] + limit_role_creation = user_crafty_data['server_quantity'][Enum_Permissions_Crafty.Roles_Config.name] + + try: + user_crafty = User_Crafty.select().where(User_Crafty.user_id == user_id).get() + user_crafty.permissions = permissions_mask + user_crafty.limit_server_creation = limit_server_creation + user_crafty.limit_user_creation = limit_user_creation + user_crafty.limit_role_creation = limit_role_creation + User_Crafty.save(user_crafty) + except: + User_Crafty.insert({ + User_Crafty.user_id: user_id, + User_Crafty.permissions: permissions_mask, + User_Crafty.limit_server_creation: limit_server_creation, + User_Crafty.limit_user_creation: limit_user_creation, + User_Crafty.limit_role_creation: limit_role_creation + }).execute() + User_Roles.delete().where(User_Roles.user_id == user_id).where(User_Roles.role_id.in_(removed_roles)).execute() if up_data: diff --git a/app/classes/web/panel_handler.py b/app/classes/web/panel_handler.py index 90a4823c..1699791d 100644 --- a/app/classes/web/panel_handler.py +++ b/app/classes/web/panel_handler.py @@ -12,7 +12,7 @@ from tornado import iostream from app.classes.shared.console import console from app.classes.shared.models import Users, installer from app.classes.web.base_handler import BaseHandler -from app.classes.shared.models import db_helper, server_permissions, Servers, Enum_Permissions_Server +from app.classes.shared.models import db_helper, server_permissions, Servers, Enum_Permissions_Server, crafty_permissions, Enum_Permissions_Crafty from app.classes.shared.helpers import helper logger = logging.getLogger(__name__) @@ -37,12 +37,14 @@ class PanelHandler(BaseHandler): if exec_user['superuser'] == 1: defined_servers = self.controller.list_defined_servers() exec_user_role.add("Super User") + exec_user_crafty_permissions = self.controller.list_defined_crafty_permissions() else: + exec_user_crafty_permissions = self.controller.get_crafty_permissions(exec_user_id) logger.debug(exec_user['roles']) for r in exec_user['roles']: role = db_helper.get_role(r) exec_user_role.add(role['role_name']) - defined_servers = db_helper.get_authorized_servers(exec_user_id) + defined_servers = self.controller.list_authorized_servers(exec_user_id) page_data = { # todo: make this actually pull and compare version data @@ -50,6 +52,12 @@ class PanelHandler(BaseHandler): 'version_data': helper.get_version_string(), 'user_data': exec_user_data, 'user_role' : exec_user_role, + 'user_crafty_permissions' : exec_user_crafty_permissions, + 'crafty_permissions': { + 'Server_Creation': Enum_Permissions_Crafty.Server_Creation, + 'User_Config': Enum_Permissions_Crafty.User_Config, + 'Roles_Config': Enum_Permissions_Crafty.Roles_Config, + }, 'server_stats': { 'total': len(defined_servers), 'running': len(self.controller.list_running_servers()), @@ -64,9 +72,13 @@ class PanelHandler(BaseHandler): # if no servers defined, let's go to the build server area if page_data['server_stats']['total'] == 0 and page != "error" and page != "credits" and page != "contribute": - self.set_status(301) - self.redirect("/server/step1") - return + + if Enum_Permissions_Crafty.Server_Creation not in exec_user_crafty_permissions and len(defined_servers) == 0: + logger.warning("User '" + exec_user['username'] + "#" + str(exec_user_id) + "' has access to 0 servers and is not a server creator") + else: + self.set_status(301) + self.redirect("/server/step1") + return if page == 'unauthorized': template = "panel/denied.html" @@ -325,15 +337,18 @@ class PanelHandler(BaseHandler): page_data['user']['last_update'] = "N/A" page_data['user']['roles'] = set() - if not exec_user['superuser']: - self.redirect("/panel/error?error=Unauthorized access: not superuser") + if Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions: + self.redirect("/panel/error?error=Unauthorized access: not a user editor") return page_data['roles_all'] = db_helper.get_all_roles() page_data['servers'] = [] page_data['servers_all'] = self.controller.list_defined_servers() - page_data['permissions_all'] = self.controller.list_defined_permissions() page_data['role-servers'] = [] + page_data['permissions_all'] = self.controller.list_defined_crafty_permissions() + page_data['permissions_list'] = set() + page_data['quantity_server'] = self.controller.list_all_crafty_permissions_quantity_limits() + template = "panel/panel_edit_user.html" elif page == "edit_user": @@ -349,12 +364,18 @@ class PanelHandler(BaseHandler): page_data['role-servers'] = page_role_servers page_data['roles_all'] = db_helper.get_all_roles() page_data['servers_all'] = self.controller.list_defined_servers() - page_data['permissions_all'] = self.controller.list_defined_permissions() + page_data['permissions_all'] = self.controller.list_defined_crafty_permissions() + page_data['permissions_list'] = self.controller.get_crafty_permissions(user_id) + page_data['quantity_server'] = self.controller.list_crafty_permissions_quantity_limits(user_id) if user_id is None: self.redirect("/panel/error?error=Invalid User ID") return - elif not exec_user['superuser']: + elif Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions: + if user_id != exec_user_id: + self.redirect("/panel/error?error=Unauthorized access: not a user editor") + return + page_data['servers'] = [] page_data['role-servers'] = [] page_data['roles_all'] = [] @@ -408,8 +429,8 @@ class PanelHandler(BaseHandler): page_data['user-roles'] = user_roles page_data['users'] = db_helper.get_all_users() - if not exec_user['superuser']: - self.redirect("/panel/error?error=Unauthorized access: not superuser") + if Enum_Permissions_Crafty.Roles_Config not in exec_user_crafty_permissions: + self.redirect("/panel/error?error=Unauthorized access: not a role editor") return page_data['servers_all'] = self.controller.list_defined_servers() @@ -435,8 +456,8 @@ class PanelHandler(BaseHandler): page_data['user-roles'] = user_roles page_data['users'] = db_helper.get_all_users() - if not exec_user['superuser']: - self.redirect("/panel/error?error=Unauthorized access: not superuser") + if Enum_Permissions_Crafty.Roles_Config not in exec_user_crafty_permissions: + self.redirect("/panel/error?error=Unauthorized access: not a role editor") return elif role_id is None: self.redirect("/panel/error?error=Invalid Role ID") @@ -491,7 +512,9 @@ class PanelHandler(BaseHandler): if exec_user['superuser'] == 1: defined_servers = self.controller.list_defined_servers() exec_user_role.add("Super User") + exec_user_crafty_permissions = self.controller.list_defined_crafty_permissions() else: + exec_user_crafty_permissions = self.controller.get_crafty_permissions(exec_user_id) defined_servers = self.controller.list_authorized_servers(exec_user_id) for r in exec_user['roles']: role = db_helper.get_role(r) @@ -592,7 +615,11 @@ class PanelHandler(BaseHandler): enabled = int(float(self.get_argument('enabled', '0'))) regen_api = int(float(self.get_argument('regen_api', '0'))) - if not exec_user['superuser']: + if Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions: + if user_id != exec_user_id: + self.redirect("/panel/error?error=Unauthorized access: not a user editor") + return + user_data = { "username": username, "password": password0, @@ -632,15 +659,24 @@ class PanelHandler(BaseHandler): if argument: roles.add(role.role_id) - servers = set() - for server in self.controller.list_defined_servers(): + permissions_mask = "00000000" + server_quantity = {} + for permission in self.controller.list_defined_crafty_permissions(): argument = int(float( bleach.clean( - self.get_argument('server_{}_access'.format(server['server_id']), '0') + self.get_argument('permission_{}'.format(permission.name), '0') ) )) if argument: - servers.add(server['server_id']) + permissions_mask = crafty_permissions.set_permission(permissions_mask, permission, argument) + + q_argument = int(float( + bleach.clean( + self.get_argument('quantity_{}'.format(permission.name), '0') + ) + )) + if q_argument: + server_quantity[permission.name] = q_argument user_data = { "username": username, @@ -649,10 +685,14 @@ class PanelHandler(BaseHandler): "regen_api": regen_api, "roles": roles, } - db_helper.update_user(user_id, user_data=user_data) + user_crafty_data = { + "permissions_mask": permissions_mask, + "server_quantity": server_quantity + } + db_helper.update_user(user_id, user_data=user_data, user_crafty_data=user_crafty_data) db_helper.add_to_audit_log(exec_user['user_id'], - "Edited user {} (UID:{}) with roles {} and servers {}".format(username, user_id, roles, servers), + "Edited user {} (UID:{}) with roles {} and permissions {}".format(username, user_id, roles, permissions_mask), server_id=0, source_ip=self.get_remote_ip()) self.redirect("/panel/panel_config") @@ -664,8 +704,8 @@ class PanelHandler(BaseHandler): password1 = bleach.clean(self.get_argument('password1', None)) enabled = int(float(self.get_argument('enabled', '0'))) - if not exec_user['superuser']: - self.redirect("/panel/error?error=Unauthorized access: not superuser") + if Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions: + self.redirect("/panel/error?error=Unauthorized access: not a user editor") return elif username is None or username == "": self.redirect("/panel/error?error=Invalid username") @@ -689,22 +729,35 @@ class PanelHandler(BaseHandler): )) if argument: roles.add(role.role_id) - - servers = set() - for server in self.controller.list_defined_servers(): + + permissions_mask = "00000000" + server_quantity = {} + for permission in self.controller.list_defined_crafty_permissions(): argument = int(float( bleach.clean( - self.get_argument('server_{}_access'.format(server['server_id']), '0') + self.get_argument('permission_{}'.format(permission.name), '0') ) )) if argument: - servers.add(server['server_id']) + permissions_mask = crafty_permissions.set_permission(permissions_mask, permission, argument) + + q_argument = int(float( + bleach.clean( + self.get_argument('quantity_{}'.format(permission.name), '0') + ) + )) + if q_argument: + server_quantity[permission.name] = q_argument user_id = db_helper.add_user(username, password=password0, enabled=enabled) user_data = { "roles": roles, } - db_helper.update_user(user_id, user_data) + user_crafty_data = { + "permissions_mask": permissions_mask, + "server_quantity": server_quantity + } + db_helper.update_user(user_id, user_data=user_data, user_crafty_data=user_crafty_data) db_helper.add_to_audit_log(exec_user['user_id'], "Added user {} (UID:{})".format(username, user_id), @@ -720,8 +773,8 @@ class PanelHandler(BaseHandler): role_id = bleach.clean(self.get_argument('id', None)) role_name = bleach.clean(self.get_argument('role_name', None)) - if not exec_user['superuser']: - self.redirect("/panel/error?error=Unauthorized access: not superuser") + if Enum_Permissions_Crafty.Roles_Config not in exec_user_crafty_permissions: + self.redirect("/panel/error?error=Unauthorized access: not a role editor") return elif role_name is None or role_name == "": self.redirect("/panel/error?error=Invalid username") @@ -771,8 +824,8 @@ class PanelHandler(BaseHandler): elif page == "add_role": role_name = bleach.clean(self.get_argument('role_name', None)) - if not exec_user['superuser']: - self.redirect("/panel/error?error=Unauthorized access: not superuser") + if Enum_Permissions_Crafty.Roles_Config not in exec_user_crafty_permissions: + self.redirect("/panel/error?error=Unauthorized access: not a role editor") return elif role_name is None or role_name == "": self.redirect("/panel/error?error=Invalid role name") diff --git a/app/classes/web/server_handler.py b/app/classes/web/server_handler.py index d1ca646b..f193e1ac 100644 --- a/app/classes/web/server_handler.py +++ b/app/classes/web/server_handler.py @@ -6,7 +6,7 @@ import shutil from app.classes.shared.console import console from app.classes.web.base_handler import BaseHandler -from app.classes.shared.models import db_helper +from app.classes.shared.models import db_helper, Enum_Permissions_Crafty from app.classes.minecraft.serverjars import server_jar_obj from app.classes.shared.helpers import helper @@ -37,7 +37,9 @@ class ServerHandler(BaseHandler): if exec_user['superuser'] == 1: defined_servers = self.controller.list_defined_servers() exec_user_role.add("Super User") + exec_user_crafty_permissions = self.controller.list_defined_crafty_permissions() else: + exec_user_crafty_permissions = self.controller.get_crafty_permissions(exec_user_id) defined_servers = self.controller.list_authorized_servers(exec_user_id) for r in exec_user['roles']: role = db_helper.get_role(r) @@ -49,6 +51,12 @@ class ServerHandler(BaseHandler): 'version_data': helper.get_version_string(), 'user_data': exec_user_data, 'user_role' : exec_user_role, + 'user_crafty_permissions' : exec_user_crafty_permissions, + 'crafty_permissions': { + 'Server_Creation': Enum_Permissions_Crafty.Server_Creation, + 'User_Config': Enum_Permissions_Crafty.User_Config, + 'Roles_Config': Enum_Permissions_Crafty.Roles_Config, + }, 'server_stats': { 'total': len(self.controller.list_defined_servers()), 'running': len(self.controller.list_running_servers()), @@ -61,6 +69,10 @@ class ServerHandler(BaseHandler): if page == "step1": + if not self.controller.can_create_server(exec_user_id): + self.redirect("/panel/error?error=Unauthorized access: not at server creator") + return + page_data['server_types'] = server_jar_obj.get_serverjar_data_sorted() page_data['js_server_types'] = json.dumps(server_jar_obj.get_serverjar_data_sorted()) template = "server/wizard.html" diff --git a/app/frontend/templates/main_menu.html b/app/frontend/templates/main_menu.html index 804280af..b7e0de6b 100644 --- a/app/frontend/templates/main_menu.html +++ b/app/frontend/templates/main_menu.html @@ -21,9 +21,11 @@
+ +
+
+

Crafty Permissions - permissions this user has on Crafty Controller

+
+
+
+
+ + + + + + + + + + {% for permission in data['permissions_all'] %} + + + + + + {% end %} + +
Permission NameAuthorized ?Quantity
{{ permission.name }} + {% if permission in data['permissions_list'] %} + + {% else %} + + {% end %} +
+
+
+
+