33 lines
942 B
Python
33 lines
942 B
Python
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import hmac
|
|
import re
|
|
|
|
from cryptography.fernet import Fernet
|
|
|
|
DEVICE_UA_RE = re.compile(r"^vpnapp/v(?P<major>\d+)\.(?P<minor>\d+)/(?P<device>[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
|