Server Administration
Administration is the one place in Cryptid where identity is the point. An operator is a known party acting on infrastructure they own, so there is nothing to anonymize and no reason to.
Admin sessions authenticate a person to their own server; PrivacyPass authenticates nobody to anybody.
struct AdminSession { token: String, expires_at: u64, permissions: Vec<AdminPermission>, admin_level: AdminLevel, // Viewer | Moderator | Admin}
enum AdminPermission { ViewMetrics, ViewAudit, ManageConfig, VerifyDevices, ModifyBudgets, BlockFederation,}RequestAdminChallenge
Section titled “RequestAdminChallenge”Obtains a nonce for an administrator to sign.
- Input:
AdminChallengeRequest { device_id } - Output:
AdminChallenge { challenge, expires_at } - Auth: None
- Idempotent: No
- Errors:
MALFORMED_REQUEST
Requirements
Section titled “Requirements”- Servers MUST generate
challengewith cryptographically secure randomness - Servers MUST expire a challenge within 5 minutes
- Servers MUST NOT reveal whether
device_idis an administrator - Servers MUST rate limit challenge issuance per source address
The third rule is especially important: a challenge endpoint that answers differently for administrators and everyone else enumerates the admin list.
HTTP Binding
Section titled “HTTP Binding”GET /admin/v1/auth/challenge?device_id={device_id}AuthenticateAdmin
Section titled “AuthenticateAdmin”Exchanges a signed challenge for a session.
- Input:
AdminAuthRequest { device_id, challenge, signature, timestamp } - Output:
AdminSession - Auth: Device signature over the challenge
- Idempotent: No
- Errors:
ADMIN_UNAUTHORIZED,CHALLENGE_EXPIRED,CHALLENGE_INVALID,DEVICE_ID_MISMATCH
Requirements
Section titled “Requirements”- Servers MUST verify
device_id == Blake3(public_key)before anything else - Servers MUST verify
signatureagainst the issued challenge - Servers MUST reject a challenge already spent
- Servers MUST reject a
timestampoutside an acceptable window - Servers MUST return
ADMIN_UNAUTHORIZEDfor a valid signature from a non-administrator - Sessions MUST expire; one hour is the default
- Servers MUST grant only the permissions configured for that administrator
HTTP Binding
Section titled “HTTP Binding”POST /admin/v1/authContent-Type: application/jsonRefreshAdminSession
Section titled “RefreshAdminSession”- Input: None - the current session authorizes
- Output:
AdminSession - Auth: Admin session
- Idempotent: No
- Errors:
ADMIN_UNAUTHORIZED
Requirements
Section titled “Requirements”- Servers MUST reject a refresh presented after expiry; re-authentication is required
- Servers MUST NOT extend permissions on refresh
- Servers SHOULD bound total session lifetime independently of refresh count
HTTP Binding
Section titled “HTTP Binding”POST /admin/v1/auth/refreshAuthorization: AdminSession <token>RevokeAdminSession
Section titled “RevokeAdminSession”- Input: None
- Output: None
- Auth: Admin session
- Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED
Requirements
Section titled “Requirements”- Servers MUST invalidate the session immediately
- Servers MUST succeed for an already-revoked session
HTTP Binding
Section titled “HTTP Binding”POST /admin/v1/auth/logoutAuthorization: AdminSession <token>GetServerConfig
Section titled “GetServerConfig”- Input: None
- Output:
ServerConfig - Auth: Admin session +
ViewMetrics - Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS
{ "server": { "server_name": "chat.example.com", "cryptid_version": "0.12", "max_message_size": 262144, "max_blob_size": 104857600, "max_retention_days": 30 }, "announcement": { "enabled": true, "vdf_iterations": 5000000, "max_challenges_per_ip_per_hour": 10, "max_announcements_per_ip_per_hour": 5, "accept_invites": true }, "progressive_trust": { "enabled": true, "new_tier_duration_hours": 6, "established_tier_duration_hours": 24, "new_tier_rate": 50, "new_tier_capacity": 200, "established_tier_rate": 500, "established_tier_capacity": 2000, "trusted_tier_rate": 2000, "trusted_tier_capacity": 10000 }, "issuance": { "key_rotation_days": 30, "key_overlap_days": 7 }, "federation": { "enabled": true, "allowlist_mode": false, "auto_block_threshold": 0.2, "publish_blocklist": true, "certificate_validation": true }}Requirements
Section titled “Requirements”- Servers MUST NOT return private key material of any kind
- Values published at
/.well-known/cryptidMUST match those returned here
HTTP Binding
Section titled “HTTP Binding”GET /admin/v1/configAuthorization: AdminSession <token>UpdateServerConfig
Section titled “UpdateServerConfig”- Input:
ConfigPatch- a partialServerConfig - Output:
ServerConfig - Auth: Admin session +
ManageConfig - Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS,CONFIG_INVALID
Requirements
Section titled “Requirements”- Servers MUST validate every key and reject the whole patch if any is invalid
- Servers MUST apply a patch atomically
- Servers MUST return the resulting full config, so a caller can confirm what applied
- Servers MUST record the change and the acting administrator in the audit log
- A change to
max_message_sizeormax_blob_sizeMUST be reflected at/.well-known/cryptidbefore taking effect
HTTP Binding
Section titled “HTTP Binding”PATCH /admin/v1/configAuthorization: AdminSession <token>GetServerMetrics
Section titled “GetServerMetrics”- Input:
MetricsQuery { period } - Output:
ServerMetrics - Auth: Admin session +
ViewMetrics - Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS
{ "period": "24h", "timestamp": 1789357668, "server": { "uptime_seconds": 2592000, "cpu_usage_percent": 35.2, "memory_usage_mb": 2048, "storage_used_gb": 125.5 }, "devices": { "announced_total": 1500, "announced_last_24h": 25, "verified": 120, "blocked": 15, "by_trust_tier": { "new": 45, "established": 320, "trusted": 1115, "verified": 120 } }, "envelopes": { "accepted_last_24h": 45000, "queued": 120, "expired_last_24h": 5, "average_size_bytes": 8192 }, "tokens": { "issued_last_24h": 98000, "redeemed_last_24h": 94500 }, "federation": { "peers_active": 25, "peers_blocked": 3 }}Requirements
Section titled “Requirements”- Every figure MUST be a server-wide aggregate
- Servers MUST NOT expose any metric attributable to an individual device beyond its
DeviceRecord - Servers MUST NOT correlate issuance counts with redemption counts per device
HTTP Binding
Section titled “HTTP Binding”GET /admin/v1/metrics?period={period}Authorization: AdminSession <token>GetMetricsTimeseries
Section titled “GetMetricsTimeseries”- Input:
TimeseriesQuery { metric, period, interval } - Output:
Timeseries { metric, points } - Auth: Admin session +
ViewMetrics - Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS,CONFIG_INVALID
Requirements
Section titled “Requirements”- Servers MUST reject an unknown
metricasCONFIG_INVALID - Servers MUST bound the number of points returned
- Only aggregate metrics MUST be available as a series
HTTP Binding
Section titled “HTTP Binding”GET /admin/v1/metrics/timeseries?metric={m}&period={p}&interval={i}Authorization: AdminSession <token>ExportMetrics
Section titled “ExportMetrics”- Input:
ExportQuery { format } - Output: encoded metrics
- Auth: Admin session +
ViewMetrics - Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS,UNSUPPORTED_CONTENT_TYPE
Requirements
Section titled “Requirements”- Servers MUST expose the same aggregates as
GetServerMetrics, in a different encoding - Servers MUST reject an unsupported format rather than silently substituting one
HTTP Binding
Section titled “HTTP Binding”GET /admin/v1/metrics/export?format=prometheusAuthorization: AdminSession <token>Export formats are a property of this binding, not of the operation. The HTTP binding supports prometheus and json.
QueryAuditLog
Section titled “QueryAuditLog”- Input:
AuditQuery { since, action, limit } - Output:
Vec<AuditEntry> - Auth: Admin session +
ViewAudit - Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS
struct AuditEntry { entry_id: Uuid, timestamp: u64,
// The administrator who acted. Admin actions are attributable by design actor: DeviceId,
action: AuditAction,
// What was acted on: a device_id, a peer domain, a config key subject: String,
reason: Option<String>,}Requirements
Section titled “Requirements”- Servers MUST log every administrative action that changes state
- Entries MUST be append-only and MUST NOT be editable through the API
- Servers MUST NOT log user traffic, mailbox addresses, or envelope contents
- Servers MUST retain entries for at least the configured retention period
HTTP Binding
Section titled “HTTP Binding”GET /admin/v1/audit?since={ts}&action={a}&limit={n}Authorization: AdminSession <token>ExportAuditLog
Section titled “ExportAuditLog”- Input:
AuditExportQuery { since, format } - Output: encoded audit entries
- Auth: Admin session +
ViewAudit - Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS,UNSUPPORTED_CONTENT_TYPE
Requirements
Section titled “Requirements”- Export MUST contain the same entries
QueryAuditLogwould return for the same range - Servers MUST record the export itself as an audit entry
HTTP Binding
Section titled “HTTP Binding”GET /admin/v1/audit/export?since={ts}&format=csvAuthorization: AdminSession <token>The HTTP binding supports csv and json.
GetAdminHealth
Section titled “GetAdminHealth”Component-level health, for the operator.
- Input: None
- Output:
AdminHealth { status, components, checked_at } - Auth: Admin session +
ViewMetrics - Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS
Requirements
Section titled “Requirements”- Servers MUST report per-component status: storage, queue, federation, issuance
- Servers MUST return
degradedrather thanhealthywhen any component is failing - this operation MUST NOT be used as the public liveness check
HTTP Binding
Section titled “HTTP Binding”GET /admin/v1/healthAuthorization: AdminSession <token>ListAlerts
Section titled “ListAlerts”- Input:
AlertQuery { severity, acknowledged } - Output:
Vec<Alert> - Auth: Admin session +
ViewMetrics - Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS
Requirements
Section titled “Requirements”- Alerts MUST derive from server-wide conditions: storage pressure, queue depth, federation failures, issuance-key expiry
- Servers MUST NOT raise an alert naming a device or a mailbox
- Servers SHOULD alert before an issuance key’s overlap window closes
HTTP Binding
Section titled “HTTP Binding”GET /admin/v1/alerts?severity={s}&acknowledged={bool}Authorization: AdminSession <token>