From c92b1209f252d24ecb48d52e5265064a71c50e93 Mon Sep 17 00:00:00 2001 From: Phan Shi Yu Date: Sat, 27 Apr 2024 10:12:36 +0800 Subject: [PATCH] test: add wrap unit tests --- src/4.0/__tests__/digest.test.ts | 2 +- src/4.0/__tests__/guard.test.ts | 2 +- src/4.0/__tests__/wrap.test.ts | 107 +++++++++++++++++++++++++++++++ src/4.0/wrap.ts | 2 +- 4 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 src/4.0/__tests__/wrap.test.ts diff --git a/src/4.0/__tests__/digest.test.ts b/src/4.0/__tests__/digest.test.ts index 7cc74fc2..7e41cd70 100644 --- a/src/4.0/__tests__/digest.test.ts +++ b/src/4.0/__tests__/digest.test.ts @@ -9,7 +9,7 @@ const credentialRoot = "f49be3b06f7a7eb074775ad12aae43936084c86646e3640eae18e7ae const { proof, ...credential } = SIGNED_WRAPPED_DOCUMENT_DID; -describe("digest v4.0", () => { +describe("V4.0 digest", () => { describe("digestCredential", () => { test("digests a document with all visible content correctly", () => { const clonedCredential = cloneDeep(credential); diff --git a/src/4.0/__tests__/guard.test.ts b/src/4.0/__tests__/guard.test.ts index 39e59b4e..5ffc4132 100644 --- a/src/4.0/__tests__/guard.test.ts +++ b/src/4.0/__tests__/guard.test.ts @@ -1,7 +1,7 @@ import { W3cVerifiableCredential, V4Document, V4WrappedDocument, V4SignedWrappedDocument } from "../types"; import { RAW_DOCUMENT_DID, SIGNED_WRAPPED_DOCUMENT_DID, WRAPPED_DOCUMENT_DID } from "../fixtures"; -describe("v4 guard", () => { +describe("V4.0 guard", () => { describe("given a raw document", () => { test("should pass w3c vc validation without removal of any data", () => { const w3cVerifiableCredential: W3cVerifiableCredential = RAW_DOCUMENT_DID; diff --git a/src/4.0/__tests__/wrap.test.ts b/src/4.0/__tests__/wrap.test.ts new file mode 100644 index 00000000..21b89f6e --- /dev/null +++ b/src/4.0/__tests__/wrap.test.ts @@ -0,0 +1,107 @@ +import { V4Document, V4WrappedDocument, W3cVerifiableCredential } from "../types"; +import { wrapDocument } from "../wrap"; + +describe("V4.0 wrap document", () => { + test("given a valid v4 document, should wrap correctly", async () => { + const wrapped = await wrapDocument({ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://schemata.openattestation.com/com/openattestation/4.0/alpha-context.json", + ], + type: ["VerifiableCredential", "OpenAttestationCredential"], + credentialSubject: { + id: "0x1234567890123456789012345678901234567890", + name: "John Doe", + country: "SG", + }, + issuer: { + id: "did:ethr:0xB26B4941941C51a4885E5B7D3A1B861E54405f90", + type: "OpenAttestationIssuer", + name: "Government Technology Agency of Singapore (GovTech)", + identityProof: { identityProofType: "DNS-DID", identifier: "example.openattestation.com" }, + }, + }); + const parsedResults = V4WrappedDocument.safeParse(wrapped); + if (!parsedResults.success) { + throw new Error("Parsing failed"); + } + const { proof } = parsedResults.data; + expect(proof.merkleRoot.length).toBe(64); + expect(proof.privacy.obfuscated).toEqual([]); + expect(proof.proofPurpose).toBe("assertionMethod"); + expect(proof.proofs).toEqual([]); + expect(proof.salts.length).toBeGreaterThan(0); + expect(proof.targetHash.length).toBe(64); + expect(proof.type).toBe("OpenAttestationMerkleProofSignature2018"); + }); + + test("given a document with explicit v4 contexts, but does not conform to the V4 document schema, should throw", async () => { + await expect( + wrapDocument({ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://schemata.openattestation.com/com/openattestation/4.0/alpha-context.json", + ], + type: ["VerifiableCredential", "OpenAttestationCredential"], + credentialSubject: { + id: "0x1234567890123456789012345678901234567890", + name: "John Doe", + country: "SG", + }, + issuer: { + id: "did:ethr:0xB26B4941941C51a4885E5B7D3A1B861E54405f90", + name: "Government Technology Agency of Singapore (GovTech)", + identityProof: { identityProofType: "DNS-DID", identifier: "example.openattestation.com" }, + } as V4Document["issuer"], + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Input document does not conform to OpenAttestation v4.0 Data Model: [{"code":"invalid_literal","expected":"OpenAttestationIssuer","path":["issuer","type"],"message":"Invalid literal value, expected \\"OpenAttestationIssuer\\""}]"` + ); + }); + + test("given a valid v4 document but has an extra field, should throw", async () => { + await expect( + wrapDocument({ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://schemata.openattestation.com/com/openattestation/4.0/alpha-context.json", + ], + type: ["VerifiableCredential", "OpenAttestationCredential"], + credentialSubject: { + id: "0x1234567890123456789012345678901234567890", + name: "John Doe", + country: "SG", + }, + issuer: { + id: "did:ethr:0xB26B4941941C51a4885E5B7D3A1B861E54405f90", + type: "OpenAttestationIssuer", + name: "Government Technology Agency of Singapore (GovTech)", + extraField: "extra", + identityProof: { identityProofType: "DNS-DID", identifier: "example.openattestation.com" }, + }, + // this should not exist + extraField: "extra", + } as V4Document) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Input document does not conform to OpenAttestation v4.0 Data Model: [{"code":"unrecognized_keys","keys":["extraField"],"path":[],"message":"Unrecognized key(s) in object: 'extraField'"}]"` + ); + }); + + test("given a generic w3c vc, should wrap with context and type corrected", async () => { + const genericW3cVc: W3cVerifiableCredential = { + "@context": ["https://www.w3.org/ns/credentials/v2"], + type: ["VerifiableCredential"], + credentialSubject: { + id: "0x1234567890123456789012345678901234567890", + name: "John Doe", + country: "SG", + }, + issuer: { + id: "https://example.com/issuer/123", + }, + }; + const wrapped = await wrapDocument(genericW3cVc as unknown as V4Document); + const parsedResults = V4WrappedDocument.pick({ "@context": true, type: true }).passthrough().safeParse(wrapped); + expect(parsedResults.success).toBe(true); + }); +}); diff --git a/src/4.0/wrap.ts b/src/4.0/wrap.ts index a310ee49..a3001480 100644 --- a/src/4.0/wrap.ts +++ b/src/4.0/wrap.ts @@ -11,7 +11,7 @@ export const wrapDocument = async ( document: NoExtraProperties ): Promise> => { /* 1a. try OpenAttestation VC validation, since most user will be issuing oa v4*/ - const oav4context = await V4Document.pick({ "@context": true }).safeParseAsync(document); // Superficial check on user intention + const oav4context = await V4Document.pick({ "@context": true }).passthrough().safeParseAsync(document); // Superficial check on user intention let validatedRawDocument: W3cVerifiableCredential | undefined; if (oav4context.success) { const oav4 = await V4Document.safeParseAsync(document);