Initial certificate system

This commit is contained in:
nelso
2026-06-06 19:32:24 +08:00
commit ce4ed6213b
105 changed files with 9133 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
import hashlib
from datetime import date
from app.core.config import settings
ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"
def _to_base32ish(value: int, length: int) -> str:
chars: list[str] = []
base = len(ALPHABET)
while value:
value, remainder = divmod(value, base)
chars.append(ALPHABET[remainder])
encoded = "".join(reversed(chars)) or ALPHABET[0]
return encoded[-length:].rjust(length, ALPHABET[0])
def _digest_int(payload: str) -> int:
digest = hashlib.sha256(payload.encode("utf-8")).digest()
return int.from_bytes(digest[:8], "big")
def build_certificate_no(sequence_id: int, project_code: str, issue_date: date | None = None) -> str:
year = (issue_date or date.today()).year
normalized_project = project_code.strip().upper()
seed = f"{settings.certificate_no_secret}:{year}:{normalized_project}:{sequence_id}"
short_code = _to_base32ish(_digest_int(seed), 7)
check_code = _to_base32ish(_digest_int(f"check:{seed}:{short_code}"), 2)
return f"PX{year}-{normalized_project}-{short_code}-{check_code}"