Files
MoviePilot/tests/test_passkey_challenge.py

93 lines
2.3 KiB
Python

from concurrent.futures import ThreadPoolExecutor
from app.core.cache import TTLCache
from app.helper.passkey import PasskeyChallengeStore
def setup_function():
PasskeyChallengeStore._cache.clear()
def test_challenge_can_only_be_consumed_once():
token = PasskeyChallengeStore.issue(
challenge="server-challenge",
purpose="authentication",
user_id=1,
)
challenge = PasskeyChallengeStore.consume(
transaction_token=token,
purpose="authentication",
)
assert challenge is not None
assert challenge.challenge == "server-challenge"
assert challenge.user_id == 1
assert (
PasskeyChallengeStore.consume(
transaction_token=token,
purpose="authentication",
)
is None
)
def test_wrong_purpose_invalidates_transaction():
token = PasskeyChallengeStore.issue(
challenge="server-challenge",
purpose="registration",
user_id=1,
)
assert (
PasskeyChallengeStore.consume(
transaction_token=token,
purpose="authentication",
)
is None
)
assert (
PasskeyChallengeStore.consume(
transaction_token=token,
purpose="registration",
)
is None
)
def test_expired_challenge_cannot_be_consumed(monkeypatch):
expired_cache = TTLCache(region="expired_passkey_challenge", maxsize=1, ttl=0)
monkeypatch.setattr(PasskeyChallengeStore, "_cache", expired_cache)
token = PasskeyChallengeStore.issue(
challenge="server-challenge",
purpose="authentication",
user_id=None,
)
assert (
PasskeyChallengeStore.consume(
transaction_token=token,
purpose="authentication",
)
is None
)
def test_concurrent_consumers_have_single_winner():
token = PasskeyChallengeStore.issue(
challenge="server-challenge",
purpose="authentication",
user_id=None,
)
def consume():
return PasskeyChallengeStore.consume(
transaction_token=token,
purpose="authentication",
)
with ThreadPoolExecutor(max_workers=8) as executor:
results = list(executor.map(lambda _: consume(), range(8)))
assert sum(result is not None for result in results) == 1