Skip to content

fix(cheqd): Populate contexts for JsonLD issuance #2250

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: v0.5.x
Choose a base branch
from
Open
5 changes: 5 additions & 0 deletions .changeset/kind-pots-yell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@credo-ts/cheqd': patch
---

Populate contexts for Cheqd DID Document Records in wallet
3 changes: 3 additions & 0 deletions packages/cheqd/src/anoncreds/utils/identifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ const QUERY = `([?][^#]*)?`
const VERSION_ID = `(.*?)`
const FRAGMENT = `([#].*)?`

export const ED25519_SUITE_CONTEXT_URL_2018 = 'https://w3id.org/security/suites/ed25519-2018/v1'
export const ED25519_SUITE_CONTEXT_URL_2020 = 'https://w3id.org/security/suites/ed25519-2020/v1'

export const cheqdSdkAnonCredsRegistryIdentifierRegex = new RegExp(
`^did:cheqd:${NETWORK}:${IDENTIFIER}${PATH}${QUERY}${FRAGMENT}$`
)
Expand Down
62 changes: 47 additions & 15 deletions packages/cheqd/src/dids/CheqdDidRegistrar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,15 @@ import {
getKeyFromVerificationMethod,
JsonTransformer,
VerificationMethod,
SECURITY_JWS_CONTEXT_URL,
DID_V1_CONTEXT_URL,
} from '@credo-ts/core'

import { parseCheqdDid } from '../anoncreds/utils/identifiers'
import {
ED25519_SUITE_CONTEXT_URL_2018,
ED25519_SUITE_CONTEXT_URL_2020,
parseCheqdDid,
} from '../anoncreds/utils/identifiers'
import { CheqdLedgerService } from '../ledger'

import {
Expand All @@ -39,6 +45,11 @@ import {

export class CheqdDidRegistrar implements DidRegistrar {
public readonly supportedMethods = ['cheqd']
private contextMapping = {
Ed25519VerificationKey2018: ED25519_SUITE_CONTEXT_URL_2018,
Ed25519VerificationKey2020: ED25519_SUITE_CONTEXT_URL_2020,
JsonWebKey2020: SECURITY_JWS_CONTEXT_URL,
}

public async create(agentContext: AgentContext, options: CheqdDidCreateOptions): Promise<DidCreateResult> {
const didRepository = agentContext.dependencyManager.resolve(DidRepository)
Expand Down Expand Up @@ -90,18 +101,6 @@ export class CheqdDidRegistrar implements DidRegistrar {
network: withoutDidDocumentOptions.options.network as CheqdNetwork,
publicKey: TypedArrayEncoder.toHex(key.publicKey),
})

const contextMapping = {
Ed25519VerificationKey2018: 'https://w3id.org/security/suites/ed25519-2018/v1',
Ed25519VerificationKey2020: 'https://w3id.org/security/suites/ed25519-2020/v1',
JsonWebKey2020: 'https://w3id.org/security/suites/jws-2020/v1',
}
const contextUrl = contextMapping[verificationMethod.type]

// Add the context to the did document
// NOTE: cheqd sdk uses https://www.w3.org/ns/did/v1 while Credo did doc uses https://w3id.org/did/v1
// We should align these at some point. For now we just return a consistent value.
didDocument.context = ['https://www.w3.org/ns/did/v1', contextUrl]
} else {
return {
didDocumentMetadata: {},
Expand All @@ -113,6 +112,25 @@ export class CheqdDidRegistrar implements DidRegistrar {
}
}

// Normalize context to an array
const contextSet = new Set<string>(
typeof didDocument.context === 'string'
? [didDocument.context]
: Array.isArray(didDocument.context)
? didDocument.context
: []
)

for (const verificationMethod of didDocument.verificationMethod || []) {
const contextUrl = this.contextMapping[verificationMethod.type as keyof typeof this.contextMapping]
if (contextUrl) {
contextSet.add(contextUrl)
}
}

// Add Cheqd default context to the did document
didDocument.context = Array.from(contextSet.add(DID_V1_CONTEXT_URL))

const didDocumentJson = didDocument.toJSON() as DIDDocument

const payloadToSign = await createMsgCreateDidDocPayloadToSign(didDocumentJson, versionId)
Expand Down Expand Up @@ -162,6 +180,7 @@ export class CheqdDidRegistrar implements DidRegistrar {
const verificationMethod = options.secret?.verificationMethod
let didDocument: DidDocument
let didRecord: DidRecord | null
let contextSet: Set<string>

try {
if (options.didDocument && validateSpecCompliantPayload(options.didDocument)) {
Expand All @@ -178,6 +197,14 @@ export class CheqdDidRegistrar implements DidRegistrar {
},
}
}
// Normalize existing context to an array
contextSet = new Set<string>(
typeof didDocument.context === 'string'
? [didDocument.context]
: Array.isArray(didDocument.context)
? didDocument.context
: []
)

if (verificationMethod) {
const privateKey = verificationMethod.privateKey
Expand Down Expand Up @@ -213,6 +240,10 @@ export class CheqdDidRegistrar implements DidRegistrar {
VerificationMethod
)
)
const contextUrl = this.contextMapping[verificationMethod.type as keyof typeof this.contextMapping]
if (contextUrl) {
contextSet.add(contextUrl)
}
}
} else {
return {
Expand All @@ -224,7 +255,8 @@ export class CheqdDidRegistrar implements DidRegistrar {
},
}
}

// Add Cheqd default context to the did document
didDocument.context = Array.from(contextSet.add(DID_V1_CONTEXT_URL))
const payloadToSign = await createMsgCreateDidDocPayloadToSign(didDocument as DIDDocument, versionId)
const signInputs = await this.signPayload(agentContext, payloadToSign, didDocument.verificationMethod)

Expand Down Expand Up @@ -300,7 +332,7 @@ export class CheqdDidRegistrar implements DidRegistrar {
didState: {
state: 'finished',
did: didDocument.id,
didDocument: JsonTransformer.fromJSON(didDocument, DidDocument),
didDocument: JsonTransformer.fromJSON(didRecord.didDocument, DidDocument),
secret: options.secret,
},
}
Expand Down
10 changes: 5 additions & 5 deletions packages/cheqd/tests/cheqd-did-registrar.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type { CheqdDidCreateOptions } from '../src'
import type { DidDocument } from '@credo-ts/core'

import {
SECURITY_JWS_CONTEXT_URL,
DidDocumentBuilder,
getEd25519VerificationKey2018,
getJsonWebKey2020,
Expand Down Expand Up @@ -127,7 +126,7 @@ describe('Cheqd DID registrar', () => {
didDocument,
},
})

expect(updateResult.didState.didDocument?.toJSON()).toMatchObject(didDocument.toJSON())
const deactivateResult = await agent.dids.deactivate({ did })
expect(deactivateResult.didState.didDocument?.toJSON()).toMatchObject(didDocument.toJSON())
expect(deactivateResult.didState.state).toEqual('finished')
Expand All @@ -148,7 +147,6 @@ describe('Cheqd DID registrar', () => {
const createResult = await agent.dids.create<CheqdDidCreateOptions>({
method: 'cheqd',
didDocument: new DidDocumentBuilder(did)
.addContext(SECURITY_JWS_CONTEXT_URL)
.addController(did)
.addAuthentication(`${did}#${ed25519Key.fingerprint}`)
.addVerificationMethod(
Expand All @@ -168,7 +166,10 @@ describe('Cheqd DID registrar', () => {
})

expect(createResult.didState.didDocument?.toJSON()).toMatchObject({
'@context': ['https://w3id.org/did/v1', 'https://w3id.org/security/suites/jws-2020/v1'],
'@context': [
'https://www.w3.org/ns/did/v1',
'https://w3id.org/security/suites/ed25519-2018/v1',
],
verificationMethod: [
{
controller: did,
Expand All @@ -189,7 +190,6 @@ describe('Cheqd DID registrar', () => {
const createResult = await agent.dids.create<CheqdDidCreateOptions>({
method: 'cheqd',
didDocument: new DidDocumentBuilder(did)
.addContext(SECURITY_JWS_CONTEXT_URL)
.addController(did)
.addAuthentication(`${did}#${p256Key.fingerprint}`)
.addVerificationMethod(
Expand Down
5 changes: 4 additions & 1 deletion packages/cheqd/tests/cheqd-did-resolver.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ describe('Cheqd DID resolver', () => {
})
expect(JsonTransformer.toJSON(resolveResult)).toMatchObject({
didDocument: {
'@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/suites/ed25519-2020/v1'],
'@context': [
'https://www.w3.org/ns/did/v1',
'https://w3id.org/security/suites/ed25519-2020/v1',
],
id: did,
controller: [did],
verificationMethod: [
Expand Down
Loading