Skip to content

Commit 4f2d1d4

Browse files
committed
BasePasswordHasher abstract base class
1 parent dd950c6 commit 4f2d1d4

File tree

1 file changed

+10
-13
lines changed

1 file changed

+10
-13
lines changed

plain-passwords/plain/passwords/hashers.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import hmac
77
import math
88
import warnings
9+
from abc import ABC, abstractmethod
910
from collections.abc import Callable
1011
from typing import Any
1112

@@ -158,7 +159,7 @@ def must_update_salt(salt: str, expected_entropy: int) -> bool:
158159
return len(salt) * math.log2(len(RANDOM_STRING_CHARS)) < expected_entropy
159160

160161

161-
class BasePasswordHasher:
162+
class BasePasswordHasher(ABC):
162163
"""
163164
Abstract base class for password hashers
164165
@@ -181,29 +182,28 @@ def salt(self) -> str:
181182
char_count = math.ceil(self.salt_entropy / math.log2(len(RANDOM_STRING_CHARS)))
182183
return get_random_string(char_count, allowed_chars=RANDOM_STRING_CHARS)
183184

185+
@abstractmethod
184186
def verify(self, password: str, encoded: str) -> bool:
185187
"""Check if the given password is correct."""
186-
raise NotImplementedError(
187-
"subclasses of BasePasswordHasher must provide a verify() method"
188-
)
188+
...
189189

190190
def _check_encode_args(self, password: str, salt: str) -> None:
191191
if password is None:
192192
raise TypeError("password must be provided.")
193193
if not salt or "$" in salt:
194194
raise ValueError("salt must be provided and cannot contain $.")
195195

196+
@abstractmethod
196197
def encode(self, password: str, salt: str) -> str:
197198
"""
198199
Create an encoded database value.
199200
200201
The result is normally formatted as "algorithm$salt$hash" and
201202
must be fewer than 128 characters.
202203
"""
203-
raise NotImplementedError(
204-
"subclasses of BasePasswordHasher must provide an encode() method"
205-
)
204+
...
206205

206+
@abstractmethod
207207
def decode(self, encoded: str) -> dict[str, Any]:
208208
"""
209209
Return a decoded database value.
@@ -212,20 +212,17 @@ def decode(self, encoded: str) -> dict[str, Any]:
212212
`salt`. Extra keys can be algorithm specific like `iterations` or
213213
`work_factor`.
214214
"""
215-
raise NotImplementedError(
216-
"subclasses of BasePasswordHasher must provide a decode() method."
217-
)
215+
...
218216

217+
@abstractmethod
219218
def safe_summary(self, encoded: str) -> dict[str, Any]:
220219
"""
221220
Return a summary of safe values.
222221
223222
The result is a dictionary and will be used where the password field
224223
must be displayed to construct a safe representation of the password.
225224
"""
226-
raise NotImplementedError(
227-
"subclasses of BasePasswordHasher must provide a safe_summary() method"
228-
)
225+
...
229226

230227
def must_update(self, encoded: str) -> bool:
231228
return False

0 commit comments

Comments
 (0)