···
def _validate_did(cls, v: str) -> None:
"""Validate DID format"""
raise ValueError("DID too long, max 2048 chars")
+
if not re.match(r"^did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]$", v):
+
raise ValueError("Invalid URI format")
def _validate_handle(cls, v: str) -> None:
"""Validate handle format"""
+
if not re.match(r"^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$", v):
raise ValueError("Handle contains invalid characters")
raise ValueError("Handle too long, max 253 chars")
···
def _validate_at_uri(cls, v: str) -> None:
+
Validate AT-URI format according to AT Protocol specification.
+
v: AT-URI string to validate
+
ValueError: If URI violates any of these rules:
+
- Must start with 'at://'
+
- Authority must be valid DID or handle
+
- Path segments must follow NSID/RKEY rules if present
if not v.startswith("at://"):
raise ValueError("AT-URI must start with 'at://'")
+
if len(v) > 8192: # 8KB
+
raise ValueError("AT-URI too long, max 8KB")
+
raise ValueError("AT-URI cannot have trailing slash")
+
parts = v[5:].split('/') # Skip 'at://'
+
# Validate authority (DID or handle)
+
raise ValueError("AT-URI must have authority")
+
if authority.startswith('did:'):
+
# Basic DID format check - actual DID validation is done elsewhere
+
if len(authority) > 2048:
+
raise ValueError("DID too long")
+
if ':' not in authority[4:]:
+
raise ValueError("Invalid DID format")
+
if not re.match(r'^[a-z0-9.-]+$', authority):
+
raise ValueError("Invalid handle characters")
+
if len(authority) > 253:
+
raise ValueError("Handle too long")
+
# Validate path segments if present
+
raise ValueError("AT-URI path too deep")
+
if not re.match(r'^[a-zA-Z0-9.-]+$', collection):
+
raise ValueError("Invalid collection NSID")
+
raise ValueError("Record key cannot be empty")
+
if not re.match(r'^[a-zA-Z0-9._:%-~]+$', rkey):
+
raise ValueError("Invalid record key characters")
def _validate_cid(cls, v: str) -> None:
···
"""Validate NSID format"""
raise ValueError("NSID too long, max 317 chars")
+
if not re.match(r"^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z]([a-zA-Z0-9]{0,62})?)$", v):
raise ValueError("NSID contains invalid characters")
···
"""Validate TID format"""
raise ValueError("TID too long, max 13 chars")
+
if not re.match(r"^[234567abcdefghij][234567abcdefghijklmnopqrstuvwxyz]{12}$", v):
raise ValueError("TID contains invalid characters")
···
"""Validate record-key format"""
raise ValueError("Record key too long, max 512 chars")
+
if v == "." or v == "..":
+
raise ValueError(f"Record key is {v}, which is not allowed")
if not re.match(r"^[a-zA-Z0-9._:%-~]+$", v):
raise ValueError("Record key contains invalid characters")