class UserAuthCode(object):
    def __init__(self, secret, salt_len=8, hash=hashlib.sha256):
        self.secret = secret
        self.salt_len = salt_len
        self.hash = hash

    def salt(self):
        s = ''
        for i in range(self.salt_len):
            s += random.choice(string.letters + string.digits)

        return s

    def digest(self, user, salt):
        # Use username, email and date_joined to generate digest
        auth_message = ''.join((self.secret, user.username, user.email,
            str(user.date_joined), salt))
        md = self.hash()
        md.update(auth_message)

        return base64.urlsafe_b64encode(md.digest()).rstrip('=')

    def auth_code(self, user):
        salt = self.salt()
        digest = self.digest(user, salt)

        return salt + digest

    def is_valid(self, user, auth_code):
        salt = auth_code[:self.salt_len]
        digest = auth_code[self.salt_len:]
 
        # CAVEAT: Make sure UserAuthCode cannot be used to reactivate locked
        # profiles.
        if user.last_login != user.date_joined:
            return False

        return digest == self.digest(user, salt)