Referencia Zigspire-zig (SDK consumido)

zig/src/cap/authority.zig

Declaraciones públicas de zig/src/cap/authority.zig (spire-zig (SDK consumido)).

ImplementadoSin versión del tren todavía· generada desde apps/docs/generated/zig/spire.json

Página generada desde spire@spire-0.2.0-XvnrRek1BgCX4Bh8miuITCQgkn0FqeQrYYE3goFfDcQd (zig/src/root.zig). No se edita a mano: bun run docs:gen la regenera y bun run docs:check falla si difiere.

Capability authority (dec-0117 I1, I2, I3; §4.1). spire-zig owns the one SCT verifier of styx (dec-0119 §9); the daemon instantiates it once and shares it with every transport.

One instance per daemon, shared by every transport (WT, MoQT, H3) and by the IPC control server. It owns the state an SCT is checked against:

  • the verification keys (current + next, for rotation; kid derived),
  • the audience (this daemon's node id),
  • the session directory: which session ids playback-svc opened over IPC, bound to which actor and resource (I2),
  • the replay cache of single-use write tokens (I3), bounded.

Deny-by-default: an authority with no keys admits nothing, a token whose session was never bound (or was closed) is refused, and a full replay cache refuses new write tokens instead of forgetting old ones.

Thread model: admit/authorize run on the transport event-loop threads, bindSession/unbindSession on IPC threads. Keys and audience are immutable after init; the two maps are guarded by mutex. Signature verification runs outside the lock.

Tokens are never logged (I12): audit lines carry the reason, the session key, the jti and the actor digest, all non-secret.

cap.authority.MAX_KEYS

const · línea 35

pub const MAX_KEYS: usize = 4

Sin ///.

cap.authority.Clock

const · línea 43

pub const Clock = *const fn () u64

Seconds since the Unix epoch.

cap.authority.Config

type · línea 49

pub const Config = struct

Sin ///.

cap.authority.Rejection

type · línea 72

pub const Rejection = struct

One refused capability as Config.on_reject receives it: identifiers only, never the token (I12).

cap.authority.Rejection.Claimed

type · línea 85

pub const Claimed = struct

Sin ///.

cap.authority.RejectSink

type · línea 96

pub const RejectSink = struct

Receiver of Rejections. emitFn runs on the refusing thread, possibly with the authority's lock held: it must not block and must not call back into the authority.

cap.authority.Denial

const · línea 103

pub const Denial = error{ Malformed, UnsupportedVersion, NoKeysConfigured, UnknownKey, BadSignature, WrongAudience, NotYetValid, Expired, LifetimeTooLong, UnknownSession, SessionMismatch, ScopeDenied, …

Why a capability was refused. Callers map these to protocol errors; the authority has already written the audit line.

cap.authority.DENIAL_KINDS

const · línea 123

pub const DENIAL_KINDS = DENIAL_NAMES.len

Sin ///.

cap.authority.BindError

const · línea 132

pub const BindError = error{ SessionCapacityExceeded, SessionAlreadyBound }

Sin ///.

cap.authority.Binding

type · línea 135

pub const Binding = struct

What a session was opened for, as playback-svc declared it over IPC.

cap.authority.Grant

type · línea 141

pub const Grant = struct

An admitted SCT: what the holder may do until exp.

cap.authority.Operation

type · línea 153

pub const Operation = enum

Sin ///.

cap.authority.Range

type · línea 174

pub const Range = struct

Half-open [start, end).

cap.authority.Target

type · línea 176

pub const Target = struct

Sin ///.

cap.authority.Verified

type · línea 200

pub const Verified = struct

A token whose signature, key, audience, time window and lifetime passed (verifyBase64 / verifyRaw) and that has not been bound to its session or spent yet: consume does that. The claims are readable (a caller can route on them before consuming), but a Verified cannot be built outside the authority that verified it: seal is an HMAC-SHA256 of the claims under a random key of that authority, drawn at init and never exported. consume recomputes it, so claims put together by hand (from peekBase64, or edited after verification) or verified by another authority are refused as BadSignature and audited — the Ed25519 check cannot be skipped by constructing the struct.

cap.authority.Authority

type · línea 220

pub const Authority = struct

Sin ///.

cap.authority.Authority.InitError

const · línea 245

pub const InitError = error{ TooManyKeys, InvalidPublicKey } || std.mem.Allocator.Error

Sin ///.

cap.authority.Authority.init

fn · línea 249

pub fn init(self: *Authority, allocator: std.mem.Allocator, cfg: Config) InitError!void

Both maps are sized up front: admission never allocates, so a flood of tokens cannot turn into an OOM path.

cap.authority.Authority.deinit

fn · línea 274

pub fn deinit(self: *Authority) void

Sin ///.

cap.authority.Authority.now

fn · línea 282

pub fn now(self: *const Authority) u64

Sin ///.

cap.authority.Authority.hasKeys

fn · línea 286

pub fn hasKeys(self: *const Authority) bool

Sin ///.

cap.authority.Authority.bindSession

fn · línea 293

pub fn bindSession(self: *Authority, sid: SessionKey, binding: Binding) BindError!void

Called by the IPC server when playback-svc opens a session.

cap.authority.Authority.unbindSession

fn · línea 303

pub fn unbindSession(self: *Authority, sid: SessionKey) bool

Called on IPC Close. Every later authorize on a grant for sid fails, so closing a session revokes its capabilities.

cap.authority.Authority.boundSessions

fn · línea 319

pub fn boundSessions(self: *Authority) usize

Sin ///.

cap.authority.Authority.unbindCount

fn · línea 328

pub fn unbindCount(self: *const Authority) u64

Sessions unbound so far. A cache of grants only has to look for dead ones again when this moved or the clock did (checkLive depends on nothing else).

cap.authority.Authority.admitBase64

fn · línea 336

pub fn admitBase64(self: *Authority, text: []const u8) Denial!Grant

Base64url form (cap= query, Authorization: Bearer): verifyBase64 then consume.

cap.authority.Authority.admitRaw

fn · línea 342

pub fn admitRaw(self: *Authority, raw: []const u8) Denial!Grant

Raw form (MoQT AUTHORIZATION TOKEN value): verifyRaw then consume.

cap.authority.Authority.verifyBase64

fn · línea 351

pub fn verifyBase64(self: *Authority, text: []const u8) Denial!Verified

First half of admitBase64: decoding, signature, key, audience, time window and lifetime. Takes no lock and spends nothing, so a caller can pay the Ed25519 check outside its own locks and only then decide (under them) whether to consume the token.

cap.authority.Authority.verifyRaw

fn · línea 357

pub fn verifyRaw(self: *Authority, raw: []const u8) Denial!Verified

Same as verifyBase64 for the raw form.

cap.authority.Authority.peekBase64

fn · línea 367

pub fn peekBase64(self: *Authority, text: []const u8) Denial!sct.Claims

The claims of a base64url token, NOT verified: no signature, time or session check. Only for routing a token before admitting it (which cache slot it would take); never grant anything on them — and they cannot be turned into a Verified (see its seal). An undecodable token is refused and audited here as in admitBase64.

cap.authority.Authority.consume

fn · línea 403

pub fn consume(self: *Authority, v: *const Verified) Denial!Grant

Second half of admitBase64: session binding and, for write scopes, single use. Only a Verified this authority sealed gets past the first check (anything else is BadSignature). Consumes the jti only when every other check passed, so a rejected attempt cannot burn a legitimate token. Expiry is checked again: time went by since the verification.

cap.authority.Authority.authorize

fn · línea 474

pub fn authorize(self: *Authority, grant: *const Grant, op: Operation, target: Target) Denial!void

Re-checked on every request, not just at admission: expiry, session still open with the same actor and resource (revocation), scope, resource and range.

cap.authority.Authority.checkLive

fn · línea 519

pub fn checkLive(self: *Authority, grant: *const Grant) Denial!void

Is an admitted grant still alive — not expired, its session still bound to the same actor and resource? Independent of any operation: long-lived flows (an open SUBSCRIBE, a FETCH being written, a publisher stream) are swept with it so expiry and IPC Close reach them, not only the next request (dec-0117 §4.1 revocation).

cap.authority.Authority.deniedCount

fn · línea 534

pub fn deniedCount(self: *const Authority, reason: Denial) u64

Sin ///.

cap.authority.Authority.admittedCount

fn · línea 538

pub fn admittedCount(self: *const Authority) u64

Sin ///.

cap.authority.parsePublicKeys

fn · línea 585

pub fn parsePublicKeys(text: []const u8, out: *[MAX_KEYS][32]u8) error{ TooManyKeys, InvalidPublicKey }!usize

STYX_SCT_PUBLIC_KEYS: comma-separated base64url (no padding) raw Ed25519 public keys, 43 chars each. Returns how many were parsed.

cap.authority.testing

type · línea 605

pub const testing = struct

A throw-away issuer for tests: deterministic key, an authority that trusts it, a controllable clock, and helpers to mint tokens bound to sessions it registered. Never used outside tests.

cap.authority.testing.NODE_ID

const · línea 606

pub const NODE_ID = "test-node"

Sin ///.

cap.authority.testing.ACTOR_ID

const · línea 607

pub const ACTOR_ID = "test-actor"

Sin ///.

cap.authority.testing.fakeClock

fn · línea 611

pub fn fakeClock() u64

Sin ///.

cap.authority.testing.setNow

fn · línea 615

pub fn setNow(v: u64) void

Sin ///.

cap.authority.testing.Issuer

type · línea 619

pub const Issuer = struct

Sin ///.

cap.authority.testing.Issuer.init

fn · línea 624

pub fn init(self: *Issuer, allocator: std.mem.Allocator) !void

Sin ///.

cap.authority.testing.Issuer.deinit

fn · línea 637

pub fn deinit(self: *Issuer) void

Sin ///.

cap.authority.testing.Issuer.bind

fn · línea 641

pub fn bind(self: *Issuer, sid: SessionKey, resource: Digest32) !void

Sin ///.

cap.authority.testing.Issuer.claims

fn · línea 645

pub fn claims(self: *Issuer, sid: SessionKey, scope: Scope, resource: Digest32) sct.Claims

Sin ///.

cap.authority.testing.Issuer.sign

fn · línea 664

pub fn sign(self: *Issuer, c: sct.Claims) [sct.TOKEN_LEN]u8

Sin ///.

cap.authority.testing.Issuer.mint

fn · línea 668

pub fn mint(self: *Issuer, sid: SessionKey, scope: Scope, resource: Digest32) [sct.TOKEN_LEN]u8

Sin ///.

cap.Authority

type · línea 220

pub const Authority = struct

Sin ///.

cap.Authority.InitError

const · línea 245

pub const InitError = error{ TooManyKeys, InvalidPublicKey } || std.mem.Allocator.Error

Sin ///.

cap.Authority.init

fn · línea 249

pub fn init(self: *Authority, allocator: std.mem.Allocator, cfg: Config) InitError!void

Both maps are sized up front: admission never allocates, so a flood of tokens cannot turn into an OOM path.

cap.Authority.deinit

fn · línea 274

pub fn deinit(self: *Authority) void

Sin ///.

cap.Authority.now

fn · línea 282

pub fn now(self: *const Authority) u64

Sin ///.

cap.Authority.hasKeys

fn · línea 286

pub fn hasKeys(self: *const Authority) bool

Sin ///.

cap.Authority.bindSession

fn · línea 293

pub fn bindSession(self: *Authority, sid: SessionKey, binding: Binding) BindError!void

Called by the IPC server when playback-svc opens a session.

cap.Authority.unbindSession

fn · línea 303

pub fn unbindSession(self: *Authority, sid: SessionKey) bool

Called on IPC Close. Every later authorize on a grant for sid fails, so closing a session revokes its capabilities.

cap.Authority.boundSessions

fn · línea 319

pub fn boundSessions(self: *Authority) usize

Sin ///.

cap.Authority.unbindCount

fn · línea 328

pub fn unbindCount(self: *const Authority) u64

Sessions unbound so far. A cache of grants only has to look for dead ones again when this moved or the clock did (checkLive depends on nothing else).

cap.Authority.admitBase64

fn · línea 336

pub fn admitBase64(self: *Authority, text: []const u8) Denial!Grant

Base64url form (cap= query, Authorization: Bearer): verifyBase64 then consume.

cap.Authority.admitRaw

fn · línea 342

pub fn admitRaw(self: *Authority, raw: []const u8) Denial!Grant

Raw form (MoQT AUTHORIZATION TOKEN value): verifyRaw then consume.

cap.Authority.verifyBase64

fn · línea 351

pub fn verifyBase64(self: *Authority, text: []const u8) Denial!Verified

First half of admitBase64: decoding, signature, key, audience, time window and lifetime. Takes no lock and spends nothing, so a caller can pay the Ed25519 check outside its own locks and only then decide (under them) whether to consume the token.

cap.Authority.verifyRaw

fn · línea 357

pub fn verifyRaw(self: *Authority, raw: []const u8) Denial!Verified

Same as verifyBase64 for the raw form.

cap.Authority.peekBase64

fn · línea 367

pub fn peekBase64(self: *Authority, text: []const u8) Denial!sct.Claims

The claims of a base64url token, NOT verified: no signature, time or session check. Only for routing a token before admitting it (which cache slot it would take); never grant anything on them — and they cannot be turned into a Verified (see its seal). An undecodable token is refused and audited here as in admitBase64.

cap.Authority.consume

fn · línea 403

pub fn consume(self: *Authority, v: *const Verified) Denial!Grant

Second half of admitBase64: session binding and, for write scopes, single use. Only a Verified this authority sealed gets past the first check (anything else is BadSignature). Consumes the jti only when every other check passed, so a rejected attempt cannot burn a legitimate token. Expiry is checked again: time went by since the verification.

cap.Authority.authorize

fn · línea 474

pub fn authorize(self: *Authority, grant: *const Grant, op: Operation, target: Target) Denial!void

Re-checked on every request, not just at admission: expiry, session still open with the same actor and resource (revocation), scope, resource and range.

cap.Authority.checkLive

fn · línea 519

pub fn checkLive(self: *Authority, grant: *const Grant) Denial!void

Is an admitted grant still alive — not expired, its session still bound to the same actor and resource? Independent of any operation: long-lived flows (an open SUBSCRIBE, a FETCH being written, a publisher stream) are swept with it so expiry and IPC Close reach them, not only the next request (dec-0117 §4.1 revocation).

cap.Authority.deniedCount

fn · línea 534

pub fn deniedCount(self: *const Authority, reason: Denial) u64

Sin ///.

cap.Authority.admittedCount

fn · línea 538

pub fn admittedCount(self: *const Authority) u64

Sin ///.

cap.authority.MAX_KEYS
cap.authority.Clock
cap.authority.Config
cap.authority.Rejection
cap.authority.Rejection.Claimed
cap.authority.RejectSink
cap.authority.Denial
cap.authority.DENIAL_KINDS
cap.authority.BindError
cap.authority.Binding
cap.authority.Grant
cap.authority.Operation
cap.authority.Range
cap.authority.Target
cap.authority.Verified
cap.authority.Authority
cap.authority.Authority.InitError
cap.authority.Authority.init
cap.authority.Authority.deinit
cap.authority.Authority.now
cap.authority.Authority.hasKeys
cap.authority.Authority.bindSession
cap.authority.Authority.unbindSession
cap.authority.Authority.boundSessions
cap.authority.Authority.unbindCount
cap.authority.Authority.admitBase64
cap.authority.Authority.admitRaw
cap.authority.Authority.verifyBase64
cap.authority.Authority.verifyRaw
cap.authority.Authority.peekBase64
cap.authority.Authority.consume
cap.authority.Authority.authorize
cap.authority.Authority.checkLive
cap.authority.Authority.deniedCount
cap.authority.Authority.admittedCount
cap.authority.parsePublicKeys
cap.authority.testing
cap.authority.testing.NODE_ID
cap.authority.testing.ACTOR_ID
cap.authority.testing.fakeClock
cap.authority.testing.setNow
cap.authority.testing.Issuer
cap.authority.testing.Issuer.init
cap.authority.testing.Issuer.deinit
cap.authority.testing.Issuer.bind
cap.authority.testing.Issuer.claims
cap.authority.testing.Issuer.sign
cap.authority.testing.Issuer.mint
cap.Authority
cap.Authority.InitError
cap.Authority.init
cap.Authority.deinit
cap.Authority.now
cap.Authority.hasKeys
cap.Authority.bindSession
cap.Authority.unbindSession
cap.Authority.boundSessions
cap.Authority.unbindCount
cap.Authority.admitBase64
cap.Authority.admitRaw
cap.Authority.verifyBase64
cap.Authority.verifyRaw
cap.Authority.peekBase64
cap.Authority.consume
cap.Authority.authorize
cap.Authority.checkLive
cap.Authority.deniedCount
cap.Authority.admittedCount