Split the 657-line operation service into eor, submit, and verify modules, add the AGENT_REVOKED and KEY_RETIRED codes the Backend already emits, and condense every multi-line comment. Mirror Node, Python, and Go at 2.1.0 with the deep-health 503, non-idempotent retry, rotation grace, and path-encoding fixes. Document which routes and response fields the self-hosted server does not provide. Claude-Session: https://claude.ai/code/session_01Agoc9bRVE9KL7mmWtey9Vq
45 lines
1.3 KiB
Python
45 lines
1.3 KiB
Python
"""Utility helpers: UUIDv7, nonce generation, base64url encoding."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import base64
|
|
import os
|
|
import struct
|
|
import time
|
|
|
|
|
|
def base64url_encode(data: bytes) -> str:
|
|
"""Encode bytes to base64url string with no padding."""
|
|
return base64.urlsafe_b64encode(data).rstrip(b"=").decode("ascii")
|
|
|
|
|
|
def base64url_decode(s: str) -> bytes:
|
|
"""Decode a base64url string (with or without padding) to bytes."""
|
|
s = s.replace("-", "+").replace("_", "/")
|
|
padding = 4 - len(s) % 4
|
|
if padding != 4:
|
|
s += "=" * padding
|
|
return base64.b64decode(s)
|
|
|
|
|
|
def generate_nonce() -> str:
|
|
"""Generate a 16-byte random nonce, base64url encoded."""
|
|
return base64url_encode(os.urandom(16))
|
|
|
|
|
|
def generate_uuidv7() -> str:
|
|
"""UUIDv7 (RFC 9562): 48-bit ms timestamp, version 7, variant 10, 74 random bits."""
|
|
timestamp_ms = int(time.time() * 1000)
|
|
ts_bytes = struct.pack(">Q", timestamp_ms)[2:]
|
|
rand_a = (struct.unpack(">H", os.urandom(2))[0] & 0x0FFF) | 0x7000
|
|
rand_b = bytearray(os.urandom(8))
|
|
rand_b[0] = (rand_b[0] & 0x3F) | 0x80
|
|
|
|
uuid_bytes = ts_bytes + struct.pack(">H", rand_a) + bytes(rand_b)
|
|
|
|
hex_str = uuid_bytes.hex()
|
|
return (
|
|
f"{hex_str[0:8]}-{hex_str[8:12]}-{hex_str[12:16]}-"
|
|
f"{hex_str[16:20]}-{hex_str[20:32]}"
|
|
)
|