from __future__ import annotations import hashlib import hmac import re from cryptography.fernet import Fernet DEVICE_UA_RE = re.compile(r"^vpnapp/v(?P\d+)\.(?P\d+)/(?P[0-9a-fA-F-]{36})$") class SecretBox: def __init__(self, key: str) -> None: self._fernet = Fernet(key.encode("ascii")) def seal(self, value: str) -> str: return self._fernet.encrypt(value.encode("utf-8")).decode("ascii") def open(self, value: str) -> str: return self._fernet.decrypt(value.encode("ascii")).decode("utf-8") def token_hash(token: str) -> str: return hashlib.sha256(token.encode("utf-8")).hexdigest() def token_matches(token: str, expected_hash: str) -> bool: return hmac.compare_digest(token_hash(token), expected_hash) def parse_user_agent(user_agent: str) -> str | None: match = DEVICE_UA_RE.fullmatch(user_agent.strip()) return match.group("device") if match else None