Skip to content

Commit 20f2a06

Browse files
committed
test: Add JsonLD issuance test cheqd
1 parent 2310b90 commit 20f2a06

File tree

1 file changed

+342
-0
lines changed

1 file changed

+342
-0
lines changed
Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
import type { CheqdDidCreateOptions } from '../src'
2+
3+
import {
4+
SECURITY_JWS_CONTEXT_URL,
5+
DidDocumentBuilder,
6+
getEd25519VerificationKey2018,
7+
KeyType,
8+
utils,
9+
Agent,
10+
TypedArrayEncoder,
11+
DifPresentationExchangeProofFormatService,
12+
JsonLdCredentialFormatService,
13+
CredentialsModule,
14+
V2CredentialProtocol,
15+
ProofsModule,
16+
V2ProofProtocol,
17+
CacheModule,
18+
InMemoryLruCache,
19+
W3cCredentialsModule,
20+
CredentialState,
21+
CredentialExchangeRecord,
22+
JsonTransformer,
23+
ProofEventTypes,
24+
CredentialEventTypes,
25+
} from '@credo-ts/core'
26+
27+
import { getInMemoryAgentOptions, makeConnection, waitForCredentialRecordSubject } from '../../core/tests/helpers'
28+
29+
import { cheqdPayerSeeds, getCheqdModules } from './setupCheqdModule'
30+
import { EventReplaySubject, setupEventReplaySubjects, setupSubjectTransports, testLogger } from '../../core/tests'
31+
32+
let did = `did:cheqd:testnet:${utils.uuid()}`
33+
34+
const signCredentialOptions = {
35+
credential: {
36+
'@context': [
37+
'https://www.w3.org/2018/credentials/v1',
38+
'https://w3id.org/citizenship/v1',
39+
'https://w3id.org/security/bbs/v1',
40+
],
41+
id: 'https://issuer.oidp.uscis.gov/credentials/83627465',
42+
type: ['VerifiableCredential', 'PermanentResidentCard'],
43+
issuer: did,
44+
issuanceDate: '2019-12-03T12:19:52Z',
45+
expirationDate: '2029-12-03T12:19:52Z',
46+
identifier: '83627465',
47+
name: 'Permanent Resident Card',
48+
credentialSubject: {
49+
id: 'did:example:b34ca6cd37bbf23',
50+
type: ['PermanentResident', 'Person'],
51+
givenName: 'JOHN',
52+
familyName: 'SMITH',
53+
gender: 'Male',
54+
image: 'data:image/png;base64,iVBORw0KGgokJggg==',
55+
residentSince: '2015-01-01',
56+
description: 'Government of Example Permanent Resident Card.',
57+
lprCategory: 'C09',
58+
lprNumber: '999-999-999',
59+
commuterClassification: 'C1',
60+
birthCountry: 'Bahamas',
61+
birthDate: '1958-07-17',
62+
},
63+
},
64+
options: {
65+
proofType: 'Ed25519Signature2018',
66+
proofPurpose: 'assertionMethod',
67+
},
68+
}
69+
70+
const jsonLdCredentialFormat = new JsonLdCredentialFormatService()
71+
const jsonLdProofFormat = new DifPresentationExchangeProofFormatService()
72+
73+
const getCheqdJsonLdModules = () =>
74+
({
75+
...getCheqdModules(cheqdPayerSeeds[0], 'https://rpc.cheqd.network'),
76+
credentials: new CredentialsModule({
77+
credentialProtocols: [
78+
new V2CredentialProtocol({
79+
credentialFormats: [jsonLdCredentialFormat],
80+
}),
81+
],
82+
}),
83+
proofs: new ProofsModule({
84+
proofProtocols: [
85+
new V2ProofProtocol({
86+
proofFormats: [jsonLdProofFormat],
87+
}),
88+
],
89+
}),
90+
cache: new CacheModule({
91+
cache: new InMemoryLruCache({ limit: 100 }),
92+
}),
93+
w3cCredentials: new W3cCredentialsModule({}),
94+
} as const)
95+
96+
97+
// TODO: extract these very specific tests to the jsonld format
98+
describe('Cheqd V2 Credentials - JSON-LD - Ed25519', () => {
99+
let faberAgent: Agent<ReturnType<typeof getCheqdJsonLdModules>>
100+
let faberReplay: EventReplaySubject
101+
let aliceAgent: Agent<ReturnType<typeof getCheqdJsonLdModules>>
102+
let aliceReplay: EventReplaySubject
103+
let aliceConnectionId: string
104+
105+
beforeAll(async () => {
106+
faberAgent = new Agent(
107+
getInMemoryAgentOptions(
108+
'Faber Agent Indy/JsonLD',
109+
{
110+
endpoints: ['rxjs:faber'],
111+
},
112+
getCheqdJsonLdModules()
113+
)
114+
)
115+
aliceAgent = new Agent(
116+
getInMemoryAgentOptions(
117+
'Alice Agent Indy/JsonLD',
118+
{
119+
endpoints: ['rxjs:alice'],
120+
},
121+
getCheqdJsonLdModules()
122+
)
123+
)
124+
125+
setupSubjectTransports([faberAgent, aliceAgent])
126+
;[faberReplay, aliceReplay] = setupEventReplaySubjects(
127+
[faberAgent, aliceAgent],
128+
[CredentialEventTypes.CredentialStateChanged, ProofEventTypes.ProofStateChanged]
129+
)
130+
await faberAgent.initialize()
131+
await aliceAgent.initialize()
132+
;[, { id: aliceConnectionId }] = await makeConnection(faberAgent, aliceAgent)
133+
134+
await faberAgent.context.wallet.createKey({
135+
privateKey: TypedArrayEncoder.fromString('testseed000000000000000000000001'),
136+
keyType: KeyType.Ed25519,
137+
})
138+
})
139+
140+
afterAll(async () => {
141+
await faberAgent.shutdown()
142+
await faberAgent.wallet.delete()
143+
await aliceAgent.shutdown()
144+
await aliceAgent.wallet.delete()
145+
})
146+
147+
it('should create a did:cheqd did using custom did document containing Ed25519 key', async () => {
148+
149+
const ed25519Key = await faberAgent.wallet.createKey({
150+
keyType: KeyType.Ed25519,
151+
})
152+
153+
const createResult = await faberAgent.dids.create<CheqdDidCreateOptions>({
154+
method: 'cheqd',
155+
didDocument: new DidDocumentBuilder(did)
156+
.addContext(SECURITY_JWS_CONTEXT_URL)
157+
.addVerificationMethod(
158+
getEd25519VerificationKey2018({
159+
key: ed25519Key,
160+
controller: did,
161+
id: `${did}#${ed25519Key.fingerprint}`,
162+
})
163+
)
164+
.addAssertionMethod(`${did}#${ed25519Key.fingerprint}`)
165+
.addAuthentication(`${did}#${ed25519Key.fingerprint}`)
166+
.build(),
167+
})
168+
169+
expect(createResult).toMatchObject({
170+
didState: {
171+
state: 'finished',
172+
},
173+
})
174+
175+
expect(createResult.didState.didDocument?.toJSON()).toMatchObject({
176+
'@context': ['https://w3id.org/did/v1', 'https://w3id.org/security/suites/jws-2020/v1'],
177+
verificationMethod: [
178+
{
179+
controller: did,
180+
type: 'Ed25519VerificationKey2018',
181+
publicKeyBase58: ed25519Key.publicKeyBase58,
182+
},
183+
],
184+
})
185+
})
186+
187+
test('Alice starts with V2 (ld format, Ed25519 signature) credential proposal to Faber', async () => {
188+
testLogger.test('Alice sends (v2 jsonld) credential proposal to Faber')
189+
190+
const credentialExchangeRecord = await aliceAgent.credentials.proposeCredential({
191+
connectionId: aliceConnectionId,
192+
protocolVersion: 'v2',
193+
credentialFormats: {
194+
jsonld: signCredentialOptions,
195+
},
196+
comment: 'v2 propose credential test for W3C Credentials',
197+
})
198+
199+
expect(credentialExchangeRecord.connectionId).toEqual(aliceConnectionId)
200+
expect(credentialExchangeRecord.protocolVersion).toEqual('v2')
201+
expect(credentialExchangeRecord.state).toEqual(CredentialState.ProposalSent)
202+
expect(credentialExchangeRecord.threadId).not.toBeNull()
203+
204+
testLogger.test('Faber waits for credential proposal from Alice')
205+
let faberCredentialRecord = await waitForCredentialRecordSubject(faberReplay, {
206+
threadId: credentialExchangeRecord.threadId,
207+
state: CredentialState.ProposalReceived,
208+
})
209+
210+
testLogger.test('Faber sends credential offer to Alice')
211+
await faberAgent.credentials.acceptProposal({
212+
credentialRecordId: faberCredentialRecord.id,
213+
comment: 'V2 W3C Offer',
214+
})
215+
216+
testLogger.test('Alice waits for credential offer from Faber')
217+
let aliceCredentialRecord = await waitForCredentialRecordSubject(aliceReplay, {
218+
threadId: faberCredentialRecord.threadId,
219+
state: CredentialState.OfferReceived,
220+
})
221+
222+
const offerMessage = await aliceAgent.credentials.findOfferMessage(aliceCredentialRecord.id)
223+
expect(JsonTransformer.toJSON(offerMessage)).toMatchObject({
224+
'@type': 'https://didcomm.org/issue-credential/2.0/offer-credential',
225+
'@id': expect.any(String),
226+
comment: 'V2 W3C Offer',
227+
formats: [
228+
{
229+
attach_id: expect.any(String),
230+
format: 'aries/ld-proof-vc-detail@v1.0',
231+
},
232+
],
233+
'offers~attach': [
234+
{
235+
'@id': expect.any(String),
236+
'mime-type': 'application/json',
237+
data: expect.any(Object),
238+
lastmod_time: undefined,
239+
byte_count: undefined,
240+
},
241+
],
242+
'~thread': {
243+
thid: expect.any(String),
244+
pthid: undefined,
245+
sender_order: undefined,
246+
received_orders: undefined,
247+
},
248+
'~service': undefined,
249+
'~attach': undefined,
250+
'~please_ack': undefined,
251+
'~timing': undefined,
252+
'~transport': undefined,
253+
'~l10n': undefined,
254+
credential_preview: expect.any(Object),
255+
replacement_id: undefined,
256+
})
257+
expect(aliceCredentialRecord.id).not.toBeNull()
258+
expect(aliceCredentialRecord.type).toBe(CredentialExchangeRecord.type)
259+
260+
const offerCredentialExchangeRecord = await aliceAgent.credentials.acceptOffer({
261+
credentialRecordId: aliceCredentialRecord.id,
262+
credentialFormats: {
263+
jsonld: {},
264+
},
265+
})
266+
267+
expect(offerCredentialExchangeRecord.connectionId).toEqual(aliceConnectionId)
268+
expect(offerCredentialExchangeRecord.protocolVersion).toEqual('v2')
269+
expect(offerCredentialExchangeRecord.state).toEqual(CredentialState.RequestSent)
270+
expect(offerCredentialExchangeRecord.threadId).not.toBeNull()
271+
272+
testLogger.test('Faber waits for credential request from Alice')
273+
await waitForCredentialRecordSubject(faberReplay, {
274+
threadId: aliceCredentialRecord.threadId,
275+
state: CredentialState.RequestReceived,
276+
})
277+
278+
testLogger.test('Faber sends credential to Alice')
279+
280+
await faberAgent.credentials.acceptRequest({
281+
credentialRecordId: faberCredentialRecord.id,
282+
comment: 'V2 Indy Credential',
283+
})
284+
285+
testLogger.test('Alice waits for credential from Faber')
286+
aliceCredentialRecord = await waitForCredentialRecordSubject(aliceReplay, {
287+
threadId: faberCredentialRecord.threadId,
288+
state: CredentialState.CredentialReceived,
289+
})
290+
291+
testLogger.test('Alice sends credential ack to Faber')
292+
await aliceAgent.credentials.acceptCredential({ credentialRecordId: aliceCredentialRecord.id })
293+
294+
testLogger.test('Faber waits for credential ack from Alice')
295+
faberCredentialRecord = await waitForCredentialRecordSubject(faberReplay, {
296+
threadId: faberCredentialRecord.threadId,
297+
state: CredentialState.Done,
298+
})
299+
expect(aliceCredentialRecord).toMatchObject({
300+
type: CredentialExchangeRecord.type,
301+
id: expect.any(String),
302+
createdAt: expect.any(Date),
303+
threadId: expect.any(String),
304+
connectionId: expect.any(String),
305+
state: CredentialState.CredentialReceived,
306+
})
307+
308+
const credentialMessage = await faberAgent.credentials.findCredentialMessage(faberCredentialRecord.id)
309+
expect(JsonTransformer.toJSON(credentialMessage)).toMatchObject({
310+
'@type': 'https://didcomm.org/issue-credential/2.0/issue-credential',
311+
'@id': expect.any(String),
312+
comment: 'V2 Indy Credential',
313+
formats: [
314+
{
315+
attach_id: expect.any(String),
316+
format: 'aries/ld-proof-vc@v1.0',
317+
},
318+
],
319+
'credentials~attach': [
320+
{
321+
'@id': expect.any(String),
322+
'mime-type': 'application/json',
323+
data: expect.any(Object),
324+
lastmod_time: undefined,
325+
byte_count: undefined,
326+
},
327+
],
328+
'~thread': {
329+
thid: expect.any(String),
330+
pthid: undefined,
331+
sender_order: undefined,
332+
received_orders: undefined,
333+
},
334+
'~please_ack': { on: ['RECEIPT'] },
335+
'~service': undefined,
336+
'~attach': undefined,
337+
'~timing': undefined,
338+
'~transport': undefined,
339+
'~l10n': undefined,
340+
})
341+
})
342+
})

0 commit comments

Comments
 (0)