@spfn/auth 0.2.0-beta.90 → 0.2.0-beta.91
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 +27 -0
- package/dist/{authenticate-CnccboAg.d.ts → authenticate-DlTGaBT8.d.ts} +26 -6
- package/dist/client-proof.d.ts +47 -118
- package/dist/client-proof.js +46 -18
- package/dist/client-proof.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/nextjs/server.d.ts +2 -2
- package/dist/server.d.ts +204 -84
- package/dist/server.js +473 -133
- package/dist/server.js.map +1 -1
- package/dist/{session-CFK4BT25.d.ts → session-DTHahDQ9.d.ts} +1 -1
- package/dist/{types-CD95yudz.d.ts → types-DYyhze28.d.ts} +1 -1
- package/dist/wire-version-CtzMKvBB.d.ts +134 -0
- package/migrations/20260805143152_vengeful_ravenous/migration.sql +4 -0
- package/migrations/20260805143152_vengeful_ravenous/snapshot.json +3190 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -856,6 +856,13 @@ HTTP status).
|
|
|
856
856
|
- `createClientProofGuard(state)` — Hono middleware for mounting `requiresSession` operations
|
|
857
857
|
on an SPFN server; tags admitted requests `clientType: 'mobile'` (the attestation slot
|
|
858
858
|
proxy-guard reserved). hono is a type-only import here.
|
|
859
|
+
- A refusal is **answered**, never thrown: `authenticate` / `optionalAuth` answer a request that
|
|
860
|
+
named this profile with the canonical envelope (`error.code` is one of the six codes, and the
|
|
861
|
+
body carries nothing else), and the guard and dev handler do the same. Handing the refusal to
|
|
862
|
+
the generic error handler instead would put the carrying error class's name in `error.code`
|
|
863
|
+
(`UnauthorizedError`) — a code no generated SDK can classify (#106). Errors raised **after**
|
|
864
|
+
admission (account status, application errors) are ordinary SPFN errors and keep the REST
|
|
865
|
+
envelope.
|
|
859
866
|
- Replay ledger is module-local, NOT core's `NonceStore` — `checkAndSet` records on check,
|
|
860
867
|
which would spend a nonce on a refused request; the contract requires spending only on
|
|
861
868
|
admission.
|
|
@@ -904,6 +911,26 @@ app.use('*', createClientVersionMiddleware());
|
|
|
904
911
|
Response header names are deliberately distinct from the request ones: a proxy that echoes a request
|
|
905
912
|
header into the response would otherwise make the client's own version look like the server's.
|
|
906
913
|
|
|
914
|
+
### When each operation became available (contract 0.6.1)
|
|
915
|
+
|
|
916
|
+
Every operation in the exported bundle carries `since` — the contract version it first appeared in.
|
|
917
|
+
`deprecatedIn` and `removedIn` are optional and absent today, because nothing has been deprecated.
|
|
918
|
+
|
|
919
|
+
| Operation | `since` |
|
|
920
|
+
|-----------|---------|
|
|
921
|
+
| `auth.clientProof.handshake`, `echo.send`, `items.list` | 0.1.0 |
|
|
922
|
+
| `auth.enroll.register`, `auth.enroll.login`, `auth.enroll.oauthNative`, `auth.keys.rotate` | 0.3.0 |
|
|
923
|
+
| `auth.keys.list`, `auth.keys.revoke`, `auth.keys.revokeAll` | 0.4.1 |
|
|
924
|
+
|
|
925
|
+
- **This is history, not policy.** The mobile contract's compatibility policy is `allOrNothing`: one
|
|
926
|
+
contract version passes or refuses the whole surface, so these three fields change no verdict here.
|
|
927
|
+
An app contract generated from SPFN routes decides `perOperation` and reads the same fields as an
|
|
928
|
+
input — the shape is shared so the two never diverge.
|
|
929
|
+
- **A removal is mark, then wait, then remove.** `deprecatedIn` in one version with the operation
|
|
930
|
+
still served, `removedIn` in a later one. Nothing is removed in the version that deprecates it.
|
|
931
|
+
- **A removed operation leaves the operations list**, so no entry carries `removedIn` today. It is
|
|
932
|
+
where the fact gets recorded when the first removal happens.
|
|
933
|
+
|
|
907
934
|
### Usage — dev surface (mobile integration target)
|
|
908
935
|
|
|
909
936
|
The fastest path: run the packaged dev handler, which already serves the three contract
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _spfn_core_route from '@spfn/core/route';
|
|
2
|
-
import { K as KeyAlgorithmType,
|
|
2
|
+
import { K as KeyAlgorithmType, h as KeyPlatformType, j as SocialProvider } from './types-DYyhze28.js';
|
|
3
3
|
import * as _sinclair_typebox from '@sinclair/typebox';
|
|
4
4
|
import { Static } from '@sinclair/typebox';
|
|
5
5
|
import { Context } from 'hono';
|
|
@@ -879,7 +879,7 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
|
|
|
879
879
|
id: number;
|
|
880
880
|
name: string;
|
|
881
881
|
displayName: string;
|
|
882
|
-
category: "
|
|
882
|
+
category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
|
|
883
883
|
}[];
|
|
884
884
|
userId: number;
|
|
885
885
|
publicId: string;
|
|
@@ -1179,8 +1179,8 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
|
|
|
1179
1179
|
}, {}, {
|
|
1180
1180
|
roles: {
|
|
1181
1181
|
description: string | null;
|
|
1182
|
-
id: number;
|
|
1183
1182
|
name: string;
|
|
1183
|
+
id: number;
|
|
1184
1184
|
displayName: string;
|
|
1185
1185
|
isBuiltin: boolean;
|
|
1186
1186
|
isSystem: boolean;
|
|
@@ -1201,8 +1201,8 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
|
|
|
1201
1201
|
}, {}, {
|
|
1202
1202
|
role: {
|
|
1203
1203
|
description: string | null;
|
|
1204
|
-
id: number;
|
|
1205
1204
|
name: string;
|
|
1205
|
+
id: number;
|
|
1206
1206
|
displayName: string;
|
|
1207
1207
|
isBuiltin: boolean;
|
|
1208
1208
|
isSystem: boolean;
|
|
@@ -1225,8 +1225,8 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
|
|
|
1225
1225
|
}, {}, {
|
|
1226
1226
|
role: {
|
|
1227
1227
|
description: string | null;
|
|
1228
|
-
id: number;
|
|
1229
1228
|
name: string;
|
|
1229
|
+
id: number;
|
|
1230
1230
|
displayName: string;
|
|
1231
1231
|
isBuiltin: boolean;
|
|
1232
1232
|
isSystem: boolean;
|
|
@@ -1314,6 +1314,26 @@ declare function resolveAuthenticatedUser(userId: number): Promise<{
|
|
|
1314
1314
|
role: string | null;
|
|
1315
1315
|
locale: string;
|
|
1316
1316
|
}>;
|
|
1317
|
+
/** What the profile path produced for one request. */
|
|
1318
|
+
type AuthProfileOutcome = {
|
|
1319
|
+
kind: 'none';
|
|
1320
|
+
} | {
|
|
1321
|
+
kind: 'authenticated';
|
|
1322
|
+
auth: AuthContext;
|
|
1323
|
+
} | {
|
|
1324
|
+
kind: 'refused';
|
|
1325
|
+
response: Response;
|
|
1326
|
+
};
|
|
1327
|
+
/**
|
|
1328
|
+
* The profile path from dispatch to answer — what `authenticate` and
|
|
1329
|
+
* `optionalAuth` both run before their own Bearer code.
|
|
1330
|
+
*
|
|
1331
|
+
* `none` means the request named no profile and the caller continues on the
|
|
1332
|
+
* Bearer path. A refusal comes back as a built response rather than a throw:
|
|
1333
|
+
* the answer a proven call gets is the contract's own envelope, and an error
|
|
1334
|
+
* handed to the generic error handler is classified by its class name instead.
|
|
1335
|
+
*/
|
|
1336
|
+
declare function runAuthProfile(c: Context): Promise<AuthProfileOutcome>;
|
|
1317
1337
|
|
|
1318
1338
|
declare module 'hono' {
|
|
1319
1339
|
interface ContextVariableMap {
|
|
@@ -1380,4 +1400,4 @@ declare const authenticate: _spfn_core_route.NamedMiddleware<"auth">;
|
|
|
1380
1400
|
*/
|
|
1381
1401
|
declare const optionalAuth: _spfn_core_route.NamedMiddleware<"optionalAuth">;
|
|
1382
1402
|
|
|
1383
|
-
export {
|
|
1403
|
+
export { type UnlinkNotifyResult as $, type AuthInitOptions as A, PasswordSchema as B, type ChangePasswordParams as C, DeviceNameSchema as D, EmailSchema as E, PhoneSchema as F, PlatformSchema as G, type RegisterParams as H, type IssueOneTimeTokenResult as I, type RegisterPublicKeyParams as J, type KeySummary as K, type LoginResult as L, type RevokeAllKeysParams as M, type NativeVerifyOptions as N, type OAuthStartResult as O, type PermissionConfig as P, type RevokeKeyParams as Q, type RoleConfig as R, type SendVerificationCodeResult as S, type RotateKeyParams as T, type UserProfile as U, VERIFICATION_PURPOSES as V, type SendVerificationCodeParams as W, TargetTypeSchema as X, type UnlinkNotification as Y, UnlinkNotifyRejection as Z, type UnlinkNotifyRequest as _, type RegisterResult as a, VerificationPurposeSchema as a0, type VerifyCodeParams as a1, type VerifyCodeResult as a2, authenticate as a3, buildOAuthErrorUrl as a4, changePasswordService as a5, getEnabledOAuthProviders as a6, getGoogleAccessToken as a7, getOAuthProvider as a8, getRegisteredProviders as a9, isOAuthProviderEnabled as aa, issueOneTimeTokenService as ab, listKeysService as ac, loginService as ad, logoutService as ae, oauthCallbackService as af, oauthNativeService as ag, oauthStartService as ah, oauthUnlinkNotifyService as ai, optionalAuth as aj, registerOAuthProvider as ak, registerPublicKeyService as al, registerService as am, requireEnabledProvider as an, resolveAuthenticatedUser as ao, revokeAllKeysService as ap, revokeKeyService as aq, rotateKeyService as ar, runAuthProfile as as, selectAuthProfile as at, sendVerificationCodeService as au, verifyCodeService as av, verifyOneTimeTokenService as aw, type RotateKeyResult as b, type RevokeAllKeysResult as c, type OAuthNativeResult as d, type ProfileInfo as e, type AuthSession as f, PERMISSION_CATEGORIES as g, type PermissionCategory as h, VERIFICATION_TARGET_TYPES as i, type VerificationPurpose as j, type VerificationTargetType as k, type OAuthProvider as l, mainAuthRouter as m, type AuthContext as n, type AuthProfileOutcome as o, type AuthProfileVerifier as p, KEY_FINGERPRINT_PREFIX_LENGTH as q, type LoginParams as r, type LogoutParams as s, type NormalizedIdentity as t, type OAuthCallbackParams as u, type OAuthCallbackResult as v, type OAuthCodeExchangeOptions as w, type OAuthNativeParams as x, type OAuthStartParams as y, type OAuthTokens as z };
|
package/dist/client-proof.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { KeyObject } from 'node:crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { C as ClientProofRefusal } from './wire-version-CtzMKvBB.js';
|
|
3
|
+
export { a as CLIENT_IDENTITY_HEADERS, b as CLIENT_KINDS, c as ClientIdentity, d as ClientKind, e as ClientProofErrorCode, S as SERVER_CONTRACT_HEADERS, f as applyServerContractHeaders, i as isAppKind, g as isContractVersionSupported, j as judgeClientIdentity, n as newHexId, r as readClientIdentity, s as serverContractHeaders } from './wire-version-CtzMKvBB.js';
|
|
4
|
+
import { MiddlewareHandler, Context } from 'hono';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* SPFN-CANON-JSON-1 — the canonical JSON form the mobile contract pins.
|
|
@@ -121,49 +123,6 @@ declare function signClientProof(input: ClientProofInput, privateKeyPkcs8DerBase
|
|
|
121
123
|
/** Lowercase base16 SHA-256 of `bytes`. */
|
|
122
124
|
declare function sha256Hex(bytes: Uint8Array): string;
|
|
123
125
|
|
|
124
|
-
/** The six wire codes. The SDKs classify by code, never HTTP status. */
|
|
125
|
-
type ClientProofErrorCode = 'PROOF_INVALID' | 'PROOF_REPLAYED' | 'PROOF_EXPIRED' | 'SESSION_REVOKED' | 'PROFILE_REJECTED' | 'CONTRACT_UNSUPPORTED';
|
|
126
|
-
/** 128 random bits as lowercase base16 — request ids and control tokens. */
|
|
127
|
-
declare function newHexId(): string;
|
|
128
|
-
declare class ClientProofRefusal {
|
|
129
|
-
readonly code: ClientProofErrorCode;
|
|
130
|
-
readonly message: string;
|
|
131
|
-
constructor(code: ClientProofErrorCode, message: string);
|
|
132
|
-
get httpStatus(): number;
|
|
133
|
-
/** The canonical bytes of `{"error":{"code":…,"message":…,"requestId":…}}`. */
|
|
134
|
-
envelopeBytes(requestId: string): Uint8Array;
|
|
135
|
-
/** Nothing request-derived reaches a log through this. */
|
|
136
|
-
toString(): string;
|
|
137
|
-
static unroutable(): ClientProofRefusal;
|
|
138
|
-
static malformedHeaders(): ClientProofRefusal;
|
|
139
|
-
static missingContentType(): ClientProofRefusal;
|
|
140
|
-
static bodyTooLarge(): ClientProofRefusal;
|
|
141
|
-
/**
|
|
142
|
-
* The body parsed but its bytes are not the canonical form of what it
|
|
143
|
-
* parsed to. Not PROOF_INVALID even though it is discovered next to the
|
|
144
|
-
* proof: the proof over these bytes verifies perfectly well, and an
|
|
145
|
-
* auth-family answer would tell the client to re-handshake and send the
|
|
146
|
-
* same non-canonical bytes again.
|
|
147
|
-
*/
|
|
148
|
-
static bodyNotCanonical(): ClientProofRefusal;
|
|
149
|
-
static bodyNotTheDeclaredType(): ClientProofRefusal;
|
|
150
|
-
static sessionHeaderMisplaced(): ClientProofRefusal;
|
|
151
|
-
static unprocessable(): ClientProofRefusal;
|
|
152
|
-
/**
|
|
153
|
-
* A client that ships separately from the server said nothing about which
|
|
154
|
-
* contract it was built against. Without it the server cannot tell whether
|
|
155
|
-
* the two ends agree, and answering as though they do is what produces the
|
|
156
|
-
* undecodable body this check exists to replace.
|
|
157
|
-
*/
|
|
158
|
-
static contractVersionMissing(): ClientProofRefusal;
|
|
159
|
-
static contractVersionUnsupported(): ClientProofRefusal;
|
|
160
|
-
static profileRejected(): ClientProofRefusal;
|
|
161
|
-
static sessionRevoked(): ClientProofRefusal;
|
|
162
|
-
static proofExpired(): ClientProofRefusal;
|
|
163
|
-
static proofReplayed(): ClientProofRefusal;
|
|
164
|
-
static proofInvalid(): ClientProofRefusal;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
126
|
/** Millisecond clock. Injectable so expiry paths are testable without waiting. */
|
|
168
127
|
interface ClientProofClock {
|
|
169
128
|
nowMillis(): number;
|
|
@@ -452,6 +411,33 @@ interface ContractOperation {
|
|
|
452
411
|
requestType: string;
|
|
453
412
|
responseType: string;
|
|
454
413
|
summary: string;
|
|
414
|
+
/**
|
|
415
|
+
* The contract version this operation first appeared in. Required, so an
|
|
416
|
+
* operation added later cannot ship without one: omitting it is a compile
|
|
417
|
+
* error rather than a hole a consumer discovers.
|
|
418
|
+
*
|
|
419
|
+
* It is history, not policy. This contract's compatibility policy is
|
|
420
|
+
* `allOrNothing` — one version passes or refuses the whole surface — so
|
|
421
|
+
* nothing here changes a verdict. It exists so a deprecation has somewhere
|
|
422
|
+
* to be recorded, and as the precedent an app contract's `perOperation`
|
|
423
|
+
* policy reads.
|
|
424
|
+
*/
|
|
425
|
+
since: string;
|
|
426
|
+
/**
|
|
427
|
+
* The contract version that marked this operation deprecated, if one has.
|
|
428
|
+
* A deprecated operation is still served: the mark is the notice that opens
|
|
429
|
+
* the grace period before removal.
|
|
430
|
+
*/
|
|
431
|
+
deprecatedIn?: string;
|
|
432
|
+
/**
|
|
433
|
+
* The contract version that removed this operation, if one has.
|
|
434
|
+
*
|
|
435
|
+
* A removed operation leaves this list, so nothing here carries the field
|
|
436
|
+
* today. When the first removal happens, `removedIn` is where the fact is
|
|
437
|
+
* recorded — how a removed operation stays visible after leaving the list
|
|
438
|
+
* is decided then, not invented in advance.
|
|
439
|
+
*/
|
|
440
|
+
removedIn?: string;
|
|
455
441
|
}
|
|
456
442
|
declare const CONTRACT_OPERATIONS: readonly ContractOperation[];
|
|
457
443
|
/**
|
|
@@ -563,87 +549,30 @@ interface ClientProofGuardOptions {
|
|
|
563
549
|
declare function createClientProofGuard(state: ClientProofState, options?: ClientProofGuardOptions): MiddlewareHandler;
|
|
564
550
|
|
|
565
551
|
/**
|
|
566
|
-
*
|
|
552
|
+
* One place turns a clientProofV1 refusal into a response.
|
|
567
553
|
*
|
|
568
|
-
*
|
|
569
|
-
*
|
|
570
|
-
*
|
|
554
|
+
* A proven call is answered by a generated SDK that classifies a failure by
|
|
555
|
+
* `error.code` alone and refuses a code it does not know. So a refusal must
|
|
556
|
+
* leave this server as the contract's own envelope — the canonical bytes of
|
|
557
|
+
* `{"error":{"code","message","requestId"}}` carrying one of the six refusal
|
|
558
|
+
* codes — and nothing else. Routing a refusal through the generic error
|
|
559
|
+
* handler instead puts the wrapper error class's name in `error.code`
|
|
560
|
+
* (`UnauthorizedError`), which no SDK can classify (#106).
|
|
571
561
|
*
|
|
572
|
-
*
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
declare const CLIENT_IDENTITY_HEADERS: {
|
|
576
|
-
readonly kind: "x-spfn-client-kind";
|
|
577
|
-
readonly version: "x-spfn-client-version";
|
|
578
|
-
readonly contractVersion: "x-spfn-client-contract-version";
|
|
579
|
-
};
|
|
580
|
-
/**
|
|
581
|
-
* What the server says about itself, on every response.
|
|
562
|
+
* Every refusal surface (the guard, the profile middleware) builds its answer
|
|
563
|
+
* here rather than assembling one of its own, so a code path added later
|
|
564
|
+
* cannot reintroduce a body that says something else.
|
|
582
565
|
*
|
|
583
|
-
*
|
|
584
|
-
* request header into the response would otherwise make the client's own
|
|
585
|
-
* version look like the server's.
|
|
586
|
-
*/
|
|
587
|
-
declare const SERVER_CONTRACT_HEADERS: {
|
|
588
|
-
readonly version: "x-spfn-server-contract-version";
|
|
589
|
-
readonly supportedRange: "x-spfn-supported-contract-range";
|
|
590
|
-
};
|
|
591
|
-
/**
|
|
592
|
-
* The client kinds the server distinguishes.
|
|
566
|
+
* hono is imported as types only, so this module adds no runtime dependency.
|
|
593
567
|
*
|
|
594
|
-
*
|
|
595
|
-
* version: a browser bundle is deployed with the server that serves it, so
|
|
596
|
-
* there is no second version to reconcile.
|
|
568
|
+
* @module server/client-proof/refusal-response
|
|
597
569
|
*/
|
|
598
|
-
declare const CLIENT_KINDS: readonly ["web", "ios", "android"];
|
|
599
|
-
type ClientKind = typeof CLIENT_KINDS[number];
|
|
600
|
-
/** A kind that ships independently of the server, so its contract version matters. */
|
|
601
|
-
declare function isAppKind(kind: ClientKind): boolean;
|
|
602
570
|
|
|
603
|
-
/** What one request announced about the client that sent it. */
|
|
604
|
-
interface ClientIdentity {
|
|
605
|
-
kind: ClientKind;
|
|
606
|
-
/** The client's own release — a store version, or a bundle build. */
|
|
607
|
-
version: string | null;
|
|
608
|
-
/** The contract version the client was generated from. Never set for `web`. */
|
|
609
|
-
contractVersion: string | null;
|
|
610
|
-
}
|
|
611
571
|
/**
|
|
612
|
-
*
|
|
613
|
-
*
|
|
614
|
-
* Null is not by itself a refusal — a request from something that predates
|
|
615
|
-
* these headers reaches here too. `judgeClientIdentity` decides.
|
|
616
|
-
*/
|
|
617
|
-
declare function readClientIdentity(headers: Headers): ClientIdentity | null;
|
|
618
|
-
/**
|
|
619
|
-
* Whether the server serves what the client was generated against.
|
|
620
|
-
*
|
|
621
|
-
* Under 0.x the minor carries breaking changes, so a supported client agrees on
|
|
622
|
-
* major and minor. From 1.0.0 the major alone decides. This is the rule
|
|
623
|
-
* `CONTRACT_SUPPORTED_RANGE` spells out; keeping it as a comparison rather than
|
|
624
|
-
* parsing that string leaves one place to change when the line reaches 1.0.0.
|
|
625
|
-
*/
|
|
626
|
-
declare function isContractVersionSupported(clientVersion: string): boolean;
|
|
627
|
-
/**
|
|
628
|
-
* The refusal a request's announced identity earns, or null to let it through.
|
|
629
|
-
*
|
|
630
|
-
* An app kind must state a contract version this server serves. A version it
|
|
631
|
-
* does not serve, and the absence of one, are the same answer: the two ends do
|
|
632
|
-
* not agree on what the contract is, which is what CONTRACT_UNSUPPORTED means.
|
|
633
|
-
* The response carries the server's version and range, so the client can say
|
|
634
|
-
* which way the gap runs.
|
|
635
|
-
*
|
|
636
|
-
* `web` is exempt from the contract check by construction, not by leniency.
|
|
637
|
-
*
|
|
638
|
-
* A request with no recognised kind passes. The check is on what a client says
|
|
639
|
-
* about itself, and a caller that says nothing — a curl, a health probe, a
|
|
640
|
-
* server-to-server call — is not a deployed client this rule is about.
|
|
572
|
+
* The canonical contract envelope for one refusal, with the server's contract
|
|
573
|
+
* announcement — a refused client needs the range most.
|
|
641
574
|
*/
|
|
642
|
-
declare function
|
|
643
|
-
/** Writes the server's own announcement onto a response's headers. */
|
|
644
|
-
declare function applyServerContractHeaders(headers: Headers): void;
|
|
645
|
-
/** The same announcement as a plain object, for a response built from one. */
|
|
646
|
-
declare function serverContractHeaders(): Record<string, string>;
|
|
575
|
+
declare function clientProofRefusalResponse(c: Context, refusal: ClientProofRefusal): Response;
|
|
647
576
|
|
|
648
577
|
/**
|
|
649
578
|
* The version announcement, applied to every request rather than to the proven
|
|
@@ -674,4 +603,4 @@ declare const CLIENT_IDENTITY_CONTEXT_KEY = "clientIdentity";
|
|
|
674
603
|
*/
|
|
675
604
|
declare function createClientVersionMiddleware(): MiddlewareHandler;
|
|
676
605
|
|
|
677
|
-
export { ABSENT_BODY_SHA256, AUTH_SURFACE_OPERATIONS, type Admission, CLIENT_IDENTITY_CONTEXT_KEY,
|
|
606
|
+
export { ABSENT_BODY_SHA256, AUTH_SURFACE_OPERATIONS, type Admission, CLIENT_IDENTITY_CONTEXT_KEY, CLIENT_PROOF_CONTENT_TYPE, CLIENT_PROOF_HEADERS, CLIENT_PROOF_PROFILE, CONTRACT_OPERATIONS, CONTROL_PREFIX, CONTROL_TOKEN_HEADER, CanonicalJsonError, type CanonicalJsonErrorCode, type CanonicalObject, type CanonicalValue, type ClientProofClock, type ClientProofContext, type ClientProofCredentials, type ClientProofDevHandler, type ClientProofDevHandlerOptions, type ClientProofGuardOptions, type ClientProofInput, ClientProofRefusal, type ClientProofReplayStore, ClientProofState, type ClientProofStateOptions, type ClientProofStats, type ContractItem, type ContractOperation, ContractTypeError, DEFAULT_REPLAY_WINDOW_MILLIS, DEFAULT_SESSION_TTL_MILLIS, DEV_CATALOGUE, DEV_MAX_LIMIT, type EchoRequest, type HandshakeRequest, type ListItemsRequest, MemoryReplayLedger, MemoryReplayStore, PROOF_SIGNATURE_BYTES, PROOF_SIGNATURE_HEX_LENGTH, ProofInputError, RedisReplayStore, TestClock, admitClientProofRequest, canonicalProofInput, clientProofRefusalResponse, configureClientProofReplayStore, createClientProofDevHandler, createClientProofGuard, createClientVersionMiddleware, decodeEchoRequest, decodeHandshakeRequest, decodeListItemsRequest, encodeCanonicalJson, encodeEchoResponse, encodeHandshakeResponse, encodeListItemsResponse, getClientProofReplayStore, isCanonicalBytes, isRequestContentType, parseCanonicalJson, parseClientProofPublicKey, readCredentials, replayLedgerKey, sha256Hex, signClientProof, systemClock, verifyClientProof };
|
package/dist/client-proof.js
CHANGED
|
@@ -512,6 +512,18 @@ var ClientProofRefusal = class _ClientProofRefusal {
|
|
|
512
512
|
static profileRejected() {
|
|
513
513
|
return new _ClientProofRefusal("PROFILE_REJECTED", "the named auth profile is not on this contract's allowlist");
|
|
514
514
|
}
|
|
515
|
+
/**
|
|
516
|
+
* A request that names a profile and presents Bearer credentials as well.
|
|
517
|
+
* The profile named is a real one, so this is not a shape the two ends
|
|
518
|
+
* disagree about: the request asked to be authenticated two ways at once
|
|
519
|
+
* and the profile it named is the one refused.
|
|
520
|
+
*/
|
|
521
|
+
static credentialsMixed() {
|
|
522
|
+
return new _ClientProofRefusal(
|
|
523
|
+
"PROFILE_REJECTED",
|
|
524
|
+
"an auth profile and Bearer credentials must not be mixed in one request"
|
|
525
|
+
);
|
|
526
|
+
}
|
|
515
527
|
// ---- auth: a new session might clear it (rule 1) -------------------------
|
|
516
528
|
static sessionRevoked() {
|
|
517
529
|
return new _ClientProofRefusal("SESSION_REVOKED", "the key or session was revoked");
|
|
@@ -932,7 +944,8 @@ var CONTRACT_OPERATIONS = [
|
|
|
932
944
|
requiresSession: false,
|
|
933
945
|
requestType: "HandshakeRequest",
|
|
934
946
|
responseType: "HandshakeResponse",
|
|
935
|
-
summary: "Presents a client proof and opens a session."
|
|
947
|
+
summary: "Presents a client proof and opens a session.",
|
|
948
|
+
since: "0.1.0"
|
|
936
949
|
},
|
|
937
950
|
{
|
|
938
951
|
id: "echo.send",
|
|
@@ -942,7 +955,8 @@ var CONTRACT_OPERATIONS = [
|
|
|
942
955
|
requiresSession: true,
|
|
943
956
|
requestType: "EchoRequest",
|
|
944
957
|
responseType: "EchoResponse",
|
|
945
|
-
summary: "Authenticated round trip used as the smallest real vertical slice."
|
|
958
|
+
summary: "Authenticated round trip used as the smallest real vertical slice.",
|
|
959
|
+
since: "0.1.0"
|
|
946
960
|
},
|
|
947
961
|
{
|
|
948
962
|
id: "items.list",
|
|
@@ -952,7 +966,8 @@ var CONTRACT_OPERATIONS = [
|
|
|
952
966
|
requiresSession: true,
|
|
953
967
|
requestType: "ListItemsRequest",
|
|
954
968
|
responseType: "ListItemsResponse",
|
|
955
|
-
summary: "Authenticated paged read covering optional fields and arrays."
|
|
969
|
+
summary: "Authenticated paged read covering optional fields and arrays.",
|
|
970
|
+
since: "0.1.0"
|
|
956
971
|
}
|
|
957
972
|
];
|
|
958
973
|
var AUTH_SURFACE_OPERATIONS = [
|
|
@@ -964,7 +979,8 @@ var AUTH_SURFACE_OPERATIONS = [
|
|
|
964
979
|
requiresSession: false,
|
|
965
980
|
requestType: "RegisterRequest",
|
|
966
981
|
responseType: "RegisterResponse",
|
|
967
|
-
summary: "Registers an account with a verification token and enrolls the client-generated public key."
|
|
982
|
+
summary: "Registers an account with a verification token and enrolls the client-generated public key.",
|
|
983
|
+
since: "0.3.0"
|
|
968
984
|
},
|
|
969
985
|
{
|
|
970
986
|
id: "auth.enroll.login",
|
|
@@ -974,7 +990,8 @@ var AUTH_SURFACE_OPERATIONS = [
|
|
|
974
990
|
requiresSession: false,
|
|
975
991
|
requestType: "LoginRequest",
|
|
976
992
|
responseType: "LoginResponse",
|
|
977
|
-
summary: "Authenticates with password credentials and enrolls a fresh client-generated public key."
|
|
993
|
+
summary: "Authenticates with password credentials and enrolls a fresh client-generated public key.",
|
|
994
|
+
since: "0.3.0"
|
|
978
995
|
},
|
|
979
996
|
{
|
|
980
997
|
id: "auth.enroll.oauthNative",
|
|
@@ -984,7 +1001,8 @@ var AUTH_SURFACE_OPERATIONS = [
|
|
|
984
1001
|
requiresSession: false,
|
|
985
1002
|
requestType: "OauthNativeRequest",
|
|
986
1003
|
responseType: "OauthNativeResponse",
|
|
987
|
-
summary: "Verifies a native/web social id_token server-side and enrolls the client-generated public key."
|
|
1004
|
+
summary: "Verifies a native/web social id_token server-side and enrolls the client-generated public key.",
|
|
1005
|
+
since: "0.3.0"
|
|
988
1006
|
},
|
|
989
1007
|
{
|
|
990
1008
|
id: "auth.keys.rotate",
|
|
@@ -994,7 +1012,8 @@ var AUTH_SURFACE_OPERATIONS = [
|
|
|
994
1012
|
requiresSession: false,
|
|
995
1013
|
requestType: "RotateKeyRequest",
|
|
996
1014
|
responseType: "RotateKeyResponse",
|
|
997
|
-
summary: "Replaces the authenticated key with a new client-generated public key before its TTL runs out."
|
|
1015
|
+
summary: "Replaces the authenticated key with a new client-generated public key before its TTL runs out.",
|
|
1016
|
+
since: "0.3.0"
|
|
998
1017
|
},
|
|
999
1018
|
{
|
|
1000
1019
|
id: "auth.keys.list",
|
|
@@ -1004,7 +1023,8 @@ var AUTH_SURFACE_OPERATIONS = [
|
|
|
1004
1023
|
requiresSession: false,
|
|
1005
1024
|
requestType: "ListKeysRequest",
|
|
1006
1025
|
responseType: "ListKeysResponse",
|
|
1007
|
-
summary: "Lists the keys registered to the caller, one per device that can sign for them."
|
|
1026
|
+
summary: "Lists the keys registered to the caller, one per device that can sign for them.",
|
|
1027
|
+
since: "0.4.1"
|
|
1008
1028
|
},
|
|
1009
1029
|
{
|
|
1010
1030
|
id: "auth.keys.revoke",
|
|
@@ -1014,7 +1034,8 @@ var AUTH_SURFACE_OPERATIONS = [
|
|
|
1014
1034
|
requiresSession: false,
|
|
1015
1035
|
requestType: "RevokeKeyRequest",
|
|
1016
1036
|
responseType: "RevokeKeyResponse",
|
|
1017
|
-
summary: "Revokes one of the caller's keys, signing that device out."
|
|
1037
|
+
summary: "Revokes one of the caller's keys, signing that device out.",
|
|
1038
|
+
since: "0.4.1"
|
|
1018
1039
|
},
|
|
1019
1040
|
{
|
|
1020
1041
|
id: "auth.keys.revokeAll",
|
|
@@ -1024,7 +1045,8 @@ var AUTH_SURFACE_OPERATIONS = [
|
|
|
1024
1045
|
requiresSession: false,
|
|
1025
1046
|
requestType: "RevokeAllKeysRequest",
|
|
1026
1047
|
responseType: "RevokeAllKeysResponse",
|
|
1027
|
-
summary: "Revokes every key the caller has, sparing the calling device unless asked otherwise."
|
|
1048
|
+
summary: "Revokes every key the caller has, sparing the calling device unless asked otherwise.",
|
|
1049
|
+
since: "0.4.1"
|
|
1028
1050
|
}
|
|
1029
1051
|
];
|
|
1030
1052
|
var ContractTypeError = class extends Error {
|
|
@@ -1285,9 +1307,9 @@ function isAppKind(kind) {
|
|
|
1285
1307
|
}
|
|
1286
1308
|
|
|
1287
1309
|
// src/server/client-proof/contract-bundle.ts
|
|
1288
|
-
var CONTRACT_VERSION = "0.
|
|
1310
|
+
var CONTRACT_VERSION = "0.8.0";
|
|
1289
1311
|
var CONTRACT_MAJOR = 0;
|
|
1290
|
-
var CONTRACT_SUPPORTED_RANGE = ">=0.
|
|
1312
|
+
var CONTRACT_SUPPORTED_RANGE = ">=0.8.0 <0.9.0";
|
|
1291
1313
|
function required(name, type) {
|
|
1292
1314
|
return { name, type, optional: false };
|
|
1293
1315
|
}
|
|
@@ -1697,6 +1719,16 @@ function toArrayBuffer(bytes) {
|
|
|
1697
1719
|
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
1698
1720
|
}
|
|
1699
1721
|
|
|
1722
|
+
// src/server/client-proof/refusal-response.ts
|
|
1723
|
+
function clientProofRefusalResponse(c, refusal) {
|
|
1724
|
+
const bytes = refusal.envelopeBytes(newHexId());
|
|
1725
|
+
const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
1726
|
+
return c.newResponse(buffer, refusal.httpStatus, {
|
|
1727
|
+
"content-type": "application/json",
|
|
1728
|
+
...serverContractHeaders()
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1700
1732
|
// src/server/client-proof/guard.ts
|
|
1701
1733
|
function createClientProofGuard(state, options = {}) {
|
|
1702
1734
|
return async (c, next) => {
|
|
@@ -1711,12 +1743,7 @@ function createClientProofGuard(state, options = {}) {
|
|
|
1711
1743
|
});
|
|
1712
1744
|
if (!admission.admitted) {
|
|
1713
1745
|
state.recordRefusal();
|
|
1714
|
-
|
|
1715
|
-
const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
1716
|
-
return c.newResponse(buffer, admission.refusal.httpStatus, {
|
|
1717
|
-
"content-type": "application/json",
|
|
1718
|
-
...serverContractHeaders()
|
|
1719
|
-
});
|
|
1746
|
+
return clientProofRefusalResponse(c, admission.refusal);
|
|
1720
1747
|
}
|
|
1721
1748
|
c.set("clientType", "mobile");
|
|
1722
1749
|
c.set("clientProof", {
|
|
@@ -1782,6 +1809,7 @@ export {
|
|
|
1782
1809
|
admitClientProofRequest,
|
|
1783
1810
|
applyServerContractHeaders,
|
|
1784
1811
|
canonicalProofInput,
|
|
1812
|
+
clientProofRefusalResponse,
|
|
1785
1813
|
configureClientProofReplayStore,
|
|
1786
1814
|
createClientProofDevHandler,
|
|
1787
1815
|
createClientProofGuard,
|