@openvtc/pnm-core 0.1.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 +129 -0
- package/dist/did/derive-signing-key.d.ts +19 -0
- package/dist/did/derive-signing-key.d.ts.map +1 -0
- package/dist/did/derive-signing-key.js +96 -0
- package/dist/did/derive-signing-key.js.map +1 -0
- package/dist/did/index.d.ts +5 -0
- package/dist/did/index.d.ts.map +1 -0
- package/dist/did/index.js +5 -0
- package/dist/did/index.js.map +1 -0
- package/dist/did/peer.d.ts +37 -0
- package/dist/did/peer.d.ts.map +1 -0
- package/dist/did/peer.js +49 -0
- package/dist/did/peer.js.map +1 -0
- package/dist/did/verification-method.d.ts +43 -0
- package/dist/did/verification-method.d.ts.map +1 -0
- package/dist/did/verification-method.js +32 -0
- package/dist/did/verification-method.js.map +1 -0
- package/dist/did/verify.d.ts +49 -0
- package/dist/did/verify.d.ts.map +1 -0
- package/dist/did/verify.js +89 -0
- package/dist/did/verify.js.map +1 -0
- package/dist/didcomm/index.d.ts +235 -0
- package/dist/didcomm/index.d.ts.map +1 -0
- package/dist/didcomm/index.js +415 -0
- package/dist/didcomm/index.js.map +1 -0
- package/dist/inbound/confirm.d.ts +50 -0
- package/dist/inbound/confirm.d.ts.map +1 -0
- package/dist/inbound/confirm.js +64 -0
- package/dist/inbound/confirm.js.map +1 -0
- package/dist/inbound/dedup.d.ts +9 -0
- package/dist/inbound/dedup.d.ts.map +1 -0
- package/dist/inbound/dedup.js +31 -0
- package/dist/inbound/dedup.js.map +1 -0
- package/dist/inbound/index.d.ts +3 -0
- package/dist/inbound/index.d.ts.map +1 -0
- package/dist/inbound/index.js +3 -0
- package/dist/inbound/index.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/onboarding/index.d.ts +2 -0
- package/dist/onboarding/index.d.ts.map +1 -0
- package/dist/onboarding/index.js +2 -0
- package/dist/onboarding/index.js.map +1 -0
- package/dist/onboarding/swap.d.ts +60 -0
- package/dist/onboarding/swap.d.ts.map +1 -0
- package/dist/onboarding/swap.js +148 -0
- package/dist/onboarding/swap.js.map +1 -0
- package/dist/provision/adopt.d.ts +31 -0
- package/dist/provision/adopt.d.ts.map +1 -0
- package/dist/provision/adopt.js +114 -0
- package/dist/provision/adopt.js.map +1 -0
- package/dist/provision/armor.d.ts +19 -0
- package/dist/provision/armor.d.ts.map +1 -0
- package/dist/provision/armor.js +243 -0
- package/dist/provision/armor.js.map +1 -0
- package/dist/provision/crc24.d.ts +5 -0
- package/dist/provision/crc24.d.ts.map +1 -0
- package/dist/provision/crc24.js +30 -0
- package/dist/provision/crc24.js.map +1 -0
- package/dist/provision/hpke.d.ts +17 -0
- package/dist/provision/hpke.d.ts.map +1 -0
- package/dist/provision/hpke.js +60 -0
- package/dist/provision/hpke.js.map +1 -0
- package/dist/provision/index.d.ts +10 -0
- package/dist/provision/index.d.ts.map +1 -0
- package/dist/provision/index.js +16 -0
- package/dist/provision/index.js.map +1 -0
- package/dist/provision/open.d.ts +28 -0
- package/dist/provision/open.d.ts.map +1 -0
- package/dist/provision/open.js +224 -0
- package/dist/provision/open.js.map +1 -0
- package/dist/provision/request.d.ts +65 -0
- package/dist/provision/request.d.ts.map +1 -0
- package/dist/provision/request.js +53 -0
- package/dist/provision/request.js.map +1 -0
- package/dist/provision/run.d.ts +76 -0
- package/dist/provision/run.d.ts.map +1 -0
- package/dist/provision/run.js +110 -0
- package/dist/provision/run.js.map +1 -0
- package/dist/provision/send.d.ts +85 -0
- package/dist/provision/send.d.ts.map +1 -0
- package/dist/provision/send.js +87 -0
- package/dist/provision/send.js.map +1 -0
- package/dist/provision/types.d.ts +110 -0
- package/dist/provision/types.d.ts.map +1 -0
- package/dist/provision/types.js +17 -0
- package/dist/provision/types.js.map +1 -0
- package/dist/rp-login/didcomm.d.ts +34 -0
- package/dist/rp-login/didcomm.d.ts.map +1 -0
- package/dist/rp-login/didcomm.js +72 -0
- package/dist/rp-login/didcomm.js.map +1 -0
- package/dist/rp-login/index.d.ts +3 -0
- package/dist/rp-login/index.d.ts.map +1 -0
- package/dist/rp-login/index.js +3 -0
- package/dist/rp-login/index.js.map +1 -0
- package/dist/rp-login/step-up.d.ts +43 -0
- package/dist/rp-login/step-up.d.ts.map +1 -0
- package/dist/rp-login/step-up.js +118 -0
- package/dist/rp-login/step-up.js.map +1 -0
- package/dist/siop/index.d.ts +3 -0
- package/dist/siop/index.d.ts.map +1 -0
- package/dist/siop/index.js +3 -0
- package/dist/siop/index.js.map +1 -0
- package/dist/siop/login-client.d.ts +29 -0
- package/dist/siop/login-client.d.ts.map +1 -0
- package/dist/siop/login-client.js +79 -0
- package/dist/siop/login-client.js.map +1 -0
- package/dist/siop/self-issued.d.ts +96 -0
- package/dist/siop/self-issued.d.ts.map +1 -0
- package/dist/siop/self-issued.js +162 -0
- package/dist/siop/self-issued.js.map +1 -0
- package/dist/store/holder-identity.d.ts +241 -0
- package/dist/store/holder-identity.d.ts.map +1 -0
- package/dist/store/holder-identity.js +441 -0
- package/dist/store/holder-identity.js.map +1 -0
- package/dist/store/index.d.ts +4 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +4 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/kv-store.d.ts +51 -0
- package/dist/store/kv-store.d.ts.map +1 -0
- package/dist/store/kv-store.js +100 -0
- package/dist/store/kv-store.js.map +1 -0
- package/dist/store/secret-wrap.d.ts +109 -0
- package/dist/store/secret-wrap.d.ts.map +1 -0
- package/dist/store/secret-wrap.js +85 -0
- package/dist/store/secret-wrap.js.map +1 -0
- package/dist/trust-tasks/index.d.ts +2 -0
- package/dist/trust-tasks/index.d.ts.map +1 -0
- package/dist/trust-tasks/index.js +2 -0
- package/dist/trust-tasks/index.js.map +1 -0
- package/dist/trust-tasks/sign.d.ts +31 -0
- package/dist/trust-tasks/sign.d.ts.map +1 -0
- package/dist/trust-tasks/sign.js +141 -0
- package/dist/trust-tasks/sign.js.map +1 -0
- package/dist/util/timing.d.ts +14 -0
- package/dist/util/timing.d.ts.map +1 -0
- package/dist/util/timing.js +20 -0
- package/dist/util/timing.js.map +1 -0
- package/dist/vault/delete.d.ts +19 -0
- package/dist/vault/delete.d.ts.map +1 -0
- package/dist/vault/delete.js +35 -0
- package/dist/vault/delete.js.map +1 -0
- package/dist/vault/index.d.ts +8 -0
- package/dist/vault/index.d.ts.map +1 -0
- package/dist/vault/index.js +7 -0
- package/dist/vault/index.js.map +1 -0
- package/dist/vault/list.d.ts +96 -0
- package/dist/vault/list.d.ts.map +1 -0
- package/dist/vault/list.js +106 -0
- package/dist/vault/list.js.map +1 -0
- package/dist/vault/proxy-login.d.ts +100 -0
- package/dist/vault/proxy-login.d.ts.map +1 -0
- package/dist/vault/proxy-login.js +106 -0
- package/dist/vault/proxy-login.js.map +1 -0
- package/dist/vault/release.d.ts +33 -0
- package/dist/vault/release.d.ts.map +1 -0
- package/dist/vault/release.js +83 -0
- package/dist/vault/release.js.map +1 -0
- package/dist/vault/sign-trust-task.d.ts +26 -0
- package/dist/vault/sign-trust-task.d.ts.map +1 -0
- package/dist/vault/sign-trust-task.js +53 -0
- package/dist/vault/sign-trust-task.js.map +1 -0
- package/dist/vault/transport.d.ts +50 -0
- package/dist/vault/transport.d.ts.map +1 -0
- package/dist/vault/transport.js +118 -0
- package/dist/vault/transport.js.map +1 -0
- package/dist/vault/upsert.d.ts +102 -0
- package/dist/vault/upsert.d.ts.map +1 -0
- package/dist/vault/upsert.js +92 -0
- package/dist/vault/upsert.js.map +1 -0
- package/dist/vta/bridge-mediator-session.d.ts +26 -0
- package/dist/vta/bridge-mediator-session.d.ts.map +1 -0
- package/dist/vta/bridge-mediator-session.js +37 -0
- package/dist/vta/bridge-mediator-session.js.map +1 -0
- package/dist/vta/bridge-memory.d.ts +80 -0
- package/dist/vta/bridge-memory.d.ts.map +1 -0
- package/dist/vta/bridge-memory.js +162 -0
- package/dist/vta/bridge-memory.js.map +1 -0
- package/dist/vta/client.d.ts +40 -0
- package/dist/vta/client.d.ts.map +1 -0
- package/dist/vta/client.js +91 -0
- package/dist/vta/client.js.map +1 -0
- package/dist/vta/contexts.d.ts +60 -0
- package/dist/vta/contexts.d.ts.map +1 -0
- package/dist/vta/contexts.js +118 -0
- package/dist/vta/contexts.js.map +1 -0
- package/dist/vta/didcomm.d.ts +57 -0
- package/dist/vta/didcomm.d.ts.map +1 -0
- package/dist/vta/didcomm.js +138 -0
- package/dist/vta/didcomm.js.map +1 -0
- package/dist/vta/errors.d.ts +20 -0
- package/dist/vta/errors.d.ts.map +1 -0
- package/dist/vta/errors.js +64 -0
- package/dist/vta/errors.js.map +1 -0
- package/dist/vta/index.d.ts +15 -0
- package/dist/vta/index.d.ts.map +1 -0
- package/dist/vta/index.js +15 -0
- package/dist/vta/index.js.map +1 -0
- package/dist/vta/mediation.d.ts +80 -0
- package/dist/vta/mediation.d.ts.map +1 -0
- package/dist/vta/mediation.js +29 -0
- package/dist/vta/mediation.js.map +1 -0
- package/dist/vta/mediator-client.d.ts +66 -0
- package/dist/vta/mediator-client.d.ts.map +1 -0
- package/dist/vta/mediator-client.js +139 -0
- package/dist/vta/mediator-client.js.map +1 -0
- package/dist/vta/pickup.d.ts +81 -0
- package/dist/vta/pickup.d.ts.map +1 -0
- package/dist/vta/pickup.js +30 -0
- package/dist/vta/pickup.js.map +1 -0
- package/dist/vta/protocol.d.ts +76 -0
- package/dist/vta/protocol.d.ts.map +1 -0
- package/dist/vta/protocol.js +30 -0
- package/dist/vta/protocol.js.map +1 -0
- package/dist/vta/smoke.d.ts +59 -0
- package/dist/vta/smoke.d.ts.map +1 -0
- package/dist/vta/smoke.js +408 -0
- package/dist/vta/smoke.js.map +1 -0
- package/dist/vta/transport.d.ts +55 -0
- package/dist/vta/transport.d.ts.map +1 -0
- package/dist/vta/transport.js +2 -0
- package/dist/vta/transport.js.map +1 -0
- package/dist/vta/types.d.ts +50 -0
- package/dist/vta/types.d.ts.map +1 -0
- package/dist/vta/types.js +2 -0
- package/dist/vta/types.js.map +1 -0
- package/dist/vta/wallet-session.d.ts +87 -0
- package/dist/vta/wallet-session.d.ts.map +1 -0
- package/dist/vta/wallet-session.js +106 -0
- package/dist/vta/wallet-session.js.map +1 -0
- package/dist/webauthn/base64url.d.ts +3 -0
- package/dist/webauthn/base64url.d.ts.map +1 -0
- package/dist/webauthn/base64url.js +17 -0
- package/dist/webauthn/base64url.js.map +1 -0
- package/dist/webauthn/index.d.ts +4 -0
- package/dist/webauthn/index.d.ts.map +1 -0
- package/dist/webauthn/index.js +4 -0
- package/dist/webauthn/index.js.map +1 -0
- package/dist/webauthn/multikey.d.ts +26 -0
- package/dist/webauthn/multikey.d.ts.map +1 -0
- package/dist/webauthn/multikey.js +91 -0
- package/dist/webauthn/multikey.js.map +1 -0
- package/dist/webauthn/register.d.ts +36 -0
- package/dist/webauthn/register.d.ts.map +1 -0
- package/dist/webauthn/register.js +77 -0
- package/dist/webauthn/register.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Shared transport for the vault/* Trust Task REST surface.
|
|
2
|
+
//
|
|
3
|
+
// Two helpers, reused by every vault/* operation (upsert, delete, release,
|
|
4
|
+
// and — eventually — list/get when they're migrated off the inlined auth
|
|
5
|
+
// flow in `list.ts`):
|
|
6
|
+
//
|
|
7
|
+
// - `getVtaBearer` — runs the canonical /auth/challenge → DIDComm
|
|
8
|
+
// authcrypt → /auth/ → bearer-token round-trip. Same auth primitive
|
|
9
|
+
// `swapAclRest` and `vaultListRest` already use.
|
|
10
|
+
// - `postTrustTask` — POSTs an authenticated Trust Task envelope to
|
|
11
|
+
// /api/trust-tasks and validates the response shape.
|
|
12
|
+
//
|
|
13
|
+
// Token caching is NOT done here. Each vault op currently does a fresh
|
|
14
|
+
// auth round-trip — adding session-token caching is a separate concern
|
|
15
|
+
// that lands when sync/event/0.1 (M5) needs a long-lived authenticated
|
|
16
|
+
// connection anyway.
|
|
17
|
+
import { packAuthcrypt } from "../didcomm/index.js";
|
|
18
|
+
const VTA_AUTHENTICATE = "https://affinidi.com/atm/1.0/authenticate";
|
|
19
|
+
/**
|
|
20
|
+
* Run /auth/challenge → authcrypt /auth/ → bearer token. The token's
|
|
21
|
+
* 15-minute TTL is more than enough for a single trust-task POST; we
|
|
22
|
+
* don't cache because the next vault op happens whenever the user
|
|
23
|
+
* clicks something and would likely fall outside the cache window.
|
|
24
|
+
*/
|
|
25
|
+
export async function getVtaBearer(opts) {
|
|
26
|
+
const f = opts.fetch ?? fetch.bind(globalThis);
|
|
27
|
+
const base = opts.baseUrl.replace(/\/+$/, "");
|
|
28
|
+
// 1. /auth/challenge → flat { challenge, sessionId, expiresAt }.
|
|
29
|
+
const cRes = await f(`${base}/auth/challenge`, {
|
|
30
|
+
method: "POST",
|
|
31
|
+
headers: { "content-type": "application/json" },
|
|
32
|
+
body: JSON.stringify({ did: opts.holder.did }),
|
|
33
|
+
});
|
|
34
|
+
if (!cRes.ok) {
|
|
35
|
+
throw new Error(`vta /auth/challenge failed (${cRes.status}): ${await cRes.text()}`);
|
|
36
|
+
}
|
|
37
|
+
const cBody = (await cRes.json());
|
|
38
|
+
if (!cBody.sessionId || !cBody.challenge) {
|
|
39
|
+
throw new Error(`vta /auth/challenge: malformed response: ${JSON.stringify(cBody)}`);
|
|
40
|
+
}
|
|
41
|
+
// 2. Authcrypt an `atm/1.0/authenticate` message to the VTA.
|
|
42
|
+
const authMsg = {
|
|
43
|
+
id: globalThis.crypto.randomUUID(),
|
|
44
|
+
type: VTA_AUTHENTICATE,
|
|
45
|
+
from: opts.holder.did,
|
|
46
|
+
to: [opts.service.did],
|
|
47
|
+
body: { challenge: cBody.challenge, session_id: cBody.sessionId },
|
|
48
|
+
};
|
|
49
|
+
const packed = await packAuthcrypt(authMsg, opts.holder, [
|
|
50
|
+
{
|
|
51
|
+
kid: opts.service.keyAgreementKid,
|
|
52
|
+
jwk: opts.service.keyAgreementPublicJwk,
|
|
53
|
+
},
|
|
54
|
+
]);
|
|
55
|
+
// 3. POST → AuthenticateResponse { session, tokens: { accessToken, ... } }.
|
|
56
|
+
const aRes = await f(`${base}/auth/`, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: { "content-type": "application/didcomm-encrypted+json" },
|
|
59
|
+
body: packed,
|
|
60
|
+
});
|
|
61
|
+
if (!aRes.ok) {
|
|
62
|
+
throw new Error(`vta /auth/ failed (${aRes.status}): ${await aRes.text()}`);
|
|
63
|
+
}
|
|
64
|
+
const aBody = (await aRes.json());
|
|
65
|
+
const accessToken = aBody.tokens?.accessToken;
|
|
66
|
+
if (!accessToken) {
|
|
67
|
+
throw new Error(`vta /auth/: malformed response: ${JSON.stringify(aBody)}`);
|
|
68
|
+
}
|
|
69
|
+
return accessToken;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* POST an authenticated Trust Task envelope to /api/trust-tasks. The
|
|
73
|
+
* framework's dispatcher returns either a `<task>#response` document
|
|
74
|
+
* (success) or a `trust-task-error/0.1` document (reject). This helper
|
|
75
|
+
* differentiates the two: success returns the parsed `payload` cast as
|
|
76
|
+
* `R`; reject throws an `Error` carrying the framework's error code +
|
|
77
|
+
* comment so callers see "vault/upsert:version_conflict — ..." rather
|
|
78
|
+
* than a raw 400.
|
|
79
|
+
*/
|
|
80
|
+
export async function postTrustTask(opts) {
|
|
81
|
+
const f = opts.fetch ?? fetch.bind(globalThis);
|
|
82
|
+
const base = opts.baseUrl.replace(/\/+$/, "");
|
|
83
|
+
const op = opts.operationLabel ?? opts.envelope.type;
|
|
84
|
+
const reqId = globalThis.crypto.randomUUID();
|
|
85
|
+
const fullEnvelope = {
|
|
86
|
+
id: reqId,
|
|
87
|
+
type: opts.envelope.type,
|
|
88
|
+
...(opts.envelope.issuer ? { issuer: opts.envelope.issuer } : {}),
|
|
89
|
+
...(opts.envelope.recipient ? { recipient: opts.envelope.recipient } : {}),
|
|
90
|
+
issuedAt: new Date().toISOString(),
|
|
91
|
+
payload: opts.envelope.payload,
|
|
92
|
+
};
|
|
93
|
+
const res = await f(`${base}/api/trust-tasks`, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: {
|
|
96
|
+
"content-type": "application/json",
|
|
97
|
+
authorization: `Bearer ${opts.bearer}`,
|
|
98
|
+
},
|
|
99
|
+
body: JSON.stringify(fullEnvelope),
|
|
100
|
+
});
|
|
101
|
+
if (!res.ok) {
|
|
102
|
+
throw new Error(`${op}: /api/trust-tasks failed (${res.status}): ${await res.text()}`);
|
|
103
|
+
}
|
|
104
|
+
const doc = (await res.json());
|
|
105
|
+
if (doc.type === opts.expectedResponseType) {
|
|
106
|
+
return doc.payload;
|
|
107
|
+
}
|
|
108
|
+
// Trust Task error envelope: type = trust-task-error/0.1 with
|
|
109
|
+
// payload.code = "<slug>:<error>" and payload.comment = explanation.
|
|
110
|
+
if (doc.type === "https://trusttasks.org/spec/trust-task-error/0.1") {
|
|
111
|
+
const errPayload = doc.payload;
|
|
112
|
+
const code = errPayload?.code ?? "unknown";
|
|
113
|
+
const comment = errPayload?.comment ?? "(no comment)";
|
|
114
|
+
throw new Error(`${code}: ${comment}`);
|
|
115
|
+
}
|
|
116
|
+
throw new Error(`${op}: unexpected response type ${doc.type ?? "(none)"} — ${JSON.stringify(doc)}`);
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/vault/transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { SecretKind, SiteTarget, VaultEntry } from "./list.js";
|
|
2
|
+
import { type VtaAuthInputs } from "./transport.js";
|
|
3
|
+
/** Optional driver config on Password-kind entries — instructs the
|
|
4
|
+
* VTA to POST these credentials at a specific URL during
|
|
5
|
+
* `vault/proxy-login/0.1`. Mirrors
|
|
6
|
+
* `vault/_shared/0.1/vault-secret#/$defs/PasswordLoginConfig`. */
|
|
7
|
+
export interface PasswordLoginConfig {
|
|
8
|
+
loginUrl: string;
|
|
9
|
+
format?: "json" | "form-urlencoded";
|
|
10
|
+
usernameField?: string;
|
|
11
|
+
passwordField?: string;
|
|
12
|
+
totpField?: string;
|
|
13
|
+
extraFields?: Record<string, string>;
|
|
14
|
+
successStatus?: number[];
|
|
15
|
+
}
|
|
16
|
+
/** Cleartext shape of the inner DIDComm message body — matches the
|
|
17
|
+
* canonical `vault/_shared/0.1/vault-secret#/$defs/VaultSecret` tagged
|
|
18
|
+
* union. M2A ships Password / Passkey / OauthTokens / BearerToken /
|
|
19
|
+
* Custom; M2B.4 adds `did-self-issued`. `didcomm-peer` and `ssh-key`
|
|
20
|
+
* follow when the UI grows fields for them. */
|
|
21
|
+
export type VaultSecret = {
|
|
22
|
+
kind: "password";
|
|
23
|
+
username?: string;
|
|
24
|
+
password: string;
|
|
25
|
+
loginConfig?: PasswordLoginConfig;
|
|
26
|
+
secureNotes?: string;
|
|
27
|
+
} | {
|
|
28
|
+
kind: "passkey";
|
|
29
|
+
credentialId: string;
|
|
30
|
+
privateKey: string;
|
|
31
|
+
algorithm?: string;
|
|
32
|
+
rpId: string;
|
|
33
|
+
userHandle?: string;
|
|
34
|
+
secureNotes?: string;
|
|
35
|
+
} | {
|
|
36
|
+
kind: "oauth-tokens";
|
|
37
|
+
provider: string;
|
|
38
|
+
refreshToken: string;
|
|
39
|
+
accessToken?: string;
|
|
40
|
+
accessTokenExpiresAt?: string;
|
|
41
|
+
scopes?: string[];
|
|
42
|
+
secureNotes?: string;
|
|
43
|
+
} | {
|
|
44
|
+
kind: "did-self-issued";
|
|
45
|
+
/** The persona DID the entry acts AS (becomes the SIOP `iss`
|
|
46
|
+
* + `sub`). */
|
|
47
|
+
did: string;
|
|
48
|
+
/** Key the VTA uses to sign the id_token. References a key the
|
|
49
|
+
* VTA's keystore can resolve — typically `<did>#key-0`. */
|
|
50
|
+
signingKeyId: string;
|
|
51
|
+
secureNotes?: string;
|
|
52
|
+
} | {
|
|
53
|
+
kind: "bearer-token";
|
|
54
|
+
token: string;
|
|
55
|
+
headerName?: string;
|
|
56
|
+
headerPrefix?: string;
|
|
57
|
+
secureNotes?: string;
|
|
58
|
+
} | {
|
|
59
|
+
kind: "custom";
|
|
60
|
+
fields: Array<{
|
|
61
|
+
name: string;
|
|
62
|
+
value: string;
|
|
63
|
+
hidden?: boolean;
|
|
64
|
+
kind?: string;
|
|
65
|
+
}>;
|
|
66
|
+
secureNotes?: string;
|
|
67
|
+
};
|
|
68
|
+
export interface VaultUpsertRestOptions extends VtaAuthInputs {
|
|
69
|
+
/** Omit to create with a maintainer-assigned ULID; supply to update or
|
|
70
|
+
* upsert-with-id. */
|
|
71
|
+
id?: string;
|
|
72
|
+
/** REQUIRED on update — the consumer's last-observed `version`. */
|
|
73
|
+
expectedVersion?: number;
|
|
74
|
+
contextId: string;
|
|
75
|
+
targets: SiteTarget[];
|
|
76
|
+
label: string;
|
|
77
|
+
secretKind: SecretKind;
|
|
78
|
+
tags?: string[];
|
|
79
|
+
notes?: string;
|
|
80
|
+
favicon?: string;
|
|
81
|
+
selectors?: string[];
|
|
82
|
+
customFieldNames?: string[];
|
|
83
|
+
expiresAt?: string;
|
|
84
|
+
/** REQUIRED on create unless secretKind is `did-self-issued` or
|
|
85
|
+
* `didcomm-peer`. On update, supply to rotate the secret; omit to
|
|
86
|
+
* keep the existing secret untouched. */
|
|
87
|
+
secret?: VaultSecret;
|
|
88
|
+
/** Metadata fields to explicitly null out. */
|
|
89
|
+
clearFields?: Array<"notes" | "favicon" | "expiresAt" | "tags" | "selectors" | "customFieldNames">;
|
|
90
|
+
}
|
|
91
|
+
export interface VaultUpsertResponse {
|
|
92
|
+
entry: VaultEntry;
|
|
93
|
+
created: boolean;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Create or update a vault entry. The cleartext secret never crosses
|
|
97
|
+
* the wire in plain — it's authcrypt-packed to the VTA's keyAgreement
|
|
98
|
+
* key. The maintainer unseals server-side, validates the variant
|
|
99
|
+
* against `secretKind`, and persists.
|
|
100
|
+
*/
|
|
101
|
+
export declare function vaultUpsertRest(opts: VaultUpsertRestOptions): Promise<VaultUpsertResponse>;
|
|
102
|
+
//# sourceMappingURL=upsert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../src/vault/upsert.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Vault — upsert (M2A.5).
|
|
2
|
+
//
|
|
3
|
+
// Posts a `https://trusttasks.org/spec/vault/upsert/0.1` envelope to the
|
|
4
|
+
// VTA's trust-task dispatcher. The cleartext secret is wrapped in a
|
|
5
|
+
// DIDComm authcrypt envelope (the `didcomm-authcrypt` variant of the
|
|
6
|
+
// canonical SealedEnvelope schema), so the long-term credential rides
|
|
7
|
+
// the wire as ciphertext only — even the VTA's own logs see just the
|
|
8
|
+
// JWE.
|
|
9
|
+
//
|
|
10
|
+
// Flow:
|
|
11
|
+
// 1. Build the cleartext VaultSecret JSON.
|
|
12
|
+
// 2. Pack it as authcrypt: sender = holder's keyAgreement, recipient =
|
|
13
|
+
// VTA's keyAgreement (same primitive the auth handshake uses, just
|
|
14
|
+
// pointing the opposite direction with a different message body).
|
|
15
|
+
// 3. Bearer-auth via `getVtaBearer` (REST + DIDComm-authcrypt /auth/
|
|
16
|
+
// round-trip).
|
|
17
|
+
// 4. POST the upsert envelope with `sealedSecret: { envelope:
|
|
18
|
+
// "didcomm-authcrypt", jwe }`.
|
|
19
|
+
// 5. Return the maintainer's response (metadata view + `created` flag).
|
|
20
|
+
import { packAuthcrypt } from "../didcomm/index.js";
|
|
21
|
+
import { getVtaBearer, postTrustTask } from "./transport.js";
|
|
22
|
+
const TASK_VAULT_UPSERT = "https://trusttasks.org/spec/vault/upsert/0.1";
|
|
23
|
+
const TASK_VAULT_UPSERT_RESPONSE = "https://trusttasks.org/spec/vault/upsert/0.1#response";
|
|
24
|
+
const INNER_MSG_TYPE = "https://openvtc.org/vault/upsert/secret-envelope/1.0";
|
|
25
|
+
/**
|
|
26
|
+
* Create or update a vault entry. The cleartext secret never crosses
|
|
27
|
+
* the wire in plain — it's authcrypt-packed to the VTA's keyAgreement
|
|
28
|
+
* key. The maintainer unseals server-side, validates the variant
|
|
29
|
+
* against `secretKind`, and persists.
|
|
30
|
+
*/
|
|
31
|
+
export async function vaultUpsertRest(opts) {
|
|
32
|
+
const bearer = await getVtaBearer({
|
|
33
|
+
baseUrl: opts.baseUrl,
|
|
34
|
+
holder: opts.holder,
|
|
35
|
+
service: opts.service,
|
|
36
|
+
...(opts.fetch ? { fetch: opts.fetch } : {}),
|
|
37
|
+
});
|
|
38
|
+
// Build the sealedSecret envelope — only built when `secret` is
|
|
39
|
+
// supplied. Update paths that keep the existing secret pass no
|
|
40
|
+
// sealedSecret at all.
|
|
41
|
+
let sealedSecret;
|
|
42
|
+
if (opts.secret) {
|
|
43
|
+
const jwe = await packSecretAsAuthcrypt({
|
|
44
|
+
secret: opts.secret,
|
|
45
|
+
holder: opts.holder,
|
|
46
|
+
service: opts.service,
|
|
47
|
+
});
|
|
48
|
+
sealedSecret = { envelope: "didcomm-authcrypt", jwe };
|
|
49
|
+
}
|
|
50
|
+
const payload = {
|
|
51
|
+
...(opts.id ? { id: opts.id } : {}),
|
|
52
|
+
...(opts.expectedVersion !== undefined ? { expectedVersion: opts.expectedVersion } : {}),
|
|
53
|
+
contextId: opts.contextId,
|
|
54
|
+
targets: opts.targets,
|
|
55
|
+
label: opts.label,
|
|
56
|
+
secretKind: opts.secretKind,
|
|
57
|
+
...(opts.tags ? { tags: opts.tags } : {}),
|
|
58
|
+
...(opts.notes !== undefined ? { notes: opts.notes } : {}),
|
|
59
|
+
...(opts.favicon ? { favicon: opts.favicon } : {}),
|
|
60
|
+
...(opts.selectors ? { selectors: opts.selectors } : {}),
|
|
61
|
+
...(opts.customFieldNames ? { customFieldNames: opts.customFieldNames } : {}),
|
|
62
|
+
...(opts.expiresAt ? { expiresAt: opts.expiresAt } : {}),
|
|
63
|
+
...(sealedSecret ? { sealedSecret } : {}),
|
|
64
|
+
...(opts.clearFields ? { clearFields: opts.clearFields } : {}),
|
|
65
|
+
};
|
|
66
|
+
return postTrustTask({
|
|
67
|
+
baseUrl: opts.baseUrl,
|
|
68
|
+
bearer,
|
|
69
|
+
envelope: {
|
|
70
|
+
type: TASK_VAULT_UPSERT,
|
|
71
|
+
payload,
|
|
72
|
+
issuer: opts.holder.did,
|
|
73
|
+
recipient: opts.service.did,
|
|
74
|
+
},
|
|
75
|
+
expectedResponseType: TASK_VAULT_UPSERT_RESPONSE,
|
|
76
|
+
operationLabel: "vault/upsert/0.1",
|
|
77
|
+
...(opts.fetch ? { fetch: opts.fetch } : {}),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
async function packSecretAsAuthcrypt(opts) {
|
|
81
|
+
const innerMsg = {
|
|
82
|
+
id: globalThis.crypto.randomUUID(),
|
|
83
|
+
type: INNER_MSG_TYPE,
|
|
84
|
+
from: opts.holder.did,
|
|
85
|
+
to: [opts.service.did],
|
|
86
|
+
body: opts.secret,
|
|
87
|
+
};
|
|
88
|
+
return packAuthcrypt(innerMsg, opts.holder, [
|
|
89
|
+
{ kid: opts.service.keyAgreementKid, jwk: opts.service.keyAgreementPublicJwk },
|
|
90
|
+
]);
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=upsert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upsert.js","sourceRoot":"","sources":["../../src/vault/upsert.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,EAAE;AACF,yEAAyE;AACzE,oEAAoE;AACpE,qEAAqE;AACrE,sEAAsE;AACtE,qEAAqE;AACrE,OAAO;AACP,EAAE;AACF,QAAQ;AACR,4CAA4C;AAC5C,wEAAwE;AACxE,uEAAuE;AACvE,sEAAsE;AACtE,sEAAsE;AACtE,mBAAmB;AACnB,+DAA+D;AAC/D,mCAAmC;AACnC,yEAAyE;AAEzE,OAAO,EAAE,aAAa,EAAiB,MAAM,qBAAqB,CAAC;AAInE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAsB,MAAM,gBAAgB,CAAC;AAEjF,MAAM,iBAAiB,GAAG,8CAA8C,CAAC;AACzE,MAAM,0BAA0B,GAAG,uDAAuD,CAAC;AAC3F,MAAM,cAAc,GAAG,sDAAsD,CAAC;AAqG9E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAA4B;IAE5B,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC;QAChC,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAC,CAAC;IAEH,gEAAgE;IAChE,+DAA+D;IAC/D,uBAAuB;IACvB,IAAI,YAAwE,CAAC;IAC7E,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,MAAM,qBAAqB,CAAC;YACtC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC,CAAC;QACH,YAAY,GAAG,EAAE,QAAQ,EAAE,mBAAmB,EAAE,GAAG,EAAE,CAAC;IACxD,CAAC;IAED,MAAM,OAAO,GAAG;QACd,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnC,GAAG,CAAC,IAAI,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxF,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7E,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/D,CAAC;IAEF,OAAO,aAAa,CAAsB;QACxC,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM;QACN,QAAQ,EAAE;YACR,IAAI,EAAE,iBAAiB;YACvB,OAAO;YACP,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG;YACvB,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG;SAC5B;QACD,oBAAoB,EAAE,0BAA0B;QAChD,cAAc,EAAE,kBAAkB;QAClC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,qBAAqB,CAAC,IAIpC;IACC,MAAM,QAAQ,GAAG;QACf,EAAE,EAAE,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE;QAClC,IAAI,EAAE,cAAc;QACpB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG;QACrB,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;QACtB,IAAI,EAAE,IAAI,CAAC,MAA4C;KACxD,CAAC;IACF,OAAO,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE;QAC1C,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE;KAC/E,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { MediatorConnection } from "../didcomm/index.js";
|
|
2
|
+
import type { DidcommMessageBridge, DidcommReply } from "./transport.js";
|
|
3
|
+
/**
|
|
4
|
+
* `DidcommMessageBridge` backed by the library's authenticated
|
|
5
|
+
* `MediatorSession` (via {@link connectMediatorSession}). The session
|
|
6
|
+
* owns the WebSocket, mediator auth, pickup live-delivery, inbound
|
|
7
|
+
* unpacking, and `thid` correlation — this class just adapts its
|
|
8
|
+
* `send` / `waitFor` to the bridge contract.
|
|
9
|
+
*
|
|
10
|
+
* Because the session only surfaces successfully sender-authenticated
|
|
11
|
+
* authcrypt frames (anoncrypt is dropped), every reply this bridge
|
|
12
|
+
* returns is already authenticated; callers validate `from` / `thid` /
|
|
13
|
+
* `type` on the decrypted message.
|
|
14
|
+
*/
|
|
15
|
+
export declare class MediatorSessionBridge implements DidcommMessageBridge {
|
|
16
|
+
private readonly connection;
|
|
17
|
+
private readonly defaultTimeoutMs;
|
|
18
|
+
constructor(connection: MediatorConnection, timeoutMs?: number);
|
|
19
|
+
sendAndAwaitReply(outerPackedJwe: string, expectThreadId: string, options?: {
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
}): Promise<DidcommReply>;
|
|
22
|
+
send(outerPackedJwe: string): Promise<void>;
|
|
23
|
+
/** Tear down the underlying session. */
|
|
24
|
+
close(): void;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=bridge-mediator-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-mediator-session.d.ts","sourceRoot":"","sources":["../../src/vta/bridge-mediator-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAIzE;;;;;;;;;;;GAWG;AACH,qBAAa,qBAAsB,YAAW,oBAAoB;IAChE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,UAAU,EAAE,kBAAkB,EAAE,SAAS,CAAC,EAAE,MAAM;IAKxD,iBAAiB,CACrB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/B,OAAO,CAAC,YAAY,CAAC;IAYlB,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjD,wCAAwC;IACxC,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
2
|
+
/**
|
|
3
|
+
* `DidcommMessageBridge` backed by the library's authenticated
|
|
4
|
+
* `MediatorSession` (via {@link connectMediatorSession}). The session
|
|
5
|
+
* owns the WebSocket, mediator auth, pickup live-delivery, inbound
|
|
6
|
+
* unpacking, and `thid` correlation — this class just adapts its
|
|
7
|
+
* `send` / `waitFor` to the bridge contract.
|
|
8
|
+
*
|
|
9
|
+
* Because the session only surfaces successfully sender-authenticated
|
|
10
|
+
* authcrypt frames (anoncrypt is dropped), every reply this bridge
|
|
11
|
+
* returns is already authenticated; callers validate `from` / `thid` /
|
|
12
|
+
* `type` on the decrypted message.
|
|
13
|
+
*/
|
|
14
|
+
export class MediatorSessionBridge {
|
|
15
|
+
connection;
|
|
16
|
+
defaultTimeoutMs;
|
|
17
|
+
constructor(connection, timeoutMs) {
|
|
18
|
+
this.connection = connection;
|
|
19
|
+
this.defaultTimeoutMs = timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
20
|
+
}
|
|
21
|
+
async sendAndAwaitReply(outerPackedJwe, expectThreadId, options) {
|
|
22
|
+
// Register the waiter before sending so a fast reply can't race
|
|
23
|
+
// ahead of the correlation (the session also buffers unclaimed
|
|
24
|
+
// frames, but registering first is unconditionally safe).
|
|
25
|
+
const reply = this.connection.waitFor(expectThreadId, options?.timeoutMs ?? this.defaultTimeoutMs);
|
|
26
|
+
this.connection.send(outerPackedJwe);
|
|
27
|
+
return (await reply);
|
|
28
|
+
}
|
|
29
|
+
async send(outerPackedJwe) {
|
|
30
|
+
this.connection.send(outerPackedJwe);
|
|
31
|
+
}
|
|
32
|
+
/** Tear down the underlying session. */
|
|
33
|
+
close() {
|
|
34
|
+
this.connection.close();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=bridge-mediator-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-mediator-session.js","sourceRoot":"","sources":["../../src/vta/bridge-mediator-session.ts"],"names":[],"mappings":"AAGA,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,qBAAqB;IACf,UAAU,CAAqB;IAC/B,gBAAgB,CAAS;IAE1C,YAAY,UAA8B,EAAE,SAAkB;QAC5D,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,gBAAgB,GAAG,SAAS,IAAI,kBAAkB,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,iBAAiB,CACrB,cAAsB,EACtB,cAAsB,EACtB,OAAgC;QAEhC,gEAAgE;QAChE,+DAA+D;QAC/D,0DAA0D;QAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CACnC,cAAc,EACd,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC,gBAAgB,CAC5C,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACrC,OAAO,CAAC,MAAM,KAAK,CAAiB,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,cAAsB;QAC/B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACvC,CAAC;IAED,wCAAwC;IACxC,KAAK;QACH,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Identity, type PublicJwk } from "../didcomm/index.js";
|
|
2
|
+
import type { DidcommMessageBridge, DidcommReply } from "./transport.js";
|
|
3
|
+
/** Reply contract a fake-VTA or fake-mediator handler returns to the bridge.
|
|
4
|
+
* Returning `null` or `undefined` signals "no reply" — appropriate for
|
|
5
|
+
* DIDComm notifications like `pickup/3.0/live-delivery-change` and
|
|
6
|
+
* `pickup/3.0/messages-received`. */
|
|
7
|
+
export interface InMemoryHandlerReply {
|
|
8
|
+
type: string;
|
|
9
|
+
body: unknown;
|
|
10
|
+
}
|
|
11
|
+
export type InMemoryHandler = (request: {
|
|
12
|
+
type: string;
|
|
13
|
+
from?: string;
|
|
14
|
+
body: unknown;
|
|
15
|
+
id: string;
|
|
16
|
+
}) => Promise<InMemoryHandlerReply | null | undefined> | InMemoryHandlerReply | null | undefined;
|
|
17
|
+
export interface InMemoryDidcommBridgeOptions {
|
|
18
|
+
/** Fake VTA identity (unpacks inner authcrypt + signs replies). */
|
|
19
|
+
vta?: Identity;
|
|
20
|
+
/** Sender public JWK so VTA can authenticate inner authcrypt. */
|
|
21
|
+
holderPublicJwk: {
|
|
22
|
+
kid: string;
|
|
23
|
+
jwk: PublicJwk;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Fake mediator identity. When set, the bridge tries to unpack
|
|
27
|
+
* the outer message with the mediator first. If the result is a
|
|
28
|
+
* `routing/2.0/forward` envelope, the inner JWE is extracted from
|
|
29
|
+
* attachments and dispatched against `vtaHandlers`; otherwise the
|
|
30
|
+
* decrypted message is dispatched against `mediatorHandlers`.
|
|
31
|
+
*
|
|
32
|
+
* When omitted, the outer is treated as the inner authcrypt
|
|
33
|
+
* directly (VTA-only, mediator-less transport).
|
|
34
|
+
*/
|
|
35
|
+
mediator?: Identity;
|
|
36
|
+
/** Handlers for messages that reached the (fake) VTA. */
|
|
37
|
+
vtaHandlers?: Record<string, InMemoryHandler>;
|
|
38
|
+
/** Handlers for direct-to-mediator messages (coordinate-mediation, pickup, …). */
|
|
39
|
+
mediatorHandlers?: Record<string, InMemoryHandler>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Deterministic, single-process simulator covering two delivery
|
|
43
|
+
* patterns:
|
|
44
|
+
*
|
|
45
|
+
* 1. **Forward-wrapped to VTA** (passkey-management): outer anoncrypt
|
|
46
|
+
* to mediator → forward envelope → inner authcrypt holder→VTA.
|
|
47
|
+
* The bridge unwraps the forward, decrypts the inner as VTA,
|
|
48
|
+
* dispatches against `vtaHandlers`, and authcrypts the reply
|
|
49
|
+
* VTA→holder.
|
|
50
|
+
* 2. **Direct to mediator** (coordinate-mediation): outer authcrypt
|
|
51
|
+
* holder→mediator. The bridge decrypts as mediator, dispatches
|
|
52
|
+
* against `mediatorHandlers`, and authcrypts the reply
|
|
53
|
+
* mediator→holder.
|
|
54
|
+
*
|
|
55
|
+
* Pattern detection is runtime — try mediator-unpack first and
|
|
56
|
+
* inspect the decoded `type`. Falls back to direct VTA-unpack if no
|
|
57
|
+
* mediator is configured.
|
|
58
|
+
*
|
|
59
|
+
* Not for production. Drives the smokes in `./smoke.ts`.
|
|
60
|
+
*/
|
|
61
|
+
export declare class InMemoryDidcommBridge implements DidcommMessageBridge {
|
|
62
|
+
private readonly vta?;
|
|
63
|
+
private readonly mediator?;
|
|
64
|
+
private readonly holderPublicJwk;
|
|
65
|
+
private readonly vtaHandlers;
|
|
66
|
+
private readonly mediatorHandlers;
|
|
67
|
+
constructor(opts: InMemoryDidcommBridgeOptions);
|
|
68
|
+
sendAndAwaitReply(outerPackedJwe: string, _expectThreadId: string, _options?: {
|
|
69
|
+
timeoutMs?: number;
|
|
70
|
+
}): Promise<DidcommReply>;
|
|
71
|
+
send(outerPackedJwe: string): Promise<void>;
|
|
72
|
+
/** Internal: route the outer envelope to the right pattern's
|
|
73
|
+
* handler and return its decrypted reply (or null for notifications). */
|
|
74
|
+
private process;
|
|
75
|
+
private handleForwarded;
|
|
76
|
+
private handleDirectVta;
|
|
77
|
+
private handleMediatorDirect;
|
|
78
|
+
private dispatch;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=bridge-memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-memory.d.ts","sourceRoot":"","sources":["../../src/vta/bridge-memory.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EAER,KAAK,SAAS,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA2BzE;;;sCAGsC;AACtC,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACZ,KAAK,OAAO,CAAC,oBAAoB,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,oBAAoB,GAAG,IAAI,GAAG,SAAS,CAAC;AAEjG,MAAM,WAAW,4BAA4B;IAC3C,mEAAmE;IACnE,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,iEAAiE;IACjE,eAAe,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,SAAS,CAAA;KAAE,CAAC;IACjD;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC9C,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CACpD;AAeD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,qBAAsB,YAAW,oBAAoB;IAChE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAW;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkC;IAClE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkC;IAC9D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkC;gBAEvD,IAAI,EAAE,4BAA4B;IAQxC,iBAAiB,CACrB,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,MAAM,EACvB,QAAQ,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAChC,OAAO,CAAC,YAAY,CAAC;IAUlB,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjD;8EAC0E;YAC5D,OAAO;YA+BP,eAAe;YAaf,eAAe;YAqBf,oBAAoB;YAOpB,QAAQ;CAgCvB"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { Identity, unpackMessage, } from "../didcomm/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parse a JWE protected-header `skid` without decrypting. Authcrypt
|
|
4
|
+
* (ECDH-1PU) sets it; anoncrypt (ECDH-ES) doesn't — so its presence
|
|
5
|
+
* tells the in-memory bridge whether to expect a sender for unpack.
|
|
6
|
+
*/
|
|
7
|
+
function readJweSenderKid(jwe) {
|
|
8
|
+
try {
|
|
9
|
+
const parsed = JSON.parse(jwe);
|
|
10
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
11
|
+
return undefined;
|
|
12
|
+
const protectedB64 = parsed.protected;
|
|
13
|
+
if (typeof protectedB64 !== "string")
|
|
14
|
+
return undefined;
|
|
15
|
+
const headerJson = atob(protectedB64.replaceAll("-", "+").replaceAll("_", "/"));
|
|
16
|
+
const header = JSON.parse(headerJson);
|
|
17
|
+
if (typeof header !== "object" || header === null)
|
|
18
|
+
return undefined;
|
|
19
|
+
const skid = header.skid;
|
|
20
|
+
return typeof skid === "string" ? skid : undefined;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const FORWARD_TYPE = "https://didcomm.org/routing/2.0/forward";
|
|
27
|
+
/**
|
|
28
|
+
* Deterministic, single-process simulator covering two delivery
|
|
29
|
+
* patterns:
|
|
30
|
+
*
|
|
31
|
+
* 1. **Forward-wrapped to VTA** (passkey-management): outer anoncrypt
|
|
32
|
+
* to mediator → forward envelope → inner authcrypt holder→VTA.
|
|
33
|
+
* The bridge unwraps the forward, decrypts the inner as VTA,
|
|
34
|
+
* dispatches against `vtaHandlers`, and authcrypts the reply
|
|
35
|
+
* VTA→holder.
|
|
36
|
+
* 2. **Direct to mediator** (coordinate-mediation): outer authcrypt
|
|
37
|
+
* holder→mediator. The bridge decrypts as mediator, dispatches
|
|
38
|
+
* against `mediatorHandlers`, and authcrypts the reply
|
|
39
|
+
* mediator→holder.
|
|
40
|
+
*
|
|
41
|
+
* Pattern detection is runtime — try mediator-unpack first and
|
|
42
|
+
* inspect the decoded `type`. Falls back to direct VTA-unpack if no
|
|
43
|
+
* mediator is configured.
|
|
44
|
+
*
|
|
45
|
+
* Not for production. Drives the smokes in `./smoke.ts`.
|
|
46
|
+
*/
|
|
47
|
+
export class InMemoryDidcommBridge {
|
|
48
|
+
vta;
|
|
49
|
+
mediator;
|
|
50
|
+
holderPublicJwk;
|
|
51
|
+
vtaHandlers;
|
|
52
|
+
mediatorHandlers;
|
|
53
|
+
constructor(opts) {
|
|
54
|
+
if (opts.vta !== undefined)
|
|
55
|
+
this.vta = opts.vta;
|
|
56
|
+
if (opts.mediator !== undefined)
|
|
57
|
+
this.mediator = opts.mediator;
|
|
58
|
+
this.holderPublicJwk = opts.holderPublicJwk;
|
|
59
|
+
this.vtaHandlers = opts.vtaHandlers ?? {};
|
|
60
|
+
this.mediatorHandlers = opts.mediatorHandlers ?? {};
|
|
61
|
+
}
|
|
62
|
+
async sendAndAwaitReply(outerPackedJwe, _expectThreadId, _options) {
|
|
63
|
+
const reply = await this.process(outerPackedJwe);
|
|
64
|
+
if (reply === null) {
|
|
65
|
+
throw new Error("bridge: handler returned no reply (notification) but caller awaited one");
|
|
66
|
+
}
|
|
67
|
+
return reply;
|
|
68
|
+
}
|
|
69
|
+
async send(outerPackedJwe) {
|
|
70
|
+
// Fire-and-forget. The in-memory bridge still routes through
|
|
71
|
+
// the same dispatch path so that handlers see notifications,
|
|
72
|
+
// but it discards any reply (which should be null for proper
|
|
73
|
+
// notification message types).
|
|
74
|
+
await this.process(outerPackedJwe);
|
|
75
|
+
}
|
|
76
|
+
/** Internal: route the outer envelope to the right pattern's
|
|
77
|
+
* handler and return its decrypted reply (or null for notifications). */
|
|
78
|
+
async process(outerPackedJwe) {
|
|
79
|
+
// ── Pattern 1 + 2: mediator configured → try mediator-unpack first
|
|
80
|
+
if (this.mediator) {
|
|
81
|
+
const outerIsAuthcrypt = readJweSenderKid(outerPackedJwe) !== undefined;
|
|
82
|
+
const outerView = await unpackMessage({
|
|
83
|
+
input: outerPackedJwe,
|
|
84
|
+
...(outerIsAuthcrypt
|
|
85
|
+
? { sender_public_jwk: this.holderPublicJwk.jwk }
|
|
86
|
+
: {}),
|
|
87
|
+
}, this.mediator);
|
|
88
|
+
if (outerView.kind !== "encrypted") {
|
|
89
|
+
throw new Error(`bridge: outer unpack returned ${outerView.kind}, expected encrypted`);
|
|
90
|
+
}
|
|
91
|
+
const outer = outerView.message;
|
|
92
|
+
if (outer.type === FORWARD_TYPE) {
|
|
93
|
+
return this.handleForwarded(outer);
|
|
94
|
+
}
|
|
95
|
+
return this.handleMediatorDirect(outer);
|
|
96
|
+
}
|
|
97
|
+
// ── Pattern 3: no mediator, outer IS the inner authcrypt to VTA
|
|
98
|
+
return this.handleDirectVta(outerPackedJwe);
|
|
99
|
+
}
|
|
100
|
+
async handleForwarded(outer) {
|
|
101
|
+
if (!this.vta) {
|
|
102
|
+
throw new Error("bridge: forward envelope received but no VTA identity configured");
|
|
103
|
+
}
|
|
104
|
+
const innerJson = outer.attachments?.[0]?.data?.json;
|
|
105
|
+
if (innerJson === undefined) {
|
|
106
|
+
throw new Error("bridge: forward envelope missing inner attachment");
|
|
107
|
+
}
|
|
108
|
+
const innerJwe = typeof innerJson === "string" ? innerJson : JSON.stringify(innerJson);
|
|
109
|
+
return this.handleDirectVta(innerJwe);
|
|
110
|
+
}
|
|
111
|
+
async handleDirectVta(innerJwe) {
|
|
112
|
+
if (!this.vta) {
|
|
113
|
+
throw new Error("bridge: direct-to-VTA path requires `vta` identity");
|
|
114
|
+
}
|
|
115
|
+
const inner = await unpackMessage({ input: innerJwe, sender_public_jwk: this.holderPublicJwk.jwk }, this.vta);
|
|
116
|
+
if (inner.kind !== "encrypted") {
|
|
117
|
+
throw new Error(`bridge: expected encrypted inner, got ${inner.kind}`);
|
|
118
|
+
}
|
|
119
|
+
if (!inner.authenticated) {
|
|
120
|
+
throw new Error("bridge: inner authcrypt failed sender authentication");
|
|
121
|
+
}
|
|
122
|
+
return this.dispatch(inner.message, this.vtaHandlers, this.vta);
|
|
123
|
+
}
|
|
124
|
+
async handleMediatorDirect(decrypted) {
|
|
125
|
+
if (!this.mediator) {
|
|
126
|
+
throw new Error("unreachable: mediator-direct without mediator");
|
|
127
|
+
}
|
|
128
|
+
return this.dispatch(decrypted, this.mediatorHandlers, this.mediator);
|
|
129
|
+
}
|
|
130
|
+
async dispatch(req, handlers, replier) {
|
|
131
|
+
if (!req.type)
|
|
132
|
+
throw new Error("bridge: message missing `type`");
|
|
133
|
+
if (!req.id)
|
|
134
|
+
throw new Error("bridge: message missing `id`");
|
|
135
|
+
if (!req.from) {
|
|
136
|
+
throw new Error("bridge: message missing `from` (cannot reply)");
|
|
137
|
+
}
|
|
138
|
+
const handler = handlers[req.type];
|
|
139
|
+
if (!handler) {
|
|
140
|
+
throw new Error(`bridge: no handler for ${req.type}`);
|
|
141
|
+
}
|
|
142
|
+
const reply = await handler({
|
|
143
|
+
type: req.type,
|
|
144
|
+
from: req.from,
|
|
145
|
+
body: req.body ?? {},
|
|
146
|
+
id: req.id,
|
|
147
|
+
});
|
|
148
|
+
if (reply == null)
|
|
149
|
+
return null;
|
|
150
|
+
// The real mediator-session bridge returns the *decrypted* reply, so
|
|
151
|
+
// this simulator returns the reply message directly rather than
|
|
152
|
+
// packing it (it holds only the holder's public key and couldn't
|
|
153
|
+
// unpack a self-packed reply anyway).
|
|
154
|
+
return {
|
|
155
|
+
type: reply.type,
|
|
156
|
+
from: replier.did,
|
|
157
|
+
thid: req.id,
|
|
158
|
+
body: reply.body,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=bridge-memory.js.map
|