Skip to content

Commit

Permalink
fix: DID Document validation (#73)
Browse files Browse the repository at this point in the history
* fix: DID Document validation

* feat: Update error handling

* fix: Deactivate DID bug
  • Loading branch information
DaevMithran authored Jan 30, 2023
1 parent 28e6414 commit c963e78
Show file tree
Hide file tree
Showing 7 changed files with 462 additions and 510 deletions.
851 changes: 410 additions & 441 deletions package-lock.json

Large diffs are not rendered by default.

27 changes: 13 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,39 +21,38 @@
"dependencies": {
"@cheqd/sdk": "2.0.0",
"@cheqd/ts-proto": "^2.0.0-develop.1",
"@cosmjs/proto-signing": "^0.29.2",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"express-validator": "^6.14.2",
"helmet": "^6.0.0",
"node-cache": "^5.1.2",
"node-fetch": "^3.2.10",
"swagger-ui-express": "^4.5.0",
"uuid": "^9.0.0"
"@cosmjs/proto-signing": "^0.29.4",
"helmet": "^6.0.1",
"node-fetch": "^3.3.0",
"swagger-ui-express": "^4.6.0"
},
"devDependencies": {
"@semantic-release/changelog": "^6.0.1",
"@semantic-release/changelog": "^6.0.2",
"@semantic-release/commit-analyzer": "^9.0.2",
"@semantic-release/git": "^10.0.1",
"@semantic-release/github": "^8.0.6",
"@semantic-release/github": "^8.0.7",
"@semantic-release/npm": "^9.0.1",
"@semantic-release/release-notes-generator": "^10.0.3",
"@types/express": "^4.17.14",
"@types/helmet": "^4.0.0",
"@types/node": "^18.11.4",
"@types/node": "^18.11.9",
"@types/node-fetch": "^2.6.2",
"@types/swagger-ui-express": "^4.1.3",
"@types/uuid": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^5.40.1",
"@typescript-eslint/parser": "^5.40.1",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"conventional-changelog-conventionalcommits": "^5.0.0",
"esbuild": "^0.15.11",
"eslint": "^8.25.0",
"esbuild": "^0.15.16",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-typescript": "^3.0.0",
"prettier": "^2.7.1",
"prettier": "^2.8.0",
"semantic-release": "^19.0.5",
"typescript": "^4.8.4"
"typescript": "^4.9.3"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/",
Expand Down
23 changes: 13 additions & 10 deletions src/controllers/did.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ export class DidController {
return valid
}
return true
}).withMessage(Messages.InvalidDidDocument)
}).withMessage(Messages.InvalidDidDocument),
check('options.versionId').optional().isString().withMessage(Messages.InvalidOptions),
check('secret.signingResponse').optional().isArray().withMessage(Messages.InvalidSecret),
check('secret.signingResponse.*.signature').isString().withMessage(Messages.InvalidSecret),
check('secret.signingResponse.*.verificationMethodId').isString().withMessage(Messages.InvalidSecret)
]

public static updateValidator = [
Expand All @@ -35,7 +39,8 @@ export class DidController {
check('did').custom((value, {req})=>{
if(!value && !req.body.jobId) return false
return true
}).withMessage(Messages.InvalidDid)
}).withMessage(Messages.InvalidDid),
check('did').optional().isString().withMessage(Messages.InvalidDid).contains('did:cheqd:').withMessage(Messages.InvalidDid)
]

public async create(request: Request, response: Response) {
Expand Down Expand Up @@ -64,7 +69,7 @@ export class DidController {
versionId = storeData.versionId
} else {
jobId = v4()
versionId = v4()
versionId = options.versionId || v4()
}

let signInputs: SignInfo[]
Expand Down Expand Up @@ -130,7 +135,7 @@ export class DidController {

updatedDocument = didDocument[0]
jobId = v4()
versionId = v4()
versionId = options.versionId || v4()
} else {
const storeData = LocalStore.instance.getItem(jobId)
if(!storeData) {
Expand Down Expand Up @@ -180,7 +185,7 @@ export class DidController {
))
}

let { jobId, secret={}, options, did } = request.body as IDIDUpdateRequest
let { jobId, secret={}, options={}, did } = request.body as IDIDUpdateRequest

let payload: DIDDocument
let versionId: string
Expand All @@ -194,11 +199,11 @@ export class DidController {
}

payload = storeData.didDocument
did = storeData.didDocument.id!
did = storeData.didDocument.id
versionId = storeData.versionId
} else {
jobId = v4()
versionId = v4()
versionId = options.versionId || v4()
// check if did is registered on the ledger
let resolvedDocument = await CheqdResolver(did)

Expand Down Expand Up @@ -226,7 +231,7 @@ export class DidController {

options.network = options?.network || ((did!.split(':'))[2] as NetworkType)
await CheqdRegistrar.instance.connect(options)
const result = await CheqdRegistrar.instance.deactivate(signInputs, payload, v4())
const result = await CheqdRegistrar.instance.deactivate(signInputs, payload, versionId)
if ( result.code == 0 ) {
return response.status(201).json(Responses.GetSuccessResponse(
jobId,
Expand All @@ -243,7 +248,5 @@ export class DidController {
} catch (error) {
return response.status(500).json(Responses.GetInternalErrorResponse({id: did}, secret, error as string))
}


}
}
2 changes: 1 addition & 1 deletion src/controllers/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class ResourceController {
try {
// check if did is registered on the ledger
let resolvedDocument = await CheqdResolver(did)
if(!resolvedDocument?.didDocument) {
if(!resolvedDocument?.didDocument || resolvedDocument.didDocumentMetadata.deactivated) {
return response.status(400).send(Responses.GetInvalidResponse(
{id: did},
secret,
Expand Down
59 changes: 19 additions & 40 deletions src/helpers/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DIDDocument, SpecValidationResult, VerificationMethods } from "@cheqd/sdk/build/types";
import { Service, SignInfo, VerificationMethod } from "@cheqd/ts-proto/cheqd/did/v2";
import { SignInfo } from "@cheqd/ts-proto/cheqd/did/v2";

import { base64ToBytes } from "did-jwt";

Expand All @@ -16,59 +16,38 @@ export function convertToSignInfo(payload: ISignInfo[]): SignInfo[] {

export function validateSpecCompliantPayload(didDocument: DIDDocument) : SpecValidationResult {
// id is required, validated on both compile and runtime
if (!didDocument?.id) return { valid: false, error: 'id is required' }
if (!didDocument.id) return { valid: false, error: 'id is required' }

// verificationMethod is required
if (!didDocument?.verificationMethod) return { valid: false, error: 'verificationMethod is required' }
if (!didDocument.verificationMethod) return { valid: false, error: 'verificationMethod is required' }

// verificationMethod must be an array
if (!Array.isArray(didDocument?.verificationMethod)) return { valid: false, error: 'verificationMethod must be an array' }
if (!Array.isArray(didDocument.verificationMethod)) return { valid: false, error: 'verificationMethod must be an array' }

// verificationMethod must be not be empty
if (didDocument?.verificationMethod.length) return { valid: false, error: 'verificationMethod must be not be empty' }
if (!didDocument.verificationMethod.length) return { valid: false, error: 'verificationMethod must be not be empty' }

// verificationMethod types must be supported
const protoVerificationMethod = didDocument.verificationMethod.map((vm) => {
switch (vm?.type) {
const isValidVerificationMethod = didDocument.verificationMethod.every((vm) => {
switch (vm.type) {
case VerificationMethods.Ed255192020:
if (!vm?.publicKeyMultibase) throw new Error('publicKeyMultibase is required')

return VerificationMethod.fromPartial({
id: vm.id,
controller: vm.controller,
verificationMethodType: VerificationMethods.Ed255192020,
verificationMaterial: vm.publicKeyMultibase,
})
return vm.publicKeyMultibase != null
case VerificationMethods.JWK:
if (!vm?.publicKeyJwk) throw new Error('publicKeyJwk is required')

return VerificationMethod.fromPartial({
id: vm.id,
controller: vm.controller,
verificationMethodType: VerificationMethods.JWK,
verificationMaterial: JSON.stringify(vm.publicKeyJwk),
})
return vm.publicKeyJwk != null
case VerificationMethods.Ed255192018:
if (!vm?.publicKeyBase58) throw new Error('publicKeyBase58 is required')

return VerificationMethod.fromPartial({
id: vm.id,
controller: vm.controller,
verificationMethodType: VerificationMethods.Ed255192018,
verificationMaterial: vm.publicKeyBase58,
})
return vm.publicKeyBase58 != null
default:
throw new Error('Unsupported verificationMethod type')
return false
}
})

const protoService = didDocument?.service?.map((s) => {
return Service.fromPartial({
id: s?.id,
serviceType: s?.type,
serviceEndpoint: <string[]>s?.serviceEndpoint,
})
})
if(!isValidVerificationMethod) return { valid: false, error: 'verificationMethod publicKey is Invalid'}

const isValidService = didDocument.service ? didDocument?.service?.every((s) => {
return Array.isArray(s?.serviceEndpoint) && s?.id && s?.type
}) : true

if(!isValidService) return { valid: false, error: 'Service is Invalid'}

return { valid: true, protobufVerificationMethod: protoVerificationMethod, protobufService: protoService } as SpecValidationResult
return { valid: true } as SpecValidationResult
}
4 changes: 3 additions & 1 deletion src/types/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ export enum Messages {
SecretValidation = "Provide either a valid KeyPair or Signature",
InvalidResource = "Resource Data is invalid",
TestnetFaucet = "sketch mountain erode window enact net enrich smoke claim kangaroo another visual write meat latin bacon pulp similar forum guilt father state erase bright",
SigingResponse = "e.g. { verificationMethodId: did:cheqd:testnet:qsqdcansoica#key-1, signature: aca1s12q14213casdvaadcfas }"
SigingResponse = "e.g. { verificationMethodId: did:cheqd:testnet:qsqdcansoica#key-1, signature: aca1s12q14213casdvaadcfas }",
InvalidOptions = "The provided options are invalid",
InvalidSecret = "The provided secret is invalid"
}
6 changes: 3 additions & 3 deletions src/types/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DIDDocument, DidStdFee, ISignInputs } from '@cheqd/sdk/build/types'
import { DIDDocument, DidStdFee } from '@cheqd/sdk/build/types'
import { AlternativeUri } from '@cheqd/ts-proto/cheqd/resource/v2'

import { NetworkType } from '../service/cheqd'
Expand Down Expand Up @@ -84,7 +84,7 @@ export interface ISecret {

export interface IOptions {
network?: NetworkType,
keytype?: string,
rpcUrl?: string,
fee?: DidStdFee
fee?: DidStdFee,
versionId?: string
}

0 comments on commit c963e78

Please sign in to comment.