Secured config endpoints #334

This commit is contained in:
Sven Heidemann 2023-08-15 21:50:37 +02:00
parent 8a0d939147
commit e549341196
10 changed files with 67 additions and 19 deletions

View File

@ -9,6 +9,7 @@ from cpl_query.extension import List
from bot_api.exception.service_error_code_enum import ServiceErrorCode from bot_api.exception.service_error_code_enum import ServiceErrorCode
from bot_api.exception.service_exception import ServiceException from bot_api.exception.service_exception import ServiceException
from bot_api.route.route import Route from bot_api.route.route import Route
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_data.model.auth_role_enum import AuthRoleEnum from bot_data.model.auth_role_enum import AuthRoleEnum
from bot_data.model.auth_user import AuthUser from bot_data.model.auth_user import AuthUser
from bot_data.model.auto_role import AutoRole from bot_data.model.auto_role import AutoRole
@ -17,6 +18,7 @@ from bot_data.model.client import Client
from bot_data.model.known_user import KnownUser from bot_data.model.known_user import KnownUser
from bot_data.model.level import Level from bot_data.model.level import Level
from bot_data.model.server import Server from bot_data.model.server import Server
from bot_data.model.server_config import ServerConfig
from bot_data.model.user import User from bot_data.model.user import User
from bot_data.model.user_joined_game_server import UserJoinedGameServer from bot_data.model.user_joined_game_server import UserJoinedGameServer
from bot_data.model.user_joined_server import UserJoinedServer from bot_data.model.user_joined_server import UserJoinedServer
@ -66,8 +68,12 @@ class QueryABC(ObjectType):
self.set_field(f"{name}s", wrapper) self.set_field(f"{name}s", wrapper)
self.set_field(f"{name}Count", lambda *args: wrapper(*args).count()) self.set_field(f"{name}Count", lambda *args: wrapper(*args).count())
@ServiceProviderABC.inject def _can_user_see_element(self, user: AuthUser, element: T) -> bool:
def _can_user_see_element(self, user: AuthUser, element: T, services: ServiceProviderABC) -> bool: @ServiceProviderABC.inject
def get_services(services: ServiceProviderABC) -> ServiceProviderABC:
return services
services = get_services()
permissions: PermissionService = services.get_service(PermissionService) permissions: PermissionService = services.get_service(PermissionService)
bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC) bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC)
@ -158,6 +164,24 @@ class QueryABC(ObjectType):
access = True access = True
break break
elif type(element) == ServerConfig:
for u in user.users:
u: User = u
guild = bot.get_guild(u.server.discord_id)
member = guild.get_member(u.discord_id)
if permissions.is_member_technician(member):
access = True
break
elif type(element) == dict and "key" in element and element["key"] in [e.value for e in FeatureFlagsEnum]:
for u in user.users:
u: User = u
guild = bot.get_guild(u.server.discord_id)
member = guild.get_member(u.discord_id)
if permissions.is_member_technician(member):
access = True
break
return access return access
@ServiceProviderABC.inject @ServiceProviderABC.inject

View File

@ -13,6 +13,7 @@ type ServerConfig implements TableWithHistoryQuery {
helpVoiceChannelId: String helpVoiceChannelId: String
teamChannelId: String teamChannelId: String
loginMessageChannelId: String loginMessageChannelId: String
featureFlagCount: Int
featureFlags: [FeatureFlag] featureFlags: [FeatureFlag]
afkChannelIds: [String] afkChannelIds: [String]
@ -42,6 +43,7 @@ type ServerConfigHistory implements HistoryTableQuery {
helpVoiceChannelId: String helpVoiceChannelId: String
teamChannelId: String teamChannelId: String
loginMessageChannelId: String loginMessageChannelId: String
featureFlagCount: Int
featureFlags: [FeatureFlag] featureFlags: [FeatureFlag]
serverId: ID serverId: ID

View File

@ -4,6 +4,7 @@ type TechnicianConfig implements TableWithHistoryQuery {
waitForRestart: Int waitForRestart: Int
waitForShutdown: Int waitForShutdown: Int
cacheMaxMessages: Int cacheMaxMessages: Int
featureFlagCount: Int
featureFlags: [FeatureFlag] featureFlags: [FeatureFlag]
pingURLs: [String] pingURLs: [String]
technicianIds: [String] technicianIds: [String]
@ -22,6 +23,7 @@ type TechnicianConfigHistory implements HistoryTableQuery {
waitForRestart: Int waitForRestart: Int
waitForShutdown: Int waitForShutdown: Int
cacheMaxMessages: Int cacheMaxMessages: Int
featureFlagCount: Int
featureFlags: [FeatureFlag] featureFlags: [FeatureFlag]
deleted: Boolean deleted: Boolean

View File

@ -3,6 +3,7 @@ from cpl_discord.service import DiscordBotServiceABC
from cpl_query.extension import List from cpl_query.extension import List
from bot_api.logging.api_logger import ApiLogger from bot_api.logging.api_logger import ApiLogger
from bot_api.route.route import Route
from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.model.server_afk_channel_ids_config import ServerAFKChannelIdsConfig from bot_data.model.server_afk_channel_ids_config import ServerAFKChannelIdsConfig
@ -37,7 +38,7 @@ class ServerConfigMutation(QueryABC):
raise ValueError("Id not set") raise ValueError("Id not set")
server_config = self._server_configs.get_server_config_by_server(input["id"]) server_config = self._server_configs.get_server_config_by_server(input["id"])
self._can_user_mutate_data(server_config, UserRoleEnum.admin) self._can_user_mutate_data(Route.get_user().users[0].server, UserRoleEnum.technician)
server_config.message_delete_timer = ( server_config.message_delete_timer = (
input["messageDeleteTimer"] if "messageDeleteTimer" in input else server_config.message_delete_timer input["messageDeleteTimer"] if "messageDeleteTimer" in input else server_config.message_delete_timer
@ -166,3 +167,6 @@ class ServerConfigMutation(QueryABC):
continue continue
self._server_configs.add_server_team_role_id_config(role_id) self._server_configs.add_server_team_role_id_config(role_id)
# todo reload config
# reload permissions

View File

@ -3,6 +3,7 @@ from cpl_discord.service import DiscordBotServiceABC
from cpl_query.extension import List from cpl_query.extension import List
from bot_api.logging.api_logger import ApiLogger from bot_api.logging.api_logger import ApiLogger
from bot_api.route.route import Route
from bot_data.abc.server_repository_abc import ServerRepositoryABC from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC from bot_data.abc.technician_config_repository_abc import TechnicianConfigRepositoryABC
from bot_data.model.technician_config import TechnicianConfig from bot_data.model.technician_config import TechnicianConfig
@ -10,6 +11,7 @@ from bot_data.model.technician_id_config import TechnicianIdConfig
from bot_data.model.technician_ping_url_config import TechnicianPingUrlConfig from bot_data.model.technician_ping_url_config import TechnicianPingUrlConfig
from bot_data.model.user_role_enum import UserRoleEnum from bot_data.model.user_role_enum import UserRoleEnum
from bot_graphql.abc.query_abc import QueryABC from bot_graphql.abc.query_abc import QueryABC
from modules.permission.abc.permission_service_abc import PermissionServiceABC
class TechnicianConfigMutation(QueryABC): class TechnicianConfigMutation(QueryABC):
@ -20,6 +22,7 @@ class TechnicianConfigMutation(QueryABC):
servers: ServerRepositoryABC, servers: ServerRepositoryABC,
technician_configs: TechnicianConfigRepositoryABC, technician_configs: TechnicianConfigRepositoryABC,
db: DatabaseContextABC, db: DatabaseContextABC,
permissions: PermissionServiceABC,
): ):
QueryABC.__init__(self, "TechnicianConfigMutation") QueryABC.__init__(self, "TechnicianConfigMutation")
@ -28,12 +31,13 @@ class TechnicianConfigMutation(QueryABC):
self._servers = servers self._servers = servers
self._technician_configs = technician_configs self._technician_configs = technician_configs
self._db = db self._db = db
self._permissions = permissions
self.set_field("updateTechnicianConfig", self.resolve_update_technician_config) self.set_field("updateTechnicianConfig", self.resolve_update_technician_config)
def resolve_update_technician_config(self, *_, input: dict): def resolve_update_technician_config(self, *_, input: dict):
technician_config = self._technician_configs.get_technician_config() technician_config = self._technician_configs.get_technician_config()
self._can_user_mutate_data(technician_config, UserRoleEnum.admin) self._can_user_mutate_data(Route.get_user().users[0].server, UserRoleEnum.technician)
technician_config.help_command_reference_url = ( technician_config.help_command_reference_url = (
input["helpCommandReferenceUrl"] input["helpCommandReferenceUrl"]
@ -105,3 +109,6 @@ class TechnicianConfigMutation(QueryABC):
continue continue
self._technician_configs.add_technician_id_config(TechnicianIdConfig(technician_id)) self._technician_configs.add_technician_id_config(TechnicianIdConfig(technician_id))
# todo reload config
self._permissions.on_ready()

View File

@ -1,4 +1,5 @@
from cpl_core.database.context import DatabaseContextABC from cpl_core.database.context import DatabaseContextABC
from cpl_query.extension import List
from bot_data.model.server_config_history import ServerConfigHistory from bot_data.model.server_config_history import ServerConfigHistory
from bot_data.model.team_member_type_enum import TeamMemberTypeEnum from bot_data.model.team_member_type_enum import TeamMemberTypeEnum
@ -23,9 +24,9 @@ class ServerConfigQuery(DataQueryWithHistoryABC):
self.set_field("helpVoiceChannelId", lambda config, *_: config.help_voice_channel_id) self.set_field("helpVoiceChannelId", lambda config, *_: config.help_voice_channel_id)
self.set_field("teamChannelId", lambda config, *_: config.team_channel_id) self.set_field("teamChannelId", lambda config, *_: config.team_channel_id)
self.set_field("loginMessageChannelId", lambda config, *_: config.login_message_channel_id) self.set_field("loginMessageChannelId", lambda config, *_: config.login_message_channel_id)
self.set_field( self.add_collection(
"featureFlags", "featureFlag",
lambda config, *_: [{"key": x, "value": config.feature_flags[x]} for x in config.feature_flags], lambda config, *_: List(any, [{"key": x, "value": config.feature_flags[x]} for x in config.feature_flags]),
) )
self.set_field("afkChannelIds", lambda config, *_: config.afk_channel_ids) self.set_field("afkChannelIds", lambda config, *_: config.afk_channel_ids)
self.set_field( self.set_field(

View File

@ -1,3 +1,5 @@
from cpl_query.extension import List
from bot_graphql.abc.history_query_abc import HistoryQueryABC from bot_graphql.abc.history_query_abc import HistoryQueryABC
@ -9,7 +11,7 @@ class TechnicianConfigHistoryQuery(HistoryQueryABC):
self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart) self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart)
self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown) self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown)
self.set_field("cacheMaxMessages", lambda config, *_: config.cache_max_messages) self.set_field("cacheMaxMessages", lambda config, *_: config.cache_max_messages)
self.set_field( self.add_collection(
"featureFlags", "featureFlag",
lambda config, *_: [{"key": x, "value": config.feature_flags[x]} for x in config.feature_flags], lambda config, *_: List(any, [{"key": x, "value": config.feature_flags[x]} for x in config.feature_flags]),
) )

View File

@ -16,9 +16,9 @@ class TechnicianConfigQuery(DataQueryWithHistoryABC):
self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart) self.set_field("waitForRestart", lambda config, *_: config.wait_for_restart)
self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown) self.set_field("waitForShutdown", lambda config, *_: config.wait_for_shutdown)
self.set_field("cacheMaxMessages", lambda config, *_: config.cache_max_messages) self.set_field("cacheMaxMessages", lambda config, *_: config.cache_max_messages)
self.set_field( self.add_collection(
"featureFlags", "featureFlag",
lambda config, *_: [{"key": x, "value": config.feature_flags[x]} for x in config.feature_flags], lambda config, *_: List(any, [{"key": x, "value": config.feature_flags[x]} for x in config.feature_flags]),
) )
self.set_field("pingURLs", lambda config, *_: config.ping_urls) self.set_field("pingURLs", lambda config, *_: config.ping_urls)
self.set_field("technicianIds", lambda config, *_: config.technician_ids) self.set_field("technicianIds", lambda config, *_: config.technician_ids)

View File

@ -28,8 +28,11 @@ export class AuthGuard implements CanActivate {
const role = route.data['role']; const role = route.data['role'];
if (role) { if (role) {
this.authService.hasUserPermission(role).then(hasPermission => { this.authService.hasUserPermission(role).then(async hasPermission => {
if (!hasPermission) { let authUser = await this.authService.getLoggedInUser();
let isTechnician = authUser?.users?.map(u => u.isTechnician).filter(u => u) ?? [];
if (!hasPermission && !isTechnician) {
this.router.navigate(['/dashboard']); this.router.navigate(['/dashboard']);
return false; return false;
} }

View File

@ -67,7 +67,7 @@ export class SidebarService {
} }
} }
async buildMenu(user: UserDTO | null, hasPermission: boolean) { async buildMenu(user: UserDTO | null, hasPermission: boolean, isTechnician: boolean = false) {
this.dashboard = { this.dashboard = {
label: this.isSidebarOpen ? this.translateService.instant("sidebar.dashboard") : "", label: this.isSidebarOpen ? this.translateService.instant("sidebar.dashboard") : "",
icon: "pi pi-th-large", icon: "pi pi-th-large",
@ -127,18 +127,20 @@ export class SidebarService {
}; };
this.adminConfig = { this.adminConfig = {
label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "", label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "",
visible: hasPermission || isTechnician,
icon: "pi pi-cog", icon: "pi pi-cog",
routerLink: "/admin/settings" routerLink: "/admin/settings"
}; };
this.adminUsers = { this.adminUsers = {
label: this.isSidebarOpen ? this.translateService.instant("sidebar.auth_user_list") : "", label: this.isSidebarOpen ? this.translateService.instant("sidebar.auth_user_list") : "",
visible: hasPermission,
icon: "pi pi-user-edit", icon: "pi pi-user-edit",
routerLink: "/admin/users" routerLink: "/admin/users"
}; };
this.adminMenu = { this.adminMenu = {
label: this.isSidebarOpen ? this.translateService.instant("sidebar.administration") : "", label: this.isSidebarOpen ? this.translateService.instant("sidebar.administration") : "",
icon: "pi pi-cog", icon: "pi pi-cog",
visible: hasPermission, visible: hasPermission || isTechnician,
expanded: true, expanded: true,
items: [this.adminConfig, this.adminUsers] items: [this.adminConfig, this.adminUsers]
}; };
@ -148,9 +150,10 @@ export class SidebarService {
this.authService.hasUserPermission(AuthRoles.Admin).then(async hasPermission => { this.authService.hasUserPermission(AuthRoles.Admin).then(async hasPermission => {
let authUser = await this.authService.getLoggedInUser(); let authUser = await this.authService.getLoggedInUser();
let user: UserDTO | null = authUser?.users?.find(u => u.server == this.server$.value?.id) ?? null; let user: UserDTO | null = authUser?.users?.find(u => u.server == this.server$.value?.id) ?? null;
let isTechnician = authUser?.users?.map(u => u.isTechnician).filter(u => u) ?? [];
if (build || this.menuItems$.value.length == 0) { if (build || this.menuItems$.value.length == 0) {
await this.buildMenu(user, hasPermission); await this.buildMenu(user, hasPermission, isTechnician.length > 0);
} }
if (this.server$.value) { if (this.server$.value) {
@ -159,7 +162,7 @@ export class SidebarService {
this.serverAutoRoles.visible = !!user?.isModerator; this.serverAutoRoles.visible = !!user?.isModerator;
this.serverLevels.visible = !!user?.isModerator; this.serverLevels.visible = !!user?.isModerator;
this.serverAchievements.visible = !!user?.isModerator; this.serverAchievements.visible = !!user?.isModerator;
this.serverConfig.visible = !!user?.isAdmin; this.serverConfig.visible = !!user?.isAdmin || isTechnician.length > 0;
} else { } else {
this.serverMenu.visible = false; this.serverMenu.visible = false;
} }