Mercurial > libervia-backend
diff sat/memory/memory.py @ 2624:56f94936df1e
code style reformatting using black
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 20:14:46 +0200 |
parents | 9446f1ea9eac |
children | 5060cbeec01e |
line wrap: on
line diff
--- a/sat/memory/memory.py Wed Jun 27 07:51:29 2018 +0200 +++ b/sat/memory/memory.py Wed Jun 27 20:14:46 2018 +0200 @@ -20,6 +20,7 @@ from sat.core.i18n import _ from sat.core.log import getLogger + log = getLogger(__name__) import os.path @@ -44,11 +45,13 @@ import time -PresenceTuple = namedtuple("PresenceTuple", ('show', 'priority', 'statuses')) +PresenceTuple = namedtuple("PresenceTuple", ("show", "priority", "statuses")) MSG_NO_SESSION = "Session id doesn't exist or is finished" + class Sessions(object): """Sessions are data associated to key used for a temporary moment, with optional profile checking.""" + DEFAULT_TIMEOUT = 600 def __init__(self, timeout=None, resettable_timeout=True): @@ -72,11 +75,15 @@ if session_id is None: session_id = str(uuid4()) elif session_id in self._sessions: - raise exceptions.ConflictError(u"Session id {} is already used".format(session_id)) + raise exceptions.ConflictError( + u"Session id {} is already used".format(session_id) + ) timer = reactor.callLater(self.timeout, self._purgeSession, session_id) if session_data is None: session_data = {} - self._sessions[session_id] = (timer, session_data) if profile is None else (timer, session_data, profile) + self._sessions[session_id] = ( + (timer, session_data) if profile is None else (timer, session_data, profile) + ) return session_id, session_data def _purgeSession(self, session_id): @@ -91,7 +98,12 @@ # if the session is time-outed, the timer has been called pass del self._sessions[session_id] - log.debug(u"Session {} purged{}".format(session_id, u' (profile {})'.format(profile) if profile is not None else u'')) + log.debug( + u"Session {} purged{}".format( + session_id, + u" (profile {})".format(profile) if profile is not None else u"", + ) + ) def __len__(self): return len(self._sessions) @@ -103,7 +115,9 @@ try: timer, session_data, profile_set = self._sessions[session_id] except ValueError: - raise exceptions.InternalError("You need to use __getitem__ when profile is not set") + raise exceptions.InternalError( + "You need to use __getitem__ when profile is not set" + ) except KeyError: raise failure.Failure(KeyError(MSG_NO_SESSION)) if profile_set != profile: @@ -116,7 +130,9 @@ try: timer, session_data = self._sessions[session_id] except ValueError: - raise exceptions.InternalError("You need to use profileGet instead of __getitem__ when profile is set") + raise exceptions.InternalError( + "You need to use profileGet instead of __getitem__ when profile is set" + ) except KeyError: raise failure.Failure(KeyError(MSG_NO_SESSION)) if self.resettable_timeout: @@ -169,8 +185,12 @@ """ ids = self._profileGetAllIds(profile) if len(ids) > 1: - raise exceptions.InternalError('profileGetUnique has been used but more than one session has been found!') - return self.profileGet(ids[0], profile) if len(ids) == 1 else None # XXX: timeout might be reset + raise exceptions.InternalError( + "profileGetUnique has been used but more than one session has been found!" + ) + return ( + self.profileGet(ids[0], profile) if len(ids) == 1 else None + ) # XXX: timeout might be reset def profileDelUnique(self, profile): """Delete the unique session that is associated to the given profile. @@ -180,7 +200,9 @@ """ ids = self._profileGetAllIds(profile) if len(ids) > 1: - raise exceptions.InternalError('profileDelUnique has been used but more than one session has been found!') + raise exceptions.InternalError( + "profileDelUnique has been used but more than one session has been found!" + ) if len(ids) == 1: del self._sessions[ids[0]] @@ -194,7 +216,9 @@ ProfileSessions.__init__(self, timeout, resettable_timeout=False) def _purgeSession(self, session_id): - log.debug("FIXME: PasswordSessions should ask for the profile password after the session expired") + log.debug( + "FIXME: PasswordSessions should ask for the profile password after the session expired" + ) # XXX: tmp update code, will be removed in the future @@ -211,16 +235,20 @@ except: pass # file is readable but its structure if wrong try: - current_value = user_config.get('DEFAULT', 'local_dir') + current_value = user_config.get("DEFAULT", "local_dir") except (NoOptionError, NoSectionError): - current_value = '' + current_value = "" if current_value: return # nothing to do - old_default = '~/.sat' - if os.path.isfile(os.path.expanduser(old_default) + '/' + C.SAVEFILE_DATABASE): + old_default = "~/.sat" + if os.path.isfile(os.path.expanduser(old_default) + "/" + C.SAVEFILE_DATABASE): if not silent: - log.warning(_(u"A database has been found in the default local_dir for previous versions (< 0.5)")) - tools_config.fixConfigOption('', 'local_dir', old_default, silent) + log.warning( + _( + u"A database has been found in the default local_dir for previous versions (< 0.5)" + ) + ) + tools_config.fixConfigOption("", "local_dir", old_default, silent) class Memory(object): @@ -230,17 +258,19 @@ log.info(_("Memory manager init")) self.initialized = defer.Deferred() self.host = host - self._entities_cache = {} # XXX: keep presence/last resource/other data in cache - # /!\ an entity is not necessarily in roster - # main key is bare jid, value is a dict - # where main key is resource, or None for bare jid - self._key_signals = set() # key which need a signal to frontends when updated + self._entities_cache = {} # XXX: keep presence/last resource/other data in cache + # /!\ an entity is not necessarily in roster + # main key is bare jid, value is a dict + # where main key is resource, or None for bare jid + self._key_signals = set() # key which need a signal to frontends when updated self.subscriptions = {} self.auth_sessions = PasswordSessions() # remember the authenticated profiles self.disco = Discovery(host) fixLocalDir(False) # XXX: tmp update code, will be removed in the future self.config = tools_config.parseMainConf() - database_file = os.path.expanduser(os.path.join(self.getConfig('', 'local_dir'), C.SAVEFILE_DATABASE)) + database_file = os.path.expanduser( + os.path.join(self.getConfig("", "local_dir"), C.SAVEFILE_DATABASE) + ) self.storage = SqliteStorage(database_file, host.version) PersistentDict.storage = self.storage self.params = Params(host, self.storage) @@ -290,7 +320,7 @@ """ if not filename: return False - #TODO: need to encrypt files (at least passwords !) and set permissions + # TODO: need to encrypt files (at least passwords !) and set permissions filename = os.path.expanduser(filename) try: self.params.save_xml(filename) @@ -302,7 +332,7 @@ def load(self): """Load parameters and all memory things from db""" - #parameters data + # parameters data return self.params.loadGenParams() def loadIndividualParams(self, profile): @@ -340,7 +370,9 @@ session_d = self._entities_cache[profile] except KeyError: # else we do request the params - session_d = self._entities_cache[profile] = self.loadIndividualParams(profile) + session_d = self._entities_cache[profile] = self.loadIndividualParams( + profile + ) session_d.addCallback(createSession) finally: return session_d @@ -396,12 +428,20 @@ def check_result(result): if not result: - log.warning(u'Authentication failure of profile {}'.format(profile)) - raise failure.Failure(exceptions.PasswordError(u"The provided profile password doesn't match.")) - if not session_data: # avoid to create two profile sessions when password if specified + log.warning(u"Authentication failure of profile {}".format(profile)) + raise failure.Failure( + exceptions.PasswordError( + u"The provided profile password doesn't match." + ) + ) + if ( + not session_data + ): # avoid to create two profile sessions when password if specified return self.newAuthSession(password, profile) - d = self.asyncGetParamA(C.PROFILE_PASS_PATH[1], C.PROFILE_PASS_PATH[0], profile_key=profile) + d = self.asyncGetParamA( + C.PROFILE_PASS_PATH[1], C.PROFILE_PASS_PATH[0], profile_key=profile + ) d.addCallback(lambda sat_cipher: PasswordHasher.verify(password, sat_cipher)) return d.addCallback(check_result) @@ -414,10 +454,13 @@ @param profile: %(doc_profile)s @return: a deferred None value """ + def gotPersonalKey(personal_key): """Create the session for this profile and store the personal key""" - self.auth_sessions.newSession({C.MEMORY_CRYPTO_KEY: personal_key}, profile=profile) - log.debug(u'auth session created for profile %s' % profile) + self.auth_sessions.newSession( + {C.MEMORY_CRYPTO_KEY: personal_key}, profile=profile + ) + log.debug(u"auth session created for profile %s" % profile) d = PersistentDict(C.MEMORY_CRYPTO_NAMESPACE, profile).load() d.addCallback(lambda data: BlockCipher.decrypt(key, data[C.MEMORY_CRYPTO_KEY])) @@ -431,7 +474,12 @@ try: del self._entities_cache[profile] except KeyError: - log.error(_(u"Trying to purge roster status cache for a profile not in memory: [%s]") % profile) + log.error( + _( + u"Trying to purge roster status cache for a profile not in memory: [%s]" + ) + % profile + ) def getProfilesList(self, clients=True, components=False): """retrieve profiles list @@ -472,7 +520,7 @@ # we want to be sure that the profile exists profile = self.getProfileName(profile) - self.memory_data['Profile_default'] = profile + self.memory_data["Profile_default"] = profile def createProfile(self, name, password, component=None): """Create a new profile @@ -486,9 +534,9 @@ """ if not name: raise ValueError(u"Empty profile name") - if name[0] == '@': + if name[0] == "@": raise ValueError(u"A profile name can't start with a '@'") - if '\n' in name: + if "\n" in name: raise ValueError(u"A profile name can't contain line feed ('\\n')") if name in self._entities_cache: @@ -496,19 +544,28 @@ if component: if not component in self.host.plugins: - raise exceptions.NotFound(_(u"Can't find component {component} entry point".format( - component = component))) + raise exceptions.NotFound( + _( + u"Can't find component {component} entry point".format( + component=component + ) + ) + ) # FIXME: PLUGIN_INFO is not currently accessible after import, but type shoul be tested here - # if self.host.plugins[component].PLUGIN_INFO[u"type"] != C.PLUG_TYPE_ENTRY_POINT: - # raise ValueError(_(u"Plugin {component} is not an entry point !".format( - # component = component))) + # if self.host.plugins[component].PLUGIN_INFO[u"type"] != C.PLUG_TYPE_ENTRY_POINT: + # raise ValueError(_(u"Plugin {component} is not an entry point !".format( + # component = component))) d = self.params.createProfile(name, component) def initPersonalKey(dummy): # be sure to call this after checking that the profile doesn't exist yet - personal_key = BlockCipher.getRandomKey(base64=True) # generated once for all and saved in a PersistentDict - self.auth_sessions.newSession({C.MEMORY_CRYPTO_KEY: personal_key}, profile=name) # will be encrypted by setParam + personal_key = BlockCipher.getRandomKey( + base64=True + ) # generated once for all and saved in a PersistentDict + self.auth_sessions.newSession( + {C.MEMORY_CRYPTO_KEY: personal_key}, profile=name + ) # will be encrypted by setParam def startFakeSession(dummy): # avoid ProfileNotConnected exception in setParam @@ -521,7 +578,11 @@ d.addCallback(initPersonalKey) d.addCallback(startFakeSession) - d.addCallback(lambda dummy: self.setParam(C.PROFILE_PASS_PATH[1], password, C.PROFILE_PASS_PATH[0], profile_key=name)) + d.addCallback( + lambda dummy: self.setParam( + C.PROFILE_PASS_PATH[1], password, C.PROFILE_PASS_PATH[0], profile_key=name + ) + ) d.addCallback(stopFakeSession) d.addCallback(lambda dummy: self.auth_sessions.profileDelUnique(name)) return d @@ -534,12 +595,14 @@ To be used for direct calls only (not through the bridge). @return: a Deferred instance """ + def cleanMemory(dummy): self.auth_sessions.profileDelUnique(name) try: del self._entities_cache[name] except KeyError: pass + d = self.params.asyncDeleteProfile(name, force) d.addCallback(cleanMemory) return d @@ -567,10 +630,28 @@ def addToHistory(self, client, data): return self.storage.addToHistory(data, client.profile) - def _historyGet(self, from_jid_s, to_jid_s, limit=C.HISTORY_LIMIT_NONE, between=True, filters=None, profile=C.PROF_KEY_NONE): - return self.historyGet(jid.JID(from_jid_s), jid.JID(to_jid_s), limit, between, filters, profile) + def _historyGet( + self, + from_jid_s, + to_jid_s, + limit=C.HISTORY_LIMIT_NONE, + between=True, + filters=None, + profile=C.PROF_KEY_NONE, + ): + return self.historyGet( + jid.JID(from_jid_s), jid.JID(to_jid_s), limit, between, filters, profile + ) - def historyGet(self, from_jid, to_jid, limit=C.HISTORY_LIMIT_NONE, between=True, filters=None, profile=C.PROF_KEY_NONE): + def historyGet( + self, + from_jid, + to_jid, + limit=C.HISTORY_LIMIT_NONE, + between=True, + filters=None, + profile=C.PROF_KEY_NONE, + ): """Retrieve messages in history @param from_jid (JID): source JID (full, or bare for catchall) @@ -586,7 +667,7 @@ """ assert profile != C.PROF_KEY_NONE if limit == C.HISTORY_LIMIT_DEFAULT: - limit = int(self.getParamA(C.HISTORY_LIMIT, 'General', profile_key=profile)) + limit = int(self.getParamA(C.HISTORY_LIMIT, "General", profile_key=profile)) elif limit == C.HISTORY_LIMIT_NONE: limit = None if limit == 0: @@ -597,7 +678,7 @@ def _getPresenceStatuses(self, profile_key): ret = self.getPresenceStatuses(profile_key) - return {entity.full():data for entity, data in ret.iteritems()} + return {entity.full(): data for entity, data in ret.iteritems()} def getPresenceStatuses(self, profile_key): """Get all the presence statuses of a profile @@ -617,7 +698,9 @@ presence_data = self.getEntityDatum(full_jid, "presence", profile_key) except KeyError: continue - entities_presence.setdefault(entity_jid, {})[resource or ''] = presence_data + entities_presence.setdefault(entity_jid, {})[ + resource or "" + ] = presence_data return entities_presence @@ -631,7 +714,9 @@ @param profile_key: %(doc_profile_key)s """ presence_data = PresenceTuple(show, priority, statuses) - self.updateEntityData(entity_jid, "presence", presence_data, profile_key=profile_key) + self.updateEntityData( + entity_jid, "presence", presence_data, profile_key=profile_key + ) if entity_jid.resource and show != C.PRESENCE_UNAVAILABLE: # If a resource is available, bare jid should not have presence information try: @@ -657,13 +742,17 @@ """ # FIXME: is there a need to keep cache data for resources which are not connected anymore? if entity_jid.resource: - raise ValueError("getAllResources must be used with a bare jid (got {})".format(entity_jid)) + raise ValueError( + "getAllResources must be used with a bare jid (got {})".format(entity_jid) + ) profile_cache = self._getProfileCache(client) try: entity_data = profile_cache[entity_jid.userhostJID()] except KeyError: - raise exceptions.UnknownEntityError(u"Entity {} not in cache".format(entity_jid)) - resources= set(entity_data.keys()) + raise exceptions.UnknownEntityError( + u"Entity {} not in cache".format(entity_jid) + ) + resources = set(entity_data.keys()) resources.discard(None) return resources @@ -701,7 +790,9 @@ @return (unicode): main resource or None """ if entity_jid.resource: - raise ValueError("getMainResource must be used with a bare jid (got {})".format(entity_jid)) + raise ValueError( + "getMainResource must be used with a bare jid (got {})".format(entity_jid) + ) try: if self.host.plugins["XEP-0045"].isJoinedRoom(client, entity_jid): return None # MUC rooms have no main resource @@ -766,7 +857,9 @@ full_jid.resource = resource yield full_jid - def updateEntityData(self, entity_jid, key, value, silent=False, profile_key=C.PROF_KEY_NONE): + def updateEntityData( + self, entity_jid, key, value, silent=False, profile_key=C.PROF_KEY_NONE + ): """Set a misc data for an entity If key was registered with setSignalOnUpdate, a signal will be sent to frontends @@ -780,19 +873,27 @@ client = self.host.getClient(profile_key) profile_cache = self._getProfileCache(client) if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): - entities = self.getAllEntitiesIter(client, entity_jid==C.ENTITY_ALL) + entities = self.getAllEntitiesIter(client, entity_jid == C.ENTITY_ALL) else: entities = (entity_jid,) for jid_ in entities: - entity_data = profile_cache.setdefault(jid_.userhostJID(),{}).setdefault(jid_.resource, {}) + entity_data = profile_cache.setdefault(jid_.userhostJID(), {}).setdefault( + jid_.resource, {} + ) entity_data[key] = value if key in self._key_signals and not silent: if not isinstance(value, basestring): - log.error(u"Setting a non string value ({}) for a key ({}) which has a signal flag".format(value, key)) + log.error( + u"Setting a non string value ({}) for a key ({}) which has a signal flag".format( + value, key + ) + ) else: - self.host.bridge.entityDataUpdated(jid_.full(), key, value, self.getProfileName(profile_key)) + self.host.bridge.entityDataUpdated( + jid_.full(), key, value, self.getProfileName(profile_key) + ) def delEntityDatum(self, entity_jid, key, profile_key): """Delete a data for an entity @@ -808,7 +909,7 @@ client = self.host.getClient(profile_key) profile_cache = self._getProfileCache(client) if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): - entities = self.getAllEntitiesIter(client, entity_jid==C.ENTITY_ALL) + entities = self.getAllEntitiesIter(client, entity_jid == C.ENTITY_ALL) else: entities = (entity_jid,) @@ -816,17 +917,21 @@ try: entity_data = profile_cache[jid_.userhostJID()][jid_.resource] except KeyError: - raise exceptions.UnknownEntityError(u"Entity {} not in cache".format(jid_)) + raise exceptions.UnknownEntityError( + u"Entity {} not in cache".format(jid_) + ) try: del entity_data[key] except KeyError as e: if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL): - continue # we ignore KeyError when deleting keys from several entities + continue # we ignore KeyError when deleting keys from several entities else: raise e def _getEntitiesData(self, entities_jids, keys_list, profile_key): - ret = self.getEntitiesData([jid.JID(jid_) for jid_ in entities_jids], keys_list, profile_key) + ret = self.getEntitiesData( + [jid.JID(jid_) for jid_ in entities_jids], keys_list, profile_key + ) return {jid_.full(): data for jid_, data in ret.iteritems()} def getEntitiesData(self, entities_jids, keys_list=None, profile_key=C.PROF_KEY_NONE): @@ -843,6 +948,7 @@ @raise exceptions.UnknownEntityError: if entity is not in cache """ + def fillEntityData(entity_cache_data): entity_data = {} if keys_list is None: @@ -861,7 +967,9 @@ if entities_jids: for entity in entities_jids: try: - entity_cache_data = profile_cache[entity.userhostJID()][entity.resource] + entity_cache_data = profile_cache[entity.userhostJID()][ + entity.resource + ] except KeyError: continue ret_data[entity.full()] = fillEntityData(entity_cache_data, keys_list) @@ -891,7 +999,11 @@ try: entity_data = profile_cache[entity_jid.userhostJID()][entity_jid.resource] except KeyError: - raise exceptions.UnknownEntityError(u"Entity {} not in cache (was requesting {})".format(entity_jid, keys_list)) + raise exceptions.UnknownEntityError( + u"Entity {} not in cache (was requesting {})".format( + entity_jid, keys_list + ) + ) if keys_list is None: return entity_data @@ -910,7 +1022,9 @@ """ return self.getEntityData(entity_jid, (key,), profile_key)[key] - def delEntityCache(self, entity_jid, delete_all_resources=True, profile_key=C.PROF_KEY_NONE): + def delEntityCache( + self, entity_jid, delete_all_resources=True, profile_key=C.PROF_KEY_NONE + ): """Remove all cached data for entity @param entity_jid: JID of the entity to delete @@ -928,12 +1042,16 @@ try: del profile_cache[entity_jid] except KeyError: - raise exceptions.UnknownEntityError(u"Entity {} not in cache".format(entity_jid)) + raise exceptions.UnknownEntityError( + u"Entity {} not in cache".format(entity_jid) + ) else: try: del profile_cache[entity_jid.userhostJID()][entity_jid.resource] except KeyError: - raise exceptions.UnknownEntityError(u"Entity {} not in cache".format(entity_jid)) + raise exceptions.UnknownEntityError( + u"Entity {} not in cache".format(entity_jid) + ) ## Encryption ## @@ -947,9 +1065,14 @@ @return: the deferred encrypted value """ try: - personal_key = self.auth_sessions.profileGetUnique(profile)[C.MEMORY_CRYPTO_KEY] + personal_key = self.auth_sessions.profileGetUnique(profile)[ + C.MEMORY_CRYPTO_KEY + ] except TypeError: - raise exceptions.InternalError(_('Trying to encrypt a value for %s while the personal key is undefined!') % profile) + raise exceptions.InternalError( + _("Trying to encrypt a value for %s while the personal key is undefined!") + % profile + ) return BlockCipher.encrypt(personal_key, value) def decryptValue(self, value, profile): @@ -962,9 +1085,14 @@ @return: the deferred decrypted value """ try: - personal_key = self.auth_sessions.profileGetUnique(profile)[C.MEMORY_CRYPTO_KEY] + personal_key = self.auth_sessions.profileGetUnique(profile)[ + C.MEMORY_CRYPTO_KEY + ] except TypeError: - raise exceptions.InternalError(_('Trying to decrypt a value for %s while the personal key is undefined!') % profile) + raise exceptions.InternalError( + _("Trying to decrypt a value for %s while the personal key is undefined!") + % profile + ) return BlockCipher.decrypt(personal_key, value) def encryptPersonalData(self, data_key, data_value, crypto_key, profile): @@ -987,8 +1115,10 @@ return d.addCallback(cb) def done(dummy): - log.debug(_(u'Personal data (%(ns)s, %(key)s) has been successfuly encrypted') % - {'ns': C.MEMORY_CRYPTO_NAMESPACE, 'key': data_key}) + log.debug( + _(u"Personal data (%(ns)s, %(key)s) has been successfuly encrypted") + % {"ns": C.MEMORY_CRYPTO_NAMESPACE, "key": data_key} + ) d = PersistentDict(C.MEMORY_CRYPTO_NAMESPACE, profile).load() return d.addCallback(gotIndMemory).addCallback(done) @@ -1014,7 +1144,7 @@ """Called to get a list of currently waiting subscription requests""" profile = self.getProfileName(profile_key) if not profile: - log.error(_('Asking waiting subscriptions for a non-existant profile')) + log.error(_("Asking waiting subscriptions for a non-existant profile")) return {} if profile not in self.subscriptions: return {} @@ -1029,28 +1159,59 @@ def getParamA(self, name, category, attr="value", profile_key=C.PROF_KEY_NONE): return self.params.getParamA(name, category, attr, profile_key=profile_key) - def asyncGetParamA(self, name, category, attr="value", security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE): - return self.params.asyncGetParamA(name, category, attr, security_limit, profile_key) + def asyncGetParamA( + self, + name, + category, + attr="value", + security_limit=C.NO_SECURITY_LIMIT, + profile_key=C.PROF_KEY_NONE, + ): + return self.params.asyncGetParamA( + name, category, attr, security_limit, profile_key + ) - def asyncGetParamsValuesFromCategory(self, category, security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE): - return self.params.asyncGetParamsValuesFromCategory(category, security_limit, profile_key) + def asyncGetParamsValuesFromCategory( + self, category, security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE + ): + return self.params.asyncGetParamsValuesFromCategory( + category, security_limit, profile_key + ) - def asyncGetStringParamA(self, name, category, attr="value", security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE): - return self.params.asyncGetStringParamA(name, category, attr, security_limit, profile_key) + def asyncGetStringParamA( + self, + name, + category, + attr="value", + security_limit=C.NO_SECURITY_LIMIT, + profile_key=C.PROF_KEY_NONE, + ): + return self.params.asyncGetStringParamA( + name, category, attr, security_limit, profile_key + ) - def getParamsUI(self, security_limit=C.NO_SECURITY_LIMIT, app='', profile_key=C.PROF_KEY_NONE): + def getParamsUI( + self, security_limit=C.NO_SECURITY_LIMIT, app="", profile_key=C.PROF_KEY_NONE + ): return self.params.getParamsUI(security_limit, app, profile_key) def getParamsCategories(self): return self.params.getParamsCategories() - def setParam(self, name, value, category, security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE): + def setParam( + self, + name, + value, + category, + security_limit=C.NO_SECURITY_LIMIT, + profile_key=C.PROF_KEY_NONE, + ): return self.params.setParam(name, value, category, security_limit, profile_key) def updateParams(self, xml): return self.params.updateParams(xml) - def paramsRegisterApp(self, xml, security_limit=C.NO_SECURITY_LIMIT, app=''): + def paramsRegisterApp(self, xml, security_limit=C.NO_SECURITY_LIMIT, app=""): return self.params.paramsRegisterApp(xml, security_limit, app) def setDefault(self, name, category, callback, errback=None): @@ -1073,25 +1234,25 @@ if peer_jid is None and perms_to_check is None: return peer_jid = peer_jid.userhostJID() - if peer_jid == file_data['owner']: + if peer_jid == file_data["owner"]: # the owner has all rights return if not C.ACCESS_PERMS.issuperset(perms_to_check): - raise exceptions.InternalError(_(u'invalid permission')) + raise exceptions.InternalError(_(u"invalid permission")) for perm in perms_to_check: # we check each perm and raise PermissionError as soon as one condition is not valid # we must never return here, we only return after the loop if nothing was blocking the access try: - perm_data = file_data[u'access'][perm] - perm_type = perm_data[u'type'] + perm_data = file_data[u"access"][perm] + perm_type = perm_data[u"type"] except KeyError: raise failure.Failure(exceptions.PermissionError()) if perm_type == C.ACCESS_TYPE_PUBLIC: continue elif perm_type == C.ACCESS_TYPE_WHITELIST: try: - jids = perm_data[u'jids'] + jids = perm_data[u"jids"] except KeyError: raise failure.Failure(exceptions.PermissionError()) if peer_jid.full() in jids: @@ -1099,7 +1260,9 @@ else: raise failure.Failure(exceptions.PermissionError()) else: - raise exceptions.InternalError(_(u'unknown access type: {type}').format(type=perm_type)) + raise exceptions.InternalError( + _(u"unknown access type: {type}").format(type=perm_type) + ) @defer.inlineCallbacks def checkPermissionToRoot(self, client, file_data, peer_jid, perms_to_check): @@ -1107,17 +1270,21 @@ current = file_data while True: self.checkFilePermission(current, peer_jid, perms_to_check) - parent = current[u'parent'] + parent = current[u"parent"] if not parent: break - files_data = yield self.getFile(self, client, peer_jid=None, file_id=parent, perms_to_check=None) + files_data = yield self.getFile( + self, client, peer_jid=None, file_id=parent, perms_to_check=None + ) try: current = files_data[0] except IndexError: - raise exceptions.DataError(u'Missing parent') + raise exceptions.DataError(u"Missing parent") @defer.inlineCallbacks - def _getParentDir(self, client, path, parent, namespace, owner, peer_jid, perms_to_check): + def _getParentDir( + self, client, path, parent, namespace, owner, peer_jid, perms_to_check + ): """Retrieve parent node from a path, or last existing directory each directory of the path will be retrieved, until the last existing one @@ -1128,32 +1295,59 @@ """ # if path is set, we have to retrieve parent directory of the file(s) from it if parent is not None: - raise exceptions.ConflictError(_(u"You can't use path and parent at the same time")) - path_elts = filter(None, path.split(u'/')) - if {u'..', u'.'}.intersection(path_elts): + raise exceptions.ConflictError( + _(u"You can't use path and parent at the same time") + ) + path_elts = filter(None, path.split(u"/")) + if {u"..", u"."}.intersection(path_elts): raise ValueError(_(u'".." or "." can\'t be used in path')) # we retrieve all directories from path until we get the parent container # non existing directories will be created - parent = u'' + parent = u"" for idx, path_elt in enumerate(path_elts): - directories = yield self.storage.getFiles(client, parent=parent, type_=C.FILE_TYPE_DIRECTORY, - name=path_elt, namespace=namespace, owner=owner) + directories = yield self.storage.getFiles( + client, + parent=parent, + type_=C.FILE_TYPE_DIRECTORY, + name=path_elt, + namespace=namespace, + owner=owner, + ) if not directories: defer.returnValue((parent, path_elts[idx:])) # from this point, directories don't exist anymore, we have to create them elif len(directories) > 1: - raise exceptions.InternalError(_(u"Several directories found, this should not happen")) + raise exceptions.InternalError( + _(u"Several directories found, this should not happen") + ) else: directory = directories[0] self.checkFilePermission(directory, peer_jid, perms_to_check) - parent = directory[u'id'] + parent = directory[u"id"] defer.returnValue((parent, [])) @defer.inlineCallbacks - def getFiles(self, client, peer_jid, file_id=None, version=None, parent=None, path=None, type_=None, - file_hash=None, hash_algo=None, name=None, namespace=None, mime_type=None, - owner=None, access=None, projection=None, unique=False, perms_to_check=(C.ACCESS_PERM_READ,)): + def getFiles( + self, + client, + peer_jid, + file_id=None, + version=None, + parent=None, + path=None, + type_=None, + file_hash=None, + hash_algo=None, + name=None, + namespace=None, + mime_type=None, + owner=None, + access=None, + projection=None, + unique=False, + perms_to_check=(C.ACCESS_PERM_READ,), + ): """retrieve files with with given filters @param peer_jid(jid.JID, None): jid trying to access the file @@ -1180,12 +1374,16 @@ on the path """ if peer_jid is None and perms_to_check or perms_to_check is None and peer_jid: - raise exceptions.InternalError('if you want to disable permission check, both peer_jid and perms_to_check must be None') + raise exceptions.InternalError( + "if you want to disable permission check, both peer_jid and perms_to_check must be None" + ) if owner is not None: owner = owner.userhostJID() if path is not None: # permission are checked by _getParentDir - parent, remaining_path_elts = yield self._getParentDir(client, path, parent, namespace, owner, peer_jid, perms_to_check) + parent, remaining_path_elts = yield self._getParentDir( + client, path, parent, namespace, owner, peer_jid, perms_to_check + ) if remaining_path_elts: # if we have remaining path elements, # the parent directory is not found @@ -1197,16 +1395,30 @@ try: parent_data = parent_data[0] except IndexError: - raise exceptions.DataError(u'mising parent') - yield self.checkPermissionToRoot(client, parent_data, peer_jid, perms_to_check) + raise exceptions.DataError(u"mising parent") + yield self.checkPermissionToRoot( + client, parent_data, peer_jid, perms_to_check + ) - files = yield self.storage.getFiles(client, file_id=file_id, version=version, parent=parent, type_=type_, - file_hash=file_hash, hash_algo=hash_algo, name=name, namespace=namespace, - mime_type=mime_type, owner=owner, access=access, - projection=projection, unique=unique) + files = yield self.storage.getFiles( + client, + file_id=file_id, + version=version, + parent=parent, + type_=type_, + file_hash=file_hash, + hash_algo=hash_algo, + name=name, + namespace=namespace, + mime_type=mime_type, + owner=owner, + access=access, + projection=projection, + unique=unique, + ) if peer_jid: - # if permission are checked, we must remove all file tha use can't access + # if permission are checked, we must remove all file tha use can't access to_remove = [] for file_data in files: try: @@ -1218,10 +1430,28 @@ defer.returnValue(files) @defer.inlineCallbacks - def setFile(self, client, name, file_id=None, version=u'', parent=None, path=None, - type_=C.FILE_TYPE_FILE, file_hash=None, hash_algo=None, size=None, namespace=None, - mime_type=None, created=None, modified=None, owner=None, access=None, extra=None, - peer_jid = None, perms_to_check=(C.ACCESS_PERM_WRITE,)): + def setFile( + self, + client, + name, + file_id=None, + version=u"", + parent=None, + path=None, + type_=C.FILE_TYPE_FILE, + file_hash=None, + hash_algo=None, + size=None, + namespace=None, + mime_type=None, + created=None, + modified=None, + owner=None, + access=None, + extra=None, + peer_jid=None, + perms_to_check=(C.ACCESS_PERM_WRITE,), + ): """set a file metadata @param name(unicode): basename of the file @@ -1258,12 +1488,17 @@ if None, permission will no be checked (peer_jid must be None too in this case) @param profile(unicode): profile owning the file """ - if '/' in name: + if "/" in name: raise ValueError('name must not contain a slash ("/")') if file_id is None: file_id = shortuuid.uuid() - if file_hash is not None and hash_algo is None or hash_algo is not None and file_hash is None: - raise ValueError('file_hash and hash_algo must be set at the same time') + if ( + file_hash is not None + and hash_algo is None + or hash_algo is not None + and file_hash is None + ): + raise ValueError("file_hash and hash_algo must be set at the same time") if mime_type is None: mime_type, file_encoding = mimetypes.guess_type(name) if created is None: @@ -1271,31 +1506,56 @@ if namespace is not None: namespace = namespace.strip() or None if type_ == C.FILE_TYPE_DIRECTORY: - if any(version, file_hash, size, mime_type): - raise ValueError(u"version, file_hash, size and mime_type can't be set for a directory") + if any(version, file_hash, size, mime_type): + raise ValueError( + u"version, file_hash, size and mime_type can't be set for a directory" + ) if owner is not None: owner = owner.userhostJID() if path is not None: # _getParentDir will check permissions if peer_jid is set, so we use owner - parent, remaining_path_elts = yield self._getParentDir(client, path, parent, namespace, owner, owner, perms_to_check) + parent, remaining_path_elts = yield self._getParentDir( + client, path, parent, namespace, owner, owner, perms_to_check + ) # if remaining directories don't exist, we have to create them for new_dir in remaining_path_elts: new_dir_id = shortuuid.uuid() - yield self.storage.setFile(client, name=new_dir, file_id=new_dir_id, version=u'', parent=parent, - type_=C.FILE_TYPE_DIRECTORY, namespace=namespace, - created=time.time(), - owner=owner, - access=access, extra={}) + yield self.storage.setFile( + client, + name=new_dir, + file_id=new_dir_id, + version=u"", + parent=parent, + type_=C.FILE_TYPE_DIRECTORY, + namespace=namespace, + created=time.time(), + owner=owner, + access=access, + extra={}, + ) parent = new_dir_id elif parent is None: - parent = u'' + parent = u"" - yield self.storage.setFile(client, file_id=file_id, version=version, parent=parent, type_=type_, - file_hash=file_hash, hash_algo=hash_algo, name=name, size=size, - namespace=namespace, mime_type=mime_type, created=created, modified=modified, - owner=owner, - access=access, extra=extra) + yield self.storage.setFile( + client, + file_id=file_id, + version=version, + parent=parent, + type_=type_, + file_hash=file_hash, + hash_algo=hash_algo, + name=name, + size=size, + namespace=namespace, + mime_type=mime_type, + created=created, + modified=modified, + owner=owner, + access=access, + extra=extra, + ) def fileUpdate(self, file_id, column, update_cb): """update a file column taking care of race condition @@ -1318,7 +1578,9 @@ @return (bool): True if entity is available """ if not entity_jid.resource: - return bool(self.getAvailableResources(client, entity_jid)) # is any resource is available, entity is available + return bool( + self.getAvailableResources(client, entity_jid) + ) # is any resource is available, entity is available try: presence_data = self.getEntityDatum(entity_jid, "presence", client.profile) except KeyError: