mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-16 01:40:15 +08:00
86 lines
2.8 KiB
Python
86 lines
2.8 KiB
Python
"""Ensure frontend login logic and backend argon2id verification match.
|
|
|
|
This guards against the kind of password-hash mismatch that can be
|
|
introduced when the frontend encryption/encoding logic and the backend
|
|
verification code drift apart.
|
|
"""
|
|
|
|
from astrbot.core.utils.auth_password import (
|
|
hash_dashboard_password,
|
|
validate_dashboard_password,
|
|
verify_dashboard_password,
|
|
is_default_dashboard_password,
|
|
is_legacy_dashboard_password,
|
|
get_dashboard_login_challenge,
|
|
verify_dashboard_login_proof,
|
|
)
|
|
|
|
|
|
def test_password_hash_roundtrip():
|
|
"""Backend argon2id hash → verify round-trip."""
|
|
password = "test-password-123"
|
|
hashed = hash_dashboard_password(password)
|
|
assert hashed.startswith("$argon2id$"), f"Expected argon2id hash, got: {hashed}"
|
|
assert verify_dashboard_password(hashed, password)
|
|
assert not verify_dashboard_password(hashed, "wrong-password")
|
|
|
|
|
|
def test_validate_password_strength():
|
|
"""validate_dashboard_password should reject weak passwords."""
|
|
validate_dashboard_password("StrongPass1!") # should not raise
|
|
|
|
import pytest
|
|
|
|
with pytest.raises(ValueError):
|
|
validate_dashboard_password("short")
|
|
|
|
with pytest.raises(ValueError):
|
|
validate_dashboard_password("")
|
|
|
|
|
|
def test_is_default_password():
|
|
"""is_default / is_legacy detection helpers."""
|
|
assert is_default_dashboard_password(hash_dashboard_password("astrbot"))
|
|
|
|
# Legacy MD5-style hash detection
|
|
assert is_legacy_dashboard_password("e99a18c428cb38d5f260853678922e03")
|
|
|
|
|
|
def test_login_challenge_argon2():
|
|
"""get_dashboard_login_challenge for argon2 returns algorithm marker."""
|
|
password = "test-challenge-pw"
|
|
hashed = hash_dashboard_password(password)
|
|
|
|
challenge = get_dashboard_login_challenge(hashed)
|
|
assert challenge == {"algorithm": "argon2"}
|
|
|
|
|
|
def test_login_challenge_pbkdf2():
|
|
"""get_dashboard_login_challenge + verify_dashboard_login_proof for PBKDF2."""
|
|
import hashlib, hmac
|
|
|
|
salt = "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
|
|
password = "test-pw"
|
|
iterations = 600000
|
|
algo = "pbkdf2_sha256"
|
|
# Build a PBKDF2 hash matching auth_password format: algo$iterations$salt$derived_key
|
|
dk = hashlib.pbkdf2_hmac("sha256", password.encode(), bytes.fromhex(salt), iterations)
|
|
stored = f"{algo}${iterations}${salt}${dk.hex()}"
|
|
|
|
challenge = get_dashboard_login_challenge(stored)
|
|
assert challenge["algorithm"] == algo
|
|
assert challenge["salt"] == salt
|
|
assert challenge["iterations"] == iterations
|
|
|
|
# The proof is HMAC-SHA256(derived_key, nonce) — the derived key IS the digest
|
|
proof = hmac.new(
|
|
dk,
|
|
b"any-nonce",
|
|
hashlib.sha256,
|
|
).hexdigest()
|
|
|
|
assert verify_dashboard_login_proof(stored, "any-nonce", proof)
|
|
assert not verify_dashboard_login_proof(
|
|
stored, "any-nonce", "invalid-proof"
|
|
)
|