diff --git a/e2e/verifiable-credentials.service.e2e.ts b/e2e/verifiable-credentials.service.e2e.ts index 5df633bc..2ea95bee 100644 --- a/e2e/verifiable-credentials.service.e2e.ts +++ b/e2e/verifiable-credentials.service.e2e.ts @@ -11,13 +11,15 @@ import { claimsBySubject, } from './fixtures'; import { replenish, rpcUrl, setupENS } from './utils/setup-contracts'; -import { CacheClient, fromPrivateKey } from '../src'; import { + CacheClient, + fromPrivateKey, + InterfaceNotSatisfied, getVerifiableCredentialsService, IssuerFields, RoleCredentialSubject, VerifiableCredentialsServiceBase, -} from '../src/modules/verifiable-credentials'; +} from '../src/'; import { VC_API_EXCHANGE, VerifiableCredential, @@ -157,6 +159,12 @@ describe('Verifiable credentials tests', () => { expect(result).toBe(true); }); + test('should not create VC with invalid issuer fields', async () => { + return expect( + createExampleSignedCredential([{ key: 'foo' } as IssuerFields]) + ).rejects.toBeInstanceOf(InterfaceNotSatisfied); + }); + test('should throw an error for invalid VC during verification', async () => { const vc = await createExampleSignedCredential([]); diff --git a/src/errors/index.ts b/src/errors/index.ts index d317bea6..da1ca949 100644 --- a/src/errors/index.ts +++ b/src/errors/index.ts @@ -7,3 +7,4 @@ export { ERROR_MESSAGES } from './error-messages'; export { MalformedDIDError } from './malformed-did.error'; export { NotAuthorizedIssuer } from './not-authorized-issuer'; export { AssetNotExist } from './asset-not-exist'; +export { InterfaceNotSatisfied } from './interface-not-satisfied'; diff --git a/src/errors/interface-not-satisfied.ts b/src/errors/interface-not-satisfied.ts new file mode 100644 index 00000000..369f8cd3 --- /dev/null +++ b/src/errors/interface-not-satisfied.ts @@ -0,0 +1,5 @@ +export class InterfaceNotSatisfied extends Error { + constructor(interf: string, reason: string) { + super(`Interface ${interf} is not satisfied: ${reason}`); + } +} diff --git a/src/modules/claims/claims.types.ts b/src/modules/claims/claims.types.ts index add1130f..16d9ae77 100644 --- a/src/modules/claims/claims.types.ts +++ b/src/modules/claims/claims.types.ts @@ -10,6 +10,7 @@ import { IOrganizationDefinition, IRoleDefinition, IRoleDefinitionV2, + IssuerFields, } from '@energyweb/credential-governance'; export interface IClaimRequest extends IMessage { @@ -192,7 +193,7 @@ export interface IssueClaimRequestOptions { registrationTypes: RegistrationTypes[]; /** Issuer fields that role is requiring */ - issuerFields?: { key: string; value: string | number }[]; + issuerFields?: IssuerFields[]; /** Indicates whether to publish role on-chain or not (default: false) */ publishOnChain?: boolean; @@ -265,7 +266,7 @@ export interface IssueClaimOptions { claimTypeVersion: number; /** Issuers fields that role is requiring */ - issuerFields?: { key: string; value: string | number }[]; + issuerFields?: IssuerFields[]; }; /* @@ -334,7 +335,7 @@ export interface IssueVerifiablePresentationOptions { version: string; /** Issuers fields that role is requiring */ - issuerFields?: { key: string; value: string | number }[]; + issuerFields?: IssuerFields[]; /* * Indicates credential status (such as revocation status) diff --git a/src/modules/verifiable-credentials/types/verifiable-credentials.types.ts b/src/modules/verifiable-credentials/types/verifiable-credentials.types.ts index c5529ec3..d519154f 100644 --- a/src/modules/verifiable-credentials/types/verifiable-credentials.types.ts +++ b/src/modules/verifiable-credentials/types/verifiable-credentials.types.ts @@ -1,6 +1,7 @@ +import { IssuerFields } from '@energyweb/credential-governance'; import { StatusList2021Entry } from '@ew-did-registry/credentials-interface'; import { IPresentationDefinition, SelectResults } from '@sphereon/pex'; -import { IssuerFields } from './role-credential.types'; +import { InterfaceNotSatisfied } from '../../../errors/interface-not-satisfied'; /* * Parameters required to construct the subject for a role credential @@ -28,6 +29,19 @@ export interface RoleCredentialSubjectParams { /** Indicates if credential is actual of time of verification */ credentialStatus?: StatusList2021Entry; } +export const validateRoleCredentialSubject = ( + subject: RoleCredentialSubjectParams +) => { + const invalidField = subject.issuerFields?.find( + (field) => !['string', 'number'].includes(typeof field.value) + ); + if (invalidField) { + throw new InterfaceNotSatisfied( + 'RoleCredentialSubjectParam', + `IssuerFields invalid: ${invalidField.key} is not string or number` + ); + } +}; export interface ProofOptions { /* Proof verification method */ diff --git a/src/modules/verifiable-credentials/verifiable-credentials-base.service.ts b/src/modules/verifiable-credentials/verifiable-credentials-base.service.ts index 9139dc28..19f0e7cd 100644 --- a/src/modules/verifiable-credentials/verifiable-credentials-base.service.ts +++ b/src/modules/verifiable-credentials/verifiable-credentials-base.service.ts @@ -33,6 +33,7 @@ import { StatusList2021Credential, statusList2021CredentialEIP712Types, CredentialRevocationDetailsResult, + validateRoleCredentialSubject, } from './types'; import { ERROR_MESSAGES } from '../../errors'; import { CacheClient } from '../cache-client'; @@ -556,6 +557,7 @@ export abstract class VerifiableCredentialsServiceBase { public createCredential( params: RoleCredentialSubjectParams ): Credential { + validateRoleCredentialSubject(params); const credential: Credential = { // TODO: Host EWF VC Context and Vocabulary '@context': ['https://www.w3.org/2018/credentials/v1'],