@learncard/lca-api-service 1.3.2 → 1.5.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/.env.example +99 -2
- package/AGENTS.md +155 -44
- package/CHANGELOG.md +84 -0
- package/bootstrapLambda.test.ts +76 -0
- package/compose.env +5 -0
- package/config/config.dev.json +23 -0
- package/config/config.example.json +22 -0
- package/config/config.json +1 -0
- package/config/config.production.json +12 -0
- package/config/config.scouts.dev.json +11 -0
- package/config/config.scouts.production.json +11 -0
- package/dist/accesslayer/signing-authority/index.d.ts +8 -2
- package/dist/app.d.ts +361 -8
- package/dist/cache/challenges.d.ts +2 -0
- package/dist/cache/getDel.d.ts +2 -0
- package/dist/cache/getDel.test.d.ts +1 -0
- package/dist/cache/login-tickets.d.ts +12 -0
- package/dist/cache/recoverySessions.d.ts +42 -0
- package/dist/config/applyDockerStageConfig.d.ts +1 -0
- package/dist/config/cacheEnvironment.d.ts +16 -0
- package/dist/config/environment.d.ts +253 -2
- package/dist/config/environment.test.d.ts +1 -0
- package/dist/config/escrowBundleMode.test.d.ts +1 -0
- package/dist/config/escrowDeployment.test.d.ts +1 -0
- package/dist/config/oidcEnvironment.d.ts +74 -0
- package/dist/config/serverlessFunctionEnv.test.d.ts +1 -0
- package/dist/config/stageConfig.d.ts +62 -0
- package/dist/config/stageConfig.test.d.ts +1 -0
- package/dist/didkit_wasm_bg.wasm +0 -0
- package/dist/docker-entry.d.ts +1 -1
- package/dist/helpers/auth.helpers.d.ts +1 -1
- package/dist/helpers/escrowCancelLink.d.ts +7 -0
- package/dist/helpers/escrowCancelLink.test.d.ts +1 -0
- package/dist/helpers/escrowCancelToken.d.ts +4 -0
- package/dist/helpers/escrowCancelToken.test.d.ts +1 -0
- package/dist/helpers/keycloak.helpers.d.ts +23 -0
- package/dist/helpers/learnCard.signingAuthority.test.d.ts +1 -0
- package/dist/helpers/login-ticket.helpers.d.ts +31 -0
- package/dist/helpers/login-ticket.helpers.test.d.ts +1 -0
- package/dist/helpers/oidc.helpers.d.ts +47 -0
- package/dist/helpers/rate-limit.helpers.d.ts +6 -0
- package/dist/helpers/rate-limit.helpers.test.d.ts +1 -0
- package/dist/helpers/rateLimit.helpers.d.ts +4 -0
- package/dist/helpers/seedEncryption.helpers.d.ts +23 -0
- package/dist/helpers/seedEncryption.helpers.test.d.ts +1 -0
- package/dist/helpers/social-token.helpers.d.ts +19 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/jobs/escrowBlobRewrap.d.ts +9 -0
- package/dist/jobs/escrowHoldReminders.d.ts +12 -0
- package/dist/migrations/signingAuthoritySeeds.d.ts +13 -0
- package/dist/migrations/signingAuthoritySeedsCli.test.d.ts +1 -0
- package/dist/models/AuthSubject.d.ts +20 -0
- package/dist/models/EscrowHold.d.ts +153 -0
- package/dist/models/Notification.d.ts +5 -0
- package/dist/models/SigningAuthority.d.ts +7 -1
- package/dist/models/UserKey.d.ts +326 -3
- package/dist/models/UserKey.escrowPin.test.d.ts +1 -0
- package/dist/models/index.d.ts +2 -0
- package/dist/oidc.d.ts +5 -0
- package/dist/routes/auth.d.ts +31 -0
- package/dist/routes/escrow.d.ts +164 -0
- package/dist/routes/index.d.ts +6 -0
- package/dist/routes/keys.d.ts +182 -7
- package/dist/routes/notifications.d.ts +5 -0
- package/dist/routes/qr-login.d.ts +1 -1
- package/dist/routes/signing-authority.d.ts +14 -0
- package/dist/services/escrow-enclave/blobIdentity.d.ts +10 -0
- package/dist/services/escrow-enclave/blobIdentity.test.d.ts +1 -0
- package/dist/services/escrow-enclave/cancellation.d.ts +3 -0
- package/dist/services/escrow-enclave/enclaveTrustAnchors.d.ts +1 -0
- package/dist/services/escrow-enclave/index.d.ts +25 -0
- package/dist/services/escrow-enclave/notifications.d.ts +24 -0
- package/dist/services/escrow-enclave/notifications.test.d.ts +1 -0
- package/dist/services/escrow-enclave/production.test.d.ts +1 -0
- package/dist/services/escrow-enclave/remoteEnclave.contract.test.d.ts +1 -0
- package/dist/services/escrow-enclave/remoteEnclave.d.ts +20 -0
- package/dist/services/escrow-enclave/remoteEnclave.test.d.ts +1 -0
- package/dist/services/escrow-enclave/remoteEnclave.tls.test.d.ts +1 -0
- package/dist/services/escrow-enclave/softwareEnclave.d.ts +27 -0
- package/dist/services/escrow-enclave/softwareEnclave.test.d.ts +1 -0
- package/dist/services/escrow-enclave/types.d.ts +111 -0
- package/dist/types/notifications.d.ts +5 -0
- package/dist/types/seed-encryption.d.ts +31 -0
- package/dist/types/seed-migration.d.ts +49 -0
- package/esbuildPlugins.cjs +1 -0
- package/lambda.ts +27 -112
- package/lambdaApp.ts +146 -0
- package/oidcLambda.test.ts +38 -0
- package/oidcLambda.ts +18 -0
- package/oidcLambdaApp.ts +11 -0
- package/package.json +30 -14
- package/scripts/README.md +88 -0
- package/scripts/check-seed-encryption-infrastructure.mjs +139 -0
- package/scripts/check-signing-authority-redis.mjs +93 -0
- package/scripts/escrow-blob-mode-report.test.ts +227 -0
- package/scripts/escrow-blob-mode-report.ts +465 -0
- package/scripts/keycloak-admin.ts +108 -0
- package/scripts/keycloak-provider-links.ts +147 -0
- package/scripts/migrate-signing-authority-seeds-local.sh +51 -0
- package/scripts/migrate-signing-authority-seeds.mjs +105 -0
- package/scripts/print-seed-rollout-flags.ts +21 -0
- package/scripts/provision-keycloak-users.ts +419 -0
- package/seedMigrationApp.test.ts +145 -0
- package/seedMigrationApp.ts +50 -0
- package/seedMigrationLambda.test.ts +40 -0
- package/seedMigrationLambda.ts +19 -0
- package/serverless-local.yml +28 -1
- package/serverless.function-env.cjs +58 -0
- package/serverless.yml +294 -26
- package/src/accesslayer/notifications/index.ts +9 -2
- package/src/accesslayer/signing-authority/create.ts +11 -7
- package/src/accesslayer/signing-authority/index.ts +4 -1
- package/src/app.ts +4 -0
- package/src/cache/challenges.ts +12 -2
- package/src/cache/getDel.test.ts +34 -0
- package/src/cache/getDel.ts +32 -0
- package/src/cache/in-memory-lru.ts +1 -0
- package/src/cache/index.ts +1 -1
- package/src/cache/login-tickets.ts +26 -0
- package/src/cache/recoverySessions.ts +252 -0
- package/src/config/applyDockerStageConfig.ts +6 -0
- package/src/config/cacheEnvironment.ts +34 -0
- package/src/config/environment.test.ts +159 -0
- package/src/config/environment.ts +164 -0
- package/src/config/escrowBundleMode.test.ts +52 -0
- package/src/config/escrowDeployment.test.ts +114 -0
- package/src/config/oidcEnvironment.ts +59 -0
- package/src/config/serverlessFunctionEnv.test.ts +98 -0
- package/src/config/stageConfig.test.ts +26 -0
- package/src/config/stageConfig.ts +24 -0
- package/src/docker-entry.ts +13 -0
- package/src/helpers/auth.helpers.ts +68 -30
- package/src/helpers/escrowCancelLink.test.ts +60 -0
- package/src/helpers/escrowCancelLink.ts +38 -0
- package/src/helpers/escrowCancelToken.test.ts +105 -0
- package/src/helpers/escrowCancelToken.ts +47 -0
- package/src/helpers/keycloak.helpers.ts +120 -0
- package/src/helpers/learnCard.helpers.test.ts +11 -1
- package/src/helpers/learnCard.helpers.ts +57 -45
- package/src/helpers/learnCard.signingAuthority.test.ts +194 -0
- package/src/helpers/login-ticket.helpers.test.ts +45 -0
- package/src/helpers/login-ticket.helpers.ts +91 -0
- package/src/helpers/oidc.helpers.ts +354 -0
- package/src/helpers/rate-limit.helpers.test.ts +61 -0
- package/src/helpers/rate-limit.helpers.ts +73 -0
- package/src/helpers/rateLimit.helpers.ts +112 -0
- package/src/helpers/seedEncryption.helpers.test.ts +427 -0
- package/src/helpers/seedEncryption.helpers.ts +372 -0
- package/src/helpers/signingAuthority.helpers.ts +4 -1
- package/src/helpers/social-token.helpers.ts +144 -0
- package/src/index.ts +1 -0
- package/src/jobs/escrowBlobRewrap.ts +121 -0
- package/src/jobs/escrowHoldReminders.ts +177 -0
- package/src/migrations/signingAuthoritySeeds.ts +430 -0
- package/src/migrations/signingAuthoritySeedsCli.test.ts +70 -0
- package/src/models/AuthSubject.ts +147 -0
- package/src/models/EscrowHold.ts +541 -0
- package/src/models/SigningAuthority.ts +14 -3
- package/src/models/UserKey.escrowPin.test.ts +49 -0
- package/src/models/UserKey.ts +1109 -40
- package/src/models/index.ts +2 -0
- package/src/models/pruneOrphanedRecoveryMethods.ts +3 -1
- package/src/oidc.ts +371 -0
- package/src/routes/auth.ts +173 -0
- package/src/routes/credentials.ts +8 -0
- package/src/routes/escrow.ts +1073 -0
- package/src/routes/firebase.ts +90 -48
- package/src/routes/index.ts +98 -5
- package/src/routes/keys.ts +1022 -174
- package/src/routes/qr-login.ts +51 -53
- package/src/routes/signing-authority.ts +39 -1
- package/src/services/delivery/adapters/postmark.adapter.ts +48 -1
- package/src/services/escrow-enclave/README.md +122 -0
- package/src/services/escrow-enclave/__fixtures__/tls/pinned-ca.pem +11 -0
- package/src/services/escrow-enclave/__fixtures__/tls/pinned-leaf.key +5 -0
- package/src/services/escrow-enclave/__fixtures__/tls/pinned-leaf.pem +12 -0
- package/src/services/escrow-enclave/__fixtures__/tls/rogue-ca.pem +11 -0
- package/src/services/escrow-enclave/__fixtures__/tls/rogue-leaf.key +5 -0
- package/src/services/escrow-enclave/__fixtures__/tls/rogue-leaf.pem +12 -0
- package/src/services/escrow-enclave/blobIdentity.test.ts +42 -0
- package/src/services/escrow-enclave/blobIdentity.ts +55 -0
- package/src/services/escrow-enclave/cancellation.ts +59 -0
- package/src/services/escrow-enclave/enclaveTrustAnchors.ts +34 -0
- package/src/services/escrow-enclave/index.ts +174 -0
- package/src/services/escrow-enclave/notifications.test.ts +377 -0
- package/src/services/escrow-enclave/notifications.ts +348 -0
- package/src/services/escrow-enclave/production.test.ts +34 -0
- package/src/services/escrow-enclave/remoteEnclave.contract.test.ts +344 -0
- package/src/services/escrow-enclave/remoteEnclave.test.ts +490 -0
- package/src/services/escrow-enclave/remoteEnclave.tls.test.ts +62 -0
- package/src/services/escrow-enclave/remoteEnclave.ts +263 -0
- package/src/services/escrow-enclave/softwareEnclave.test.ts +450 -0
- package/src/services/escrow-enclave/softwareEnclave.ts +254 -0
- package/src/services/escrow-enclave/types.ts +122 -0
- package/src/types/seed-encryption.ts +51 -0
- package/src/types/seed-migration.ts +61 -0
- package/test/auth-tickets.spec.ts +480 -0
- package/test/credentials.spec.ts +2 -0
- package/test/helpers/keycloak-broker.ts +181 -0
- package/test/helpers/live-mongo.ts +9 -0
- package/test/jobs/escrowBlobRewrap.spec.ts +262 -0
- package/test/jobs/escrowHoldReminders.spec.ts +319 -0
- package/test/keycloak-admin.spec.ts +58 -0
- package/test/keycloak-broker-roundtrip.integration.spec.ts +40 -0
- package/test/keycloak-migration.integration.spec.ts +266 -0
- package/test/keycloak-provider-links.spec.ts +201 -0
- package/test/keycloak-social-broker.integration.spec.ts +228 -0
- package/test/keycloak-verify.integration.spec.ts +100 -0
- package/test/keycloak-verify.spec.ts +307 -0
- package/test/keys-escrow.spec.ts +2328 -0
- package/test/keys-identity-rebind.spec.ts +456 -0
- package/test/keys-lifecycle-invariants.spec.ts +785 -0
- package/test/keys-recovery-confirmation.spec.ts +586 -0
- package/test/keys-recovery-rate-limit.spec.ts +123 -0
- package/test/keys-secret-leakage.spec.ts +265 -0
- package/test/models/authSubjectIndexes.spec.ts +132 -0
- package/test/models/escrow.spec.ts +572 -0
- package/test/notifications.spec.ts +4 -0
- package/test/oidc-e2e/broker.spec.ts +116 -0
- package/test/oidc-e2e/compose.yaml +33 -0
- package/test/oidc-e2e/fixtures.ts +245 -0
- package/test/oidc-e2e/lock.test.mjs +73 -0
- package/test/oidc-e2e/playwright.config.ts +21 -0
- package/test/oidc-e2e/run.mjs +312 -0
- package/test/oidc-e2e/tsconfig.json +10 -0
- package/test/oidc-e2e/types.ts +21 -0
- package/test/oidc.integration.spec.ts +54 -0
- package/test/oidc.spec.ts +697 -0
- package/test/oidcLambdaApp.boot.spec.ts +105 -0
- package/test/provision-keycloak-users.spec.ts +299 -0
- package/test/signing-authority-http.spec.ts +161 -0
- package/test/signing-authority-seed-migration.spec.ts +414 -0
- package/test/signing-authority.spec.ts +90 -0
- package/tsconfig.build.json +1 -1
- package/tsconfig.json +1 -0
- package/vitest.config.ts +24 -1
- package/vitest.integration.config.ts +25 -3
- package/dist/cache/signing-authority.d.ts +0 -6
- package/src/cache/signing-authority.ts +0 -37
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { Agent } from 'node:https';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import {
|
|
5
|
+
ESCROW_ALGORITHM,
|
|
6
|
+
ESCROW_ENVELOPE_VERSION,
|
|
7
|
+
type EscrowEnvelope,
|
|
8
|
+
} from '@learncard/sss-key-manager';
|
|
9
|
+
import {
|
|
10
|
+
EscrowBlobError,
|
|
11
|
+
EscrowPinMismatchError,
|
|
12
|
+
EscrowPolicyError,
|
|
13
|
+
EscrowUnavailableError,
|
|
14
|
+
type CarryPinVerifierInput,
|
|
15
|
+
type EnclaveAttestation,
|
|
16
|
+
type EscrowEnclave,
|
|
17
|
+
type ReleaseRequest,
|
|
18
|
+
type ReleaseResult,
|
|
19
|
+
type RewrapEscrowBlobInput,
|
|
20
|
+
type VerifyEscrowBlobInput,
|
|
21
|
+
type VerifyEscrowBlobResult,
|
|
22
|
+
} from './types';
|
|
23
|
+
|
|
24
|
+
// Mirrors services/escrow-enclave-app/src/wire.rs camelCase field names exactly,
|
|
25
|
+
// minus the vsock wire's `method` tag (the HTTP paths below take its place).
|
|
26
|
+
const measurementsValidator = z.object({
|
|
27
|
+
imageSha384: z.string().optional(),
|
|
28
|
+
pcr0: z.string().optional(),
|
|
29
|
+
pcr1: z.string().optional(),
|
|
30
|
+
pcr2: z.string().optional(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const attestResponseValidator = z.object({
|
|
34
|
+
mode: z.enum(['software', 'nitro']),
|
|
35
|
+
keyId: z.string(),
|
|
36
|
+
// Optional/defaulted (not required, unlike the host's own wire.rs field) so
|
|
37
|
+
// a not-yet-upgraded host during a rolling deploy still parses; P9.1.
|
|
38
|
+
previousKeyIds: z.array(z.string()).optional().default([]),
|
|
39
|
+
publicKey: z.string(),
|
|
40
|
+
measurements: measurementsValidator,
|
|
41
|
+
document: z.string(),
|
|
42
|
+
issuedAt: z.string(),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const envelopeValidator = z.object({
|
|
46
|
+
version: z.literal(ESCROW_ENVELOPE_VERSION),
|
|
47
|
+
algorithm: z.literal(ESCROW_ALGORITHM),
|
|
48
|
+
keyId: z.string(),
|
|
49
|
+
ephemeralPublicKey: z.string(),
|
|
50
|
+
salt: z.string(),
|
|
51
|
+
iv: z.string(),
|
|
52
|
+
ciphertext: z.string(),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const verifyBlobResponseValidator = z.union([
|
|
56
|
+
z.object({ ok: z.literal(true), hasPin: z.boolean() }),
|
|
57
|
+
z.object({ ok: z.literal(false), hasPin: z.boolean(), reason: z.string() }),
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
const carryPinVerifierResponseValidator = z.object({ envelope: envelopeValidator });
|
|
61
|
+
const rewrapEscrowBlobResponseValidator = z.object({ envelope: envelopeValidator });
|
|
62
|
+
|
|
63
|
+
// Opaque SignedHoldRecord JSON: validate shape while preserving signed extensions.
|
|
64
|
+
const holdRecordValidator = z
|
|
65
|
+
.object({
|
|
66
|
+
hold: z
|
|
67
|
+
.object({
|
|
68
|
+
holdId: z.string().min(1),
|
|
69
|
+
did: z.string().min(1),
|
|
70
|
+
shareVersion: z.number().int().positive(),
|
|
71
|
+
blobHash: z.string().regex(/^[0-9a-f]{64}$/),
|
|
72
|
+
enrollmentEpoch: z.number().int().positive(),
|
|
73
|
+
releasePolicy: z.enum(['hold', 'pin']),
|
|
74
|
+
clientEphemeralPublicKey: z.string().min(1),
|
|
75
|
+
createdLo: z.number().int().nonnegative(),
|
|
76
|
+
createdHi: z.number().int().nonnegative(),
|
|
77
|
+
policyVersion: z.number().int().positive(),
|
|
78
|
+
signature: z.string().min(1),
|
|
79
|
+
})
|
|
80
|
+
.passthrough(),
|
|
81
|
+
holdDurationMs: z.number().int().nonnegative(),
|
|
82
|
+
ledgerSeq: z.number().int().nonnegative(),
|
|
83
|
+
})
|
|
84
|
+
.passthrough();
|
|
85
|
+
const validatedHold = (hold: ReleaseRequest['hold']): ReleaseRequest['hold'] => {
|
|
86
|
+
if (!holdRecordValidator.safeParse(hold).success) throw new EscrowUnavailableError();
|
|
87
|
+
return hold;
|
|
88
|
+
};
|
|
89
|
+
const releaseResponseValidator = z.object({ sealed: envelopeValidator });
|
|
90
|
+
|
|
91
|
+
const errorCodeValidator = z.enum([
|
|
92
|
+
'policy',
|
|
93
|
+
'pinMismatch',
|
|
94
|
+
'blob',
|
|
95
|
+
'unavailable',
|
|
96
|
+
'ledger',
|
|
97
|
+
'time',
|
|
98
|
+
]);
|
|
99
|
+
const errorResponseValidator = z.object({ code: errorCodeValidator, message: z.string() });
|
|
100
|
+
|
|
101
|
+
const errorForCode = (code: z.infer<typeof errorCodeValidator>): Error => {
|
|
102
|
+
if (code === 'policy') return new EscrowPolicyError();
|
|
103
|
+
if (code === 'pinMismatch') return new EscrowPinMismatchError();
|
|
104
|
+
if (code === 'blob') return new EscrowBlobError();
|
|
105
|
+
return new EscrowUnavailableError(); // 'unavailable' | 'ledger' | 'time'
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export interface RemoteEnclaveTransportResponse {
|
|
109
|
+
status: number;
|
|
110
|
+
data: unknown;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface RemoteEnclaveTransport {
|
|
114
|
+
post(
|
|
115
|
+
url: string,
|
|
116
|
+
body: unknown,
|
|
117
|
+
config: { headers: Record<string, string>; timeout: number }
|
|
118
|
+
): Promise<RemoteEnclaveTransportResponse>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** With `caPem`, the connection trusts only that CA (system roots are not consulted). */
|
|
122
|
+
export const createHttpTransport = (caPem?: string): RemoteEnclaveTransport => {
|
|
123
|
+
const httpsAgent = caPem ? new Agent({ ca: caPem, keepAlive: true }) : undefined;
|
|
124
|
+
return {
|
|
125
|
+
post: async (url, body, config) => {
|
|
126
|
+
const response = await axios.post(url, body, {
|
|
127
|
+
...config,
|
|
128
|
+
httpsAgent,
|
|
129
|
+
validateStatus: () => true,
|
|
130
|
+
});
|
|
131
|
+
return { status: response.status, data: response.data };
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export interface RemoteEnclaveConfig {
|
|
137
|
+
/** Origin of the enclave-host parent service (P3.3), e.g. `https://escrow.internal`. */
|
|
138
|
+
baseUrl: string;
|
|
139
|
+
token: string;
|
|
140
|
+
timeoutMs: number;
|
|
141
|
+
/** Private CA pinned for this host (see enclaveTrustAnchors.ts); system roots otherwise. */
|
|
142
|
+
caPem?: string;
|
|
143
|
+
/** Injectable for tests; defaults to a real HTTP (axios) transport. */
|
|
144
|
+
transport?: RemoteEnclaveTransport;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* `EscrowEnclave` backend for `ESCROW_ENCLAVE_MODE=remote`: an HTTP client to the
|
|
149
|
+
* enclave-host parent service fronting a real Nitro Enclave. See issues.md
|
|
150
|
+
* "P4.1 report" for the full contract (paths, bodies, error format).
|
|
151
|
+
*
|
|
152
|
+
* Fail-closed: any transport failure (network error, timeout, non-2xx without a
|
|
153
|
+
* recognized error code, or a response failing its zod schema) becomes
|
|
154
|
+
* `EscrowUnavailableError`. Request/response bodies (sealed envelopes, PIN
|
|
155
|
+
* proofs) are never logged anywhere in this module.
|
|
156
|
+
*/
|
|
157
|
+
export const createRemoteEnclave = (config: RemoteEnclaveConfig): EscrowEnclave => {
|
|
158
|
+
const transport = config.transport ?? createHttpTransport(config.caPem);
|
|
159
|
+
|
|
160
|
+
const call = async <T>(path: string, body: unknown, validator: z.ZodType<T>): Promise<T> => {
|
|
161
|
+
let status: number;
|
|
162
|
+
let data: unknown;
|
|
163
|
+
try {
|
|
164
|
+
const response = await transport.post(`${config.baseUrl}${path}`, body, {
|
|
165
|
+
headers: { Authorization: `Bearer ${config.token}` },
|
|
166
|
+
timeout: config.timeoutMs,
|
|
167
|
+
});
|
|
168
|
+
status = response.status;
|
|
169
|
+
data = response.data;
|
|
170
|
+
} catch {
|
|
171
|
+
throw new EscrowUnavailableError();
|
|
172
|
+
}
|
|
173
|
+
if (status < 200 || status >= 300) {
|
|
174
|
+
const parsedError = errorResponseValidator.safeParse(data);
|
|
175
|
+
if (parsedError.success) throw errorForCode(parsedError.data.code);
|
|
176
|
+
throw new EscrowUnavailableError();
|
|
177
|
+
}
|
|
178
|
+
const parsed = validator.safeParse(data);
|
|
179
|
+
if (!parsed.success) throw new EscrowUnavailableError();
|
|
180
|
+
return parsed.data;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
getAttestation: (nonce?: Uint8Array): Promise<EnclaveAttestation> =>
|
|
185
|
+
call('/v1/attest', { nonce: Array.from(nonce ?? []) }, attestResponseValidator),
|
|
186
|
+
verifyEscrowBlob: (input: VerifyEscrowBlobInput): Promise<VerifyEscrowBlobResult> =>
|
|
187
|
+
call(
|
|
188
|
+
'/v1/verify-blob',
|
|
189
|
+
{
|
|
190
|
+
envelope: input.envelope,
|
|
191
|
+
expectedDid: input.expectedDid,
|
|
192
|
+
expectedShareVersion: input.expectedShareVersion,
|
|
193
|
+
},
|
|
194
|
+
verifyBlobResponseValidator
|
|
195
|
+
),
|
|
196
|
+
carryPinVerifier: (input: CarryPinVerifierInput): Promise<{ envelope: EscrowEnvelope }> =>
|
|
197
|
+
call(
|
|
198
|
+
'/v1/carry-pin-verifier',
|
|
199
|
+
{
|
|
200
|
+
sourceEnvelope: input.sourceEnvelope,
|
|
201
|
+
targetEnvelope: input.targetEnvelope,
|
|
202
|
+
expectedDid: input.expectedDid,
|
|
203
|
+
sourceShareVersion: input.sourceShareVersion,
|
|
204
|
+
targetShareVersion: input.targetShareVersion,
|
|
205
|
+
sourceEnrollmentEpoch: input.sourceEnrollmentEpoch,
|
|
206
|
+
targetEnrollmentEpoch: input.targetEnrollmentEpoch,
|
|
207
|
+
},
|
|
208
|
+
carryPinVerifierResponseValidator
|
|
209
|
+
),
|
|
210
|
+
rewrapEscrowBlob: (input: RewrapEscrowBlobInput): Promise<{ envelope: EscrowEnvelope }> =>
|
|
211
|
+
call(
|
|
212
|
+
'/v1/rewrap-escrow-blob',
|
|
213
|
+
{
|
|
214
|
+
envelope: input.envelope,
|
|
215
|
+
expectedDid: input.expectedDid,
|
|
216
|
+
expectedShareVersion: input.expectedShareVersion,
|
|
217
|
+
sourceEnrollmentEpoch: input.sourceEnrollmentEpoch,
|
|
218
|
+
},
|
|
219
|
+
rewrapEscrowBlobResponseValidator
|
|
220
|
+
),
|
|
221
|
+
createHold: async input => ({
|
|
222
|
+
holdRecord: await call(
|
|
223
|
+
'/v1/create-hold',
|
|
224
|
+
{
|
|
225
|
+
envelope: input.envelope,
|
|
226
|
+
holdId: input.holdId,
|
|
227
|
+
expectedDid: input.expectedDid,
|
|
228
|
+
expectedShareVersion: input.expectedShareVersion,
|
|
229
|
+
enrollmentEpoch: input.enrollmentEpoch,
|
|
230
|
+
releasePolicy: input.releasePolicy,
|
|
231
|
+
clientEphemeralPublicKey: input.clientEphemeralPublicKey,
|
|
232
|
+
},
|
|
233
|
+
holdRecordValidator
|
|
234
|
+
),
|
|
235
|
+
}),
|
|
236
|
+
cancelHold: async input => {
|
|
237
|
+
await call(
|
|
238
|
+
'/v1/cancel-hold',
|
|
239
|
+
{
|
|
240
|
+
envelope: input.envelope,
|
|
241
|
+
hold: validatedHold(input.hold),
|
|
242
|
+
clientEphemeralPublicKey: input.clientEphemeralPublicKey,
|
|
243
|
+
expectedDid: input.expectedDid,
|
|
244
|
+
},
|
|
245
|
+
z.object({ ok: z.literal(true) })
|
|
246
|
+
);
|
|
247
|
+
},
|
|
248
|
+
releaseEscrow: async (input: ReleaseRequest): Promise<ReleaseResult> => {
|
|
249
|
+
validatedHold(input.hold);
|
|
250
|
+
return call(
|
|
251
|
+
'/v1/release',
|
|
252
|
+
{
|
|
253
|
+
envelope: input.envelope,
|
|
254
|
+
hold: input.hold,
|
|
255
|
+
clientEphemeralPublicKey: input.clientEphemeralPublicKey,
|
|
256
|
+
expectedDid: input.expectedDid,
|
|
257
|
+
...(input.pinProof !== undefined ? { pinProof: input.pinProof } : {}),
|
|
258
|
+
},
|
|
259
|
+
releaseResponseValidator
|
|
260
|
+
);
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
};
|