fix password digests
This commit is contained in:
parent
7eb06b150e
commit
76e65def2c
|
@ -1,7 +1,9 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import hmac
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
@ -57,6 +59,21 @@ class Password(Field):
|
||||||
salt_size = 4
|
salt_size = 4
|
||||||
digest_size = 16
|
digest_size = 16
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_digest(cls, passwd: str):
|
||||||
|
if not passwd:
|
||||||
|
return False
|
||||||
|
offset = 2 * cls.salt_size # each byte is 2 hex chars
|
||||||
|
try:
|
||||||
|
if passwd[offset] != ":":
|
||||||
|
return False
|
||||||
|
digest = passwd[offset + 1 :]
|
||||||
|
if len(digest) != cls.digest_size * 2:
|
||||||
|
return False
|
||||||
|
return re.match(r"^[0-9a-f]+$", digest)
|
||||||
|
except IndexError:
|
||||||
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_digest(cls, passwd: str, salt: bytes = None):
|
def get_digest(cls, passwd: str, salt: bytes = None):
|
||||||
if not salt:
|
if not salt:
|
||||||
|
@ -68,10 +85,10 @@ class Password(Field):
|
||||||
def compare(cls, passwd: value_type, stored: value_type):
|
def compare(cls, passwd: value_type, stored: value_type):
|
||||||
stored_salt, stored_digest = stored.split(":")
|
stored_salt, stored_digest = stored.split(":")
|
||||||
input_digest, input_salt = cls.get_digest(passwd, bytes.fromhex(stored_salt))
|
input_digest, input_salt = cls.get_digest(passwd, bytes.fromhex(stored_salt))
|
||||||
return input_digest == stored_digest
|
return hmac.compare_digest(input_digest, stored_digest)
|
||||||
|
|
||||||
def before_insert(self, value: value_type, db: TinyDB, record: Record) -> None:
|
def before_insert(self, value: value_type, db: TinyDB, record: Record) -> None:
|
||||||
if value:
|
if value and not self.__class__.is_digest(value):
|
||||||
digest, salt = self.__class__.get_digest(value)
|
digest, salt = self.__class__.get_digest(value)
|
||||||
record[self.name] = f"{salt}:{digest}"
|
record[self.name] = f"{salt}:{digest}"
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,9 @@ def test_search(db):
|
||||||
def test_password(db):
|
def test_password(db):
|
||||||
user = db.save(examples.User(name="john", email="john@foo", password="fnord"))
|
user = db.save(examples.User(name="john", email="john@foo", password="fnord"))
|
||||||
|
|
||||||
|
# make sure we don't compute the digest on an existing digest
|
||||||
|
user = db.save(user)
|
||||||
|
|
||||||
assert ":" in user.password
|
assert ":" in user.password
|
||||||
assert user.password != "fnord"
|
assert user.password != "fnord"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user