@axtary/actionpass 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @axtary/actionpass
2
2
 
3
- Scoped, signed ActionPass artifacts for runtime-governed AI agent actions.
3
+ Scoped, signed and proof-of-possession-bound ActionPass artifacts for runtime-governed AI agent actions.
4
4
 
5
5
  Early `0.x` release: the runtime path is real and tested, but the API is not stable yet and may change between minor versions.
6
6
 
@@ -8,17 +8,54 @@ Early `0.x` release: the runtime path is real and tested, but the API is not sta
8
8
  npm install @axtary/actionpass
9
9
  ```
10
10
 
11
+ The base format lives in `spec/actionpass-v0.md`; the sender-constrained
12
+ `cnf`/DPoP and delegation profile is `spec/actionpass-v1.md`; authenticated
13
+ status distribution is `spec/actionpass-v2.md`.
14
+
11
15
  ## What It Does
12
16
 
13
17
  - Validates normalized agent actions at runtime.
14
18
  - Produces canonical SHA-256 payload hashes.
15
19
  - Produces payload-bound approval artifacts for exact human or policy override approvals.
16
20
  - Issues signed ActionPass JWT/JWS artifacts for allowed actions.
17
- - Produces revocation records and rejects revoked passes during verification.
21
+ - Issues ActionPass v1 bound to a holder key with RFC 7800 `cnf.jkt`.
22
+ - Creates and verifies RFC 9449 DPoP proofs with method/URI/token binding,
23
+ nonce, clock-window, and replay enforcement.
24
+ - Backs replay enforcement with a shared `DpopReplayStore`: an in-process
25
+ `InMemoryDpopReplayStore` and a durable, lock-serialized `FileDpopReplayStore`
26
+ (`0600`) that keeps a captured proof rejected across a verifier restart within
27
+ its window and compacts itself to the in-flight proof window. Single-host
28
+ state, not cross-host distribution.
29
+ - Exchanges a holder-authorized v1 pass for an attenuated child pass, walks
30
+ root-to-leaf delegation chains, enforces remaining depth, and binds the child
31
+ to a distinct sub-agent key.
32
+ - Applies one revocation source across the full delegation chain, so revoking a
33
+ root or intermediate parent invalidates every downstream child without
34
+ enumerating descendants.
35
+ - Binds authority-owned budget reservation cost/limit/state into the pass so a
36
+ presenter cannot alter metering fields.
37
+ - Produces durable local revocation records and rejects revoked passes during
38
+ verification; a revocation-source error also fails closed.
18
39
  - Verifies passes against a keyring by `kid` so rotated keys can coexist.
19
40
  - Persists local public verification keys and revocations in a JSON trust store.
41
+ - Issues and verifies ActionPass v2 with a signed Token Status List reference,
42
+ freshness-bounded caching, and fail-closed unavailable/stale/invalid status.
43
+ - Uses the IESG-approved Token Status List revision-21 wire format through the
44
+ pinned, stricter `axtary.status-list.v1` profile, so RFC number assignment is
45
+ not a runtime dependency.
46
+ - Validates `axtary.provenance.v0` field/source bindings and binds their
47
+ canonical hash into ActionPasses and ledger records.
48
+ - Persists the issuer ES256 keyring, publishes public JWKS by `kid`, and rotates
49
+ with bounded retired-key overlap.
50
+ - Verifies generic final SSF/CAEP `session-revoked` SETs and maps their explicit
51
+ subjects to live delegation roots without inventing provider support.
20
52
  - Verifies that a signed pass and any embedded approval evidence still match the exact action payload.
21
- - Records ledger entries with hashable decision evidence.
53
+ - Records ledger entries with hashable decision evidence and parent-to-child
54
+ delegation edges.
55
+ - Owns the provider-neutral native-connector governance descriptors used to
56
+ derive GitHub/Jira/Linear/Postgres/Google Drive capability metadata, normalized evidence dispatch, config
57
+ defaults, and doctor scope/smoke metadata without importing secret-bearing
58
+ adapter runtimes.
22
59
 
23
60
  ## Current Status
24
61
 
@@ -27,13 +64,44 @@ npm install @axtary/actionpass
27
64
  Before production use, Axtary still needs:
28
65
 
29
66
  - Stable schema versioning.
30
- - External signing-key management.
67
+ - External/HSM signing-key management.
31
68
  - Hosted approval queue integration.
32
69
  - External security review.
33
70
 
34
71
  The package builds to `dist/` and publishes JavaScript plus TypeScript declarations.
35
72
 
36
- ## Quickstart
73
+ ## SDK facade
74
+
75
+ For most callers the `axtary` facade is the simplest entry point: five verbs —
76
+ `authorize`, `verify`, `record`, `revoke`, `explain` — over a flat request
77
+ shape. It delegates to the lower-level functions below and adds no new
78
+ authorization logic.
79
+
80
+ ```ts
81
+ import { axtary } from "@axtary/actionpass";
82
+
83
+ const decision = await axtary.authorize({
84
+ agent: "codex-prod",
85
+ human: "user@company.com",
86
+ intent: "Open a PR for Linear issue AXT-418",
87
+ tool: "github.pull_requests.create",
88
+ resource: "repo:company/web-app",
89
+ payload,
90
+ });
91
+
92
+ if (decision.status === "allow") {
93
+ await github.createPullRequest(payload);
94
+ }
95
+ ```
96
+
97
+ With no signing key configured, the facade signs with a **persistent local dev
98
+ key** (`AXTARY_DEV_SIGNING_KEY`, else a `0600` keyring file under `.axtary/`), so
99
+ quickstart passes verify across restarts with zero key code. Call
100
+ `devKeypair()` to obtain that keypair explicitly, or
101
+ `createAxtary({ issuer, signingKey, verificationKey })` to use your own issuer
102
+ key in production. See the [SDK guide](https://docs.axtary.com/sdk).
103
+
104
+ ## Quickstart (low-level functions)
37
105
 
38
106
  This example runs as-is with Node 20+:
39
107
 
@@ -86,10 +154,24 @@ ActionPass is designed to fail closed:
86
154
  - Denied and step-up actions do not receive passes.
87
155
  - Verification rejects expired tokens.
88
156
  - Verification rejects revoked pass IDs.
157
+ - Delegation verification checks every root-to-leaf member against the same
158
+ revocation source; an ancestor revoke cascades to all descendants.
159
+ - Verification rejects when a configured revocation source cannot be queried;
160
+ it never treats source failure as an empty set.
89
161
  - Verification rejects payload hash mismatches.
90
162
  - Pass issuance rejects approval artifacts that were created for a different action or payload.
91
163
  - Keyring verification fails closed when the JWT `kid` is unknown.
92
- - The local trust store persists public verification JWKs only; signing keys should remain in KMS, env-managed dev secrets, or another controlled key custodian.
164
+ - The local trust store is atomically written with mode `0600`. It persists
165
+ public verification JWKs and local revocation records only; signing keys
166
+ should remain in KMS, env-managed dev secrets, or another controlled key
167
+ custodian.
168
+ - Local revocation records still rely on the trusted filesystem boundary.
169
+ ActionPass v2 additionally publishes signed freshness-bounded status evidence
170
+ for independent/multi-process verification.
93
171
  - Verification binds agent, human owner, runtime, task, tool, resource, and payload hash.
172
+ - V1 verification additionally requires the holder key, fresh proof target,
173
+ exact ActionPass hash, and one-time proof `jti`.
174
+ - V2 verification additionally requires authenticated fresh status evidence;
175
+ status-source failure or stale evidence blocks execution.
94
176
 
95
177
  Signing currently defaults to `ES256`.
package/dist/caep.d.ts ADDED
@@ -0,0 +1,89 @@
1
+ import { type CryptoKey, type JWK, type KeyObject } from "jose";
2
+ import { z } from "zod";
3
+ export declare const SSF_SET_TYP = "secevent+jwt";
4
+ export declare const CAEP_SESSION_REVOKED_EVENT = "https://schemas.openid.net/secevent/caep/event-type/session-revoked";
5
+ export declare const CAEP_MAPPING_STORE_VERSION = "axtary.caep_mapping_store.v0";
6
+ export declare const SSF_REPLAY_STORE_VERSION = "axtary.ssf_replay_store.v0";
7
+ export declare const SsfSubjectIdentifierSchema: z.ZodObject<{
8
+ format: z.ZodString;
9
+ }, z.core.$catchall<z.ZodType<string | number | boolean | Record<string, unknown> | unknown[] | null, unknown, z.core.$ZodTypeInternals<string | number | boolean | Record<string, unknown> | unknown[] | null, unknown>>>>;
10
+ export type SsfSubjectIdentifier = z.infer<typeof SsfSubjectIdentifierSchema>;
11
+ export declare const CaepSessionRevokedClaimsSchema: z.ZodObject<{
12
+ iss: z.ZodString;
13
+ aud: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>;
14
+ iat: z.ZodNumber;
15
+ jti: z.ZodString;
16
+ txn: z.ZodOptional<z.ZodString>;
17
+ sub_id: z.ZodObject<{
18
+ format: z.ZodString;
19
+ }, z.core.$catchall<z.ZodType<string | number | boolean | Record<string, unknown> | unknown[] | null, unknown, z.core.$ZodTypeInternals<string | number | boolean | Record<string, unknown> | unknown[] | null, unknown>>>>;
20
+ events: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodType<string | number | boolean | Record<string, unknown> | unknown[] | null, unknown, z.core.$ZodTypeInternals<string | number | boolean | Record<string, unknown> | unknown[] | null, unknown>>>>;
21
+ }, z.core.$strip>;
22
+ export type CaepSessionRevokedClaims = z.infer<typeof CaepSessionRevokedClaimsSchema>;
23
+ export declare const CaepMappingSchema: z.ZodObject<{
24
+ transmitterIssuer: z.ZodString;
25
+ subjectKey: z.ZodString;
26
+ rootPassIds: z.ZodArray<z.ZodString>;
27
+ createdAt: z.ZodString;
28
+ }, z.core.$strip>;
29
+ export type CaepMapping = z.infer<typeof CaepMappingSchema>;
30
+ export declare const CaepMappingStoreSchema: z.ZodObject<{
31
+ schemaVersion: z.ZodLiteral<"axtary.caep_mapping_store.v0">;
32
+ mappings: z.ZodArray<z.ZodObject<{
33
+ transmitterIssuer: z.ZodString;
34
+ subjectKey: z.ZodString;
35
+ rootPassIds: z.ZodArray<z.ZodString>;
36
+ createdAt: z.ZodString;
37
+ }, z.core.$strip>>;
38
+ }, z.core.$strip>;
39
+ export type CaepMappingStoreData = z.infer<typeof CaepMappingStoreSchema>;
40
+ export declare function ssfSubjectKey(subjectInput: SsfSubjectIdentifier): string;
41
+ export declare function verifyCaepSessionRevoked(input: {
42
+ token: string;
43
+ issuer: string;
44
+ audience: string;
45
+ verificationKeys?: Readonly<Record<string, JWK | KeyObject | CryptoKey | Uint8Array>> | ((kid: string | undefined) => JWK | KeyObject | CryptoKey | Uint8Array | undefined | Promise<JWK | KeyObject | CryptoKey | Uint8Array | undefined>);
46
+ jwksUri?: string;
47
+ currentDate?: Date;
48
+ maxAgeSeconds?: number;
49
+ }): Promise<CaepSessionRevokedClaims>;
50
+ export declare class LocalCaepMappingStore {
51
+ readonly filePath: string;
52
+ constructor(filePath: string);
53
+ read(): Promise<CaepMappingStoreData>;
54
+ put(input: {
55
+ transmitterIssuer: string;
56
+ subject: SsfSubjectIdentifier;
57
+ rootPassIds: string[];
58
+ createdAt?: Date;
59
+ }): Promise<CaepMapping>;
60
+ rootsFor(transmitterIssuer: string, subject: SsfSubjectIdentifier): Promise<string[]>;
61
+ }
62
+ export declare class LocalSsfReplayStore {
63
+ readonly filePath: string;
64
+ constructor(filePath: string);
65
+ consume(issuer: string, eventId: string, now?: Date, retentionSeconds?: number): Promise<boolean>;
66
+ processOnce<T>(issuer: string, eventId: string, operation: () => Promise<T>, now?: Date, retentionSeconds?: number): Promise<{
67
+ processed: true;
68
+ result: T;
69
+ } | {
70
+ processed: false;
71
+ }>;
72
+ }
73
+ export declare function processCaepSessionRevoked(input: {
74
+ token: string;
75
+ issuer: string;
76
+ audience: string;
77
+ verificationKeys?: Readonly<Record<string, JWK | KeyObject | CryptoKey | Uint8Array>> | ((kid: string | undefined) => JWK | KeyObject | CryptoKey | Uint8Array | undefined | Promise<JWK | KeyObject | CryptoKey | Uint8Array | undefined>);
78
+ jwksUri?: string;
79
+ mappingStore: LocalCaepMappingStore;
80
+ replayStore: LocalSsfReplayStore;
81
+ revoke: (rootPassId: string, claims: CaepSessionRevokedClaims) => Promise<void>;
82
+ currentDate?: Date;
83
+ }): Promise<{
84
+ eventId: string;
85
+ subjectKey: string;
86
+ rootPassIds: string[];
87
+ status: "applied" | "unmapped" | "replayed";
88
+ }>;
89
+ //# sourceMappingURL=caep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caep.d.ts","sourceRoot":"","sources":["../src/caep.ts"],"names":[],"mappings":"AAIA,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,GAAG,EAER,KAAK,SAAS,EACf,MAAM,MAAM,CAAC;AAEd,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,WAAW,iBAAiB,CAAC;AAC1C,eAAO,MAAM,0BAA0B,wEACgC,CAAC;AACxE,eAAO,MAAM,0BAA0B,iCAAiC,CAAC;AACzE,eAAO,MAAM,wBAAwB,+BAA+B,CAAC;AAerE,eAAO,MAAM,0BAA0B;;2NAIX,CAAC;AAC7B,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E,eAAO,MAAM,8BAA8B;;;;;;;;;;iBAQzC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAC5C,OAAO,8BAA8B,CACtC,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,sBAAsB;;;;;;;;iBAGjC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAY1E,wBAAgB,aAAa,CAAC,YAAY,EAAE,oBAAoB,GAAG,MAAM,CAExE;AAED,wBAAsB,wBAAwB,CAAC,KAAK,EAAE;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EACb,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC,CAAC,GAClE,CAAC,CACC,GAAG,EAAE,MAAM,GAAG,SAAS,KAErB,GAAG,GACH,SAAS,GACT,SAAS,GACT,UAAU,GACV,SAAS,GACT,OAAO,CAAC,GAAG,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CA0CpC;AAED,qBAAa,qBAAqB;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM;gBAAhB,QAAQ,EAAE,MAAM;IAE/B,IAAI,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAarC,GAAG,CAAC,KAAK,EAAE;QACf,iBAAiB,EAAE,MAAM,CAAC;QAC1B,OAAO,EAAE,oBAAoB,CAAC;QAC9B,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,SAAS,CAAC,EAAE,IAAI,CAAC;KAClB,GAAG,OAAO,CAAC,WAAW,CAAC;IA8BlB,QAAQ,CACZ,iBAAiB,EAAE,MAAM,EACzB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC;CAUrB;AAED,qBAAa,mBAAmB;IAClB,QAAQ,CAAC,QAAQ,EAAE,MAAM;gBAAhB,QAAQ,EAAE,MAAM;IAE/B,OAAO,CACX,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,GAAG,OAAa,EAChB,gBAAgB,SAAS,GACxB,OAAO,CAAC,OAAO,CAAC;IAYb,WAAW,CAAC,CAAC,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,GAAG,OAAa,EAChB,gBAAgB,SAAS,GACxB,OAAO,CAAC;QAAE,SAAS,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,CAAC,CAAA;KAAE,GAAG;QAAE,SAAS,EAAE,KAAK,CAAA;KAAE,CAAC;CAoClE;AAED,wBAAsB,yBAAyB,CAAC,KAAK,EAAE;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EACb,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC,CAAC,GAClE,CAAC,CACC,GAAG,EAAE,MAAM,GAAG,SAAS,KAErB,GAAG,GACH,SAAS,GACT,SAAS,GACT,UAAU,GACV,SAAS,GACT,OAAO,CAAC,GAAG,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,qBAAqB,CAAC;IACpC,WAAW,EAAE,mBAAmB,CAAC;IACjC,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,wBAAwB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB,GAAG,OAAO,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;CAC7C,CAAC,CAgCD"}
package/dist/caep.js ADDED
@@ -0,0 +1,258 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdir, open, readFile, rename, rm } from "node:fs/promises";
3
+ import { dirname } from "node:path";
4
+ import { createRemoteJWKSet, decodeProtectedHeader, jwtVerify, } from "jose";
5
+ import { lock } from "proper-lockfile";
6
+ import { z } from "zod";
7
+ export const SSF_SET_TYP = "secevent+jwt";
8
+ export const CAEP_SESSION_REVOKED_EVENT = "https://schemas.openid.net/secevent/caep/event-type/session-revoked";
9
+ export const CAEP_MAPPING_STORE_VERSION = "axtary.caep_mapping_store.v0";
10
+ export const SSF_REPLAY_STORE_VERSION = "axtary.ssf_replay_store.v0";
11
+ const JsonValueSchema = z.lazy(() => z.union([
12
+ z.string(),
13
+ z.number(),
14
+ z.boolean(),
15
+ z.null(),
16
+ z.array(JsonValueSchema),
17
+ z.record(z.string(), JsonValueSchema),
18
+ ]));
19
+ export const SsfSubjectIdentifierSchema = z
20
+ .object({
21
+ format: z.string().min(1),
22
+ })
23
+ .catchall(JsonValueSchema);
24
+ export const CaepSessionRevokedClaimsSchema = z.object({
25
+ iss: z.string().url(),
26
+ aud: z.union([z.string().min(1), z.array(z.string().min(1))]),
27
+ iat: z.number().int().positive(),
28
+ jti: z.string().min(1),
29
+ txn: z.string().min(1).optional(),
30
+ sub_id: SsfSubjectIdentifierSchema,
31
+ events: z.record(z.string(), z.record(z.string(), JsonValueSchema)),
32
+ });
33
+ export const CaepMappingSchema = z.object({
34
+ transmitterIssuer: z.string().url(),
35
+ subjectKey: z.string().min(1),
36
+ rootPassIds: z.array(z.string().min(1)).min(1),
37
+ createdAt: z.string().datetime(),
38
+ });
39
+ export const CaepMappingStoreSchema = z.object({
40
+ schemaVersion: z.literal(CAEP_MAPPING_STORE_VERSION),
41
+ mappings: z.array(CaepMappingSchema),
42
+ });
43
+ const SsfReplayEntrySchema = z.object({
44
+ issuer: z.string().url(),
45
+ eventId: z.string().min(1),
46
+ expiresAt: z.string().datetime(),
47
+ });
48
+ const SsfReplayStoreSchema = z.object({
49
+ schemaVersion: z.literal(SSF_REPLAY_STORE_VERSION),
50
+ entries: z.array(SsfReplayEntrySchema),
51
+ });
52
+ export function ssfSubjectKey(subjectInput) {
53
+ return stableStringify(SsfSubjectIdentifierSchema.parse(subjectInput));
54
+ }
55
+ export async function verifyCaepSessionRevoked(input) {
56
+ const header = decodeProtectedHeader(input.token);
57
+ if (header.typ !== SSF_SET_TYP) {
58
+ throw new Error("ssf_set_type_invalid");
59
+ }
60
+ const localKey = input.jwksUri
61
+ ? undefined
62
+ : await resolveKey(input.verificationKeys, header.kid);
63
+ if (!input.jwksUri && !localKey) {
64
+ throw new Error(header.kid
65
+ ? `ssf_verification_key_not_found:${header.kid}`
66
+ : "ssf_verification_key_id_required");
67
+ }
68
+ const currentDate = input.currentDate ?? new Date();
69
+ const verifyOptions = {
70
+ issuer: input.issuer,
71
+ audience: input.audience,
72
+ algorithms: ["ES256"],
73
+ currentDate,
74
+ };
75
+ const { payload } = input.jwksUri
76
+ ? await jwtVerify(input.token, createRemoteJWKSet(new URL(input.jwksUri)), verifyOptions)
77
+ : await jwtVerify(input.token, localKey, verifyOptions);
78
+ const claims = CaepSessionRevokedClaimsSchema.parse(payload);
79
+ const ageSeconds = Math.floor(currentDate.getTime() / 1000) - claims.iat;
80
+ if (ageSeconds < -5 || ageSeconds > (input.maxAgeSeconds ?? 300)) {
81
+ throw new Error("ssf_set_outside_accepted_window");
82
+ }
83
+ const eventKeys = Object.keys(claims.events);
84
+ if (eventKeys.length !== 1 ||
85
+ eventKeys[0] !== CAEP_SESSION_REVOKED_EVENT) {
86
+ throw new Error("caep_event_type_unsupported");
87
+ }
88
+ return claims;
89
+ }
90
+ export class LocalCaepMappingStore {
91
+ filePath;
92
+ constructor(filePath) {
93
+ this.filePath = filePath;
94
+ }
95
+ async read() {
96
+ try {
97
+ return CaepMappingStoreSchema.parse(JSON.parse(await readFile(this.filePath, "utf8")));
98
+ }
99
+ catch (error) {
100
+ if (isEnoent(error)) {
101
+ return { schemaVersion: CAEP_MAPPING_STORE_VERSION, mappings: [] };
102
+ }
103
+ throw error;
104
+ }
105
+ }
106
+ async put(input) {
107
+ const mapping = CaepMappingSchema.parse({
108
+ transmitterIssuer: input.transmitterIssuer,
109
+ subjectKey: ssfSubjectKey(input.subject),
110
+ rootPassIds: [...new Set(input.rootPassIds)].sort(),
111
+ createdAt: (input.createdAt ?? new Date()).toISOString(),
112
+ });
113
+ await withFileLock(this.filePath, async () => {
114
+ const data = await this.read();
115
+ await writePrivateJson(this.filePath, {
116
+ ...data,
117
+ mappings: [
118
+ ...data.mappings.filter((entry) => !(entry.transmitterIssuer === mapping.transmitterIssuer &&
119
+ entry.subjectKey === mapping.subjectKey)),
120
+ mapping,
121
+ ].sort((left, right) => `${left.transmitterIssuer}:${left.subjectKey}`.localeCompare(`${right.transmitterIssuer}:${right.subjectKey}`)),
122
+ });
123
+ });
124
+ return mapping;
125
+ }
126
+ async rootsFor(transmitterIssuer, subject) {
127
+ const key = ssfSubjectKey(subject);
128
+ return ((await this.read()).mappings.find((entry) => entry.transmitterIssuer === transmitterIssuer &&
129
+ entry.subjectKey === key)?.rootPassIds ?? []);
130
+ }
131
+ }
132
+ export class LocalSsfReplayStore {
133
+ filePath;
134
+ constructor(filePath) {
135
+ this.filePath = filePath;
136
+ }
137
+ async consume(issuer, eventId, now = new Date(), retentionSeconds = 86_400) {
138
+ return (await this.processOnce(issuer, eventId, async () => undefined, now, retentionSeconds)).processed;
139
+ }
140
+ async processOnce(issuer, eventId, operation, now = new Date(), retentionSeconds = 86_400) {
141
+ return withFileLock(this.filePath, async () => {
142
+ let data;
143
+ try {
144
+ data = SsfReplayStoreSchema.parse(JSON.parse(await readFile(this.filePath, "utf8")));
145
+ }
146
+ catch (error) {
147
+ if (!isEnoent(error))
148
+ throw error;
149
+ data = { schemaVersion: SSF_REPLAY_STORE_VERSION, entries: [] };
150
+ }
151
+ const live = data.entries.filter((entry) => Date.parse(entry.expiresAt) > now.getTime());
152
+ if (live.some((entry) => entry.issuer === issuer && entry.eventId === eventId)) {
153
+ return { processed: false };
154
+ }
155
+ const result = await operation();
156
+ live.push({
157
+ issuer,
158
+ eventId,
159
+ expiresAt: new Date(now.getTime() + retentionSeconds * 1000).toISOString(),
160
+ });
161
+ await writePrivateJson(this.filePath, {
162
+ schemaVersion: SSF_REPLAY_STORE_VERSION,
163
+ entries: live,
164
+ });
165
+ return { processed: true, result };
166
+ });
167
+ }
168
+ }
169
+ export async function processCaepSessionRevoked(input) {
170
+ const claims = await verifyCaepSessionRevoked(input);
171
+ const processed = await input.replayStore.processOnce(claims.iss, claims.jti, async () => {
172
+ const rootPassIds = await input.mappingStore.rootsFor(claims.iss, claims.sub_id);
173
+ for (const rootPassId of rootPassIds) {
174
+ await input.revoke(rootPassId, claims);
175
+ }
176
+ return rootPassIds;
177
+ }, input.currentDate);
178
+ if (!processed.processed) {
179
+ return {
180
+ eventId: claims.jti,
181
+ subjectKey: ssfSubjectKey(claims.sub_id),
182
+ rootPassIds: [],
183
+ status: "replayed",
184
+ };
185
+ }
186
+ const rootPassIds = processed.result;
187
+ return {
188
+ eventId: claims.jti,
189
+ subjectKey: ssfSubjectKey(claims.sub_id),
190
+ rootPassIds,
191
+ status: rootPassIds.length > 0 ? "applied" : "unmapped",
192
+ };
193
+ }
194
+ async function resolveKey(keys, kid) {
195
+ if (!keys)
196
+ return undefined;
197
+ return typeof keys === "function" ? keys(kid) : kid ? keys[kid] : undefined;
198
+ }
199
+ async function writePrivateJson(filePath, value) {
200
+ await mkdir(dirname(filePath), { recursive: true });
201
+ const tmpPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
202
+ let renamed = false;
203
+ try {
204
+ const handle = await open(tmpPath, "wx", 0o600);
205
+ try {
206
+ await handle.writeFile(`${JSON.stringify(value, null, 2)}\n`, "utf8");
207
+ await handle.sync();
208
+ }
209
+ finally {
210
+ await handle.close();
211
+ }
212
+ await rename(tmpPath, filePath);
213
+ renamed = true;
214
+ }
215
+ finally {
216
+ if (!renamed)
217
+ await rm(tmpPath, { force: true });
218
+ }
219
+ }
220
+ async function withFileLock(filePath, operation) {
221
+ await mkdir(dirname(filePath), { recursive: true });
222
+ const release = await lock(filePath, {
223
+ realpath: false,
224
+ lockfilePath: `${filePath}.lock`,
225
+ stale: 10_000,
226
+ update: 5_000,
227
+ retries: {
228
+ retries: 100,
229
+ factor: 1.2,
230
+ minTimeout: 10,
231
+ maxTimeout: 100,
232
+ },
233
+ });
234
+ try {
235
+ return await operation();
236
+ }
237
+ finally {
238
+ await release();
239
+ }
240
+ }
241
+ function stableStringify(value) {
242
+ if (Array.isArray(value)) {
243
+ return `[${value.map(stableStringify).join(",")}]`;
244
+ }
245
+ if (value && typeof value === "object") {
246
+ return `{${Object.entries(value)
247
+ .sort(([left], [right]) => left.localeCompare(right))
248
+ .map(([key, entry]) => `${JSON.stringify(key)}:${stableStringify(entry)}`)
249
+ .join(",")}}`;
250
+ }
251
+ return JSON.stringify(value);
252
+ }
253
+ function isEnoent(error) {
254
+ return (error instanceof Error &&
255
+ "code" in error &&
256
+ error.code === "ENOENT");
257
+ }
258
+ //# sourceMappingURL=caep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caep.js","sourceRoot":"","sources":["../src/caep.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,SAAS,GAKV,MAAM,MAAM,CAAC;AACd,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,WAAW,GAAG,cAAc,CAAC;AAC1C,MAAM,CAAC,MAAM,0BAA0B,GACrC,qEAAqE,CAAC;AACxE,MAAM,CAAC,MAAM,0BAA0B,GAAG,8BAA8B,CAAC;AACzE,MAAM,CAAC,MAAM,wBAAwB,GAAG,4BAA4B,CAAC;AAErE,MAAM,eAAe,GAEjB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CACd,CAAC,CAAC,KAAK,CAAC;IACN,CAAC,CAAC,MAAM,EAAE;IACV,CAAC,CAAC,MAAM,EAAE;IACV,CAAC,CAAC,OAAO,EAAE;IACX,CAAC,CAAC,IAAI,EAAE;IACR,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC;IACxB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC;CACtC,CAAC,CACH,CAAC;AAEF,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC;KACxC,MAAM,CAAC;IACN,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC1B,CAAC;KACD,QAAQ,CAAC,eAAe,CAAC,CAAC;AAG7B,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,CAAC,MAAM,CAAC;IACrD,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACrB,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAChC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACjC,MAAM,EAAE,0BAA0B;IAClC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC;CACpE,CAAC,CAAC;AAKH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACnC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7B,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,0BAA0B,CAAC;IACpD,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC;CACrC,CAAC,CAAC;AAGH,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACxB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC;AACH,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAAC;IAClD,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;CACvC,CAAC,CAAC;AAEH,MAAM,UAAU,aAAa,CAAC,YAAkC;IAC9D,OAAO,eAAe,CAAC,0BAA0B,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,KAkB9C;IACC,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,MAAM,CAAC,GAAG,KAAK,WAAW,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO;QAC5B,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,MAAM,UAAU,CAAC,KAAK,CAAC,gBAAgB,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IACzD,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CACb,MAAM,CAAC,GAAG;YACR,CAAC,CAAC,kCAAkC,MAAM,CAAC,GAAG,EAAE;YAChD,CAAC,CAAC,kCAAkC,CACvC,CAAC;IACJ,CAAC;IACD,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,IAAI,IAAI,EAAE,CAAC;IACpD,MAAM,aAAa,GAAqB;QACtC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,UAAU,EAAE,CAAC,OAAO,CAAC;QACrB,WAAW;KACZ,CAAC;IACF,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO;QAC/B,CAAC,CAAC,MAAM,SAAS,CACb,KAAK,CAAC,KAAK,EACX,kBAAkB,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAC1C,aAAa,CACd;QACH,CAAC,CAAC,MAAM,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,QAAS,EAAE,aAAa,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,8BAA8B,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC;IACzE,IAAI,UAAU,GAAG,CAAC,CAAC,IAAI,UAAU,GAAG,CAAC,KAAK,CAAC,aAAa,IAAI,GAAG,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7C,IACE,SAAS,CAAC,MAAM,KAAK,CAAC;QACtB,SAAS,CAAC,CAAC,CAAC,KAAK,0BAA0B,EAC3C,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,OAAO,qBAAqB;IACX;IAArB,YAAqB,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;IAAG,CAAC;IAEzC,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,OAAO,sBAAsB,CAAC,KAAK,CACjC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAClD,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpB,OAAO,EAAE,aAAa,EAAE,0BAA0B,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;YACrE,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAKT;QACC,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,CAAC;YACtC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;YAC1C,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC;YACxC,WAAW,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE;YACnD,SAAS,EAAE,CAAC,KAAK,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE;SACzD,CAAC,CAAC;QACH,MAAM,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;YAC3C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YAC/B,MAAM,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE;gBACpC,GAAG,IAAI;gBACP,QAAQ,EAAE;oBACR,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CACrB,CAAC,KAAK,EAAE,EAAE,CACR,CAAC,CACC,KAAK,CAAC,iBAAiB,KAAK,OAAO,CAAC,iBAAiB;wBACrD,KAAK,CAAC,UAAU,KAAK,OAAO,CAAC,UAAU,CACxC,CACJ;oBACD,OAAO;iBACR,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CACrB,GAAG,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC,aAAa,CAC1D,GAAG,KAAK,CAAC,iBAAiB,IAAI,KAAK,CAAC,UAAU,EAAE,CACjD,CACF;aACF,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,QAAQ,CACZ,iBAAyB,EACzB,OAA6B;QAE7B,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QACnC,OAAO,CACL,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAC/B,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,iBAAiB,KAAK,iBAAiB;YAC7C,KAAK,CAAC,UAAU,KAAK,GAAG,CAC3B,EAAE,WAAW,IAAI,EAAE,CACrB,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,mBAAmB;IACT;IAArB,YAAqB,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;IAAG,CAAC;IAEzC,KAAK,CAAC,OAAO,CACX,MAAc,EACd,OAAe,EACf,GAAG,GAAG,IAAI,IAAI,EAAE,EAChB,gBAAgB,GAAG,MAAM;QAEzB,OAAO,CACL,MAAM,IAAI,CAAC,WAAW,CACpB,MAAM,EACN,OAAO,EACP,KAAK,IAAI,EAAE,CAAC,SAAS,EACrB,GAAG,EACH,gBAAgB,CACjB,CACF,CAAC,SAAS,CAAC;IACd,CAAC;IAED,KAAK,CAAC,WAAW,CACf,MAAc,EACd,OAAe,EACf,SAA2B,EAC3B,GAAG,GAAG,IAAI,IAAI,EAAE,EAChB,gBAAgB,GAAG,MAAM;QAEzB,OAAO,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;YAC5C,IAAI,IAA0C,CAAC;YAC/C,IAAI,CAAC;gBACH,IAAI,GAAG,oBAAoB,CAAC,KAAK,CAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAClD,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;oBAAE,MAAM,KAAK,CAAC;gBAClC,IAAI,GAAG,EAAE,aAAa,EAAE,wBAAwB,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YAClE,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAC9B,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,OAAO,EAAE,CACvD,CAAC;YACF,IACE,IAAI,CAAC,IAAI,CACP,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,CAChE,EACD,CAAC;gBACD,OAAO,EAAE,SAAS,EAAE,KAAc,EAAE,CAAC;YACvC,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC;gBACR,MAAM;gBACN,OAAO;gBACP,SAAS,EAAE,IAAI,IAAI,CACjB,GAAG,CAAC,OAAO,EAAE,GAAG,gBAAgB,GAAG,IAAI,CACxC,CAAC,WAAW,EAAE;aAChB,CAAC,CAAC;YACH,MAAM,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE;gBACpC,aAAa,EAAE,wBAAwB;gBACvC,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;YACH,OAAO,EAAE,SAAS,EAAE,IAAa,EAAE,MAAM,EAAE,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,KAoB/C;IAMC,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAAC,KAAK,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,WAAW,CACnD,MAAM,CAAC,GAAG,EACV,MAAM,CAAC,GAAG,EACV,KAAK,IAAI,EAAE;QACT,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,QAAQ,CACnD,MAAM,CAAC,GAAG,EACV,MAAM,CAAC,MAAM,CACd,CAAC;QACF,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;YACrC,MAAM,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC,EACD,KAAK,CAAC,WAAW,CAClB,CAAC;IACF,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;QACzB,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,GAAG;YACnB,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC;YACxC,WAAW,EAAE,EAAE;YACf,MAAM,EAAE,UAAU;SACnB,CAAC;IACJ,CAAC;IACD,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC;IACrC,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,GAAG;QACnB,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC;QACxC,WAAW;QACX,MAAM,EAAE,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU;KACxD,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,IAWa,EACb,GAAuB;IAEvB,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,OAAO,OAAO,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9E,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,QAAgB,EAAE,KAAc;IAC9D,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,GAAG,QAAQ,IAAI,OAAO,CAAC,GAAG,IAAI,UAAU,EAAE,MAAM,CAAC;IACjE,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAChD,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACtE,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACtB,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QACD,MAAM,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAChC,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,OAAO;YAAE,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,QAAgB,EAChB,SAA2B;IAE3B,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE;QACnC,QAAQ,EAAE,KAAK;QACf,YAAY,EAAE,GAAG,QAAQ,OAAO;QAChC,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,KAAK;QACb,OAAO,EAAE;YACP,OAAO,EAAE,GAAG;YACZ,MAAM,EAAE,GAAG;YACX,UAAU,EAAE,EAAE;YACd,UAAU,EAAE,GAAG;SAChB;KACF,CAAC,CAAC;IACH,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,EAAE,CAAC;IAC3B,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IACrD,CAAC;IACD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;aACxD,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;aACpD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;aACzE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,CACL,KAAK,YAAY,KAAK;QACtB,MAAM,IAAI,KAAK;QACd,KAA+B,CAAC,IAAI,KAAK,QAAQ,CACnD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { type JWK, type KeyObject } from "jose";
2
+ /** Env var holding an ES256 private key (PEM, or base64-encoded PEM). */
3
+ export declare const AXTARY_DEV_SIGNING_KEY_ENV = "AXTARY_DEV_SIGNING_KEY";
4
+ /** Optional env var overriding the dev key id (`kid`). */
5
+ export declare const AXTARY_DEV_KEY_ID_ENV = "AXTARY_DEV_KEY_ID";
6
+ /** Env var pointing the local keyring at a directory other than ./.axtary. */
7
+ export declare const AXTARY_HOME_ENV = "AXTARY_HOME";
8
+ /** Filename of the file-backed dev keyring inside the resolved home dir. */
9
+ export declare const AXTARY_DEV_KEYRING_FILENAME = "sdk-dev-keyring.json";
10
+ /** Default `kid` for an env-backed dev key when none is supplied. */
11
+ export declare const AXTARY_DEFAULT_DEV_KEY_ID = "axtary-dev";
12
+ export type DevKeypairSource = "env" | "file";
13
+ export type DevKeypair = {
14
+ /** ES256 private key, ready to pass to createAxtary({ signingKey }). */
15
+ signingKey: KeyObject;
16
+ /** Matching public JWK, used by verify(). */
17
+ verificationKey: JWK;
18
+ /** Key id stamped into issued passes (`kid`). */
19
+ signingKeyId: string;
20
+ algorithm: "ES256";
21
+ /** Where the key came from: an env var or the local keyring file. */
22
+ source: DevKeypairSource;
23
+ /** Keyring file path when source === "file"; omitted for env-backed keys. */
24
+ path?: string;
25
+ };
26
+ export type DevKeypairOptions = {
27
+ /** Override the keyring file path (file-backed source). */
28
+ path?: string;
29
+ /** Environment to read; defaults to process.env. */
30
+ env?: Record<string, string | undefined>;
31
+ };
32
+ /**
33
+ * Resolve the file-backed dev keyring path: an explicit override, else
34
+ * `$AXTARY_HOME/sdk-dev-keyring.json`, else project-local
35
+ * `.axtary/sdk-dev-keyring.json`.
36
+ */
37
+ export declare function resolveDevKeyringPath(options?: DevKeypairOptions): string;
38
+ /**
39
+ * Resolve a stable, persistent ES256 dev keypair with zero manual JWK code.
40
+ * Resolution order: AXTARY_DEV_SIGNING_KEY (env-backed, shared across
41
+ * processes) → a local keyring file (default `.axtary/sdk-dev-keyring.json`,
42
+ * `0600`, gitignored). Both verify across process restarts. Pass the result
43
+ * straight to the SDK: `createAxtary(await devKeypair())`.
44
+ *
45
+ * This is a development convenience. For production use a real issuer key or a
46
+ * hosted issuer; the file-backed key never leaves the machine and the env-backed
47
+ * key is whatever the operator provisions.
48
+ */
49
+ export declare function devKeypair(options?: DevKeypairOptions): Promise<DevKeypair>;
50
+ //# sourceMappingURL=dev-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-key.d.ts","sourceRoot":"","sources":["../src/dev-key.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAa,KAAK,GAAG,EAAE,KAAK,SAAS,EAAE,MAAM,MAAM,CAAC;AAG3D,yEAAyE;AACzE,eAAO,MAAM,0BAA0B,2BAA2B,CAAC;AACnE,0DAA0D;AAC1D,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AACzD,8EAA8E;AAC9E,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,4EAA4E;AAC5E,eAAO,MAAM,2BAA2B,yBAAyB,CAAC;AAClE,qEAAqE;AACrE,eAAO,MAAM,yBAAyB,eAAe,CAAC;AAEtD,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,MAAM,CAAC;AAE9C,MAAM,MAAM,UAAU,GAAG;IACvB,wEAAwE;IACxE,UAAU,EAAE,SAAS,CAAC;IACtB,6CAA6C;IAC7C,eAAe,EAAE,GAAG,CAAC;IACrB,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,qEAAqE;IACrE,MAAM,EAAE,gBAAgB,CAAC;IACzB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC1C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAU7E;AAgCD;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAC9B,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,UAAU,CAAC,CAkBrB"}