import time import pytest from finbot.auth import Claims, TokenError, dashboard_url, issue, verify SECRET = "a-test-signing-secret" class TestRoundTrip: def test_issue_and_verify(self): token = issue(42, SECRET) claims = verify(token, SECRET) assert claims.user_id == 42 def test_large_user_ids(self): # Telegram ids are well past 32-bit. assert verify(issue(7_000_000_123, SECRET), SECRET).user_id == 7_000_000_123 def test_tokens_are_url_safe(self): token = issue(42, SECRET) assert "/" not in token and "+" not in token and "=" not in token def test_seconds_left(self): claims = Claims(user_id=1, expires_at=int(time.time()) + 60) assert 55 <= claims.seconds_left <= 60 class TestRejection: def test_wrong_secret(self): token = issue(42, SECRET) with pytest.raises(TokenError, match="bad signature"): verify(token, "a-different-secret") def test_tampered_payload(self): # Swap the user id for someone else's and the signature must fail. token = issue(42, SECRET) forged = issue(99, SECRET).split(".")[0] + "." + token.split(".")[1] with pytest.raises(TokenError): verify(forged, SECRET) def test_expired(self): past = int(time.time()) - 100 token = issue(42, SECRET, ttl_seconds=1, now=past) with pytest.raises(TokenError, match="expired"): verify(token, SECRET) def test_still_valid_just_before_expiry(self): now = int(time.time()) token = issue(42, SECRET, ttl_seconds=60, now=now) assert verify(token, SECRET, now=now + 59).user_id == 42 @pytest.mark.parametrize("bad", ["", "nonsense", "no-dot", "a.b.c.d", "...."]) def test_malformed(self, bad): with pytest.raises(TokenError): verify(bad, SECRET) def test_no_secret_configured(self): with pytest.raises(TokenError): verify(issue(42, SECRET), "") def test_cannot_issue_without_a_secret(self): with pytest.raises(TokenError): issue(42, "") class TestURL: def test_builds_a_query_url(self): assert dashboard_url("https://x.hf.space/", "abc") == "https://x.hf.space/?t=abc" def test_handles_missing_trailing_slash(self): assert dashboard_url("https://x.hf.space", "abc") == "https://x.hf.space/?t=abc"