diff --git a/allianceauth/services/modules/mumble/authenticator.py b/allianceauth/services/modules/mumble/authenticator.py index ceaf97a9..01e1dab9 100644 --- a/allianceauth/services/modules/mumble/authenticator.py +++ b/allianceauth/services/modules/mumble/authenticator.py @@ -56,7 +56,20 @@ from allianceauth import __version__ # noqa from allianceauth.services.modules.mumble.models import MumbleServerServer, MumbleUser, TempUser # noqa -def main() -> None: +def main(server_id: int = 1) -> None: + """_summary_ + + Args: + server_id (int, optional): _description_. Defaults to 1. + + Raises: + e: _description_ + Murmur.InvalidSecretException: _description_ + e: _description_ + + Returns: + _type_: _description_ + """ slicedir = Ice.getSliceDir() if not slicedir: slicedir = ["-I/usr/share/Ice/slice", "-I/usr/share/slice"] @@ -64,7 +77,7 @@ def main() -> None: slicedir = ['-I' + slicedir] package_dir = next(iter(importlib.util.find_spec('allianceauth.services.modules.mumble').submodule_search_locations)) - package_ice = os.path.join(package_dir, MumbleServerServer.objects.get(id=1).slice) + package_ice = os.path.join(package_dir, server_config_obj.slice) logger.info(f"Using slice file: {package_ice}") slicedir.append("-I" + os.path.dirname(package_ice)) @@ -75,6 +88,8 @@ def main() -> None: except ImportError: import Murmur # Mumble <=1.5.17 + server_config_obj = MumbleServerServer.objects.get(id=server_id) + class AllianceAuthAuthenticatorApp(Ice.Application): def run(self, args) -> int: self.shutdownOnInterrupt() @@ -82,7 +97,7 @@ def main() -> None: if not self.initializeIceConnection(): return 1 - if MumbleServerServer.objects.get(id=1).watchdog > 0: + if server_config_obj.watchdog > 0: self.failedWatch = True self.checkConnection() @@ -102,13 +117,13 @@ def main() -> None: """ ice = self.communicator() logger.debug("Using shared ice secret") - ice.getImplicitContext().put("secret", MumbleServerServer.objects.get(id=1).secret) + ice.getImplicitContext().put("secret", server_config_obj.secret) - logger.info(f"Connecting to Ice server ({MumbleServerServer.objects.get(id=1).ip}:{MumbleServerServer.objects.get(id=1).port})") - base = ice.stringToProxy(f"Meta:tcp -h {MumbleServerServer.objects.get(id=1).ip} -p {MumbleServerServer.objects.get(id=1).port}") + logger.info(f"Connecting to Ice server ({server_config_obj.ip}:{server_config_obj.port})") + base = ice.stringToProxy(f"Meta:tcp -h {server_config_obj.ip} -p {server_config_obj.port}") self.meta = Murmur.MetaPrx.uncheckedCast(base) - adapter = ice.createObjectAdapterWithEndpoints("Callback.Client", f"tcp -h {MumbleServerServer.objects.get(id=1).endpoint}") + adapter = ice.createObjectAdapterWithEndpoints("Callback.Client", f"tcp -h {server_config_obj.endpoint}") adapter.activate() metacbprx = adapter.addWithUUID(metaCallback(self)) @@ -136,11 +151,11 @@ def main() -> None: self.meta.addCallback(self.metacb) for server in self.meta.getBootedServers(): - if server.id() in MumbleServerServer.objects.get(id=1).virtual_servers_list(): + if server.id() in server_config_obj.virtual_servers_list(): logger.info("Setting authenticator for virtual server %d", server.id()) server.setAuthenticator(self.auth) server.addCallback(self.servercb) - if MumbleServerServer.objects.get(id=1).idler_handler: + if server_config_obj.idler_handler: idler_handler(server) except (Murmur.InvalidSecretException, Ice.UnknownUserException, Ice.ConnectionRefusedException) as e: @@ -170,12 +185,12 @@ def main() -> None: else: self.failedWatch = False except Ice.Exception as e: - logger.error(f"Failed connection check, will retry in next watchdog run ({MumbleServerServer.objects.get(id=1).watchdog}s)") + logger.error(f"Failed connection check, will retry in next watchdog run ({server_config_obj.watchdog}s)") logger.exception(e) self.failedWatch = True # Renew the timer - self.watchdog = Timer(MumbleServerServer.objects.get(id=1).watchdog, self.checkConnection) + self.watchdog = Timer(server_config_obj.watchdog, self.checkConnection) self.watchdog.start() def checkSecret(func): @@ -183,7 +198,7 @@ def main() -> None: Decorator that checks whether the server transmitted the right secret if a secret is supposed to be used. """ - if not MumbleServerServer.objects.get(id=1).secret: + if not server_config_obj.secret: return func def newfunc(*args, **kws): @@ -192,7 +207,7 @@ def main() -> None: else: current = args[-1] - if not current or "secret" not in current.ctx or current.ctx["secret"] != MumbleServerServer.objects.get(id=1).secret: + if not current or "secret" not in current.ctx or current.ctx["secret"] != server_config_obj.secret: logger.error("Server transmitted invalid secret. Possible injection attempt.") raise Murmur.InvalidSecretException() @@ -242,7 +257,7 @@ def main() -> None: This function is called when a virtual server is started and makes sure an authenticator gets attached if needed. """ - if server.id() in MumbleServerServer.objects.get(id=1).virtual_servers_list(): + if server.id() in server_config_obj.virtual_servers_list(): logger.info("Setting authenticator for virtual server %d", server.id()) try: server.setAuthenticator(self.app.auth) @@ -266,7 +281,7 @@ def main() -> None: # Only try to output the server id if we think we are still connected to prevent # flooding of our thread pool try: - if server.id() in MumbleServerServer.objects.get(id=1).virtual_servers_list(): + if server.id() in server_config_obj.virtual_servers_list(): logger.info(f"Authenticated virtual server {server.id()} got stopped") else: logger.debug(f"Virtual server {server.id()} got stopped") @@ -276,7 +291,7 @@ def main() -> None: logger.debug("Server shutdown stopped a virtual server") - if MumbleServerServer.objects.get(id=1).reject_on_error: # Python 2.4 compat + if server_config_obj.reject_on_error: # Python 2.4 compat authenticateFortifyResult = (-1, None, None) else: authenticateFortifyResult = (-2, None, None) @@ -328,7 +343,7 @@ def main() -> None: users = self.server.getUsers() for (userid, auser) in users.items(): - if auser.userid > (MumbleServerServer.objects.get(id=1).offset * 2): + if auser.userid > (server_config_obj.offset * 2): self.server.kickUser(auser.session, "Kicking all temp users! :-)") self.server.sendMessage(user.session, "All templink clients kicked!") @@ -373,11 +388,11 @@ def main() -> None: logger.debug("checking password with hash function: %s" % mumble_user.hashfn) if allianceauth_check_hash(pw, mumble_user.pwhash, mumble_user.hashfn): - logger.info(f'User authenticated: {mumble_user.display_name} {mumble_user.user_id + MumbleServerServer.objects.get(id=1).offset}') + logger.info(f'User authenticated: {mumble_user.display_name} {mumble_user.user_id + server_config_obj.offset}') logger.debug("Group memberships: %s", mumble_user.group_string()) - return (mumble_user.user_id + MumbleServerServer.objects.get(id=1).offset, mumble_user.display_name, mumble_user.group_string()) + return (mumble_user.user_id + server_config_obj.offset, mumble_user.display_name, mumble_user.group_string()) logger.info( - f'Failed authentication attempt for user: {name} {mumble_user.user_id + MumbleServerServer.objects.get(id=1).offset}') + f'Failed authentication attempt for user: {name} {mumble_user.user_id + server_config_obj.offset}') return (AUTH_REFUSED, None, None) @fortifyIceFu((False, None)) @@ -401,10 +416,10 @@ def main() -> None: return -2 # FALL_THROUGH try: - return (MumbleUser.objects.get(username=name).pk + MumbleServerServer.objects.get(id=1).offset) + return (MumbleUser.objects.get(username=name).pk + server_config_obj.offset) except MumbleUser.DoesNotExist: try: - return (TempUser.objects.get(username=name).pk + MumbleServerServer.objects.get(id=1).offset * 2) + return (TempUser.objects.get(username=name).pk + server_config_obj.offset * 2) except TempUser.DoesNotExist: return -2 # FALL_THROUGH @@ -414,15 +429,15 @@ def main() -> None: """ Gets called to get the username for a given id """ - if id < MumbleServerServer.objects.get(id=1).offset: + if id < server_config_obj.offset: return "" # FALL_THROUGH try: - mumble_user = MumbleUser.objects.get(user_id=id - MumbleServerServer.objects.get(id=1).offset) + mumble_user = MumbleUser.objects.get(user_id=id - server_config_obj.offset) mumble_user.username except MumbleUser.DoesNotExist: try: - mumble_user = TempUser.objects.get(user_id=id - MumbleServerServer.objects.get(id=1).offset * 2) + mumble_user = TempUser.objects.get(user_id=id - server_config_obj.offset * 2) mumble_user.username except TempUser.DoesNotExist: return "" # FALL_THROUGH @@ -430,7 +445,7 @@ def main() -> None: # I dont quite rightly know why we have this # SuperUser shouldnt be in our Authenticator? # But Maybe it can be? - if MumbleUser.objects.get(user_id=id - MumbleServerServer.objects.get(id=1).offset).username == "SuperUser": + if MumbleUser.objects.get(user_id=id - server_config_obj.offset).username == "SuperUser": logger.debug('idToName %d -> "SuperUser" caught') return "" # FALL_THROUGH else: @@ -442,15 +457,15 @@ def main() -> None: """ Gets called to get the corresponding texture for a user """ - if MumbleServerServer.objects.get(id=1).avatar_enable is False: + if server_config_obj.avatar_enable is False: logger.debug(f"idToTexture {id} -> avatar display disabled, fall through") return "" # FALL_THROUGH - if id < MumbleServerServer.objects.get(id=1).offset: + if id < server_config_obj.offset: return "" # FALL_THROUGH try: - avatar_url = MumbleUser.objects.get(user_id=id - MumbleServerServer.objects.get(id=1).offset).user.profile.main_character.portrait_url() + avatar_url = MumbleUser.objects.get(user_id=id - server_config_obj.offset).user.profile.main_character.portrait_url() except MumbleUser.DoesNotExist: logger.debug(f"idToTexture {id} -> MumbleUser.DoesNotExist, Fall Through") return "" # FALL_THROUGH @@ -520,7 +535,7 @@ def main() -> None: return {} logger.debug(f'getRegisteredUsers -> {len(mumble_users)} results for filter {filter}') - return {mumble_user.user_id + MumbleServerServer.objects.get(id=1).offset: mumble_user.username for mumble_user in mumble_users} + return {mumble_user.user_id + server_config_obj.offset: mumble_user.username for mumble_user in mumble_users} @fortifyIceFu(-1) @checkSecret @@ -586,30 +601,30 @@ def idler_handler(server) -> None: logger.debug(f"IdleHandler: Skipping User {user.name}, This happens occasionally") continue - if user_idlesecs > MumbleServerServer.objects.get(id=1).idler_handler.seconds: + if user_idlesecs > server_config_obj.idler_handler.seconds: logger.debug( - f"IdleHandler: User {user.name} is AFK, for {user_idlesecs}/{MumbleServerServer.objects.get(id=1).idler_handler.seconds}" + f"IdleHandler: User {user.name} is AFK, for {user_idlesecs}/{server_config_obj.idler_handler.seconds}" ) state = server.getState(user.session) if state: # AllowList > DenyList - if MumbleServerServer.objects.get(id=1).idler_handler.denylist is False: - if state.channel not in MumbleServerServer.objects.get(id=1).idler_handler.list: + if server_config_obj.idler_handler.denylist is False: + if state.channel not in server_config_obj.idler_handler.list: return - elif MumbleServerServer.objects.get(id=1).idler_handler.denylist is True: - if state.channel in MumbleServerServer.objects.get(id=1).idler_handler.list: + elif server_config_obj.idler_handler.denylist is True: + if state.channel in server_config_obj.idler_handler.list: return - if state.channel == MumbleServerServer.objects.get(id=1).idler_handler.channel: + if state.channel == server_config_obj.idler_handler.channel: return - state.channel = MumbleServerServer.objects.get(id=1).idler_handler.channel + state.channel = server_config_obj.idler_handler.channel state.selfMute = True state.selfDeaf = True server.setState(state) logger.debug(f"IdleHandler: Moved AFK User {user.name}") - Timer(MumbleServerServer.objects.get(id=1).idler_handler.interval, idler_handler, (server,)).start() + Timer(server_config_obj.idler_handler.interval, idler_handler, (server,)).start() if __name__ == "__main__": diff --git a/allianceauth/services/modules/mumble/management/__init.py b/allianceauth/services/modules/mumble/management/__init.py new file mode 100644 index 00000000..e69de29b diff --git a/allianceauth/services/modules/mumble/management/commands/__init.py b/allianceauth/services/modules/mumble/management/commands/__init.py new file mode 100644 index 00000000..e69de29b diff --git a/allianceauth/services/modules/mumble/management/commands/mumble_authenticator.py b/allianceauth/services/modules/mumble/management/commands/mumble_authenticator.py new file mode 100644 index 00000000..6eb8a6aa --- /dev/null +++ b/allianceauth/services/modules/mumble/management/commands/mumble_authenticator.py @@ -0,0 +1,15 @@ +from allianceauth.services.modules.mumble import authenticator + +from django.core.management.base import BaseCommand + + +class Command(BaseCommand): + help = 'Run the Mumble Authenticator' + + def add_arguments(self, parser) -> None: + parser.add_argument( + '--server_id', action='store', default=1, + help='Run the Mumble Authenticator for the given Server Configuration ID') + + def handle(self, *args, **options) -> None: + authenticator.main()