Cybersecurity-Projects/PROJECTS/beginner/jwt-auditor/tests/conftest.py

70 lines
2.2 KiB
Python

"""
Shared test helpers for building JWTs.
Tokens are built with the project's own hmac_sign so the tests exercise the
real signing path and stay dependency free. A fixed clock is exposed so the
time based checks are deterministic.
"""
import base64
import json
from typing import Any
import pytest
from jwt_auditor.signatures import hmac_sign
# A fixed "now" used across time based tests: 2026-01-01 00:00:00 UTC.
FIXED_NOW = 1767225600.0
ONE_HOUR = 3600.0
ONE_DAY = 86400.0
def b64url(data: bytes) -> str:
"""Encode bytes as base64url without padding, the way JWT does."""
return base64.urlsafe_b64encode(data).rstrip(b"=").decode("ascii")
def _segment(obj: dict[str, Any]) -> str:
"""Encode a JSON object as a base64url JWT segment."""
return b64url(json.dumps(obj, separators = (",", ":")).encode("utf-8"))
def build_hs_token(
payload: dict[str,
Any],
secret: str = "secret",
alg: str = "HS256",
header: dict[str,
Any] | None = None,
) -> str:
"""Build an HMAC signed token using the given secret."""
head = header or {"alg": alg, "typ": "JWT"}
signing_input = f"{_segment(head)}.{_segment(payload)}".encode("ascii")
signature = hmac_sign(signing_input, secret.encode("utf-8"), alg)
return f"{_segment(head)}.{_segment(payload)}.{b64url(signature)}"
def build_none_token(payload: dict[str, Any]) -> str:
"""Build an unsigned alg none token ending in a trailing dot."""
head = {"alg": "none", "typ": "JWT"}
return f"{_segment(head)}.{_segment(payload)}."
def build_unsigned_token(payload: dict[str, Any], alg: str = "HS256") -> str:
"""Build a token that declares a real alg but carries no signature."""
head = {"alg": alg, "typ": "JWT"}
return f"{_segment(head)}.{_segment(payload)}."
def build_bare_alg_token(payload: dict[str, Any], alg: str) -> str:
"""Build a token with an arbitrary alg and a dummy signature segment."""
head = {"alg": alg, "typ": "JWT"}
return f"{_segment(head)}.{_segment(payload)}.{b64url(b'dummy-signature')}"
@pytest.fixture
def now() -> float:
"""The fixed clock value for deterministic time checks."""
return FIXED_NOW