-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into chore/upgrade-sdk
- Loading branch information
Showing
11 changed files
with
406 additions
and
101 deletions.
There are no files selected for viewing
116 changes: 116 additions & 0 deletions
116
integration-tests/verification-flow/vpi-verification.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import {IWallet} from '@docknetwork/wallet-sdk-core/lib/types'; | ||
import { | ||
closeWallet, | ||
getCredentialProvider, | ||
getWallet, | ||
} from '../helpers/wallet-helpers'; | ||
import {createVerificationController} from '@docknetwork/wallet-sdk-core/src/verification-controller'; | ||
import {ProofTemplateIds, createProofRequest} from '../helpers/certs-helpers'; | ||
|
||
const credential = { | ||
"@context": [ | ||
"https://www.w3.org/2018/credentials/v1", | ||
"https://www.w3.org/2018/credentials/examples/v1", | ||
"https://ld.dock.io/security/bddt16/v1", | ||
{ | ||
"dk": "https://ld.dock.io/credentials#", | ||
"name": "dk:name" | ||
} | ||
], | ||
"id": "https://***REMOVED***/f20a0b87efb4ccd4313b2d08056e48e12a1927d747d68bb2d45c722d9cd8e6be", | ||
"type": [ | ||
"VerifiableCredential", | ||
"BasicCredential" | ||
], | ||
"credentialSubject": { | ||
"id": "did:key:z6Mkujh84aPZ3EaYP6t7ftS2kLRkw6G7pkKswEJq2bn86ALs", | ||
"name": "T VPI" | ||
}, | ||
"issuanceDate": "2024-05-03T06:50:36.901Z", | ||
"issuer": { | ||
"name": "Profile bbs", | ||
"id": "did:dock:5CDpZeS2fAas4Du87f2VyTj1BospmvQ5BZwZrKFtb3GeAppq" | ||
}, | ||
"credentialSchema": { | ||
"id": "data:application/json;charset=utf-8,%7B%22%24id%22%3A%22https%3A%2F%2Fschema.dock.io%2FBasicCredential-V2-1703777584571.json%22%2C%22%24schema%22%3A%22http%3A%2F%2Fjson-schema.org%2Fdraft-07%2Fschema%23%22%2C%22additionalProperties%22%3Atrue%2C%22description%22%3A%22A%20representation%20of%20a%20very%20basic%20example%20credential%22%2C%22name%22%3A%22Basic%20Credential%22%2C%22properties%22%3A%7B%22%40context%22%3A%7B%22type%22%3A%22string%22%7D%2C%22credentialSchema%22%3A%7B%22type%22%3A%22string%22%7D%2C%22credentialSubject%22%3A%7B%22properties%22%3A%7B%22id%22%3A%7B%22description%22%3A%22A%20unique%20identifier%20of%20the%20recipient.%20Example%3A%20DID%2C%20email%20address%2C%20national%20ID%20number%2C%20employee%20ID%2C%20student%20ID%20etc.%20If%20you%20enter%20the%20recipient's%20DID%2C%20the%20person%20will%20automatically%20receive%20the%20credential%20in%20their%20Dock%20wallet.%22%2C%22title%22%3A%22Subject%20ID%22%2C%22type%22%3A%22string%22%7D%2C%22name%22%3A%7B%22description%22%3A%22The%20name%20of%20the%20credential%20holder.%22%2C%22title%22%3A%22Subject%20Name%22%2C%22type%22%3A%22string%22%7D%7D%2C%22required%22%3A%5B%22name%22%5D%2C%22type%22%3A%22object%22%7D%2C%22cryptoVersion%22%3A%7B%22type%22%3A%22string%22%7D%2C%22id%22%3A%7B%22type%22%3A%22string%22%7D%2C%22issuanceDate%22%3A%7B%22format%22%3A%22date-time%22%2C%22type%22%3A%22string%22%7D%2C%22issuer%22%3A%7B%22properties%22%3A%7B%22id%22%3A%7B%22type%22%3A%22string%22%7D%2C%22name%22%3A%7B%22type%22%3A%22string%22%7D%7D%2C%22type%22%3A%22object%22%7D%2C%22name%22%3A%7B%22type%22%3A%22string%22%7D%2C%22proof%22%3A%7B%22properties%22%3A%7B%22%40context%22%3A%7B%22items%22%3A%5B%7B%22properties%22%3A%7B%22proof%22%3A%7B%22properties%22%3A%7B%22%40container%22%3A%7B%22type%22%3A%22string%22%7D%2C%22%40id%22%3A%7B%22type%22%3A%22string%22%7D%2C%22%40type%22%3A%7B%22type%22%3A%22string%22%7D%7D%2C%22type%22%3A%22object%22%7D%2C%22sec%22%3A%7B%22type%22%3A%22string%22%7D%7D%2C%22type%22%3A%22object%22%7D%2C%7B%22type%22%3A%22string%22%7D%5D%2C%22type%22%3A%22array%22%7D%2C%22created%22%3A%7B%22format%22%3A%22date-time%22%2C%22type%22%3A%22string%22%7D%2C%22proofPurpose%22%3A%7B%22type%22%3A%22string%22%7D%2C%22type%22%3A%7B%22type%22%3A%22string%22%7D%2C%22verificationMethod%22%3A%7B%22type%22%3A%22string%22%7D%7D%2C%22type%22%3A%22object%22%7D%2C%22type%22%3A%7B%22type%22%3A%22string%22%7D%7D%2C%22type%22%3A%22object%22%7D", | ||
"type": "JsonSchemaValidator2018", | ||
"parsingOptions": { | ||
"useDefaults": true, | ||
"defaultMinimumInteger": -4294967295, | ||
"defaultMinimumDate": -17592186044415, | ||
"defaultDecimalPlaces": 4 | ||
}, | ||
"version": "0.3.0" | ||
}, | ||
"name": "VPI credential", | ||
"cryptoVersion": "0.5.0", | ||
"proof": { | ||
"@context": [ | ||
{ | ||
"sec": "https://w3id.org/security#", | ||
"proof": { | ||
"@id": "sec:proof", | ||
"@type": "@id", | ||
"@container": "@graph" | ||
} | ||
}, | ||
"https://ld.dock.io/security/bddt16/v1" | ||
], | ||
"type": "Bls12381BDDT16MACDock2024", | ||
"created": "2024-05-03T06:50:37Z", | ||
"verificationMethod": "did:dock:5CDpZeS2fAas4Du87f2VyTj1BospmvQ5BZwZrKFtb3GeAppq#7jvC9bs4PXheGvBsbRUQQqXCXddRBK1fNmZfJfTnM7HW6jioKVBZN35tFLyG2yTte9", | ||
"proofPurpose": "assertionMethod", | ||
"proofValue": "zb1UmaJsbUqDCLDYdmhR34kFD1YdcwaJc3YbN3kXJKn7g6zpZwVCKUufKtnaJJ8AthESCz2txWBMm7MsjoEsFEEz1kpWVBTsPQrYPm3hU7o4MA1KT1MkwLmqy5VCbaLbSdBoXZWaAzkkbZmd2453XS9iBV" | ||
} | ||
} | ||
|
||
describe('VPI verification', () => { | ||
it('should verify a vpi credential', async () => { | ||
const wallet: IWallet = await getWallet(); | ||
|
||
getCredentialProvider().addCredential(credential); | ||
|
||
const proofRequest = await createProofRequest( | ||
ProofTemplateIds.ANY_CREDENTIAL, | ||
); | ||
|
||
const result: any = await getCredentialProvider().isValid(credential); | ||
|
||
expect(result.status).toBe('verified'); | ||
|
||
const controller = await createVerificationController({ | ||
wallet, | ||
}); | ||
|
||
await controller.start({ | ||
template: proofRequest, | ||
}); | ||
|
||
let attributesToReveal = ['credentialSubject.name']; | ||
|
||
controller.selectedCredentials.set(credential.id, { | ||
credential: credential, | ||
attributesToReveal, | ||
}); | ||
|
||
const presentation = await controller.createPresentation(); | ||
console.log('Presentation generated'); | ||
console.log(JSON.stringify(presentation, null, 2)); | ||
console.log('Sending presentation to Certs API'); | ||
|
||
let certsResponse; | ||
try { | ||
certsResponse = await controller.submitPresentation(presentation); | ||
console.log('CERTS response'); | ||
console.log(JSON.stringify(certsResponse, null, 2)); | ||
} catch (err) { | ||
certsResponse = err.response.data; | ||
console.log('Certs API returned an error'); | ||
console.log(JSON.stringify(certsResponse, null, 2)); | ||
} | ||
|
||
expect(certsResponse.verified).toBe(true); | ||
}); | ||
|
||
afterAll(() => closeWallet()); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import { useDocument, useDocuments } from './documentsHooks'; | ||
import { WalletEvents } from '@docknetwork/wallet-sdk-wasm/src/modules/wallet'; | ||
import { getWallet } from './wallet'; | ||
import { act, renderHook } from '@testing-library/react-hooks'; | ||
|
||
const mockDocument = { id: 'mock-document-id' }; | ||
|
||
const mockWallet = { | ||
getDocumentById: jest.fn(() => Promise.resolve(mockDocument)), | ||
getDocumentsByType: jest.fn(() => Promise.resolve([])), | ||
eventManager: { | ||
on: jest.fn(), | ||
removeListener: jest.fn(), | ||
}, | ||
}; | ||
|
||
jest.mock('./wallet', () => ({ | ||
getWallet: jest.fn(() => mockWallet), | ||
})); | ||
|
||
describe('useDocument', () => { | ||
|
||
beforeEach(() => { | ||
getWallet.mockReturnValue(mockWallet); | ||
mockWallet.getDocumentById.mockReset(); | ||
mockWallet.eventManager.on.mockReset(); | ||
mockWallet.eventManager.removeListener.mockReset(); | ||
}); | ||
|
||
it('should fetch the document by documentId', async () => { | ||
const documentId = 'document-id'; | ||
const document = { id: documentId, content: 'content' }; | ||
mockWallet.getDocumentById.mockResolvedValue(document); | ||
|
||
const { result, waitFor } = renderHook(() => | ||
useDocument(documentId), | ||
); | ||
|
||
await waitFor(() => expect(getWallet).toHaveBeenCalled()) | ||
expect(mockWallet.getDocumentById).toHaveBeenCalledWith(documentId); | ||
expect(result.current).toEqual(document); | ||
}); | ||
|
||
it('should fetch the document when documentUpdated event is emitted', async () => { | ||
const documentId = 'document-id'; | ||
const initialDocument = { id: documentId, content: 'content' }; | ||
const updatedDocument = { id: documentId, content: 'updated content' }; | ||
mockWallet.getDocumentById | ||
.mockResolvedValueOnce(initialDocument) | ||
.mockResolvedValueOnce(updatedDocument); | ||
|
||
const { result, waitFor } = renderHook(() => | ||
useDocument(documentId), | ||
); | ||
|
||
act(() => { | ||
mockWallet.eventManager.on.mock.calls[0][1](updatedDocument); | ||
}); | ||
|
||
await waitFor(() => expect(mockWallet.getDocumentById).toHaveBeenCalledTimes(2)); | ||
expect(result.current).toEqual(updatedDocument); | ||
}); | ||
|
||
it('should fetch the document when documentAdded event is emitted', async () => { | ||
const documentId = 'document-id'; | ||
const initialDocument = null; | ||
const newDocument = { id: documentId, content: 'added content' }; | ||
mockWallet.getDocumentById | ||
.mockResolvedValueOnce(initialDocument) | ||
.mockResolvedValueOnce(newDocument); | ||
|
||
const { result, waitFor } = renderHook(() => | ||
useDocument(documentId), | ||
); | ||
|
||
act(() => { | ||
mockWallet.eventManager.on.mock.calls[0][1](newDocument); | ||
}); | ||
|
||
await waitFor(() => expect(mockWallet.getDocumentById).toHaveBeenCalledTimes(2)); | ||
expect(result.current).toEqual(newDocument); | ||
}); | ||
|
||
it('should fetch the document when documentRemoved event is emitted', async () => { | ||
const documentId = 'document-id'; | ||
const initialDocument = { id: documentId, content: 'content' }; | ||
const newDocument = { id: documentId, content: 'updated content' }; | ||
mockWallet.getDocumentById | ||
.mockResolvedValueOnce(initialDocument) | ||
.mockResolvedValueOnce(newDocument); | ||
|
||
const { result, waitFor } = renderHook(() => | ||
useDocument(documentId), | ||
); | ||
|
||
act(() => { | ||
mockWallet.eventManager.on.mock.calls[0][1](newDocument); | ||
}); | ||
|
||
await waitFor(() => expect(mockWallet.getDocumentById).toHaveBeenCalledTimes(2)); | ||
expect(result.current).toEqual(newDocument); | ||
}); | ||
|
||
}); | ||
|
||
describe('useDocuments', () => { | ||
beforeEach(() => { | ||
getWallet.mockReturnValue(mockWallet); | ||
mockWallet.getDocumentById.mockReset(); | ||
mockWallet.eventManager.on.mockReset(); | ||
mockWallet.eventManager.removeListener.mockReset(); | ||
}); | ||
|
||
it('should fetch the document correctly', async () => { | ||
const type = 'type1'; | ||
const documents = [ | ||
{ id: 'doc1', type }, | ||
{ id: 'doc2', type }, | ||
]; | ||
mockWallet.getDocumentsByType.mockResolvedValue(documents); | ||
|
||
const { result, waitFor } = renderHook(() => useDocuments({ type })); | ||
|
||
await waitFor(() => expect(mockWallet.getDocumentsByType).toHaveBeenCalledWith(type)); | ||
expect(result.current.documents).toEqual(documents); | ||
expect(result.current.loading).toEqual(false); | ||
}); | ||
it('should refetch documents on networkUpdated event', async () => { | ||
const { waitFor } = renderHook(() => | ||
useDocuments({ type: 'mockType' }), | ||
); | ||
await mockWallet.eventManager.on.mock.calls[2][1](); | ||
|
||
expect(mockWallet.getDocumentsByType).toHaveBeenCalledWith('mockType'); | ||
}); | ||
|
||
it('should force refetch documents on networkUpdated event if type is not set', async () => { | ||
const { waitFor } = renderHook(() => | ||
useDocuments(), | ||
); | ||
mockWallet.getDocumentsByType.mockReset(); | ||
await mockWallet.eventManager.on.mock.calls[3][1](); | ||
|
||
expect(mockWallet.getDocumentsByType).toHaveBeenCalledTimes(1); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import {WalletEvents} from '@docknetwork/wallet-sdk-wasm/src/modules/wallet'; | ||
import {useCallback, useEffect, useState} from 'react'; | ||
import {getWallet} from './wallet'; | ||
|
||
const useEventListener = (eventManager, eventNames, listener) => { | ||
useEffect(() => { | ||
eventNames.forEach(eventName => eventManager.on(eventName, listener)); | ||
return () => | ||
eventNames.forEach(eventName => | ||
eventManager.removeListener(eventName, listener), | ||
); | ||
}, [eventManager, eventNames, listener]); | ||
}; | ||
|
||
const events = [ | ||
WalletEvents.documentAdded, | ||
WalletEvents.documentRemoved, | ||
WalletEvents.documentUpdated, | ||
]; | ||
|
||
export function useDocument(id) { | ||
const [document, setDocument] = useState(null); | ||
|
||
const refetchDocument = useCallback( | ||
async updatedDoc => { | ||
if (updatedDoc.id !== id) return; | ||
const doc = await getWallet().getDocumentById(id); | ||
setDocument(doc); | ||
}, | ||
[id], | ||
); | ||
|
||
useEffect(() => { | ||
getWallet().getDocumentById(id).then(setDocument); | ||
}, [id]); | ||
|
||
useEventListener(getWallet().eventManager, events, refetchDocument); | ||
|
||
return document; | ||
} | ||
|
||
export function useDocuments({type = null} = {}) { | ||
const [documents, setDocuments] = useState([]); | ||
const [loading, setLoading] = useState(true); | ||
|
||
const fetchDocuments = useCallback( | ||
async (updatedDoc, forceFetch = false) => { | ||
console.log('fetching documents', updatedDoc, forceFetch); | ||
if ( | ||
forceFetch || | ||
updatedDoc?.type === type || | ||
updatedDoc?.type?.includes(type) | ||
) { | ||
const docs = await getWallet().getDocumentsByType(type); | ||
setDocuments(docs); | ||
setLoading(false); | ||
} | ||
}, | ||
[type], | ||
); | ||
|
||
useEffect(() => { | ||
fetchDocuments(null, true); | ||
}, [fetchDocuments, setLoading]); | ||
|
||
useEventListener(getWallet().eventManager, events, fetchDocuments); | ||
useEventListener( | ||
getWallet().eventManager, | ||
[WalletEvents.networkUpdated], | ||
async () => fetchDocuments(null, true), | ||
); | ||
|
||
return { | ||
documents, | ||
loading, | ||
}; | ||
} |
Oops, something went wrong.