Skip to content

Commit

Permalink
Allow didUrl in fragments for verify
Browse files Browse the repository at this point in the history
  • Loading branch information
DaevMithran committed Oct 7, 2024
1 parent bc7082a commit 59d2397
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 29 deletions.
55 changes: 49 additions & 6 deletions src/controllers/api/accreditation.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import type { Request, Response } from 'express';
import type { VerifiableCredential } from '@veramo/core';
import type { DIDAccreditationRequestBody, DIDAccreditationRequestParams } from '../../types/accreditation.js';
import type {
DIDAccreditationRequestBody,
DIDAccreditationRequestParams,
VerifyAccreditationRequestBody,
} from '../../types/accreditation.js';
import type { ICredentialTrack, ITrackOperation } from '../../types/track.js';
import type { CredentialRequest } from '../../types/credential.js';
import { StatusCodes } from 'http-status-codes';
import { v4 } from 'uuid';
import { AccreditationRequestType, DIDAccreditationTypes } from '../../types/accreditation.js';
import {
AccreditationRequestType,
DIDAccreditationTypes,
isDidAndResourceId,
isDidAndResourceName,
isDidUrl,
} from '../../types/accreditation.js';
import { CredentialConnectors, VerifyCredentialRequestQuery } from '../../types/credential.js';
import { OperationCategoryNameEnum, OperationNameEnum } from '../../types/constants.js';
import { IdentityServiceStrategySetup } from '../../services/identity/index.js';
Expand All @@ -14,6 +24,7 @@ import { Credentials } from '../../services/api/credentials.js';
import { eventTracker } from '../../services/track/tracker.js';
import { body, query } from '../validator/index.js';
import { validate } from '../validator/decorator.js';
import { parseDidFromDidUrl } from '../../helpers/helpers.js';

export class AccreditationController {
public static issueValidator = [
Expand Down Expand Up @@ -66,7 +77,20 @@ export class AccreditationController {
];

public static verifyValidator = [
body('accreditation').exists().withMessage('accreditation should be a DID Url').bail(),
body('did')
.custom((value, { req }) => {
const { didUrl, resourceId, resourceName, resourceType } = req.body;
if (!value && !didUrl) {
throw new Error('Either "did" or "didUrl" is required');
}

// If did is provided, ensure either resourceId or both resourceName and resourceType are provided
if (value && !(resourceId || (resourceName && resourceType))) {
throw new Error('Either "resourceId" or both "resourceName" and "resourceType" are required');
}
return true;
})
.bail(),
body('subjectDid').exists().isDID().bail(),
query('verifyStatus')
.optional()
Expand Down Expand Up @@ -335,11 +359,30 @@ export class AccreditationController {
public async verify(request: Request, response: Response) {
// Extract did from params
let { verifyStatus = false, allowDeactivatedDid = false } = request.query as VerifyCredentialRequestQuery;
const { accreditation, policies, subjectDid } = request.body;
const { policies, subjectDid } = request.body as VerifyAccreditationRequestBody;

// construct didUrl
let didUrl: string;
let did: string;
if (isDidUrl(request.body)) {
didUrl = request.body.didUrl;
did = parseDidFromDidUrl(didUrl);
} else if (isDidAndResourceId(request.body)) {
did = request.body.did;
didUrl = `${did}/resources/${request.body.resourceId}`;
} else if (isDidAndResourceName(request.body)) {
did = request.body.did;
didUrl = `${did}?resourceName=${request.body.resourceName}&resourceType=${request.body.resourceType}`;
} else {
return response.status(400).json({
error: `Invalid Request: Either didUrl or did with resource attributes are required`,
});
}

try {
const result = await AccreditationService.instance.verify_accreditation(
subjectDid,
accreditation,
didUrl,
verifyStatus,
allowDeactivatedDid,
response.locals.customer,
Expand All @@ -352,7 +395,7 @@ export class AccreditationController {
customer: response.locals.customer,
user: response.locals.user,
data: {
did: accreditation.split('/')[0],
did,
} satisfies ICredentialTrack,
} as ITrackOperation;

Expand Down
4 changes: 4 additions & 0 deletions src/helpers/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,7 @@ export async function decryptPrivateKey(encryptedPrivateKeyHex: string, ivHex: s

return secretKey;
}

export function parseDidFromDidUrl(didUrl: string) {
return didUrl.includes('?') ? didUrl.split('?')[0] : didUrl.split('/')[0];
}
3 changes: 2 additions & 1 deletion src/services/api/accreditation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ export class AccreditationService {
error: `Invalid termsOfUse`,
};
}
const accreditorDid = didUrl.split('?')[0];

const accreditorDid = didUrl.includes('?') ? didUrl.split('?')[0] : didUrl.split('/')[0];

accreditationUrl = termsOfUse.parentAccreditation;
accreditedSubject = accreditorDid;
Expand Down
10 changes: 5 additions & 5 deletions src/static/swagger-api.json
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@
],
"example": {
"issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0",
"subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"subjectDid": "did:cheqd:testnet:cbe7ccf6-5937-44e6-8480-282b2d7ccc5b",
"schemas": [
{
"type": "MuseumPassCredential",
Expand All @@ -713,12 +713,12 @@
"type": "object",
"properties": {
"subjectDid": {
"description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.",
"description": "DID of the Verifiable Accreditation holder/subject. This needs to be a `did:cheqd` DID.",
"type": "string",
"example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
"example": "did:cheqd:testnet:cbe7ccf6-5937-44e6-8480-282b2d7ccc5b"
},
"accreditation": {
"description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.",
"didUrl": {
"description": "Verifiable Accreditation to be verified as a VC-JWT string or a JSON object.",
"type": "object"
},
"policies": {
Expand Down
40 changes: 39 additions & 1 deletion src/types/accreditation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { CredentialRequest } from './credential';
import type { CredentialRequest, VerifyCredentialRequestBody } from './credential';

// Enums
export enum DIDAccreditationTypes {
Expand Down Expand Up @@ -33,3 +33,41 @@ export type DIDAccreditationRequestBody = Omit<
export type DIDAccreditationRequestParams = {
accreditationType: 'authorize' | 'accredit' | 'attest';
};

export interface VerifyAccreditationRequestBody extends Pick<VerifyCredentialRequestBody, 'policies'> {
didUrl?: string;
did?: string;
resourceId?: string;
resourceName?: string;
resourceType?: string;
subjectDid: string;
}

type DidUrl = Pick<VerifyAccreditationRequestBody, 'policies' | 'subjectDid'> & {
didUrl: string;
};
type DidAndResourceId = Pick<VerifyAccreditationRequestBody, 'policies' | 'subjectDid'> & {
did: string;
resourceId: string;
};
type DidResourceNameAndType = Pick<VerifyAccreditationRequestBody, 'policies' | 'subjectDid'> & {
did: string;
resourceName: string;
resourceType: string;
};

export type VerifyAccreditationRequest = DidUrl | DidAndResourceId | DidResourceNameAndType;

export function isDidUrl(body: VerifyAccreditationRequestBody): body is DidUrl {
return typeof body.didUrl === 'string';
}

export function isDidAndResourceId(body: VerifyAccreditationRequestBody): body is DidAndResourceId {
return typeof body.did === 'string' && typeof body.resourceId === 'string';
}

export function isDidAndResourceName(body: VerifyAccreditationRequestBody): body is DidResourceNameAndType {
return (
typeof body.did === 'string' && typeof body.resourceName === 'string' && typeof body.resourceType === 'string'
);
}
38 changes: 25 additions & 13 deletions src/types/swagger-api-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,16 +328,16 @@
* publicKeyBase58: BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt
* type: Ed25519VerificationKey2018
* AccreditationIssueRequest:
* description: Input fields for the creating a Verifiable Credential.
* description: Input fields for the creating a Verifiable Accreditation.
* type: object
* additionalProperties: false
* properties:
* issuerDid:
* description: DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.
* description: DID of the Verifiable Accreditation issuer. This needs to be a `did:cheqd` DID.
* type: string
* example: did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0
* subjectDid:
* description: DID of the Verifiable Credential holder/subject. This needs to be a `did:cheqd` DID.
* description: DID of the Verifiable Accreditation holder/subject. This needs to be a `did:cheqd` DID.
* type: string
* example: did:cheqd:testnet:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK
* schemas:
Expand All @@ -346,10 +346,10 @@
* items:
* $ref: '#/components/schemas/SchemaUrl'
* attributes:
* description: JSON object containing the attributes to be included in the credential.
* description: JSON object containing the attributes to be included in the Accreditation.
* type: object
* '@context':
* description: Optional properties to be included in the `@context` property of the credential.
* description: Optional properties to be included in the `@context` property of the Accreditation.
* type: array
* items:
* type: string
Expand All @@ -361,7 +361,7 @@
* description: DID Url of the root Verifiable Accreditation.
* type: string
* type:
* description: Optional properties to be included in the `type` property of the credential.
* description: Optional properties to be included in the `type` property of the Accreditation.
* type: array
* items:
* type: string
Expand All @@ -372,7 +372,7 @@
* format: date-time
* example: 2023-06-08T13:49:28.000Z
* format:
* description: Format of the Verifiable Credential. Defaults to VC-JWT.
* description: Format of the Verifiable Accreditation. Defaults to VC-JWT.
* type: string
* enum:
* - jwt
Expand Down Expand Up @@ -473,14 +473,27 @@
* type: object
* properties:
* subjectDid:
* description: DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.
* description: DID of the Verifiable Accreditation holder/subject. This needs to be a `did:key` DID.
* type: string
* example: did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK
* accreditation:
* description: Verifiable Credential to be verified as a VC-JWT string or a JSON object.
* type: object
* didUrl:
* description: Verifiable Accreditation to be verified as a VC-JWT string or a JSON object.
* type: string
* example: did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-issuer-logo&resourceType=CredentialArtwork
* did:
* type: string
* example: did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e
* resourceId:
* type: string
* example: 398cee0a-efac-4643-9f4c-74c48c72a14b
* resourceName:
* type: string
* example: cheqd-issuer-logo
* resourceType:
* type: string
* example: CredentialArtwork
* policies:
* description: Custom verification policies to execute when verifying credential.
* description: Custom verification policies to execute when verifying Accreditation.
* type: object
* properties:
* issuanceDate:
Expand All @@ -496,7 +509,6 @@
* type: boolean
* default: false
* required:
* - accreditation
* - subjectDid
* PresentationCreateRequest:
* type: object
Expand Down
6 changes: 3 additions & 3 deletions tests/e2e/sequential/accreditation/issue-verify-flow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ test(' Issue and verify a authorize accreditation', async ({ request }) => {
const verifyResponse = await request.post(`/trust-registry/accreditation/verify`, {
data: JSON.stringify({
subjectDid: `${credentialData.subjectDid}`,
accreditation: `did:cheqd:testnet:5RpEg66jhhbmASWPXJRWrA?resourceName=authorizeAccreditation&resourceType=VerifiableAuthorisationForTrustChain`,
didUrl: `did:cheqd:testnet:5RpEg66jhhbmASWPXJRWrA?resourceName=authorizeAccreditation&resourceType=VerifiableAuthorisationForTrustChain`,
}),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
Expand Down Expand Up @@ -96,7 +96,7 @@ test(' Issue and verify a accredit accreditation', async ({ request }) => {
const verifyResponse = await request.post(`/trust-registry/accreditation/verify`, {
data: JSON.stringify({
subjectDid: `${credentialData.subjectDid}`,
accreditation: `did:cheqd:testnet:15b74787-6e48-4fd5-8020-eab24e990578?resourceName=accreditAccreditation&resourceType=VerifiableAccreditationToAccredit`,
didUrl: `did:cheqd:testnet:15b74787-6e48-4fd5-8020-eab24e990578?resourceName=accreditAccreditation&resourceType=VerifiableAccreditationToAccredit`,
}),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
Expand Down Expand Up @@ -138,7 +138,7 @@ test(' Issue and verify a attest accreditation', async ({ request }) => {
const verifyResponse = await request.post(`/trust-registry/accreditation/verify`, {
data: JSON.stringify({
subjectDid: `${credentialData.subjectDid}`,
accreditation: `did:cheqd:testnet:BjS4Nv8bVdxm2WW28MCfXA?resourceName=attestAccreditation&resourceType=VerifiableAccreditationToAttest`,
didUrl: `did:cheqd:testnet:BjS4Nv8bVdxm2WW28MCfXA?resourceName=attestAccreditation&resourceType=VerifiableAccreditationToAttest`,
}),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
Expand Down

0 comments on commit 59d2397

Please sign in to comment.