Source code for nautilus.auth.primitives.passwordHash

# from: http://variable-scope.com/posts/storing-and-verifying-passwords-with-sqlalchemy

import bcrypt

[docs]class PasswordHash: """ This is a wrapper class over password hashes that abstracts equality """ def __init__(self, hash_, rounds=None): # make sure the hash is valid if len(hash_) != 60: raise ValueError('bcrypt hash should be 60 chars.') elif hash_.count('$'.encode('utf-8')) != 3: raise ValueError('bcrypt hash should have 3x "$".') # save the required instance variables self.hash = hash_ # figure out the current strength based on the saved hash self.rounds = int(str(self.hash).split('$')[2]) # the intended number of rounds (in case there is an upgrade) self.desired_rounds = rounds or self.rounds # this allows us to easily check if a candidate password matches the hash # using: hash == 'foo'
[docs] def __eq__(self, candidate): """Hashes the candidate string and compares it to the stored hash.""" if isinstance(candidate, str): # convert it to a byte string candidate = candidate.encode('utf-8') # if the candidate matches the saved hash if self.hash == bcrypt.hashpw(candidate, self.hash): # if the computed number of rounds is less than the designated one if self.rounds < self.desired_rounds: # rehash the password self.rehash(candidate) return True # otherwise the password doesn't match else: return False
[docs] def __repr__(self): """Simple object representation.""" return '<{}: {}>'.format(type(self).__name__, self.hash)
@classmethod
[docs] def new(cls, password, rounds): """Creates a PasswordHash from the given password.""" if isinstance(password, str): password = password.encode('utf-8') return cls(cls._new(password, rounds))
@classmethod
[docs] def coerce(cls, key, value): """Ensure that loaded values are PasswordHashes.""" if isinstance(value, PasswordHash): return value return super(PasswordHash, cls).coerce(key, value)
@staticmethod def _new(password, rounds): """ Returns a new bcrypt hash for the given password and rounds. note: Implemented to reduce repitition in `new` and `rehash`. """ return bcrypt.hashpw(password, bcrypt.gensalt(rounds))
[docs] def rehash(self, password): """Recreates the internal hash.""" self.hash = self._new(password, self.desired_rounds) self.rounds = self.desired_rounds