mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-07-30 07:05:20 +00:00
73 lines
2.3 KiB
Python
73 lines
2.3 KiB
Python
"""Engine TOTP operations."""
|
|
import json
|
|
import time
|
|
from pathlib import Path
|
|
|
|
import pyotp
|
|
import pytest
|
|
|
|
from api import engine, totp
|
|
|
|
|
|
@pytest.fixture
|
|
def store(tmp_path: Path):
|
|
p = tmp_path / "users.json"
|
|
p.write_text(json.dumps({"version": 2, "users": [], "groups": []}))
|
|
eng = engine.Engine(users_path=p)
|
|
eng.create_user("alice", email="a@b.c", role="admin")
|
|
return eng
|
|
|
|
|
|
def test_enroll_totp_persists_secret_and_10_codes(store: engine.Engine):
|
|
secret = totp.generate_secret()
|
|
backup_plain = store.enroll_totp("alice", secret)
|
|
assert len(backup_plain) == 10
|
|
u = store.get_user("alice")
|
|
assert u["totp"]["enabled"] is True
|
|
assert u["totp"]["secret"] == secret
|
|
assert len(u["totp"]["backup_codes"]) == 10
|
|
assert all(bc["used_at"] is None for bc in u["totp"]["backup_codes"])
|
|
assert all(bc["hash"].startswith("$argon2id$") for bc in u["totp"]["backup_codes"])
|
|
|
|
|
|
def test_verify_totp_for_user_accepts_current(store: engine.Engine):
|
|
secret = totp.generate_secret()
|
|
store.enroll_totp("alice", secret)
|
|
code = pyotp.TOTP(secret).now()
|
|
ok = store.verify_totp_for_user("alice", code)
|
|
assert ok is True
|
|
|
|
|
|
def test_verify_totp_refuses_replay(store: engine.Engine):
|
|
secret = totp.generate_secret()
|
|
store.enroll_totp("alice", secret)
|
|
code = pyotp.TOTP(secret).now()
|
|
assert store.verify_totp_for_user("alice", code) is True
|
|
assert store.verify_totp_for_user("alice", code) is False # replay
|
|
|
|
|
|
def test_consume_backup_code_marks_used_once(store: engine.Engine):
|
|
secret = totp.generate_secret()
|
|
backup = store.enroll_totp("alice", secret)
|
|
code = backup[0]
|
|
assert store.consume_backup_code("alice", code) is True
|
|
assert store.consume_backup_code("alice", code) is False # already used
|
|
|
|
|
|
def test_disable_totp_removes_block(store: engine.Engine):
|
|
secret = totp.generate_secret()
|
|
store.enroll_totp("alice", secret)
|
|
store.disable_totp("alice")
|
|
u = store.get_user("alice")
|
|
assert u["totp"] is None
|
|
|
|
|
|
def test_regenerate_backup_codes(store: engine.Engine):
|
|
secret = totp.generate_secret()
|
|
old = store.enroll_totp("alice", secret)
|
|
new = store.regenerate_backup_codes("alice")
|
|
assert len(new) == 10
|
|
assert set(new).isdisjoint(set(old))
|
|
u = store.get_user("alice")
|
|
assert len(u["totp"]["backup_codes"]) == 10
|