Skip to content
Merged
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
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@
"@tradetrust-tt/token-registry-v4": "npm:@tradetrust-tt/token-registry@^4.16.0",
"@tradetrust-tt/token-registry-v5": "npm:@tradetrust-tt/token-registry@^5.3.0",
"@tradetrust-tt/tradetrust": "^6.10.1",
"@tradetrust-tt/tradetrust-utils": "^2.3.1",
"@tradetrust-tt/tradetrust-utils": "^2.3.2",
"@tradetrust-tt/tt-verify": "^9.4.0",
"@trustvc/w3c-context": "^1.2.13",
"@trustvc/w3c-credential-status": "^1.2.12",
Expand Down
16 changes: 9 additions & 7 deletions src/__tests__/core/verify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
WRAPPED_DOCUMENT_DID_TOKEN_REGISTRY_V3,
WRAPPED_DOCUMENT_DNS_TXT_V2,
} from '../fixtures/fixtures';
import { W3CCredentialStatusCode } from 'src/verify/fragments/document-status/w3cCredentialStatus';

const providerUrl = 'https://rpc-amoy.polygon.technology';

Expand Down Expand Up @@ -98,7 +99,7 @@ describe.concurrent('W3C verify', () => {
expect.objectContaining({
name: 'W3CSignatureIntegrity',
reason: {
code: 0,
code: W3CCredentialStatusCode.SKIPPED,
codeString: 'SKIPPED',
message: "Document either has no proof or proof.type is not 'BbsBlsSignature2020'.",
},
Expand All @@ -120,7 +121,7 @@ describe.concurrent('W3C verify', () => {
expect.objectContaining({
name: 'W3CIssuerIdentity',
reason: {
code: 0,
code: W3CCredentialStatusCode.SKIPPED,
codeString: 'SKIPPED',
message: 'Document has no issuer field.',
},
Expand Down Expand Up @@ -188,7 +189,7 @@ describe.concurrent('W3C verify', () => {
expect.objectContaining({
name: 'W3CCredentialStatus',
reason: {
code: 0,
code: W3CCredentialStatusCode.SKIPPED,
codeString: 'SKIPPED',
message: 'Document does not have a valid credentialStatus or type.',
},
Expand Down Expand Up @@ -237,12 +238,13 @@ describe.concurrent('W3C verify', () => {
statusListIndex: '131072',
},
};

expect(await verifyDocument(tampered)).toEqual(
expect.arrayContaining([
expect.objectContaining({
name: 'W3CCredentialStatus',
reason: {
code: W3CCredentialStatusCode.UNEXPECTED_ERROR,
codeString: 'ERROR',
message: 'Invalid statusListIndex: Index out of range: min=0, max=131071',
},
status: 'ERROR',
Expand Down Expand Up @@ -328,7 +330,7 @@ describe.concurrent('W3C verify', () => {
expect.objectContaining({
name: 'TransferableRecords',
reason: {
code: 9,
code: W3CCredentialStatusCode.UNRECOGNIZED_DOCUMENT,
codeString: 'UNRECOGNIZED_DOCUMENT',
message: "Document's credentialStatus does not have tokenRegistry",
},
Expand Down Expand Up @@ -358,7 +360,7 @@ describe.concurrent('W3C verify', () => {
expect.objectContaining({
name: 'TransferableRecords',
reason: {
code: 9,
code: W3CCredentialStatusCode.UNRECOGNIZED_DOCUMENT,
codeString: 'UNRECOGNIZED_DOCUMENT',
message: "Document's credentialStatus does not have tokenNetwork.chainId",
},
Expand All @@ -384,7 +386,7 @@ describe.concurrent('W3C verify', () => {
expect.objectContaining({
name: 'TransferableRecords',
reason: {
code: 1,
code: W3CCredentialStatusCode.DOCUMENT_NOT_ISSUED,
codeString: 'DOCUMENT_NOT_MINTED',
message: 'Document has not been issued under token registry',
},
Expand Down
55 changes: 54 additions & 1 deletion src/utils/fragment/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,54 @@
export { errorMessageHandling, interpretFragments } from '@tradetrust-tt/tradetrust-utils';
import {
errorMessageHandling as OAErrorMessageHandling,
CONSTANTS,
interpretFragments,
} from '@tradetrust-tt/tradetrust-utils';
import { InvalidVerificationFragment, utils, VerificationFragment } from '@tradetrust-tt/tt-verify';
import { W3CCredentialStatusCode } from '../../verify/fragments/document-status/w3cCredentialStatus';
import { CredentialStatusResult } from '@trustvc/w3c-vc';

const getW3CCredentialStatusFragment =
utils.getFragmentByName<InvalidVerificationFragment<CredentialStatusResult>>(
'W3CCredentialStatus',
);

const w3cCredentialStatusRevoked = (fragments: VerificationFragment[]): boolean => {
const issuedFragment = getW3CCredentialStatusFragment(fragments);
return (
issuedFragment?.reason?.code === W3CCredentialStatusCode.DOCUMENT_REVOKED ||
issuedFragment?.reason?.code === W3CCredentialStatusCode.DOCUMENT_REVOKED_AND_SUSPENDED
);
};

const w3cCredentialStatusSuspended = (fragments: VerificationFragment[]): boolean => {
const issuedFragment = getW3CCredentialStatusFragment(fragments);
//checking for both revoked and suspended
return (
issuedFragment?.reason?.code === W3CCredentialStatusCode.DOCUMENT_SUSPENDED ||
issuedFragment?.reason?.code === W3CCredentialStatusCode.DOCUMENT_REVOKED_AND_SUSPENDED
);
};

const errorMessageHandling = (fragments: VerificationFragment[]): string[] => {
const errors = [];
const isW3cFragments = fragments.some(
(f) => f.name.startsWith('W3C') || f.name === 'TransferableRecords',
);
if (isW3cFragments) {
if (w3cCredentialStatusRevoked(fragments)) {
errors.push(CONSTANTS.TYPES.REVOKED);
}
if (w3cCredentialStatusSuspended(fragments)) {
errors.push(CONSTANTS.TYPES.SUSPENDED);
}

return errors;
} else return OAErrorMessageHandling(fragments);
};
Comment thread
nghaninn marked this conversation as resolved.

export {
interpretFragments,
errorMessageHandling,
w3cCredentialStatusRevoked,
w3cCredentialStatusSuspended,
};
41 changes: 39 additions & 2 deletions src/verify/fragments/document-status/w3cCredentialStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,28 @@ import {
} from '@trustvc/w3c-credential-status';
import { CredentialStatus, isSignedDocument, verifyCredentialStatus } from '@trustvc/w3c-vc';
import { SignedVerifiableCredential } from '../../..';

//w3cCredentialStatus enums
export enum W3CCredentialStatusCode {
SKIPPED = 0,
DOCUMENT_NOT_ISSUED = 1,
DOCUMENT_REVOKED = 11,
DOCUMENT_SUSPENDED = 12,
DOCUMENT_REVOKED_AND_SUSPENDED = 101,
STATUS_LIST_NOT_FOUND = 404,
INVALID_VALIDATION_METHOD = 8,
UNRECOGNIZED_DOCUMENT = 9,
SERVER_ERROR = 500,
UNEXPECTED_ERROR = 4,
INVALID_ARGUMENT = 6,
INVALID_ISSUERS = 7,
}
export const w3cCredentialStatus: Verifier<VerificationFragment> = {
skip: async () => {
return {
type: 'DOCUMENT_STATUS',
name: 'W3CCredentialStatus',
reason: {
code: 0,
code: W3CCredentialStatusCode.SKIPPED,
codeString: 'SKIPPED',
message: `Document does not have a valid credentialStatus or type.`,
},
Expand Down Expand Up @@ -47,12 +61,18 @@ export const w3cCredentialStatus: Verifier<VerificationFragment> = {
verifyCredentialStatus(cs, cs?.type as CredentialStatusType, verifierOptions),
),
);
const purposes = verificationResult.map((item) => item.purpose);
const hasRevocation = purposes.includes('revocation');
const hasSuspension = purposes.includes('suspension');
const hasRevocationAndSuspension = hasRevocation && hasSuspension;

if (verificationResult.some((r) => r.error)) {
return {
type: 'DOCUMENT_STATUS',
name: 'W3CCredentialStatus',
reason: {
code: W3CCredentialStatusCode.UNEXPECTED_ERROR,
codeString: 'ERROR',
message: verificationResult.map((r) => r.error).join(', '),
},
data: verificationResult,
Expand All @@ -71,6 +91,23 @@ export const w3cCredentialStatus: Verifier<VerificationFragment> = {
name: 'W3CCredentialStatus',
data: verificationResult,
status: 'INVALID',
reason: {
code: hasRevocationAndSuspension
? W3CCredentialStatusCode.DOCUMENT_REVOKED_AND_SUSPENDED
: hasRevocation
? W3CCredentialStatusCode.DOCUMENT_REVOKED
: W3CCredentialStatusCode.DOCUMENT_SUSPENDED,
codeString: hasRevocationAndSuspension
? 'REVOKED_AND_SUSPENDED'
: hasRevocation
? 'REVOKED'
: 'SUSPENDED',
message: hasRevocationAndSuspension
? 'Document has been revoked and suspended.'
: hasRevocation
? 'Document has been revoked.'
: 'Document has been suspended.',
},
};
}
},
Expand Down