# HG changeset patch # User Goffi # Date 1605389269 -3600 # Node ID 45ebeea1bacdee12a6e716c226e9ed7c7e98e12a # Parent 626b7bbb7f902108b295a8cc84583f0758ae8f71 server: improved service profile check + auto creation: When service profile can't be connected, bridge exception is checked and if the profile doesn't exists yet, Libervia tried to create it using in-band registration. diff -r 626b7bbb7f90 -r 45ebeea1bacd libervia/server/server.py --- a/libervia/server/server.py Sat Nov 14 22:24:58 2020 +0100 +++ b/libervia/server/server.py Sat Nov 14 22:27:49 2020 +0100 @@ -54,6 +54,7 @@ from sat.tools.common.utils import recursive_update, OrderedSet from sat.tools.common import data_format from sat.tools.common import tls +from sat_frontends.bridge.bridge_frontend import BridgeException import libervia from libervia.server import websockets from libervia.server.pages import LiberviaPage @@ -932,16 +933,132 @@ if default_dict: conf[''] = default_dict + async def checkAndConnectServiceProfile(self): + passphrase = self.options["passphrase"] + if not passphrase: + raise SysExit( + C.EXIT_BAD_ARG, + _("No passphrase set for service profile, please check installation " + "documentation.") + ) + try: + s_prof_connected = await self.bridgeCall("isConnected", C.SERVICE_PROFILE) + except BridgeException as e: + if e.classname == "ProfileUnknownError": + log.info("Service profile doesn't exist, creating it.") + try: + xmpp_domain = await self.bridgeCall("getConfig", "", "xmpp_domain") + xmpp_domain = xmpp_domain.strip() + if not xmpp_domain: + raise SysExit( + C.EXIT_BAD_ARG, + _('"xmpp_domain" must be set to create new accounts, please ' + 'check documentation') + ) + service_profile_jid_s = f"{C.SERVICE_PROFILE}@{xmpp_domain}" + await self.bridgeCall( + "inBandAccountNew", + service_profile_jid_s, + passphrase, + "", + xmpp_domain, + 0, + ) + except BridgeException as e: + if e.condition == "conflict": + log.info( + _("Service's profile JID {profile_jid} already exists") + .format(profile_jid=service_profile_jid_s) + ) + elif e.classname == "UnknownMethod": + raise SysExit( + C.EXIT_BRIDGE_ERROR, + _("Can't create service profile XMPP account, In-Band " + "Registration plugin is not activated, you'll have to " + "create the {profile!r} profile with {profile_jid!r} JID " + "manually.").format( + profile=C.SERVICE_PROFILE, + profile_jid=service_profile_jid_s) + ) + elif e.condition == "service-unavailable": + raise SysExit( + C.EXIT_BRIDGE_ERROR, + _("Can't create service profile XMPP account, In-Band " + "Registration is not activated on your server, you'll have " + "to create the {profile!r} profile with {profile_jid!r} JID " + "manually.\nNote that you'll need to activate In-Band " + "Registation on your server if you want users to be able " + "to create new account from {app_name}, please check " + "documentation.").format( + profile=C.SERVICE_PROFILE, + profile_jid=service_profile_jid_s, + app_name=C.APP_NAME) + ) + elif e.condition == "not-acceptable": + raise SysExit( + C.EXIT_BRIDGE_ERROR, + _("Can't create service profile XMPP account, your XMPP " + "server doesn't allow us to create new accounts with " + "In-Band Registration please check XMPP server " + "configuration: {reason}" + ).format( + profile=C.SERVICE_PROFILE, + profile_jid=service_profile_jid_s, + reason=e.message) + ) + + else: + raise SysExit( + C.EXIT_BRIDGE_ERROR, + _("Can't create service profile XMPP account, you'll have " + "do to it manually: {reason}").format(reason=e.message) + ) + try: + await self.bridgeCall("profileCreate", C.SERVICE_PROFILE, passphrase) + await self.bridgeCall( + "profileStartSession", passphrase, C.SERVICE_PROFILE) + await self.bridgeCall( + "setParam", "JabberID", service_profile_jid_s, "Connection", -1, + C.SERVICE_PROFILE) + await self.bridgeCall( + "setParam", "Password", passphrase, "Connection", -1, + C.SERVICE_PROFILE) + except BridgeException as e: + raise SysExit( + C.EXIT_BRIDGE_ERROR, + _("Can't create service profile XMPP account, you'll have " + "do to it manually: {reason}").format(reason=e.message) + ) + log.info(_("Service profile has been successfully created")) + s_prof_connected = False + else: + raise SysExit(C.EXIT_BRIDGE_ERROR, e.message) + + if not s_prof_connected: + try: + await self.bridgeCall( + "connect", + C.SERVICE_PROFILE, + passphrase, + {}, + ) + except BridgeException as e: + raise SysExit( + C.EXIT_BRIDGE_ERROR, + _("Connection of service profile failed: {reason}").format(reason=e) + ) + async def backendReady(self): log.info(f"Libervia v{self.full_version}") + + # settings if self.options['dev_mode']: log.info(_("Developer mode activated")) - self.media_dir = self.bridge.getConfig("", "media_dir") - self.local_dir = self.bridge.getConfig("", "local_dir") + self.media_dir = await self.bridgeCall("getConfig", "", "media_dir") + self.local_dir = await self.bridgeCall("getConfig", "", "local_dir") self.cache_root_dir = os.path.join(self.local_dir, C.CACHE_DIR) self.renderer = template.Renderer(self, self._front_url_filter) sites_names = list(self.renderer.sites_paths.keys()) - self.restricted_bridge = RestrictedBridge(self) self._moveFirstLevelToDict(self.options, "url_redirections_dict", sites_names) self._moveFirstLevelToDict(self.options, "menu_json", sites_names) @@ -952,6 +1069,12 @@ for site, value in self.options["menu_extra_json"].items(): menu[site].extend(value) + # service profile + await self.checkAndConnectServiceProfile() + + # restricted bridge, the one used by browser code + self.restricted_bridge = RestrictedBridge(self) + # we create virtual hosts and import Libervia pages into them self.vhost_root = vhost.NameVirtualHost() default_site_path = Path(libervia.__file__).parent.resolve() @@ -1436,34 +1559,7 @@ def startService(self): """Connect the profile for Libervia and start the HTTP(S) server(s)""" self._init() - - def eb(e): - log.error(_("Connection failed: %s") % e) - self.stop() - - def initOk(__): - try: - connected = self.bridge.isConnected(C.SERVICE_PROFILE) - except Exception as e: - # we don't want the traceback - msg = [l for l in str(e).split("\n") if l][-1] - log.error( - "Can't check service profile ({profile}), are you sure it exists ?" - "\n{error}".format(profile=C.SERVICE_PROFILE, error=msg)) - self.stop() - return - if not connected: - self.bridge.connect( - C.SERVICE_PROFILE, - self.options["passphrase"], - {}, - callback=self._startService, - errback=eb, - ) - else: - self._startService() - - self.initialised.addCallback(initOk) + self.initialised.addCallback(self._startService) self.initialised.addErrback(self.initEb) ## URLs ##