@atlasauth/backend 0.1.7 → 0.4.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.
@@ -1,30 +1,235 @@
1
1
  import { type RequestFn } from './request';
2
2
  /**
3
- * §BYOK messaging provider config — wire the tenant's own email/SMS provider
4
- * (Resend/SES/SMTP/Brevo/Mailgun, Twilio) over the secret-key BAPI.
3
+ * Messaging providers — wire your own email or SMS provider (Resend, SES, SMTP,
4
+ * Brevo, Mailgun; Twilio, Vonage, MessageBird, Plivo, Telnyx, Sinch, Infobip,
5
+ * ClickSend, Bandwidth, AWS SNS) over the secret-key Backend API.
6
+ *
7
+ * Each transport accepts an exact set of `config` keys; the API refuses an
8
+ * unknown key with a 422 naming `config.<key>`. These types mirror that schema,
9
+ * so a typo or another provider's key name fails to compile.
5
10
  *
6
11
  * A provider SECRET is WRITE-ONLY: it goes in through `config` and is never
7
12
  * read back — a response reports only WHICH secret keys are set (`secrets_set`).
8
- * Omit a secret on an edit to keep the stored one (so a from-address change need
9
- * not re-enter the API key).
13
+ *
14
+ * Required keys: every key marked "Required on first setup" must be sent the
15
+ * first time you configure a transport (or when you switch the channel to a
16
+ * different transport). When you update the SAME transport, the stored config is
17
+ * kept: omit a key — or send it as `''` — and its stored value (including a
18
+ * stored secret) stays. So a from-address change need not re-enter the API key.
10
19
  */
11
- export interface MessagingProvider {
12
- object: 'messaging_provider';
13
- channel: 'email' | 'sms';
14
- transport: string;
15
- from_address: string | null;
16
- status: string;
17
- /** Non-secret config only — secret values are stripped before serialising. */
18
- config: Record<string, unknown>;
19
- /** Which secret keys are set for this transport, never their values. */
20
- secrets_set: Record<string, boolean>;
21
- updated_at: number;
20
+ /** Email transports accepted by `PUT /v1/messaging_providers/email`. */
21
+ export type EmailTransport = 'resend' | 'ses' | 'smtp' | 'brevo' | 'mailgun';
22
+ /** SMS transports accepted by `PUT /v1/messaging_providers/sms`. */
23
+ export type SmsTransport = 'twilio' | 'vonage' | 'messagebird' | 'plivo' | 'telnyx' | 'sinch' | 'infobip' | 'clicksend' | 'bandwidth' | 'aws_sns';
24
+ export type MessagingTransport = EmailTransport | SmsTransport;
25
+ /** Sender number or ID for an SMS provider. `from_address` on the request takes precedence. */
26
+ interface SmsFrom {
27
+ /** Sender number or ID for this provider. Optional; `from_address` on the request takes precedence. */
28
+ from?: string;
22
29
  }
23
- export interface MessagingProviders {
24
- object: 'messaging_providers';
25
- email: MessagingProvider | null;
26
- sms: MessagingProvider | null;
30
+ /** Resend. */
31
+ export interface ResendConfig {
32
+ /** Resend API key (`re_…`). Required on first setup. Write-only: never returned. */
33
+ api_key: string;
34
+ }
35
+ /** Brevo. */
36
+ export interface BrevoConfig {
37
+ /** Brevo API key (`xkeysib-…`). Required on first setup. Write-only: never returned. */
38
+ api_key: string;
39
+ }
40
+ /** Mailgun. */
41
+ export interface MailgunConfig {
42
+ /** Mailgun private API key. Required on first setup. Write-only: never returned. */
43
+ api_key: string;
44
+ /** Your Mailgun sending domain, e.g. `mg.example.com`. Required on first setup. */
45
+ domain: string;
46
+ /** Mailgun region. Default `us`. */
47
+ region?: 'us' | 'eu';
48
+ }
49
+ /** Amazon SES. */
50
+ export interface SesConfig {
51
+ /** AWS region, e.g. `us-east-1`. Required on first setup. */
52
+ region: string;
53
+ /** IAM access key ID. Required on first setup. Write-only: never returned. */
54
+ access_key_id: string;
55
+ /** IAM secret access key. Required on first setup. Write-only: never returned. */
56
+ secret_access_key: string;
57
+ /** STS session token, only for temporary credentials. Write-only: never returned. */
58
+ session_token?: string;
59
+ }
60
+ /** Any SMTP server. */
61
+ export interface SmtpConfig {
62
+ /** SMTP server hostname, e.g. `smtp.example.com`. Required on first setup. */
63
+ host: string;
64
+ /** SMTP port (1-65535). Default 587. */
65
+ port?: number;
66
+ /** Use implicit TLS. Default: `true` on port 465, otherwise STARTTLS. */
67
+ secure?: boolean;
68
+ /** SMTP username, if the server requires authentication. */
69
+ username?: string;
70
+ /** SMTP password or app password. Write-only: never returned. */
71
+ password?: string;
72
+ }
73
+ /** Twilio. */
74
+ export interface TwilioConfig extends SmsFrom {
75
+ /** Twilio Account SID (`AC…`). Required on first setup. */
76
+ account_sid: string;
77
+ /** Twilio auth token. Required on first setup. Write-only: never returned. */
78
+ auth_token: string;
79
+ /** WhatsApp-enabled sender number, for the WhatsApp channel. */
80
+ whatsapp_from?: string;
81
+ /** Voice-capable number, for the voice channel. */
82
+ voice_from?: string;
83
+ }
84
+ /** Vonage. */
85
+ export interface VonageConfig extends SmsFrom {
86
+ /** Vonage API key. Required on first setup. */
87
+ api_key: string;
88
+ /** Vonage API secret. Required on first setup. Write-only: never returned. */
89
+ api_secret: string;
90
+ }
91
+ /** MessageBird (Bird). */
92
+ export interface MessagebirdConfig extends SmsFrom {
93
+ /** MessageBird (Bird) access key. Required on first setup. Write-only: never returned. */
94
+ access_key: string;
95
+ }
96
+ /** Plivo. */
97
+ export interface PlivoConfig extends SmsFrom {
98
+ /** Plivo Auth ID. Required on first setup. */
99
+ auth_id: string;
100
+ /** Plivo auth token. Required on first setup. Write-only: never returned. */
101
+ auth_token: string;
102
+ }
103
+ /** Telnyx. */
104
+ export interface TelnyxConfig extends SmsFrom {
105
+ /** Telnyx API key. Required on first setup. Write-only: never returned. */
106
+ api_key: string;
107
+ }
108
+ /** Sinch. */
109
+ export interface SinchConfig extends SmsFrom {
110
+ /** Sinch service plan ID. Required on first setup. */
111
+ service_plan_id: string;
112
+ /** Sinch API token. Required on first setup. Write-only: never returned. */
113
+ api_token: string;
114
+ /** Sinch API region, a short lowercase code such as `us` or `eu`. Default `us`. */
115
+ region?: string;
116
+ }
117
+ /** Infobip. */
118
+ export interface InfobipConfig extends SmsFrom {
119
+ /** Your Infobip base URL, e.g. `https://xxxxx.api.infobip.com`. Must be https. Required on first setup. */
120
+ base_url: string;
121
+ /** Infobip API key. Required on first setup. Write-only: never returned. */
122
+ api_key: string;
123
+ }
124
+ /** ClickSend. */
125
+ export interface ClicksendConfig extends SmsFrom {
126
+ /** ClickSend username (your login email). Required on first setup. */
127
+ username: string;
128
+ /** ClickSend API key. Required on first setup. Write-only: never returned. */
129
+ api_key: string;
130
+ }
131
+ /** Bandwidth. */
132
+ export interface BandwidthConfig extends SmsFrom {
133
+ /** Bandwidth account ID. Required on first setup. */
134
+ account_id: string;
135
+ /** Bandwidth messaging application ID. Required on first setup. */
136
+ application_id: string;
137
+ /** Bandwidth API username. Required on first setup. */
138
+ username: string;
139
+ /** Bandwidth API password. Required on first setup. Write-only: never returned. */
140
+ password: string;
141
+ }
142
+ /** Amazon SNS. */
143
+ export interface AwsSnsConfig extends SmsFrom {
144
+ /** AWS region, e.g. `us-east-1`. Required on first setup. */
145
+ region: string;
146
+ /** IAM access key ID. Required on first setup. */
147
+ access_key_id: string;
148
+ /** IAM secret access key. Required on first setup. Write-only: never returned. */
149
+ secret_access_key: string;
150
+ /** STS session token, only for temporary credentials. Write-only: never returned. */
151
+ session_token?: string;
152
+ }
153
+ /** The `config` shape for each transport, keyed by transport. */
154
+ export interface MessagingTransportConfigs {
155
+ resend: ResendConfig;
156
+ ses: SesConfig;
157
+ smtp: SmtpConfig;
158
+ brevo: BrevoConfig;
159
+ mailgun: MailgunConfig;
160
+ twilio: TwilioConfig;
161
+ vonage: VonageConfig;
162
+ messagebird: MessagebirdConfig;
163
+ plivo: PlivoConfig;
164
+ telnyx: TelnyxConfig;
165
+ sinch: SinchConfig;
166
+ infobip: InfobipConfig;
167
+ clicksend: ClicksendConfig;
168
+ bandwidth: BandwidthConfig;
169
+ aws_sns: AwsSnsConfig;
27
170
  }
171
+ /** The write-only (secret) keys of each transport — never present in a response. */
172
+ export interface MessagingSecretKeys {
173
+ resend: 'api_key';
174
+ ses: 'access_key_id' | 'secret_access_key' | 'session_token';
175
+ smtp: 'password';
176
+ brevo: 'api_key';
177
+ mailgun: 'api_key';
178
+ twilio: 'auth_token';
179
+ vonage: 'api_secret';
180
+ messagebird: 'access_key';
181
+ plivo: 'auth_token';
182
+ telnyx: 'api_key';
183
+ sinch: 'api_token';
184
+ infobip: 'api_key';
185
+ clicksend: 'api_key';
186
+ bandwidth: 'password';
187
+ aws_sns: 'secret_access_key' | 'session_token';
188
+ }
189
+ interface ProviderBodyBase<T extends MessagingTransport> {
190
+ transport: T;
191
+ /**
192
+ * Email: the From address, e.g. `"Acme <no-reply@acme.com>"` — a sender your
193
+ * provider accepts. SMS: the sender number in E.164 format, e.g. `+15551234567`.
194
+ */
195
+ from_address?: string;
196
+ }
197
+ /**
198
+ * First setup of transport `T` (or a switch to it): `config` carries every
199
+ * required key.
200
+ */
201
+ export interface MessagingProviderSetup<T extends MessagingTransport> extends ProviderBodyBase<T> {
202
+ config: MessagingTransportConfigs[T];
203
+ }
204
+ /**
205
+ * An update of the transport already configured on the channel: every `config`
206
+ * key is optional. An omitted (or `''`) key keeps its stored value — including a
207
+ * stored secret.
208
+ */
209
+ export interface MessagingProviderUpdate<T extends MessagingTransport> extends ProviderBodyBase<T> {
210
+ config?: Partial<MessagingTransportConfigs[T]>;
211
+ }
212
+ /** Body for `messaging.setEmail` — discriminated by `transport`. */
213
+ export type EmailProviderInput = {
214
+ [T in EmailTransport]: MessagingProviderSetup<T> | MessagingProviderUpdate<T>;
215
+ }[EmailTransport];
216
+ /** Body for `messaging.setSms` — discriminated by `transport`. */
217
+ export type SmsProviderInput = {
218
+ [T in SmsTransport]: MessagingProviderSetup<T> | MessagingProviderUpdate<T>;
219
+ }[SmsTransport];
220
+ /** First-setup body for the email channel. Use with `satisfies` to require every required key. */
221
+ export type EmailProviderSetup = {
222
+ [T in EmailTransport]: MessagingProviderSetup<T>;
223
+ }[EmailTransport];
224
+ /** First-setup body for the SMS channel. Use with `satisfies` to require every required key. */
225
+ export type SmsProviderSetup = {
226
+ [T in SmsTransport]: MessagingProviderSetup<T>;
227
+ }[SmsTransport];
228
+ /**
229
+ * @deprecated The untyped body accepted before per-transport typing. Use
230
+ * {@link EmailProviderInput} / {@link SmsProviderInput} instead; the API refuses
231
+ * any `config` key the transport does not use.
232
+ */
28
233
  export interface MessagingProviderInput {
29
234
  /** The transport, e.g. `resend`, `ses`, `smtp` (email) or `twilio` (sms). */
30
235
  transport: string;
@@ -32,6 +237,42 @@ export interface MessagingProviderInput {
32
237
  /** Transport config; carries the write-only secret keys on write. */
33
238
  config?: Record<string, unknown>;
34
239
  }
240
+ /** The non-secret config keys of transport `T`. */
241
+ type PublicConfigKey<T extends MessagingTransport> = Exclude<keyof MessagingTransportConfigs[T], MessagingSecretKeys[T]>;
242
+ /**
243
+ * A configured provider as returned by the API. `config` holds the non-secret
244
+ * settings only (values come back as strings, e.g. `port: "587"`); secrets are
245
+ * never returned — `secrets_set` says which ones are stored.
246
+ */
247
+ export interface MessagingProviderOf<C extends 'email' | 'sms', T extends MessagingTransport> {
248
+ object: 'messaging_provider';
249
+ channel: C;
250
+ transport: T;
251
+ from_address: string | null;
252
+ status: string;
253
+ /** Non-secret config only — secret values are never returned. */
254
+ config: {
255
+ [K in PublicConfigKey<T>]?: string;
256
+ };
257
+ /** For each secret key of this transport: whether a value is stored. Never the value. */
258
+ secrets_set: {
259
+ [K in MessagingSecretKeys[T]]: boolean;
260
+ };
261
+ updated_at: number;
262
+ }
263
+ export type EmailProvider = {
264
+ [T in EmailTransport]: MessagingProviderOf<'email', T>;
265
+ }[EmailTransport];
266
+ export type SmsProvider = {
267
+ [T in SmsTransport]: MessagingProviderOf<'sms', T>;
268
+ }[SmsTransport];
269
+ /** Either channel's provider. Narrow on `transport` (or `channel`) to read its config. */
270
+ export type MessagingProvider = EmailProvider | SmsProvider;
271
+ export interface MessagingProviders {
272
+ object: 'messaging_providers';
273
+ email: EmailProvider | null;
274
+ sms: SmsProvider | null;
275
+ }
35
276
  export interface MessagingTestResult {
36
277
  object: 'messaging_test';
37
278
  channel: string;
@@ -43,14 +284,39 @@ export interface DeletedMessagingProvider {
43
284
  channel: string;
44
285
  deleted: true;
45
286
  }
287
+ /**
288
+ * The deprecated untyped body, accepted only when `transport` is a plain
289
+ * `string` (not a known literal) — so a typed literal with a wrong key still
290
+ * fails to compile instead of falling through to the legacy overload.
291
+ */
292
+ type LegacyInput<T extends string> = Omit<MessagingProviderInput, 'transport'> & {
293
+ transport: T;
294
+ } & (string extends T ? unknown : never);
46
295
  export declare function messagingResource(request: RequestFn): {
47
296
  /** The instance's configured email and SMS providers, secrets omitted. */
48
297
  get(): Promise<MessagingProviders>;
49
- setEmail(body: MessagingProviderInput): Promise<MessagingProvider>;
50
- setSms(body: MessagingProviderInput): Promise<MessagingProvider>;
298
+ /**
299
+ * Configure (or update) the email provider. `config` keys are checked per
300
+ * `transport`; on an update of the same transport, omitted keys — including
301
+ * secrets — keep their stored values.
302
+ */
303
+ setEmail: {
304
+ (body: EmailProviderInput): Promise<EmailProvider>;
305
+ <T extends string>(body: LegacyInput<T>): Promise<MessagingProvider>;
306
+ };
307
+ /**
308
+ * Configure (or update) the SMS provider. `config` keys are checked per
309
+ * `transport`; on an update of the same transport, omitted keys — including
310
+ * secrets — keep their stored values.
311
+ */
312
+ setSms: {
313
+ (body: SmsProviderInput): Promise<SmsProvider>;
314
+ <T extends string>(body: LegacyInput<T>): Promise<MessagingProvider>;
315
+ };
51
316
  deleteChannel(channel: "email" | "sms"): Promise<DeletedMessagingProvider>;
52
317
  /** Send a fixed, clearly-marked test message through the channel's provider. */
53
318
  test(channel: "email" | "sms", body: {
54
319
  to: string;
55
320
  }): Promise<MessagingTestResult>;
56
321
  };
322
+ export {};
@@ -3,17 +3,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.messagingResource = messagingResource;
4
4
  const request_1 = require("./request");
5
5
  function messagingResource(request) {
6
+ function setEmail(body) {
7
+ return request({ method: 'PUT', path: '/v1/messaging_providers/email', body });
8
+ }
9
+ function setSms(body) {
10
+ return request({ method: 'PUT', path: '/v1/messaging_providers/sms', body });
11
+ }
6
12
  return {
7
13
  /** The instance's configured email and SMS providers, secrets omitted. */
8
14
  get() {
9
15
  return request({ method: 'GET', path: '/v1/messaging_providers' });
10
16
  },
11
- setEmail(body) {
12
- return request({ method: 'PUT', path: '/v1/messaging_providers/email', body });
13
- },
14
- setSms(body) {
15
- return request({ method: 'PUT', path: '/v1/messaging_providers/sms', body });
16
- },
17
+ /**
18
+ * Configure (or update) the email provider. `config` keys are checked per
19
+ * `transport`; on an update of the same transport, omitted keys — including
20
+ * secrets — keep their stored values.
21
+ */
22
+ setEmail,
23
+ /**
24
+ * Configure (or update) the SMS provider. `config` keys are checked per
25
+ * `transport`; on an update of the same transport, omitted keys — including
26
+ * secrets — keep their stored values.
27
+ */
28
+ setSms,
17
29
  deleteChannel(channel) {
18
30
  return request({ method: 'DELETE', path: `/v1/messaging_providers/${(0, request_1.enc)(channel)}` });
19
31
  },
@@ -1 +1 @@
1
- {"version":3,"file":"messaging.js","sourceRoot":"","sources":["../../src/client/messaging.ts"],"names":[],"mappings":";;AAmDA,8CAwBC;AA3ED,uCAAgD;AAmDhD,SAAgB,iBAAiB,CAAC,OAAkB;IAClD,OAAO;QACL,0EAA0E;QAC1E,GAAG;YACD,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,yBAAyB,EAAE,CAAC,CAAC;QACrE,CAAC;QACD,QAAQ,CAAC,IAA4B;YACnC,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,+BAA+B,EAAE,IAAI,EAAE,CAAC,CAAC;QACjF,CAAC;QACD,MAAM,CAAC,IAA4B;YACjC,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,6BAA6B,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,aAAa,CAAC,OAAwB;YACpC,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,2BAA2B,IAAA,aAAG,EAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACxF,CAAC;QACD,gFAAgF;QAChF,IAAI,CAAC,OAAwB,EAAE,IAAoB;YACjD,OAAO,OAAO,CAAC;gBACb,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,2BAA2B,IAAA,aAAG,EAAC,OAAO,CAAC,OAAO;gBACpD,IAAI;aACL,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"messaging.js","sourceRoot":"","sources":["../../src/client/messaging.ts"],"names":[],"mappings":";;AAsVA,8CA4CC;AAlYD,uCAAgD;AAsVhD,SAAgB,iBAAiB,CAAC,OAAkB;IAIlD,SAAS,QAAQ,CAAC,IAAa;QAC7B,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,+BAA+B,EAAE,IAAI,EAAE,CAAC,CAAC;IACjF,CAAC;IAKD,SAAS,MAAM,CAAC,IAAa;QAC3B,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,6BAA6B,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,OAAO;QACL,0EAA0E;QAC1E,GAAG;YACD,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,yBAAyB,EAAE,CAAC,CAAC;QACrE,CAAC;QACD;;;;WAIG;QACH,QAAQ;QACR;;;;WAIG;QACH,MAAM;QACN,aAAa,CAAC,OAAwB;YACpC,OAAO,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,2BAA2B,IAAA,aAAG,EAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACxF,CAAC;QACD,gFAAgF;QAChF,IAAI,CAAC,OAAwB,EAAE,IAAoB;YACjD,OAAO,OAAO,CAAC;gBACb,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,2BAA2B,IAAA,aAAG,EAAC,OAAO,CAAC,OAAO;gBACpD,IAAI;aACL,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -7,3 +7,7 @@ export type { AtlasClient } from './client';
7
7
  export * from './client';
8
8
  export { createTestIssuer } from './testing';
9
9
  export type { TestIssuer, CreateTestIssuerOptions } from './testing';
10
+ export { verifyPCActn } from './pca/verify';
11
+ export type { PcaVerdict, PcaContext, VerifyPCActnOptions } from './pca/verify';
12
+ export { requirePCA, defaultExtract, memoryPcaStore } from './pca/require-pca';
13
+ export type { RequirePcaOptions, PcaGuardResult, PcaRequestLike, PcaStateStore } from './pca/require-pca';
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.createTestIssuer = exports.createAtlasClient = void 0;
17
+ exports.memoryPcaStore = exports.defaultExtract = exports.requirePCA = exports.verifyPCActn = exports.createTestIssuer = exports.createAtlasClient = void 0;
18
18
  // §7.3 token verification — the original surface, unchanged.
19
19
  __exportStar(require("./jwks-cache"), exports);
20
20
  __exportStar(require("./verify"), exports);
@@ -30,4 +30,12 @@ __exportStar(require("./client"), exports);
30
30
  // Its own module, so it never sits on the hot verification path.
31
31
  var testing_1 = require("./testing");
32
32
  Object.defineProperty(exports, "createTestIssuer", { enumerable: true, get: function () { return testing_1.createTestIssuer; } });
33
+ // Proof-Carrying Authority (agentic auth): offline verifier + framework-agnostic guard,
34
+ // beside the session-token verifier above.
35
+ var verify_1 = require("./pca/verify");
36
+ Object.defineProperty(exports, "verifyPCActn", { enumerable: true, get: function () { return verify_1.verifyPCActn; } });
37
+ var require_pca_1 = require("./pca/require-pca");
38
+ Object.defineProperty(exports, "requirePCA", { enumerable: true, get: function () { return require_pca_1.requirePCA; } });
39
+ Object.defineProperty(exports, "defaultExtract", { enumerable: true, get: function () { return require_pca_1.defaultExtract; } });
40
+ Object.defineProperty(exports, "memoryPcaStore", { enumerable: true, get: function () { return require_pca_1.memoryPcaStore; } });
33
41
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,6DAA6D;AAC7D,+CAA6B;AAC7B,2CAAyB;AACzB,8CAA4B;AAE5B,oDAAoD;AACpD,6CAA2B;AAE3B,8DAA8D;AAC9D,mCAA6C;AAApC,2GAAA,iBAAiB,OAAA;AAE1B,2CAAyB;AAEzB,yEAAyE;AACzE,2EAA2E;AAC3E,iEAAiE;AACjE,qCAA6C;AAApC,2GAAA,gBAAgB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,6DAA6D;AAC7D,+CAA6B;AAC7B,2CAAyB;AACzB,8CAA4B;AAE5B,oDAAoD;AACpD,6CAA2B;AAE3B,8DAA8D;AAC9D,mCAA6C;AAApC,2GAAA,iBAAiB,OAAA;AAE1B,2CAAyB;AAEzB,yEAAyE;AACzE,2EAA2E;AAC3E,iEAAiE;AACjE,qCAA6C;AAApC,2GAAA,gBAAgB,OAAA;AAGzB,wFAAwF;AACxF,2CAA2C;AAC3C,uCAA4C;AAAnC,sGAAA,YAAY,OAAA;AAErB,iDAA+E;AAAtE,yGAAA,UAAU,OAAA;AAAE,6GAAA,cAAc,OAAA;AAAE,6GAAA,cAAc,OAAA"}
@@ -0,0 +1,47 @@
1
+ import { type Capability, type PCActn, type TrustBudget, type VerifyHooks } from '@atlasauth/pca';
2
+ import { type PcaContext, type PcaVerdict } from './verify';
3
+ /** Framework-agnostic request shape: anything with headers and (optionally) a parsed/raw body. */
4
+ export interface PcaRequestLike {
5
+ headers: Record<string, string | string[] | undefined> | {
6
+ get(name: string): string | null;
7
+ };
8
+ body?: unknown;
9
+ }
10
+ /** Per-holder replay + budget state. Implement over Redis/DB; the in-memory one is for tests/single node. */
11
+ export interface PcaStateStore {
12
+ get(key: string): Promise<{
13
+ budget?: TrustBudget;
14
+ lastCounter?: number;
15
+ } | undefined>;
16
+ put(key: string, state: {
17
+ budget?: TrustBudget;
18
+ lastCounter?: number;
19
+ }): Promise<void>;
20
+ }
21
+ export declare function memoryPcaStore(): PcaStateStore;
22
+ export interface RequirePcaOptions {
23
+ /** Resolve the Root Intent Grant from the PCActn's `grant_ref`. null = unknown grant. */
24
+ resolveGrant: (grantRef: string, pcactn: PCActn) => Promise<Capability | null>;
25
+ hooks?: VerifyHooks;
26
+ extract?: (req: PcaRequestLike) => PCActn | string | null;
27
+ /** Anti-replay counter + budget persistence. Without it counters are not checked (surfaced in checks). */
28
+ budgetStore?: PcaStateStore;
29
+ /** Build verification context (params, plan, risk) per request. */
30
+ context?: (req: PcaRequestLike, pcactn: PCActn) => PcaContext | Promise<PcaContext>;
31
+ now?: () => number;
32
+ /** WWW-Authenticate realm (default "pca"). */
33
+ realm?: string;
34
+ }
35
+ export type PcaGuardResult = {
36
+ ok: true;
37
+ verdict: PcaVerdict;
38
+ pcactn: PCActn;
39
+ } | {
40
+ ok: false;
41
+ status: 401 | 403;
42
+ verdict: PcaVerdict;
43
+ wwwAuthenticate?: string;
44
+ };
45
+ /** Default extraction: `PCA-Action: <base64url PCActn JSON>` header, else JSON body `{ pcactn }`. */
46
+ export declare function defaultExtract(req: PcaRequestLike): PCActn | string | null;
47
+ export declare function requirePCA(opts: RequirePcaOptions): (req: PcaRequestLike) => Promise<PcaGuardResult>;
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.memoryPcaStore = memoryPcaStore;
4
+ exports.defaultExtract = defaultExtract;
5
+ exports.requirePCA = requirePCA;
6
+ const pca_1 = require("@atlasauth/pca");
7
+ const verify_1 = require("./verify");
8
+ function memoryPcaStore() {
9
+ const m = new Map();
10
+ return { get: async (k) => m.get(k), put: async (k, v) => void m.set(k, v) };
11
+ }
12
+ function header(req, name) {
13
+ const h = req.headers;
14
+ if (typeof h.get === 'function')
15
+ return h.get(name) ?? undefined;
16
+ const v = h[name] ?? h[name.toLowerCase()];
17
+ return Array.isArray(v) ? v[0] : v;
18
+ }
19
+ function fromB64u(s) {
20
+ const b = s.replace(/-/g, '+').replace(/_/g, '/');
21
+ return Buffer.from(b, 'base64').toString('utf8');
22
+ }
23
+ /** Default extraction: `PCA-Action: <base64url PCActn JSON>` header, else JSON body `{ pcactn }`. */
24
+ function defaultExtract(req) {
25
+ const h = header(req, 'pca-action');
26
+ if (h)
27
+ return fromB64u(h.trim());
28
+ let b = req.body;
29
+ if (typeof b === 'string') {
30
+ try {
31
+ b = JSON.parse(b);
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ const x = b?.pcactn;
38
+ if (typeof x === 'string' || (x !== null && typeof x === 'object'))
39
+ return x;
40
+ return null;
41
+ }
42
+ const denyVerdict = (reason) => ({
43
+ allow: false,
44
+ r: 1,
45
+ requiredThreshold: { t: 3, proof: 'strong', optimisticAllowed: false },
46
+ checks: { pcactn: 'fail' },
47
+ reasons: [reason],
48
+ });
49
+ function requirePCA(opts) {
50
+ const realm = opts.realm ?? 'pca';
51
+ const challenge = (error) => `PCA realm="${realm}"${error ? `, error="${error}"` : ''}, hint="send PCA-Action: <base64url PCActn> or JSON body {pcactn}"`;
52
+ const unauth = (reason, error = 'invalid_request') => ({
53
+ ok: false,
54
+ status: 401,
55
+ verdict: denyVerdict(reason),
56
+ wwwAuthenticate: challenge(error),
57
+ });
58
+ return async (req) => {
59
+ try {
60
+ let raw;
61
+ try {
62
+ raw = (opts.extract ?? defaultExtract)(req);
63
+ }
64
+ catch (e) {
65
+ return unauth(`unreadable PCActn: ${e.message}`);
66
+ }
67
+ if (raw === null || raw === undefined)
68
+ return unauth('no PCActn presented', 'missing_pcactn');
69
+ let p;
70
+ try {
71
+ p = typeof raw === 'string' ? (0, pca_1.decodePCActn)(raw) : raw;
72
+ }
73
+ catch (e) {
74
+ return unauth(`undecodable PCActn: ${e.message}`, 'invalid_pcactn');
75
+ }
76
+ if (p === null || typeof p !== 'object' || typeof p.grant_ref !== 'string') {
77
+ return unauth('malformed PCActn', 'invalid_pcactn');
78
+ }
79
+ const grant = await opts.resolveGrant(p.grant_ref, p);
80
+ if (!grant)
81
+ return unauth('unknown grant_ref', 'unknown_grant');
82
+ const now = opts.now?.() ?? Date.now();
83
+ const leafHolder = p.cap_chain?.[p.cap_chain.length - 1]?.holder;
84
+ const key = `${grant.id}:${leafHolder ?? ''}`;
85
+ const state = opts.budgetStore && leafHolder ? await opts.budgetStore.get(key) : undefined;
86
+ const ctx = { ...(await opts.context?.(req, p)) };
87
+ if (state?.budget && ctx.budget === undefined)
88
+ ctx.budget = state.budget;
89
+ const verdict = await (0, verify_1.verifyPCActn)(p, { grant, hooks: opts.hooks, now, context: ctx });
90
+ // Anti-replay (Appendix A step 5): strictly increasing per holder.
91
+ if (opts.budgetStore) {
92
+ if (state?.lastCounter !== undefined && !(p.counter > state.lastCounter)) {
93
+ verdict.allow = false;
94
+ verdict.checks.counter = 'fail';
95
+ verdict.reasons.push(`counter: ${String(p.counter)} is not greater than last seen ${state.lastCounter} (replay)`);
96
+ }
97
+ else if (verdict.checks.counter === 'pass') {
98
+ verdict.checks.counter = 'pass';
99
+ }
100
+ }
101
+ else if (verdict.checks.counter === 'pass') {
102
+ verdict.checks.counter = 'not-enforced';
103
+ }
104
+ if (!verdict.allow) {
105
+ // A bad signature / chain is an authentication failure; policy denial is authorization.
106
+ const authnFailed = ['version', 'cap_chain', 'leaf_signature', 'malformed', 'grant_ref'].some((c) => verdict.checks[c] === 'fail');
107
+ return authnFailed
108
+ ? { ok: false, status: 401, verdict, wwwAuthenticate: challenge('invalid_pcactn') }
109
+ : { ok: false, status: 403, verdict };
110
+ }
111
+ if (opts.budgetStore && leafHolder) {
112
+ await opts.budgetStore.put(key, { budget: verdict.budget ?? state?.budget, lastCounter: p.counter });
113
+ }
114
+ return { ok: true, verdict, pcactn: p };
115
+ }
116
+ catch (e) {
117
+ return { ok: false, status: 403, verdict: denyVerdict(`guard error (fail closed): ${e instanceof Error ? e.message : 'unknown'}`) };
118
+ }
119
+ };
120
+ }
121
+ //# sourceMappingURL=require-pca.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-pca.js","sourceRoot":"","sources":["../../src/pca/require-pca.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { type Capability, type CheckStatus, type PCActn, type PlanNode, type RequiredThreshold, type RiskInputs, type TrustBudget, type VerifyHooks } from '@atlasauth/pca';
2
+ /**
3
+ * Resource-server side Proof-Carrying Authority verifier (spec §4, §7, Appendix A).
4
+ * Deterministic and offline; never throws (any internal error becomes a fail-closed verdict).
5
+ */
6
+ export interface PcaContext {
7
+ /** Plaintext action params. If given they MUST hash to `action.params_digest`; needed by predicates. */
8
+ params?: Record<string, unknown>;
9
+ subject?: Record<string, unknown>;
10
+ env?: Record<string, unknown>;
11
+ /** The committed plan, if the RS knows it. Its Merkle root must equal `plan.root`. */
12
+ plan?: PlanNode[];
13
+ /** Risk inputs the RS can vouch for. Missing ones fail closed (worst case) except `taint`, see below. */
14
+ risk?: Partial<RiskInputs>;
15
+ /** Current trust budget for the leaf holder. Absent = a full budget (`budget` check reports not-enforced). */
16
+ budget?: TrustBudget;
17
+ recentActionTimes?: number[];
18
+ }
19
+ export interface VerifyPCActnOptions {
20
+ grant: Capability;
21
+ hooks?: VerifyHooks;
22
+ /** epoch ms (default Date.now()) */
23
+ now?: number;
24
+ context?: PcaContext;
25
+ }
26
+ export interface PcaVerdict {
27
+ allow: boolean;
28
+ /** Recomputed risk score in [0,1]. */
29
+ r: number;
30
+ requiredThreshold: RequiredThreshold;
31
+ checks: Record<string, CheckStatus>;
32
+ reasons: string[];
33
+ /** Budget after the decision (leaked, and debited when auto-admitted). Persist it on allow. */
34
+ budget?: TrustBudget;
35
+ }
36
+ export declare function verifyPCActn(pcactn: PCActn | string, opts: VerifyPCActnOptions): Promise<PcaVerdict>;