Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
224 changes: 118 additions & 106 deletions packages/cheqd/src/dids/CheqdDidRegistrar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
createMsgCreateDidDocPayloadToSign,
createMsgDeactivateDidDocPayloadToSign,
generateDidDoc,
getVerificationMethodId,
validateSpecCompliantPayload,
} from './didCheqdUtil'

Expand Down Expand Up @@ -146,6 +147,7 @@ export class CheqdDidRegistrar implements DidRegistrar {
}
} else if (options.options.createKey || options.options.keyId) {
const methodSpecificIdAlgo = options.options.methodSpecificIdAlgo
const verificationMethod = options.options.verificationMethodType || VerificationMethods.JWK
const kms = agentContext.dependencyManager.resolve(Kms.KeyManagementApi)

let publicJwk: KmsJwkPublicOkp & { crv: 'Ed25519' }
Expand Down Expand Up @@ -194,8 +196,6 @@ export class CheqdDidRegistrar implements DidRegistrar {
}
}

// TODO: make this configureable
const verificationMethod = VerificationMethods.JWK
const jwk = Kms.PublicJwk.fromPublicJwk(publicJwk)

didDocument = generateDidDoc({
Expand Down Expand Up @@ -286,126 +286,125 @@ export class CheqdDidRegistrar implements DidRegistrar {
let didRecord: DidRecord | null

try {
if (options.didDocument) {
const isSpecCompliantPayload = validateSpecCompliantPayload(options.didDocument)
if (!isSpecCompliantPayload.valid) {
return {
didDocumentMetadata: {},
didRegistrationMetadata: {},
didState: {
state: 'failed',
reason: `Invalid did document provided. ${isSpecCompliantPayload.error}`,
},
}
if (!options.didDocument) {
return {
didDocumentMetadata: {},
didRegistrationMetadata: {},
didState: {
state: 'failed',
reason: 'Provide a valid didDocument',
},
}
}

didDocument = options.didDocument
const resolvedDocument = await cheqdLedgerService.resolve(didDocument.id)
didRecord = await didRepository.findCreatedDid(agentContext, didDocument.id)
if (!resolvedDocument.didDocument || resolvedDocument.didDocumentMetadata.deactivated || !didRecord) {
return {
didDocumentMetadata: {},
didRegistrationMetadata: {},
didState: {
state: 'failed',
reason: 'Did not found',
},
}
const isSpecCompliantPayload = validateSpecCompliantPayload(options.didDocument)
if (!isSpecCompliantPayload.valid) {
return {
didDocumentMetadata: {},
didRegistrationMetadata: {},
didState: {
state: 'failed',
reason: `Invalid did document provided. ${isSpecCompliantPayload.error}`,
},
}
}

const keys = didRecord.keys ?? []
if (options.options?.createKey || options.options?.keyId) {
const kms = agentContext.dependencyManager.resolve(Kms.KeyManagementApi)
let createdKey: DidDocumentKey
didDocument = options.didDocument
const resolvedDocument = await cheqdLedgerService.resolve(didDocument.id)
didRecord = await didRepository.findCreatedDid(agentContext, didDocument.id)
if (!resolvedDocument.didDocument || resolvedDocument.didDocumentMetadata.deactivated || !didRecord) {
return {
didDocumentMetadata: {},
didRegistrationMetadata: {},
didState: {
state: 'failed',
reason: 'Did not found',
},
}
}

let publicJwk: KmsJwkPublicOkp & { crv: 'Ed25519' }
if (options.options.createKey) {
const createKeyResult = await kms.createKey(options.options.createKey)
publicJwk = createKeyResult.publicJwk
const keys = didRecord.keys ?? []
if (options.options?.createKey || options.options?.keyId) {
const kms = agentContext.dependencyManager.resolve(Kms.KeyManagementApi)
let createdKey: DidDocumentKey

createdKey = {
didDocumentRelativeKeyId: `#${utils.uuid()}-1`,
kmsKeyId: createKeyResult.keyId,
}
} else if (options.options.keyId) {
const _publicJwk = await kms.getPublicKey({
keyId: options.options.keyId,
})
createdKey = {
didDocumentRelativeKeyId: `#${utils.uuid()}-1`,
kmsKeyId: options.options.keyId,
}
if (!_publicJwk) {
return {
didDocumentMetadata: {},
didRegistrationMetadata: {},
didState: {
state: 'failed',
reason: `notFound: key with key id '${options.options.keyId}' not found`,
},
}
}
let publicJwk: KmsJwkPublicOkp & { crv: 'Ed25519' }
if (options.options.createKey) {
const createKeyResult = await kms.createKey(options.options.createKey)
publicJwk = createKeyResult.publicJwk

if (_publicJwk.kty !== 'OKP' || _publicJwk.crv !== 'Ed25519') {
return {
didDocumentMetadata: {},
didRegistrationMetadata: {},
didState: {
state: 'failed',
reason: `key with key id '${options.options.keyId}' uses unsupported ${Kms.getJwkHumanDescription(
_publicJwk
)} for did:cheqd`,
},
}
createdKey = {
didDocumentRelativeKeyId: `#${utils.uuid()}-1`,
kmsKeyId: createKeyResult.keyId,
}
} else if (options.options.keyId) {
const _publicJwk = await kms.getPublicKey({
keyId: options.options.keyId,
})
createdKey = {
didDocumentRelativeKeyId: `#${utils.uuid()}-1`,
kmsKeyId: options.options.keyId,
}
if (!_publicJwk) {
return {
didDocumentMetadata: {},
didRegistrationMetadata: {},
didState: {
state: 'failed',
reason: `notFound: key with key id '${options.options.keyId}' not found`,
},
}
}

publicJwk = {
..._publicJwk,
crv: _publicJwk.crv,
}
} else {
// This will never happen, but to make TS happy
if (_publicJwk.kty !== 'OKP' || _publicJwk.crv !== 'Ed25519') {
return {
didDocumentMetadata: {},
didRegistrationMetadata: {},
didState: {
state: 'failed',
reason: 'Expect options.createKey or options.keyId',
reason: `key with key id '${options.options.keyId}' uses unsupported ${Kms.getJwkHumanDescription(
_publicJwk
)} for did:cheqd`,
},
}
}

// TODO: make this configureable
const verificationMethod = VerificationMethods.JWK
const jwk = Kms.PublicJwk.fromPublicJwk(publicJwk)

keys.push(createdKey)
didDocument.verificationMethod?.concat(
JsonTransformer.fromJSON(
createDidVerificationMethod(
[verificationMethod],
[
{
methodSpecificId: didDocument.id.split(':')[3],
didUrl: didDocument.id,
keyId: `${didDocument.id}${createdKey.didDocumentRelativeKeyId}` as `${string}#${string}-${number}`,
publicKey: TypedArrayEncoder.toHex(jwk.publicKey.publicKey),
},
]
),
VerificationMethod
)
)
}
} else {
return {
didDocumentMetadata: {},
didRegistrationMetadata: {},
didState: {
state: 'failed',
reason: 'Provide a valid didDocument',
},
publicJwk = {
..._publicJwk,
crv: _publicJwk.crv,
}
} else {
// This will never happen, but to make TS happy
return {
didDocumentMetadata: {},
didRegistrationMetadata: {},
didState: {
state: 'failed',
reason: 'Expect options.createKey or options.keyId',
},
}
}

const verificationMethod = options.options.verificationMethodType || VerificationMethods.JWK
const jwk = Kms.PublicJwk.fromPublicJwk(publicJwk)

keys.push(createdKey)
didDocument.verificationMethod?.concat(
JsonTransformer.fromJSON(
createDidVerificationMethod(
[verificationMethod],
[
{
methodSpecificId: didDocument.id.split(':')[3],
didUrl: didDocument.id,
keyId: `${didDocument.id}${createdKey.didDocumentRelativeKeyId}` as `${string}#${string}-${number}`,
publicKey: TypedArrayEncoder.toHex(jwk.publicKey.publicKey),
},
]
),
VerificationMethod
)
)
}

// Filter out all keys that are not present in the did document anymore
Expand Down Expand Up @@ -437,9 +436,20 @@ export class CheqdDidRegistrar implements DidRegistrar {

const payloadToSign = await createMsgCreateDidDocPayloadToSign(didDocument.toJSON() as DIDDocument, versionId)

const authentication = didDocument.authentication?.map((authentication) =>
typeof authentication === 'string' ? didDocument.dereferenceVerificationMethod(authentication) : authentication
)
const authSet = new Set<string>()

const authentication: VerificationMethod[] = [
...(didDocument.authentication || []),
...(resolvedDocument.didDocument.authentication || []),
].reduce<VerificationMethod[]>((uniqueAuths, auth) => {
const id = getVerificationMethodId(auth)
if (!authSet.has(id)) {
authSet.add(id)
uniqueAuths.push(typeof auth === 'string' ? didDocument.dereferenceVerificationMethod(auth) : auth)
}
return uniqueAuths
}, [])

if (!authentication || authentication.length === 0) {
return {
didDocumentMetadata: {},
Expand Down Expand Up @@ -685,6 +695,7 @@ export interface CheqdDidCreateWithoutDidDocumentOptions extends DidCreateOption
fee?: DidStdFee
versionId?: string
methodSpecificIdAlgo?: `${MethodSpecificIdAlgo}`
verificationMethodType?: VerificationMethods
} & XOR<{ createKey: KmsCreateKeyOptionsOkpEd25519 }, { keyId: string }>
}

Expand Down Expand Up @@ -716,6 +727,7 @@ export interface CheqdDidUpdateOptions extends DidUpdateOptions {
* in the did document anymore, and this new list will be merged into it.
*/
keys?: DidDocumentKey[]
verificationMethodType?: VerificationMethods

fee?: DidStdFee
versionId?: string
Expand Down
6 changes: 5 additions & 1 deletion packages/cheqd/src/dids/didCheqdUtil.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { CheqdNetwork, DIDDocument, MethodSpecificIdAlgo, TVerificationKey } from '@cheqd/sdk'
import type { CheqdNetwork, DIDDocument, MethodSpecificIdAlgo, TVerificationKey, VerificationMethod } from '@cheqd/sdk'
import type { Metadata } from '@cheqd/ts-proto/cheqd/resource/v2'

import {
Expand Down Expand Up @@ -160,3 +160,7 @@ export function getCosmosPayerWallet(cosmosPayerSeed?: string) {
? DirectSecp256k1HdWallet.fromMnemonic(cosmosPayerSeed, { prefix: 'cheqd' })
: DirectSecp256k1Wallet.fromKey(TypedArrayEncoder.fromString(cosmosPayerSeed.replace(/^0x/, '')), 'cheqd')
}

export function getVerificationMethodId(vm: string | VerificationMethod) {
return typeof vm === 'string' ? vm : vm.id
}
Loading