feat: add algorithm interface and registry
This commit is contained in:
40
algorithms.py
Normal file
40
algorithms.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""Algorithm interface and registry for password hashing."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Protocol
|
||||
|
||||
|
||||
class Algorithm(Protocol):
|
||||
"""Protocol defining the interface for password hashing algorithms."""
|
||||
|
||||
identifier: str
|
||||
|
||||
def hash(self, password: str, **kwargs) -> tuple[str, str]:
|
||||
"""Hash a password and return (salt_b64, hash_b64)."""
|
||||
...
|
||||
|
||||
def verify(self, password: str, salt_b64: str, hash_b64: str, **kwargs) -> bool:
|
||||
"""Verify a password against stored salt and hash."""
|
||||
...
|
||||
|
||||
|
||||
# Algorithm registry
|
||||
_ALGORITHMS: dict[str, Algorithm] = {}
|
||||
|
||||
|
||||
def register_algorithm(algo: Algorithm) -> None:
|
||||
"""Register an algorithm in the global registry."""
|
||||
_ALGORITHMS[algo.identifier] = algo
|
||||
|
||||
|
||||
def get_algorithm(name: str) -> Algorithm:
|
||||
"""Get an algorithm by name from the registry."""
|
||||
if name not in _ALGORITHMS:
|
||||
raise ValueError(f"Unknown algorithm: {name}")
|
||||
return _ALGORITHMS[name]
|
||||
|
||||
|
||||
def list_algorithms() -> list[str]:
|
||||
"""Return list of registered algorithm identifiers."""
|
||||
return sorted(_ALGORITHMS.keys())
|
||||
23
tests/test_algorithms.py
Normal file
23
tests/test_algorithms.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import pytest
|
||||
|
||||
from algorithms import Algorithm, get_algorithm
|
||||
|
||||
|
||||
def test_algorithm_has_required_methods():
|
||||
"""Verify Algorithm protocol defines required methods."""
|
||||
algo = get_algorithm("pbkdf2")
|
||||
assert hasattr(algo, "hash")
|
||||
assert hasattr(algo, "verify")
|
||||
assert hasattr(algo, "identifier")
|
||||
|
||||
|
||||
def test_get_algorithm_returns_pbkdf2():
|
||||
"""Verify default algorithm is PBKDF2."""
|
||||
algo = get_algorithm("pbkdf2")
|
||||
assert algo.identifier == "pbkdf2"
|
||||
|
||||
|
||||
def test_get_algorithm_unknown_raises_error():
|
||||
"""Verify unknown algorithm raises ValueError."""
|
||||
with pytest.raises(ValueError, match="Unknown algorithm"):
|
||||
get_algorithm("unknown")
|
||||
Reference in New Issue
Block a user