@docknetwork/wallet-sdk-core 1.5.11 → 1.7.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/generate-docs.js +33 -0
- package/jsdoc.conf.json +28 -0
- package/lib/biometric-provider.d.ts +123 -31
- package/lib/biometric-provider.d.ts.map +1 -1
- package/lib/biometric-provider.js +146 -7
- package/lib/biometric-provider.js.map +1 -1
- package/lib/cloud-wallet.d.ts +7 -3
- package/lib/cloud-wallet.d.ts.map +1 -1
- package/lib/cloud-wallet.js +29 -18
- package/lib/cloud-wallet.js.map +1 -1
- package/lib/credential-provider.d.ts +63 -30
- package/lib/credential-provider.d.ts.map +1 -1
- package/lib/credential-provider.js +220 -13
- package/lib/credential-provider.js.map +1 -1
- package/lib/credentials/oidvc.d.ts +1 -1
- package/lib/credentials/oidvc.d.ts.map +1 -1
- package/lib/credentials/oidvc.js +8 -9
- package/lib/credentials/oidvc.js.map +1 -1
- package/lib/did-provider.d.ts +102 -36
- package/lib/did-provider.d.ts.map +1 -1
- package/lib/did-provider.js +186 -28
- package/lib/did-provider.js.map +1 -1
- package/lib/ecosystem-tools.js +5 -6
- package/lib/ecosystem-tools.js.map +1 -1
- package/lib/helpers.js +6 -6
- package/lib/helpers.js.map +1 -1
- package/lib/message-provider.d.ts +39 -13
- package/lib/message-provider.d.ts.map +1 -1
- package/lib/message-provider.js +147 -21
- package/lib/message-provider.js.map +1 -1
- package/lib/messages/message-helpers.js +6 -6
- package/lib/messages/message-helpers.js.map +1 -1
- package/lib/network-resolver.d.ts +1 -1
- package/lib/network-resolver.js +5 -5
- package/lib/network-resolver.js.map +1 -1
- package/lib/qr-handlers/builtin/index.d.ts +30 -0
- package/lib/qr-handlers/builtin/index.d.ts.map +1 -0
- package/lib/qr-handlers/builtin/index.js +46 -0
- package/lib/qr-handlers/builtin/index.js.map +1 -0
- package/lib/qr-handlers/builtin/oid4vc-handler.d.ts +137 -0
- package/lib/qr-handlers/builtin/oid4vc-handler.d.ts.map +1 -0
- package/lib/qr-handlers/builtin/oid4vc-handler.js +134 -0
- package/lib/qr-handlers/builtin/oid4vc-handler.js.map +1 -0
- package/lib/qr-handlers/index.d.ts +76 -0
- package/lib/qr-handlers/index.d.ts.map +1 -0
- package/lib/qr-handlers/index.js +92 -0
- package/lib/qr-handlers/index.js.map +1 -0
- package/lib/qr-handlers/processor.d.ts +110 -0
- package/lib/qr-handlers/processor.d.ts.map +1 -0
- package/lib/qr-handlers/processor.js +251 -0
- package/lib/qr-handlers/processor.js.map +1 -0
- package/lib/qr-handlers/types.d.ts +205 -0
- package/lib/qr-handlers/types.d.ts.map +1 -0
- package/lib/qr-handlers/types.js +10 -0
- package/lib/qr-handlers/types.js.map +1 -0
- package/lib/types.d.ts +610 -14
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js +16 -0
- package/lib/types.js.map +1 -1
- package/lib/verification-controller.d.ts +0 -1
- package/lib/verification-controller.d.ts.map +1 -1
- package/lib/verification-controller.js +12 -5
- package/lib/verification-controller.js.map +1 -1
- package/lib/wallet-to-wallet-verification/walletToWalletVerificationProvider.d.ts +0 -1
- package/lib/wallet-to-wallet-verification/walletToWalletVerificationProvider.d.ts.map +1 -1
- package/lib/wallet-to-wallet-verification/walletToWalletVerificationProvider.js +3 -3
- package/lib/wallet-to-wallet-verification/walletToWalletVerificationProvider.js.map +1 -1
- package/lib/wallet-wasm.d.ts.map +1 -1
- package/lib/wallet-wasm.js +13 -14
- package/lib/wallet-wasm.js.map +1 -1
- package/lib/wallet.d.ts +36 -20
- package/lib/wallet.d.ts.map +1 -1
- package/lib/wallet.js +174 -28
- package/lib/wallet.js.map +1 -1
- package/package.json +19 -11
- package/src/biometric-provider.ts +157 -42
- package/src/cloud-wallet.ts +13 -0
- package/src/credential-provider.test.ts +220 -1
- package/src/credential-provider.ts +222 -25
- package/src/credentials/oidvc.test.ts +1 -1
- package/src/credentials/oidvc.ts +1 -1
- package/src/did-provider.ts +183 -34
- package/src/message-provider.ts +149 -35
- package/src/qr-handlers/builtin/index.ts +30 -0
- package/src/qr-handlers/builtin/oid4vc-handler.ts +198 -0
- package/src/qr-handlers/index.ts +76 -0
- package/src/qr-handlers/processor.test.ts +514 -0
- package/src/qr-handlers/processor.ts +311 -0
- package/src/qr-handlers/types.ts +228 -0
- package/src/types.ts +666 -11
- package/src/verification-controller.test.ts +1 -2
- package/src/verification-controller.ts +9 -1
- package/src/wallet-wasm.ts +1 -3
- package/src/wallet.ts +173 -24
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -227,7 +227,7 @@ describe('CredentialProvider', () => {
|
|
|
227
227
|
});
|
|
228
228
|
|
|
229
229
|
await provider.syncCredentialStatus({forceFetch: true});
|
|
230
|
-
|
|
230
|
+
|
|
231
231
|
// Clear mocks
|
|
232
232
|
jest.clearAllMocks();
|
|
233
233
|
|
|
@@ -255,8 +255,227 @@ describe('CredentialProvider', () => {
|
|
|
255
255
|
expect(credentialServiceRPC.verifyCredential).toHaveBeenCalledTimes(2);
|
|
256
256
|
});
|
|
257
257
|
|
|
258
|
+
it('should always refetch credentials with Invalid status even when cached', async () => {
|
|
259
|
+
// First, create credentials with Invalid status
|
|
260
|
+
jest
|
|
261
|
+
.spyOn(credentialServiceRPC, 'verifyCredential')
|
|
262
|
+
.mockImplementation(async () => {
|
|
263
|
+
return {
|
|
264
|
+
verified: false,
|
|
265
|
+
error: 'Credential validation failed',
|
|
266
|
+
};
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
await provider.syncCredentialStatus({forceFetch: true});
|
|
270
|
+
|
|
271
|
+
// Verify initial calls
|
|
272
|
+
expect(credentialServiceRPC.verifyCredential).toHaveBeenCalledTimes(2);
|
|
273
|
+
|
|
274
|
+
// Check that status is set to Invalid
|
|
275
|
+
const initialStatusDoc = await wallet.getDocumentById(
|
|
276
|
+
`${customerCredential.id}#status`,
|
|
277
|
+
);
|
|
278
|
+
expect(initialStatusDoc.status).toBe(CredentialStatus.Invalid);
|
|
279
|
+
|
|
280
|
+
// Clear mocks to track only subsequent calls
|
|
281
|
+
jest.clearAllMocks();
|
|
282
|
+
|
|
283
|
+
// Now mock successful verification
|
|
284
|
+
jest
|
|
285
|
+
.spyOn(credentialServiceRPC, 'verifyCredential')
|
|
286
|
+
.mockImplementation(async () => {
|
|
287
|
+
return {
|
|
288
|
+
verified: true,
|
|
289
|
+
};
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Call syncCredentialStatus again WITHOUT forceFetch
|
|
293
|
+
// Invalid status should trigger refetch even without forceFetch
|
|
294
|
+
const statusDocs = await provider.syncCredentialStatus({});
|
|
295
|
+
|
|
296
|
+
// Verify that verifyCredential was called again despite no forceFetch
|
|
297
|
+
expect(credentialServiceRPC.verifyCredential).toHaveBeenCalledTimes(2);
|
|
298
|
+
|
|
299
|
+
// Check that status is now updated to Verified
|
|
300
|
+
expect(statusDocs.length).toBe(2);
|
|
301
|
+
for (const statusDoc of statusDocs) {
|
|
302
|
+
expect(statusDoc.status).toBe(CredentialStatus.Verified);
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('should always refetch credentials with Pending status even when cached', async () => {
|
|
307
|
+
// First, manually create a Pending status document
|
|
308
|
+
const pendingStatusDoc = {
|
|
309
|
+
type: 'CredentialStatus',
|
|
310
|
+
id: `${customerCredential.id}#status`,
|
|
311
|
+
createdAt: new Date().toISOString(),
|
|
312
|
+
updatedAt: new Date().toISOString(),
|
|
313
|
+
status: CredentialStatus.Pending,
|
|
314
|
+
error: null,
|
|
315
|
+
warning: null,
|
|
316
|
+
};
|
|
317
|
+
await wallet.updateDocument(pendingStatusDoc);
|
|
318
|
+
|
|
319
|
+
// Mock successful verification
|
|
320
|
+
jest
|
|
321
|
+
.spyOn(credentialServiceRPC, 'verifyCredential')
|
|
322
|
+
.mockImplementation(async () => {
|
|
323
|
+
return {
|
|
324
|
+
verified: true,
|
|
325
|
+
};
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Call syncCredentialStatus without forceFetch
|
|
329
|
+
// Pending status should trigger refetch
|
|
330
|
+
const statusDocs = await provider.syncCredentialStatus({
|
|
331
|
+
credentialIds: [customerCredential.id],
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// Verify that verifyCredential was called for the Pending credential
|
|
335
|
+
expect(credentialServiceRPC.verifyCredential).toHaveBeenCalledTimes(1);
|
|
336
|
+
|
|
337
|
+
// Check that status is now updated to Verified
|
|
338
|
+
expect(statusDocs.length).toBe(1);
|
|
339
|
+
expect(statusDocs[0].status).toBe(CredentialStatus.Verified);
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
it('should cache Revoked status and not refetch within 24 hours', async () => {
|
|
343
|
+
// First, create credentials with Revoked status
|
|
344
|
+
jest
|
|
345
|
+
.spyOn(credentialServiceRPC, 'verifyCredential')
|
|
346
|
+
.mockImplementation(async () => {
|
|
347
|
+
return {
|
|
348
|
+
verified: false,
|
|
349
|
+
error: 'Revocation check failed',
|
|
350
|
+
};
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
await provider.syncCredentialStatus({forceFetch: true});
|
|
354
|
+
|
|
355
|
+
// Verify initial calls
|
|
356
|
+
expect(credentialServiceRPC.verifyCredential).toHaveBeenCalledTimes(2);
|
|
357
|
+
|
|
358
|
+
// Check that status is set to Revoked
|
|
359
|
+
const revokedStatusDoc = await wallet.getDocumentById(
|
|
360
|
+
`${customerCredential.id}#status`,
|
|
361
|
+
);
|
|
362
|
+
expect(revokedStatusDoc.status).toBe(CredentialStatus.Revoked);
|
|
363
|
+
|
|
364
|
+
// Clear mocks to track only subsequent calls
|
|
365
|
+
jest.clearAllMocks();
|
|
366
|
+
|
|
367
|
+
// Call syncCredentialStatus again WITHOUT forceFetch
|
|
368
|
+
// Revoked status should NOT trigger refetch within 24 hours
|
|
369
|
+
const statusDocs = await provider.syncCredentialStatus({});
|
|
370
|
+
|
|
371
|
+
// Verify that verifyCredential was NOT called (cached)
|
|
372
|
+
expect(credentialServiceRPC.verifyCredential).toHaveBeenCalledTimes(0);
|
|
373
|
+
|
|
374
|
+
// Check that status remains Revoked
|
|
375
|
+
expect(statusDocs.length).toBe(2);
|
|
376
|
+
for (const statusDoc of statusDocs) {
|
|
377
|
+
expect(statusDoc.status).toBe(CredentialStatus.Revoked);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it('should cache Verified status and not refetch within 24 hours', async () => {
|
|
382
|
+
// First, create credentials with Verified status
|
|
383
|
+
jest
|
|
384
|
+
.spyOn(credentialServiceRPC, 'verifyCredential')
|
|
385
|
+
.mockImplementation(async () => {
|
|
386
|
+
return {
|
|
387
|
+
verified: true,
|
|
388
|
+
};
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
await provider.syncCredentialStatus({forceFetch: true});
|
|
392
|
+
|
|
393
|
+
// Verify initial calls
|
|
394
|
+
expect(credentialServiceRPC.verifyCredential).toHaveBeenCalledTimes(2);
|
|
395
|
+
|
|
396
|
+
// Check that status is set to Verified
|
|
397
|
+
const verifiedStatusDoc = await wallet.getDocumentById(
|
|
398
|
+
`${customerCredential.id}#status`,
|
|
399
|
+
);
|
|
400
|
+
expect(verifiedStatusDoc.status).toBe(CredentialStatus.Verified);
|
|
401
|
+
|
|
402
|
+
// Clear mocks to track only subsequent calls
|
|
403
|
+
jest.clearAllMocks();
|
|
404
|
+
|
|
405
|
+
// Call syncCredentialStatus again WITHOUT forceFetch
|
|
406
|
+
// Verified status should NOT trigger refetch within 24 hours
|
|
407
|
+
const statusDocs = await provider.syncCredentialStatus({});
|
|
408
|
+
|
|
409
|
+
// Verify that verifyCredential was NOT called (cached)
|
|
410
|
+
expect(credentialServiceRPC.verifyCredential).toHaveBeenCalledTimes(0);
|
|
411
|
+
|
|
412
|
+
// Check that status remains Verified
|
|
413
|
+
expect(statusDocs.length).toBe(2);
|
|
414
|
+
for (const statusDoc of statusDocs) {
|
|
415
|
+
expect(statusDoc.status).toBe(CredentialStatus.Verified);
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
it('should refetch credentials without status document', async () => {
|
|
420
|
+
// Remove any existing status documents
|
|
421
|
+
await wallet.removeDocument(`${customerCredential.id}#status`).catch(() => {});
|
|
422
|
+
await wallet.removeDocument(`${biometricsBBSRevocation.id}#status`).catch(() => {});
|
|
423
|
+
|
|
424
|
+
// Mock successful verification
|
|
425
|
+
jest
|
|
426
|
+
.spyOn(credentialServiceRPC, 'verifyCredential')
|
|
427
|
+
.mockImplementation(async () => {
|
|
428
|
+
return {
|
|
429
|
+
verified: true,
|
|
430
|
+
};
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
// Call syncCredentialStatus
|
|
434
|
+
// Missing status docs should trigger fetch
|
|
435
|
+
const statusDocs = await provider.syncCredentialStatus({});
|
|
436
|
+
|
|
437
|
+
// Verify that verifyCredential was called for both credentials
|
|
438
|
+
expect(credentialServiceRPC.verifyCredential).toHaveBeenCalledTimes(2);
|
|
439
|
+
|
|
440
|
+
// Check that status documents were created
|
|
441
|
+
expect(statusDocs.length).toBe(2);
|
|
442
|
+
for (const statusDoc of statusDocs) {
|
|
443
|
+
expect(statusDoc.status).toBe(CredentialStatus.Verified);
|
|
444
|
+
expect(statusDoc.type).toBe('CredentialStatus');
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
|
|
258
448
|
afterEach(() => {
|
|
259
449
|
(credentialServiceRPC.verifyCredential as any).mockReset();
|
|
260
450
|
});
|
|
261
451
|
});
|
|
452
|
+
|
|
453
|
+
describe('isValid', () => {
|
|
454
|
+
it('should return pending status when SDK is not initialized and no cached status exists', async () => {
|
|
455
|
+
await provider.addCredential({
|
|
456
|
+
...customerCredential,
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
jest
|
|
460
|
+
.spyOn(credentialServiceRPC, 'verifyCredential')
|
|
461
|
+
.mockImplementation(async () => {
|
|
462
|
+
return {
|
|
463
|
+
verified: false,
|
|
464
|
+
error: {
|
|
465
|
+
errors: [
|
|
466
|
+
{
|
|
467
|
+
message: 'SDK is not initialized'
|
|
468
|
+
}
|
|
469
|
+
]
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
const result = await provider.isValid({credential: customerCredential});
|
|
475
|
+
|
|
476
|
+
expect(result.status).toBe(CredentialStatus.Pending);
|
|
477
|
+
expect(result.error).toContain('SDK is not initialized. Please ensure the blockchain is connected.');
|
|
478
|
+
expect(credentialServiceRPC.verifyCredential).toHaveBeenCalledTimes(1);
|
|
479
|
+
});
|
|
480
|
+
});
|
|
262
481
|
});
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module credential-provider
|
|
3
|
+
* @description Verifiable credential management functionality for the Truvera Wallet SDK.
|
|
4
|
+
* This module provides functions for importing, verifying, storing, and managing verifiable credentials.
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import {credentialServiceRPC} from '@docknetwork/wallet-sdk-wasm/src/services/credential';
|
|
2
|
-
import {IWallet} from './types';
|
|
8
|
+
import {IWallet, ICredentialProvider} from './types';
|
|
9
|
+
export type {ICredentialProvider};
|
|
3
10
|
import assert from 'assert';
|
|
4
11
|
import {blockchainService} from '@docknetwork/wallet-sdk-wasm/src/services/blockchain';
|
|
5
12
|
import {acquireOpenIDCredentialFromURI} from './credentials/oidvc';
|
|
@@ -7,26 +14,10 @@ import {IDIDProvider} from './did-provider';
|
|
|
7
14
|
|
|
8
15
|
export type Credential = any;
|
|
9
16
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
getMembershipWitness(credential: any): Promise<any>;
|
|
15
|
-
isBBSPlusCredential(credential: any): boolean;
|
|
16
|
-
isValid(credential: any, forceFetch?: boolean): Promise<boolean>;
|
|
17
|
-
addCredential(credential: any): Promise<Credential>;
|
|
18
|
-
importCredentialFromURI(
|
|
19
|
-
params: importCredentialFromUriParams,
|
|
20
|
-
): Promise<Credential>;
|
|
21
|
-
syncCredentialStatus(
|
|
22
|
-
params: SyncCredentialStatusParams,
|
|
23
|
-
): Promise<CredentialStatusDocument[]>;
|
|
24
|
-
getCredentialStatus(
|
|
25
|
-
credential: Credential,
|
|
26
|
-
): Promise<{status: string; error?: string}>;
|
|
27
|
-
removeCredential(credential: Credential): Promise<void>;
|
|
28
|
-
}
|
|
29
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Internal function to check if a credential uses BBS+ signature
|
|
19
|
+
* @private
|
|
20
|
+
*/
|
|
30
21
|
export function isBBSPlusCredential(credential) {
|
|
31
22
|
return (
|
|
32
23
|
(typeof credential?.proof?.type === 'string' &&
|
|
@@ -44,6 +35,10 @@ type importCredentialFromUriParams = {
|
|
|
44
35
|
getAuthCode?: (authorizationURL: string) => Promise<string>;
|
|
45
36
|
};
|
|
46
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Internal function to import credential from URI
|
|
40
|
+
* @private
|
|
41
|
+
*/
|
|
47
42
|
export async function importCredentialFromURI({
|
|
48
43
|
uri,
|
|
49
44
|
wallet,
|
|
@@ -65,6 +60,10 @@ export async function importCredentialFromURI({
|
|
|
65
60
|
await addCredential({wallet, credential});
|
|
66
61
|
}
|
|
67
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Internal function to check if credential is expired
|
|
65
|
+
* @private
|
|
66
|
+
*/
|
|
68
67
|
export function isCredentialExpired(credential) {
|
|
69
68
|
return (
|
|
70
69
|
!!credential.expirationDate &&
|
|
@@ -75,7 +74,7 @@ export function isCredentialExpired(credential) {
|
|
|
75
74
|
/**
|
|
76
75
|
* Uses Dock SDK to verify a credential
|
|
77
76
|
* @param credential
|
|
78
|
-
* @returns
|
|
77
|
+
* @returns {Promise<Object>} Verification result with status and optional error/warning messages
|
|
79
78
|
*/
|
|
80
79
|
export async function isValid({
|
|
81
80
|
credential,
|
|
@@ -83,7 +82,11 @@ export async function isValid({
|
|
|
83
82
|
}: {
|
|
84
83
|
credential: Credential;
|
|
85
84
|
wallet: IWallet;
|
|
86
|
-
}) {
|
|
85
|
+
}): Promise<{
|
|
86
|
+
status: string;
|
|
87
|
+
error?: string;
|
|
88
|
+
warning?: string;
|
|
89
|
+
}> {
|
|
87
90
|
assert(!!credential, 'credential is required');
|
|
88
91
|
|
|
89
92
|
try {
|
|
@@ -109,6 +112,15 @@ export async function isValid({
|
|
|
109
112
|
|
|
110
113
|
const {verified, error} = verificationResult;
|
|
111
114
|
|
|
115
|
+
if (error) {
|
|
116
|
+
const sdkNotInitialized = error?.errors?.find(err => err?.message === 'SDK is not initialized');
|
|
117
|
+
if (sdkNotInitialized) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
'SDK is not initialized. Please ensure the blockchain is connected.',
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
112
124
|
if (!verified) {
|
|
113
125
|
if (
|
|
114
126
|
typeof error === 'string' &&
|
|
@@ -156,7 +168,26 @@ export async function isValid({
|
|
|
156
168
|
|
|
157
169
|
export const ACUMM_WITNESS_PROP_KEY = '$$accum__witness$$';
|
|
158
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Internal function to add credential to wallet
|
|
173
|
+
* @private
|
|
174
|
+
*/
|
|
159
175
|
export async function addCredential({wallet, credential}) {
|
|
176
|
+
// Check if the credential is an SD-JWT (string format)
|
|
177
|
+
if (typeof credential === 'string') {
|
|
178
|
+
try {
|
|
179
|
+
const isSDJWT = await credentialServiceRPC.isSDJWTCredential({credential});
|
|
180
|
+
|
|
181
|
+
if (isSDJWT) {
|
|
182
|
+
// Convert SD-JWT to W3C format (includes _sd_jwt metadata for unwrapping)
|
|
183
|
+
credential = await credentialServiceRPC.credentialToW3C({credential});
|
|
184
|
+
}
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.error('Error checking/converting SD-JWT credential:', error);
|
|
187
|
+
throw new Error('Failed to process SD-JWT credential: ' + error.message);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
160
191
|
const acummWitness = credential[ACUMM_WITNESS_PROP_KEY];
|
|
161
192
|
|
|
162
193
|
if (acummWitness) {
|
|
@@ -179,6 +210,10 @@ export async function addCredential({wallet, credential}) {
|
|
|
179
210
|
return response;
|
|
180
211
|
}
|
|
181
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Internal function to get membership witness for credential
|
|
215
|
+
* @private
|
|
216
|
+
*/
|
|
182
217
|
async function getMembershipWitness({credentialId, wallet}) {
|
|
183
218
|
const document = await wallet.getDocumentById(`${credentialId}#witness`);
|
|
184
219
|
return document?.value;
|
|
@@ -214,6 +249,10 @@ type CredentialStatusDocument = {
|
|
|
214
249
|
* @param param0
|
|
215
250
|
* @returns CredentialStatusDocument[]
|
|
216
251
|
*/
|
|
252
|
+
/**
|
|
253
|
+
* Internal function to sync credential status from blockchain
|
|
254
|
+
* @private
|
|
255
|
+
*/
|
|
217
256
|
async function syncCredentialStatus({
|
|
218
257
|
wallet,
|
|
219
258
|
credentialIds,
|
|
@@ -252,7 +291,9 @@ async function syncCredentialStatus({
|
|
|
252
291
|
|
|
253
292
|
statusDocs.push(statusDoc);
|
|
254
293
|
|
|
255
|
-
|
|
294
|
+
// Revoked and Expired statuses should be cached
|
|
295
|
+
// The user can fore refresh that from the credentials screen
|
|
296
|
+
if (!statusDoc.status || statusDoc.status === CredentialStatus.Invalid || statusDoc.status === CredentialStatus.Pending) {
|
|
256
297
|
shouldFetch = true;
|
|
257
298
|
}
|
|
258
299
|
|
|
@@ -296,7 +337,11 @@ async function syncCredentialStatus({
|
|
|
296
337
|
/**
|
|
297
338
|
* Removes a credential and its related documents from the wallet
|
|
298
339
|
* @param param0
|
|
299
|
-
* @returns
|
|
340
|
+
* @returns {Promise<void>}
|
|
341
|
+
*/
|
|
342
|
+
/**
|
|
343
|
+
* Internal function to remove credential and related documents
|
|
344
|
+
* @private
|
|
300
345
|
*/
|
|
301
346
|
export async function removeCredential({
|
|
302
347
|
wallet,
|
|
@@ -322,6 +367,35 @@ export async function removeCredential({
|
|
|
322
367
|
}
|
|
323
368
|
}
|
|
324
369
|
|
|
370
|
+
/**
|
|
371
|
+
* Creates a credential provider instance bound to a wallet
|
|
372
|
+
* @param {Object} params - Provider configuration
|
|
373
|
+
* @param {IWallet} params.wallet - The wallet instance to use for credential storage
|
|
374
|
+
* @returns {ICredentialProvider} A credential provider instance with all verifiable credential management methods
|
|
375
|
+
* @see {@link ICredentialProvider} - The interface defining all available credential provider methods
|
|
376
|
+
* @example
|
|
377
|
+
* import { createCredentialProvider } from '@docknetwork/wallet-sdk-core';
|
|
378
|
+
*
|
|
379
|
+
* const credentialProvider = createCredentialProvider({wallet});
|
|
380
|
+
*
|
|
381
|
+
* // Add a credential
|
|
382
|
+
* const addedCredential = await credentialProvider.addCredential(myCredential);
|
|
383
|
+
*
|
|
384
|
+
* // Validate a credential
|
|
385
|
+
* const result = await credentialProvider.isValid(credential);
|
|
386
|
+
* if (result.status === 'verified') {
|
|
387
|
+
* console.log('Credential is valid');
|
|
388
|
+
* }
|
|
389
|
+
*
|
|
390
|
+
* // Get all credentials
|
|
391
|
+
* const allCredentials = credentialProvider.getCredentials();
|
|
392
|
+
*
|
|
393
|
+
* // Import from URI
|
|
394
|
+
* await credentialProvider.importCredentialFromURI({
|
|
395
|
+
* uri: 'https://example.com/credential-offer',
|
|
396
|
+
* didProvider
|
|
397
|
+
* });
|
|
398
|
+
*/
|
|
325
399
|
export function createCredentialProvider({
|
|
326
400
|
wallet,
|
|
327
401
|
}: {
|
|
@@ -332,21 +406,103 @@ export function createCredentialProvider({
|
|
|
332
406
|
}
|
|
333
407
|
|
|
334
408
|
return {
|
|
409
|
+
/**
|
|
410
|
+
* Imports a credential from a URI (supports OpenID credential offers)
|
|
411
|
+
* @memberof ICredentialProvider
|
|
412
|
+
* @param {Object} params - Import parameters
|
|
413
|
+
* @param {string} params.uri - The URI containing the credential offer
|
|
414
|
+
* @param {any} params.didProvider - DID provider instance for key management
|
|
415
|
+
* @param {Function} [params.getAuthCode] - Optional callback to handle authorization
|
|
416
|
+
* @returns {Promise<any>} The imported credential
|
|
417
|
+
* @throws {Error} If import fails
|
|
418
|
+
* @example
|
|
419
|
+
* const credential = await credentialProvider.importCredentialFromURI({
|
|
420
|
+
* uri: 'https://issuer.example.com/credential-offer',
|
|
421
|
+
* didProvider,
|
|
422
|
+
* getAuthCode: async (url) => getUserAuthCode(url)
|
|
423
|
+
* });
|
|
424
|
+
*/
|
|
335
425
|
importCredentialFromURI: async (params: importCredentialFromUriParams) =>
|
|
336
426
|
importCredentialFromURI({
|
|
337
427
|
...params,
|
|
338
428
|
wallet,
|
|
339
429
|
}),
|
|
430
|
+
/**
|
|
431
|
+
* Retrieves credentials from the wallet, optionally filtered by type
|
|
432
|
+
* @memberof ICredentialProvider
|
|
433
|
+
* @param {string} [type='VerifiableCredential'] - The credential type to filter by
|
|
434
|
+
* @returns {any[]} Array of credentials matching the specified type
|
|
435
|
+
* @example
|
|
436
|
+
* const allCredentials = credentialProvider.getCredentials();
|
|
437
|
+
* const certificates = credentialProvider.getCredentials('Certificate');
|
|
438
|
+
*/
|
|
340
439
|
getCredentials,
|
|
440
|
+
/**
|
|
441
|
+
* Gets the membership witness for a credential (used for BBS+ credentials)
|
|
442
|
+
* @memberof ICredentialProvider
|
|
443
|
+
* @param {string} credentialId - The credential ID to get the witness for
|
|
444
|
+
* @returns {Promise<any>} The membership witness data
|
|
445
|
+
* @example
|
|
446
|
+
* const witness = await credentialProvider.getMembershipWitness('credential-123');
|
|
447
|
+
*/
|
|
341
448
|
getMembershipWitness: async (credentialId: string) =>
|
|
342
449
|
getMembershipWitness({credentialId, wallet}),
|
|
450
|
+
/**
|
|
451
|
+
* Retrieves a credential by its ID
|
|
452
|
+
* @memberof ICredentialProvider
|
|
453
|
+
* @param {string} id - The unique identifier of the credential
|
|
454
|
+
* @returns {any} The credential document
|
|
455
|
+
* @throws {Error} If credential is not found
|
|
456
|
+
* @example
|
|
457
|
+
* const credential = await credentialProvider.getById('credential-123');
|
|
458
|
+
*/
|
|
343
459
|
getById: (id: string) => wallet.getDocumentById(id),
|
|
460
|
+
/**
|
|
461
|
+
* Checks if a credential uses BBS+ signature
|
|
462
|
+
* @memberof ICredentialProvider
|
|
463
|
+
* @param {any} credential - The credential to check
|
|
464
|
+
* @returns {boolean} True if the credential uses BBS+ signature
|
|
465
|
+
* @example
|
|
466
|
+
* const isBBS = credentialProvider.isBBSPlusCredential(credential);
|
|
467
|
+
* if (isBBS) {
|
|
468
|
+
* console.log('This credential uses BBS+ signatures');
|
|
469
|
+
* }
|
|
470
|
+
*/
|
|
344
471
|
isBBSPlusCredential,
|
|
472
|
+
/**
|
|
473
|
+
* Validates a credential by verifying its cryptographic proof and status
|
|
474
|
+
* @memberof ICredentialProvider
|
|
475
|
+
* @param {any} credential - The credential to validate
|
|
476
|
+
* @param {boolean} [forceFetch=false] - Whether to force refresh the credential status
|
|
477
|
+
* @returns {Promise<Object>} Validation result
|
|
478
|
+
* @returns {string} returns.status - Validation status (verified, revoked, expired, invalid, pending)
|
|
479
|
+
* @returns {string} [returns.error] - Error message if validation failed
|
|
480
|
+
* @returns {string} [returns.warning] - Warning message if any
|
|
481
|
+
* @throws {Error} If validation fails
|
|
482
|
+
* @example
|
|
483
|
+
* const result = await credentialProvider.isValid(credential);
|
|
484
|
+
* if (result.status === 'verified') {
|
|
485
|
+
* console.log('Credential is valid');
|
|
486
|
+
* } else if (result.status === 'revoked') {
|
|
487
|
+
* console.log('Credential has been revoked');
|
|
488
|
+
* }
|
|
489
|
+
*/
|
|
345
490
|
isValid: async credential =>
|
|
346
491
|
isValid({
|
|
347
492
|
credential,
|
|
348
493
|
wallet,
|
|
349
494
|
}) as any,
|
|
495
|
+
/**
|
|
496
|
+
* Gets the current status of a credential (cached, fast operation)
|
|
497
|
+
* @memberof ICredentialProvider
|
|
498
|
+
* @param {any} credential - The credential to check
|
|
499
|
+
* @returns {Promise<Object>} Current credential status
|
|
500
|
+
* @returns {string} returns.status - Current status of the credential
|
|
501
|
+
* @returns {string} [returns.error] - Error message if any
|
|
502
|
+
* @example
|
|
503
|
+
* const status = await credentialProvider.getCredentialStatus(credential);
|
|
504
|
+
* console.log(`Credential status: ${status.status}`);
|
|
505
|
+
*/
|
|
350
506
|
getCredentialStatus: async (credential: Credential) => {
|
|
351
507
|
assert(!!credential, 'credential is required');
|
|
352
508
|
|
|
@@ -363,10 +519,51 @@ export function createCredentialProvider({
|
|
|
363
519
|
error: statusDoc?.error,
|
|
364
520
|
};
|
|
365
521
|
},
|
|
522
|
+
/**
|
|
523
|
+
* Synchronizes credential status from the blockchain
|
|
524
|
+
* @memberof ICredentialProvider
|
|
525
|
+
* @param {Object} params - Sync parameters
|
|
526
|
+
* @param {string[]} [params.credentialIds] - Optional list of credential IDs to sync
|
|
527
|
+
* @param {boolean} [params.forceFetch=false] - Whether to force refresh from blockchain
|
|
528
|
+
* @returns {Promise<any[]>} Array of credential status documents
|
|
529
|
+
* @example
|
|
530
|
+
* // Sync all credentials
|
|
531
|
+
* await credentialProvider.syncCredentialStatus({});
|
|
532
|
+
*
|
|
533
|
+
* // Sync specific credentials
|
|
534
|
+
* await credentialProvider.syncCredentialStatus({
|
|
535
|
+
* credentialIds: ['cred-1', 'cred-2'],
|
|
536
|
+
* forceFetch: true
|
|
537
|
+
* });
|
|
538
|
+
*/
|
|
366
539
|
syncCredentialStatus: async (props: SyncCredentialStatusParams) => {
|
|
367
540
|
return syncCredentialStatus({wallet, ...props});
|
|
368
541
|
},
|
|
542
|
+
/**
|
|
543
|
+
* Adds a credential to the wallet
|
|
544
|
+
* @memberof ICredentialProvider
|
|
545
|
+
* @param {any} credential - The credential to add
|
|
546
|
+
* @returns {Promise<any>} The added credential document
|
|
547
|
+
* @example
|
|
548
|
+
* const addedCredential = await credentialProvider.addCredential({
|
|
549
|
+
* '@context': ['https://www.w3.org/2018/credentials/v1'],
|
|
550
|
+
* type: ['VerifiableCredential'],
|
|
551
|
+
* issuer: 'did:dock:issuer123',
|
|
552
|
+
* credentialSubject: { name: 'Alice' }
|
|
553
|
+
* });
|
|
554
|
+
*/
|
|
369
555
|
addCredential: credential => addCredential({wallet, credential}),
|
|
556
|
+
/**
|
|
557
|
+
* Removes a credential and all its related documents from the wallet
|
|
558
|
+
* @memberof ICredentialProvider
|
|
559
|
+
* @param {any} credential - The credential to remove
|
|
560
|
+
* @returns {Promise<void>}
|
|
561
|
+
* @throws {Error} If credential is not found
|
|
562
|
+
* @example
|
|
563
|
+
* await credentialProvider.removeCredential(credential);
|
|
564
|
+
* // Or by ID
|
|
565
|
+
* await credentialProvider.removeCredential('credential-123');
|
|
566
|
+
*/
|
|
370
567
|
removeCredential: credential => removeCredential({wallet, credential}),
|
|
371
568
|
// TODO: move import credential from json or URL to this provider
|
|
372
569
|
};
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from './oidvc';
|
|
7
7
|
import {credentialServiceRPC} from '@docknetwork/wallet-sdk-wasm/src/services/credential';
|
|
8
8
|
import {MetadataClient} from '@sphereon/oid4vci-client';
|
|
9
|
-
import jwtDecode from 'jwt-decode';
|
|
9
|
+
import {jwtDecode} from 'jwt-decode';
|
|
10
10
|
import axios from 'axios';
|
|
11
11
|
|
|
12
12
|
jest.mock('@docknetwork/wallet-sdk-wasm/src/services/credential');
|
package/src/credentials/oidvc.ts
CHANGED
|
@@ -2,7 +2,7 @@ import {IWallet} from '../types';
|
|
|
2
2
|
import {IDIDProvider} from '../did-provider';
|
|
3
3
|
import {credentialServiceRPC} from '@docknetwork/wallet-sdk-wasm/src/services/credential';
|
|
4
4
|
import {MetadataClient} from '@sphereon/oid4vci-client';
|
|
5
|
-
import jwtDecode from 'jwt-decode';
|
|
5
|
+
import {jwtDecode} from 'jwt-decode';
|
|
6
6
|
import axios from 'axios';
|
|
7
7
|
import {pexService} from '@docknetwork/wallet-sdk-wasm/src/services/pex';
|
|
8
8
|
import {WellKnownEndpoints} from '@sphereon/oid4vci-common';
|