gdc-sdk-node-ts 2.4.34 → 2.4.35
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.
|
@@ -11,6 +11,16 @@ export type NodeManagedWalletOptions = {
|
|
|
11
11
|
resolveRecipientJwk?: (recipientDid: string) => Promise<JWK>;
|
|
12
12
|
policy?: Partial<NodeManagedWalletPolicy>;
|
|
13
13
|
};
|
|
14
|
+
export type NodeProfessionalIdentityVpInput = Readonly<{
|
|
15
|
+
clientId: string;
|
|
16
|
+
actorDid: string;
|
|
17
|
+
profileDid?: string;
|
|
18
|
+
role: string;
|
|
19
|
+
email?: string;
|
|
20
|
+
sameAs?: string | readonly string[];
|
|
21
|
+
telephone?: string;
|
|
22
|
+
credentialMaterial?: string;
|
|
23
|
+
}>;
|
|
14
24
|
export type NodeCommunicationWalletInitialization = {
|
|
15
25
|
/**
|
|
16
26
|
* Stable secret used to reconstruct the same communication keys after a
|
|
@@ -67,26 +77,29 @@ export declare class NodeManagedWallet implements IWallet {
|
|
|
67
77
|
*/
|
|
68
78
|
getPublicJwks(context?: WalletExecutionContext, filter?: WalletKeySelection): Promise<WalletKeyDescriptor[]>;
|
|
69
79
|
/**
|
|
70
|
-
* Initializes
|
|
71
|
-
* public signing/encryption JWKS
|
|
72
|
-
*
|
|
80
|
+
* Initializes one user/profile device communication wallet and returns only
|
|
81
|
+
* its public signing/encryption JWKS. The wallet is actor-role neutral: the
|
|
82
|
+
* same custody contract can back a controller, employee/professional or
|
|
83
|
+
* individual-controller profile.
|
|
73
84
|
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
85
|
+
* These communication keys do not replace the actor's person/professional-
|
|
86
|
+
* role signing key. In the historical legal-representative flow, for example,
|
|
87
|
+
* this returned set is accepted as `controller.publicKeys`, while the
|
|
88
|
+
* independent role key is supplied as `controller.publicSignKey`.
|
|
77
89
|
*
|
|
78
90
|
* The caller owns durable wallet custody. When deterministic provisioning is
|
|
79
91
|
* used, protect `seedMaterial` in the portal wallet store (for example with
|
|
80
92
|
* its KMS/KEK and optionally a user PIN) and persist the same non-secret
|
|
81
93
|
* `context.runtime.runtimeId`. A fresh `NodeManagedWallet` reconstructs the
|
|
82
94
|
* same private keys from that seed and context after restart, so private JWKs
|
|
83
|
-
* do not need separate persistence.
|
|
84
|
-
*
|
|
95
|
+
* do not need separate persistence. Only the returned public JWKS may be
|
|
96
|
+
* submitted when the selected high-level onboarding flow requires it.
|
|
85
97
|
*/
|
|
86
98
|
initializeCommunicationJsonWebKeySet(context: WalletExecutionContext, options?: NodeCommunicationWalletInitialization): Promise<JwkSet>;
|
|
87
99
|
/**
|
|
88
100
|
* Returns only the public DIDComm signing/encryption keys for a previously
|
|
89
|
-
* initialized runtime wallet. Private material never
|
|
101
|
+
* initialized user/profile device runtime wallet. Private material never
|
|
102
|
+
* leaves the wallet, and the returned keys do not convey an actor role.
|
|
90
103
|
*/
|
|
91
104
|
getCommunicationJsonWebKeySet(context: WalletExecutionContext): Promise<JwkSet>;
|
|
92
105
|
/**
|
|
@@ -139,6 +152,12 @@ export declare class NodeManagedWallet implements IWallet {
|
|
|
139
152
|
* Builds one compact JWS using one managed signing key.
|
|
140
153
|
*/
|
|
141
154
|
signCompactJws(context: WalletExecutionContext, request: WalletCompactJwsRequest): Promise<string>;
|
|
155
|
+
/**
|
|
156
|
+
* Builds and signs the canonical employee/professional VP with the managed
|
|
157
|
+
* `vp-token-signing` key. Callers provide identity facts only; they do not
|
|
158
|
+
* assemble JOSE headers, choose a JWK or handle private key material.
|
|
159
|
+
*/
|
|
160
|
+
signProfessionalIdentityVp(context: WalletExecutionContext, input: NodeProfessionalIdentityVpInput): Promise<string>;
|
|
142
161
|
/**
|
|
143
162
|
* Builds one detached compact JWS using one managed signing key.
|
|
144
163
|
*/
|
|
@@ -4,6 +4,7 @@ import { CryptographyService } from 'gdc-common-utils-ts/CryptographyService';
|
|
|
4
4
|
import { Content } from 'gdc-common-utils-ts/utils/content';
|
|
5
5
|
import { createJwtSigner } from 'gdc-common-utils-ts/utils/jwt-signer';
|
|
6
6
|
import { buildJwtCompact, prepareJwtForSignature } from 'gdc-common-utils-ts/utils/jwt';
|
|
7
|
+
import { buildProfessionalIdentityVpPayload } from 'gdc-common-utils-ts/utils/professional-smart';
|
|
7
8
|
import { NodeCryptoHelper } from './node-crypto-helper.js';
|
|
8
9
|
const DEFAULT_POLICY = {
|
|
9
10
|
defaults: {
|
|
@@ -134,21 +135,23 @@ export class NodeManagedWallet {
|
|
|
134
135
|
return descriptors;
|
|
135
136
|
}
|
|
136
137
|
/**
|
|
137
|
-
* Initializes
|
|
138
|
-
* public signing/encryption JWKS
|
|
139
|
-
*
|
|
138
|
+
* Initializes one user/profile device communication wallet and returns only
|
|
139
|
+
* its public signing/encryption JWKS. The wallet is actor-role neutral: the
|
|
140
|
+
* same custody contract can back a controller, employee/professional or
|
|
141
|
+
* individual-controller profile.
|
|
140
142
|
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
143
|
+
* These communication keys do not replace the actor's person/professional-
|
|
144
|
+
* role signing key. In the historical legal-representative flow, for example,
|
|
145
|
+
* this returned set is accepted as `controller.publicKeys`, while the
|
|
146
|
+
* independent role key is supplied as `controller.publicSignKey`.
|
|
144
147
|
*
|
|
145
148
|
* The caller owns durable wallet custody. When deterministic provisioning is
|
|
146
149
|
* used, protect `seedMaterial` in the portal wallet store (for example with
|
|
147
150
|
* its KMS/KEK and optionally a user PIN) and persist the same non-secret
|
|
148
151
|
* `context.runtime.runtimeId`. A fresh `NodeManagedWallet` reconstructs the
|
|
149
152
|
* same private keys from that seed and context after restart, so private JWKs
|
|
150
|
-
* do not need separate persistence.
|
|
151
|
-
*
|
|
153
|
+
* do not need separate persistence. Only the returned public JWKS may be
|
|
154
|
+
* submitted when the selected high-level onboarding flow requires it.
|
|
152
155
|
*/
|
|
153
156
|
async initializeCommunicationJsonWebKeySet(context, options = {}) {
|
|
154
157
|
if (!context.runtime?.runtimeId) {
|
|
@@ -164,7 +167,8 @@ export class NodeManagedWallet {
|
|
|
164
167
|
}
|
|
165
168
|
/**
|
|
166
169
|
* Returns only the public DIDComm signing/encryption keys for a previously
|
|
167
|
-
* initialized runtime wallet. Private material never
|
|
170
|
+
* initialized user/profile device runtime wallet. Private material never
|
|
171
|
+
* leaves the wallet, and the returned keys do not convey an actor role.
|
|
168
172
|
*/
|
|
169
173
|
async getCommunicationJsonWebKeySet(context) {
|
|
170
174
|
if (!context.runtime?.runtimeId) {
|
|
@@ -335,6 +339,37 @@ export class NodeManagedWallet {
|
|
|
335
339
|
const signature = await this.sign(prepared.signingInput, context, request.key);
|
|
336
340
|
return buildJwtCompact(prepared.encodedHeader, prepared.encodedPayload, signature);
|
|
337
341
|
}
|
|
342
|
+
/**
|
|
343
|
+
* Builds and signs the canonical employee/professional VP with the managed
|
|
344
|
+
* `vp-token-signing` key. Callers provide identity facts only; they do not
|
|
345
|
+
* assemble JOSE headers, choose a JWK or handle private key material.
|
|
346
|
+
*/
|
|
347
|
+
async signProfessionalIdentityVp(context, input) {
|
|
348
|
+
const [vpSigningKey] = await this.getPublicJwks(context, {
|
|
349
|
+
ownerScope: 'runtime',
|
|
350
|
+
purpose: 'vp-token-signing',
|
|
351
|
+
});
|
|
352
|
+
if (!vpSigningKey)
|
|
353
|
+
throw new Error('Managed VP signing key is not available.');
|
|
354
|
+
const payload = buildProfessionalIdentityVpPayload({
|
|
355
|
+
clientId: input.clientId,
|
|
356
|
+
actorDid: input.actorDid,
|
|
357
|
+
role: input.role,
|
|
358
|
+
...(input.email ? { email: input.email } : {}),
|
|
359
|
+
...(input.sameAs ? { sameAs: input.sameAs } : {}),
|
|
360
|
+
...(input.telephone ? { telephone: input.telephone } : {}),
|
|
361
|
+
...(input.credentialMaterial ? { credentialMaterial: input.credentialMaterial } : {}),
|
|
362
|
+
});
|
|
363
|
+
return this.signCompactJws(context, {
|
|
364
|
+
header: { typ: 'JWT', jwk: vpSigningKey.publicJwk },
|
|
365
|
+
claims: {
|
|
366
|
+
iss: vpSigningKey.kid,
|
|
367
|
+
sub: input.profileDid || input.actorDid,
|
|
368
|
+
...payload,
|
|
369
|
+
},
|
|
370
|
+
key: { ownerScope: 'runtime', purpose: 'vp-token-signing' },
|
|
371
|
+
});
|
|
372
|
+
}
|
|
338
373
|
/**
|
|
339
374
|
* Builds one detached compact JWS using one managed signing key.
|
|
340
375
|
*/
|
|
@@ -218,6 +218,12 @@ export async function enrollInvitedOrganizationEmployeeWithDeps(input, deps) {
|
|
|
218
218
|
clientInstanceId: input.clientInstanceId,
|
|
219
219
|
dcrRedirectUris: input.dcrRedirectUris,
|
|
220
220
|
dcrClientName: input.dcrClientName,
|
|
221
|
-
|
|
221
|
+
// The grant contains the server-verified stable actor alias and role. The
|
|
222
|
+
// profile runtime signs the VP with its managed DCR wallet after GW has
|
|
223
|
+
// returned the real client_id; idToken remains only the OIDC account proof.
|
|
224
|
+
professionalProof: {
|
|
225
|
+
role: input.grant.employeeRoleCode,
|
|
226
|
+
sameAs: input.grant.employeeActorIdentifier,
|
|
227
|
+
},
|
|
222
228
|
});
|
|
223
229
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { JWK } from 'gdc-common-utils-ts/models/jwk';
|
|
2
2
|
import type { ActorKind } from 'gdc-common-utils-ts/models/actor-session';
|
|
3
3
|
import type { LegalOrganizationVerificationTransactionInput } from 'gdc-common-utils-ts/utils/legal-organization-verification-transaction';
|
|
4
|
-
import { type ConfidentialStorageProfile, type PollOptions, type SubmitAndPollResult } from 'gdc-sdk-core-ts';
|
|
4
|
+
import { type AppInfo, type ConfidentialStorageProfile, type PollOptions, type SubmitAndPollResult } from 'gdc-sdk-core-ts';
|
|
5
5
|
import type { RouteContext } from './individual-onboarding.js';
|
|
6
6
|
import type { HostRouteContext } from './host-onboarding.js';
|
|
7
7
|
import type { SecureDidcommTransportAdapter } from 'gdc-sdk-core-ts';
|
|
@@ -31,7 +31,8 @@ export type ServerProfileRecord = Readonly<{
|
|
|
31
31
|
/** Server-owned policy; browser input is never authoritative for this value. */
|
|
32
32
|
confidentialStorageProfile?: ConfidentialStorageProfile;
|
|
33
33
|
protectedWalletSeed: PinProtectedProfileSecret;
|
|
34
|
-
|
|
34
|
+
/** Present only when this actor kind requires an independent signed role/relationship VP. */
|
|
35
|
+
protectedVpToken?: PinProtectedProfileSecret;
|
|
35
36
|
failedUnlocks: number;
|
|
36
37
|
lockedUntil?: string;
|
|
37
38
|
createdAt: string;
|
|
@@ -95,8 +96,25 @@ export type ServerProfileEnrollmentInput = Readonly<{
|
|
|
95
96
|
* derives the identity from the wallet key it creates for this profile.
|
|
96
97
|
*/
|
|
97
98
|
clientInstanceId?: string;
|
|
98
|
-
/**
|
|
99
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Signed actor/controller VP protected for later SMART operations. Required
|
|
101
|
+
* for organization/professional/member actors. Individual-controller
|
|
102
|
+
* profiles omit it: their account `id_token`, DCR device binding and
|
|
103
|
+
* provider-side relationship policy are evaluated independently.
|
|
104
|
+
*/
|
|
105
|
+
vpToken?: string;
|
|
106
|
+
/**
|
|
107
|
+
* High-level employee/professional proof source. When supplied, the SDK
|
|
108
|
+
* builds and signs the VP with the managed DCR wallet after registration;
|
|
109
|
+
* callers do not compose JWT/JWK material.
|
|
110
|
+
*/
|
|
111
|
+
professionalProof?: Readonly<{
|
|
112
|
+
role: string;
|
|
113
|
+
email?: string;
|
|
114
|
+
sameAs?: string | readonly string[];
|
|
115
|
+
telephone?: string;
|
|
116
|
+
credentialMaterial?: string;
|
|
117
|
+
}>;
|
|
100
118
|
/** Redirect URIs owned by this portal/app installation. */
|
|
101
119
|
redirectUris?: string[];
|
|
102
120
|
/** Human-readable portal/app name. */
|
|
@@ -132,6 +150,20 @@ export type ServerProfileOrganizationIssueInput = Readonly<{
|
|
|
132
150
|
verificationInput: LegalOrganizationVerificationTransactionInput;
|
|
133
151
|
pollOptions?: PollOptions;
|
|
134
152
|
}>;
|
|
153
|
+
export type ServerOrganizationControllerVpInput = Readonly<{
|
|
154
|
+
/** Same protected seed that committed the controller public key to ICA. */
|
|
155
|
+
walletSeed: string;
|
|
156
|
+
/** Stable application-owned derivation id reused after every restart. */
|
|
157
|
+
walletKeyDerivationId: string;
|
|
158
|
+
/** Terminal ICA/GW verification body containing the issued organization, representative and controller VCs. */
|
|
159
|
+
verificationResponseBody: unknown;
|
|
160
|
+
/** Exact organization tenant identifier represented by the controller proof. */
|
|
161
|
+
tenantId: string;
|
|
162
|
+
/** Exact audience required by the receiving GW/host policy. */
|
|
163
|
+
audience: string;
|
|
164
|
+
/** Optional stable sameAs selector when the response contains several controller credentials. */
|
|
165
|
+
controllerSameAs?: string;
|
|
166
|
+
}>;
|
|
135
167
|
/** One explicit unlock request; scopes and subject remain session-bound. */
|
|
136
168
|
export type ServerProfileUnlockInput = Readonly<{
|
|
137
169
|
ownerId: string;
|
|
@@ -166,6 +198,8 @@ export type ServerProfileSessionManagerOptions = Readonly<{
|
|
|
166
198
|
sealer: ServerProfileSealer;
|
|
167
199
|
gatewayBaseUrl: string;
|
|
168
200
|
resolveRecipientJwk: (recipientDid: string) => Promise<JWK>;
|
|
201
|
+
/** Stable identity of the portal/application, shared by all of its user wallets. */
|
|
202
|
+
appInfo?: AppInfo;
|
|
169
203
|
fetchImpl?: typeof fetch;
|
|
170
204
|
sessionTtlSeconds?: number;
|
|
171
205
|
maxFailedUnlocks?: number;
|
|
@@ -196,6 +230,15 @@ export declare class ServerProfileSessionManager {
|
|
|
196
230
|
walletSeed: string;
|
|
197
231
|
walletKeyDerivationId: string;
|
|
198
232
|
}>): Promise<ServerProfileEnrollmentPublicKey[]>;
|
|
233
|
+
/**
|
|
234
|
+
* Builds and signs the canonical controller VP directly from ICA-issued
|
|
235
|
+
* credentials. The caller never assembles a VP/JWS or exports a private key.
|
|
236
|
+
*
|
|
237
|
+
* This proof is independent from the signed OIDC id_token: the VP proves
|
|
238
|
+
* organization/controller authority, while id_token proves control of the
|
|
239
|
+
* verified login identifier used by Token/_exchange and DCR.
|
|
240
|
+
*/
|
|
241
|
+
buildOrganizationControllerVpFromIcaProof(input: ServerOrganizationControllerVpInput): Promise<string>;
|
|
199
242
|
/**
|
|
200
243
|
* Reissues an existing organization controller activation through protected
|
|
201
244
|
* DIDComm transport before a durable profile exists. The deterministic seed
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
2
|
import { randomBytes } from 'node:crypto';
|
|
3
3
|
import { ActorKinds } from 'gdc-common-utils-ts/constants/actor-session';
|
|
4
|
+
import { readLegalOrganizationVerificationCredentialPairFromResponseBody, readServiceControllerCredentialFromResponseBody, } from 'gdc-common-utils-ts/utils/legal-organization-verification-result';
|
|
5
|
+
import { addLegalRepresentativeCredential, addOrganizationCredential, addServiceControllerCredential, createVP, } from 'gdc-common-utils-ts/utils/vp-token';
|
|
4
6
|
import { TransportProfiles, } from 'gdc-sdk-core-ts';
|
|
5
7
|
import { NodeManagedWallet } from './node-managed-wallet.js';
|
|
6
8
|
import { NodeHttpClient } from './node-runtime-client.js';
|
|
@@ -62,6 +64,14 @@ export class ServerProfileSessionManager {
|
|
|
62
64
|
throw new Error('GW DCR did not return client_id.');
|
|
63
65
|
const deviceDid = findText(dcrBody, ['device_did', 'deviceDid', 'did']) || clientId;
|
|
64
66
|
const now = this.now();
|
|
67
|
+
const managedVpToken = input.vpToken || (input.professionalProof
|
|
68
|
+
? await buildManagedProfessionalVp(wallet, context, {
|
|
69
|
+
clientId,
|
|
70
|
+
actorDid: input.actorDid,
|
|
71
|
+
profileDid: input.profileDid,
|
|
72
|
+
...input.professionalProof,
|
|
73
|
+
})
|
|
74
|
+
: undefined);
|
|
65
75
|
const record = {
|
|
66
76
|
profileId: input.profileId,
|
|
67
77
|
walletKeyDerivationId,
|
|
@@ -80,7 +90,9 @@ export class ServerProfileSessionManager {
|
|
|
80
90
|
storagePublicJwk: storagePublicJwk,
|
|
81
91
|
confidentialStorageProfile: this.options.requiredConfidentialStorageProfile ?? 'confidential-basic-v1',
|
|
82
92
|
protectedWalletSeed: await protectServerProfileSecret(seed, input.pin, `${input.profileId}:wallet-seed`, this.options.sealer, this.options.profileProtection),
|
|
83
|
-
|
|
93
|
+
...(managedVpToken ? {
|
|
94
|
+
protectedVpToken: await protectServerProfileSecret(managedVpToken, input.pin, `${input.profileId}:vp-token`, this.options.sealer, this.options.profileProtection),
|
|
95
|
+
} : {}),
|
|
84
96
|
failedUnlocks: 0,
|
|
85
97
|
createdAt: now.toISOString(),
|
|
86
98
|
updatedAt: now.toISOString(),
|
|
@@ -109,6 +121,57 @@ export class ServerProfileSessionManager {
|
|
|
109
121
|
publicJwk: entry.publicJwk,
|
|
110
122
|
}));
|
|
111
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Builds and signs the canonical controller VP directly from ICA-issued
|
|
126
|
+
* credentials. The caller never assembles a VP/JWS or exports a private key.
|
|
127
|
+
*
|
|
128
|
+
* This proof is independent from the signed OIDC id_token: the VP proves
|
|
129
|
+
* organization/controller authority, while id_token proves control of the
|
|
130
|
+
* verified login identifier used by Token/_exchange and DCR.
|
|
131
|
+
*/
|
|
132
|
+
async buildOrganizationControllerVpFromIcaProof(input) {
|
|
133
|
+
requireBase64UrlSeed32(input.walletSeed);
|
|
134
|
+
const walletKeyDerivationId = normalizedWalletKeyDerivationId(input.walletKeyDerivationId, '');
|
|
135
|
+
if (!walletKeyDerivationId) {
|
|
136
|
+
throw new Error('buildOrganizationControllerVpFromIcaProof requires walletKeyDerivationId.');
|
|
137
|
+
}
|
|
138
|
+
const tenantId = String(input.tenantId || '').trim();
|
|
139
|
+
const audience = String(input.audience || '').trim();
|
|
140
|
+
if (!tenantId)
|
|
141
|
+
throw new Error('buildOrganizationControllerVpFromIcaProof requires tenantId.');
|
|
142
|
+
if (!audience)
|
|
143
|
+
throw new Error('buildOrganizationControllerVpFromIcaProof requires audience.');
|
|
144
|
+
const { organizationCredential, legalRepresentativeCredential } = readLegalOrganizationVerificationCredentialPairFromResponseBody(input.verificationResponseBody);
|
|
145
|
+
const controllerCredential = readServiceControllerCredentialFromResponseBody(input.verificationResponseBody, input.controllerSameAs);
|
|
146
|
+
if (!controllerCredential) {
|
|
147
|
+
throw new Error('ICA verification response does not contain a ServiceControllerCredential.');
|
|
148
|
+
}
|
|
149
|
+
const wallet = await this.createWallet(walletKeyDerivationId, input.walletSeed);
|
|
150
|
+
const context = walletContext(walletKeyDerivationId);
|
|
151
|
+
const [actorSigningKey] = await wallet.getPublicJwks(context, {
|
|
152
|
+
ownerScope: 'profile',
|
|
153
|
+
purpose: 'actor-signing',
|
|
154
|
+
});
|
|
155
|
+
if (!actorSigningKey)
|
|
156
|
+
throw new Error('Controller actor-signing key is not available.');
|
|
157
|
+
const vp = createVP({
|
|
158
|
+
iss: actorSigningKey.kid,
|
|
159
|
+
sub: tenantId,
|
|
160
|
+
aud: audience,
|
|
161
|
+
vp: { holder: actorSigningKey.kid, verifiableCredential: [] },
|
|
162
|
+
});
|
|
163
|
+
addOrganizationCredential(vp, organizationCredential);
|
|
164
|
+
addLegalRepresentativeCredential(vp, legalRepresentativeCredential);
|
|
165
|
+
addServiceControllerCredential(vp, controllerCredential);
|
|
166
|
+
return wallet.signCompactJws(context, {
|
|
167
|
+
header: {
|
|
168
|
+
typ: 'JWT',
|
|
169
|
+
jwk: actorSigningKey.publicJwk,
|
|
170
|
+
},
|
|
171
|
+
claims: vp,
|
|
172
|
+
key: { ownerScope: 'profile', purpose: 'actor-signing' },
|
|
173
|
+
});
|
|
174
|
+
}
|
|
112
175
|
/**
|
|
113
176
|
* Reissues an existing organization controller activation through protected
|
|
114
177
|
* DIDComm transport before a durable profile exists. The deterministic seed
|
|
@@ -126,6 +189,7 @@ export class ServerProfileSessionManager {
|
|
|
126
189
|
baseUrl: this.options.gatewayBaseUrl,
|
|
127
190
|
ctx: input.routeContext,
|
|
128
191
|
bearerToken: input.bearerToken,
|
|
192
|
+
appInfo: this.options.appInfo,
|
|
129
193
|
fetchImpl: this.options.fetchImpl,
|
|
130
194
|
transportProfile: TransportProfiles.DidcommEncryptedForm,
|
|
131
195
|
secureTransportAdapter: {
|
|
@@ -153,7 +217,9 @@ export class ServerProfileSessionManager {
|
|
|
153
217
|
let vpToken;
|
|
154
218
|
try {
|
|
155
219
|
seed = await openServerProfileSecret(profile.protectedWalletSeed, input.pin, `${profile.profileId}:wallet-seed`, this.options.sealer);
|
|
156
|
-
vpToken =
|
|
220
|
+
vpToken = profile.protectedVpToken
|
|
221
|
+
? await openServerProfileSecret(profile.protectedVpToken, input.pin, `${profile.profileId}:vp-token`, this.options.sealer)
|
|
222
|
+
: undefined;
|
|
157
223
|
}
|
|
158
224
|
catch (reason) {
|
|
159
225
|
if (!(reason instanceof ProfilePinRejectedError))
|
|
@@ -183,6 +249,7 @@ export class ServerProfileSessionManager {
|
|
|
183
249
|
audience: smartTokenEndpoint,
|
|
184
250
|
idToken: input.idToken,
|
|
185
251
|
vpToken,
|
|
252
|
+
vpTokenFallback: vpToken ? undefined : 'omit',
|
|
186
253
|
clientAssertion: assertion,
|
|
187
254
|
clientAssertionType: 'private_key_jwt',
|
|
188
255
|
smartTokenKind: 'openid-smart',
|
|
@@ -247,6 +314,7 @@ export class ServerProfileSessionManager {
|
|
|
247
314
|
ctx,
|
|
248
315
|
bearerToken,
|
|
249
316
|
fetchImpl: this.options.fetchImpl,
|
|
317
|
+
appInfo: this.options.appInfo,
|
|
250
318
|
});
|
|
251
319
|
}
|
|
252
320
|
async createWallet(walletKeyDerivationId, seed) {
|
|
@@ -323,6 +391,10 @@ function profileSmartAcrValues(actorKind) {
|
|
|
323
391
|
? 'urn:antifraud:acr:openid4vp:individual'
|
|
324
392
|
: 'urn:antifraud:acr:openid4vp:employee';
|
|
325
393
|
}
|
|
394
|
+
/** Creates the role VP after DCR has returned the wallet's actual client_id. */
|
|
395
|
+
async function buildManagedProfessionalVp(wallet, context, input) {
|
|
396
|
+
return wallet.signProfessionalIdentityVp(context, input);
|
|
397
|
+
}
|
|
326
398
|
async function buildWalletClientAssertion(wallet, profile, audience, now) {
|
|
327
399
|
const seconds = Math.floor(now.getTime() / 1000);
|
|
328
400
|
return wallet.signCompactJws(walletContext(profile.walletKeyDerivationId || profile.profileId), {
|
|
@@ -361,10 +433,17 @@ function requireEnrollment(input) {
|
|
|
361
433
|
providerDid: input.providerDid,
|
|
362
434
|
activationCode: input.activationCode,
|
|
363
435
|
idToken: input.idToken,
|
|
364
|
-
vpToken: input.vpToken,
|
|
365
436
|
}))
|
|
366
437
|
if (!String(value || '').trim())
|
|
367
438
|
throw new Error(`Profile enrollment requires ${name}.`);
|
|
439
|
+
if (input.actorKind !== ActorKinds.IndividualController
|
|
440
|
+
&& !String(input.vpToken || '').trim()
|
|
441
|
+
&& !input.professionalProof) {
|
|
442
|
+
throw new Error('Profile enrollment requires vpToken for this actor kind.');
|
|
443
|
+
}
|
|
444
|
+
if (input.professionalProof && !String(input.professionalProof.role || '').trim()) {
|
|
445
|
+
throw new Error('Profile enrollment professionalProof requires role.');
|
|
446
|
+
}
|
|
368
447
|
if (!input.allowedSubjectDids.length)
|
|
369
448
|
throw new Error('Profile enrollment requires an allowed subject.');
|
|
370
449
|
}
|