Mercurial > libervia-backend
diff sat/memory/memory.py @ 3160:330a5f1d9eea
core (memory/crypto): replaced `PyCrypto` by `cryptography`:
`PyCrypto` is unmaintained for years but was used in SàT for password hashing. This patch
fixes that by replacing `PyCrypto` by the reference `cryptography` module which is well
maintained.
The behaviour stays the same (except that previously async `hash`, `encrypt` and `decrypt`
methods are now synchronous, as they are quick and using a deferToThread may actually be
more resource intensive than using blocking methods).
It is planed to improve `memory.crypto` by using more up-to-date cryptography/hashing
algorithms in the future.
PyCrypto is no more a dependency of SàT
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 09 Feb 2020 23:50:26 +0100 |
parents | 60a9e47ef988 |
children | d10b2368684e |
line wrap: on
line diff
--- a/sat/memory/memory.py Sun Feb 09 23:50:21 2020 +0100 +++ b/sat/memory/memory.py Sun Feb 09 23:50:26 2020 +0100 @@ -347,7 +347,7 @@ finally: return session_d - auth_d = self.profileAuthenticate(password, profile) + auth_d = defer.ensureDeferred(self.profileAuthenticate(password, profile)) auth_d.addCallback(doStartSession) return auth_d @@ -381,37 +381,30 @@ except KeyError: return False - def profileAuthenticate(self, password, profile): + async def profileAuthenticate(self, password, profile): """Authenticate the profile. @param password (unicode): the SàT profile password - @param profile: %(doc_profile)s - @return (D): a deferred None in case of success, a failure otherwise. + @return: None in case of success (an exception is raised otherwise) @raise exceptions.PasswordError: the password does not match """ if not password and self.auth_sessions.profileGetUnique(profile): # XXX: this allows any frontend to connect with the empty password as soon as # the profile has been authenticated at least once before. It is OK as long as # submitting a form with empty passwords is restricted to local frontends. - return defer.succeed(None) + return - def check_result(result): - if not result: - log.warning("Authentication failure of profile {}".format(profile)) - raise failure.Failure( - exceptions.PasswordError( - "The provided profile password doesn't match." - ) - ) - return self.newAuthSession(password, profile) - - d = self.asyncGetParamA( + sat_cipher = await 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) + valid = PasswordHasher.verify(password, sat_cipher) + if not valid: + log.warning(_("Authentication failure of profile {profile}").format( + profile=profile)) + raise exceptions.PasswordError("The provided profile password doesn't match.") + return await self.newAuthSession(password, profile) - def newAuthSession(self, key, profile): + async def newAuthSession(self, key, profile): """Start a new session for the authenticated profile. If there is already an existing session, no new one is created @@ -419,21 +412,16 @@ @param key: the key to decrypt the personal key @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""" - session_data = self.auth_sessions.profileGetUnique(profile) - if not session_data: - self.auth_sessions.newSession( - {C.MEMORY_CRYPTO_KEY: personal_key}, profile=profile - ) - log.debug("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])) - return d.addCallback(gotPersonalKey) + data = await PersistentDict(C.MEMORY_CRYPTO_NAMESPACE, profile).load() + personal_key = BlockCipher.decrypt(key, data[C.MEMORY_CRYPTO_KEY]) + # Create the session for this profile and store the personal key + session_data = self.auth_sessions.profileGetUnique(profile) + if not session_data: + self.auth_sessions.newSession( + {C.MEMORY_CRYPTO_KEY: personal_key}, profile=profile + ) + log.debug("auth session created for profile %s" % profile) def purgeProfileSession(self, profile): """Delete cache of data of profile @@ -1064,13 +1052,8 @@ """ def gotIndMemory(data): - d = BlockCipher.encrypt(crypto_key, data_value) - - def cb(cipher): - data[data_key] = cipher - return data.force(data_key) - - return d.addCallback(cb) + data[data_key] = BlockCipher.encrypt(crypto_key, data_value) + return data.force(data_key) def done(__): log.debug(