diff --git a/package-lock.json b/package-lock.json index 024b4028..ace05c92 100644 --- a/package-lock.json +++ b/package-lock.json @@ -603,9 +603,9 @@ } }, "@govtechsg/open-attestation": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@govtechsg/open-attestation/-/open-attestation-3.7.0.tgz", - "integrity": "sha512-TKtaXmDwX3VF4YWymgv7RRi5gGyVjI/llijL1yb1IQi4BLfCM9CF9UnBoRRPkR7JmvGSIpp6sulHvnXFRc+l0w==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/@govtechsg/open-attestation/-/open-attestation-3.8.1.tgz", + "integrity": "sha512-kJh/HU/9Jhta3Wb0vRaYBajC8GYWwgOFp2WJS9Qu1QzNMik2ujUc0TZf0ibswZGwO1pb4FHo9kPmNu6TIlh/rg==", "requires": { "ajv": "6.10.2", "debug": "^4.1.1", @@ -628,39 +628,6 @@ "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } - }, - "ethers": { - "version": "4.0.47", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.47.tgz", - "integrity": "sha512-hssRYhngV4hiDNeZmVU/k5/E8xmLG8UpcNUzg6mb7lqhgpFPH/t7nuv20RjRrEf0gblzvi2XwR5Te+V3ZFc9pQ==", - "requires": { - "aes-js": "3.0.0", - "bn.js": "^4.4.0", - "elliptic": "6.5.2", - "hash.js": "1.1.3", - "js-sha3": "0.5.7", - "scrypt-js": "2.0.4", - "setimmediate": "1.0.4", - "uuid": "2.0.1", - "xmlhttprequest": "1.8.0" - }, - "dependencies": { - "js-sha3": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" - }, - "uuid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", - "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" - } - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" } } }, @@ -15056,8 +15023,7 @@ "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, "v8-compile-cache": { "version": "2.1.0", diff --git a/package.json b/package.json index ed89f729..f418432e 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "license": "GPL-3.0", "dependencies": { "@govtechsg/dnsprove": "^2.0.5", - "@govtechsg/open-attestation": "3.7.0", + "@govtechsg/open-attestation": "3.8.1", "debug": "^4.1.1", "ethers": "^4.0.47" }, diff --git a/src/verifiers/documentStoreIssued/openAttestationEthereumDocumentStoreIssued.test.ts b/src/verifiers/documentStoreIssued/openAttestationEthereumDocumentStoreIssued.test.ts index c7f8132f..fe735ec6 100644 --- a/src/verifiers/documentStoreIssued/openAttestationEthereumDocumentStoreIssued.test.ts +++ b/src/verifiers/documentStoreIssued/openAttestationEthereumDocumentStoreIssued.test.ts @@ -9,44 +9,15 @@ import { } from "../../../test/fixtures/v3/documentRopstenValid"; import { documentRopstenNotIssued } from "../../../test/fixtures/v3/documentRopstenNotIssued"; import { documentRopstenNotIssuedWithTokenRegistry } from "../../../test/fixtures/v2/documentRopstenNotIssuedWithTokenRegistry"; +import { verificationBuilder } from "../verificationBuilder"; +import { documentRopstenValidWithDocumentStoreAndSignature } from "../../../test/fixtures/v2/documentRopstenValidWithDocumentStoreAndSignature"; + +const verify = verificationBuilder([openAttestationEthereumDocumentStoreIssued]); describe("openAttestationEthereumDocumentStoreIssued", () => { - // TODO create a verifier and call it to test this => check dns verifier test - describe("test", () => { - it("should return true when v2 document has at least one certificate store", () => { - const test = openAttestationEthereumDocumentStoreIssued.test(documentRopstenNotIssuedWithCertificateStore, { - network: "ropsten", - }); - expect(test).toStrictEqual(true); - }); - it("should return true when v2 document has at least one document store", () => { - const test = openAttestationEthereumDocumentStoreIssued.test(documentRopstenNotIssuedWithDocumentStore, { - network: "ropsten", - }); - expect(test).toStrictEqual(true); - }); - it("should return false when v2 document uses token registry", () => { - const test = openAttestationEthereumDocumentStoreIssued.test(documentRopstenNotIssuedWithTokenRegistry, { - network: "ropsten", - }); - expect(test).toStrictEqual(false); - }); - it("should return true when v3 document uses DOCUMENT_STORE method", () => { - const test = openAttestationEthereumDocumentStoreIssued.test(documentRopstenValidWithDocumentStore, { - network: "ropsten", - }); - expect(test).toStrictEqual(true); - }); - it("should return false when v3 document uses TOKEN_REGISTRY method", () => { - const test = openAttestationEthereumDocumentStoreIssued.test(documentRopstenValidWithTokenRegistry, { - network: "ropsten", - }); - expect(test).toStrictEqual(false); - }); - }); describe("v2", () => { it("should return an invalid fragment when document has certificate store that does not exist", async () => { - const fragment = await openAttestationEthereumDocumentStoreIssued.verify( + const fragment = await verify( { ...documentRopstenNotIssuedWithCertificateStore, data: { @@ -64,33 +35,35 @@ describe("openAttestationEthereumDocumentStoreIssued", () => { network: "ropsten", } ); - expect(fragment).toStrictEqual({ - name: "OpenAttestationEthereumDocumentStoreIssued", - type: "DOCUMENT_STATUS", - data: { - details: [ - { - address: "0x0000000000000000000000000000000000000000", - issued: false, - reason: { - code: 404, - codeString: "CONTRACT_NOT_FOUND", - message: "Contract 0x0000000000000000000000000000000000000000 was not found", + expect(fragment).toStrictEqual([ + { + name: "OpenAttestationEthereumDocumentStoreIssued", + type: "DOCUMENT_STATUS", + data: { + details: [ + { + address: "0x0000000000000000000000000000000000000000", + issued: false, + reason: { + code: 404, + codeString: "CONTRACT_NOT_FOUND", + message: "Contract 0x0000000000000000000000000000000000000000 was not found", + }, }, - }, - ], - issuedOnAll: false, - }, - reason: { - code: 404, - codeString: "CONTRACT_NOT_FOUND", - message: "Contract 0x0000000000000000000000000000000000000000 was not found", + ], + issuedOnAll: false, + }, + reason: { + code: 404, + codeString: "CONTRACT_NOT_FOUND", + message: "Contract 0x0000000000000000000000000000000000000000 was not found", + }, + status: "INVALID", }, - status: "INVALID", - }); + ]); }); it("should return an invalid fragment when document has invalid certificate store", async () => { - const fragment = await openAttestationEthereumDocumentStoreIssued.verify( + const fragment = await verify( { ...documentRopstenNotIssuedWithCertificateStore, data: { @@ -107,33 +80,35 @@ describe("openAttestationEthereumDocumentStoreIssued", () => { network: "ropsten", } ); - expect(fragment).toStrictEqual({ - name: "OpenAttestationEthereumDocumentStoreIssued", - type: "DOCUMENT_STATUS", - data: { - details: [ - { - address: "0xabcd", - issued: false, - reason: { - code: 2, - codeString: "CONTRACT_ADDRESS_INVALID", - message: "Contract address 0xabcd is invalid", + expect(fragment).toStrictEqual([ + { + name: "OpenAttestationEthereumDocumentStoreIssued", + type: "DOCUMENT_STATUS", + data: { + details: [ + { + address: "0xabcd", + issued: false, + reason: { + code: 2, + codeString: "CONTRACT_ADDRESS_INVALID", + message: "Contract address 0xabcd is invalid", + }, }, - }, - ], - issuedOnAll: false, - }, - reason: { - code: 2, - codeString: "CONTRACT_ADDRESS_INVALID", - message: "Contract address 0xabcd is invalid", + ], + issuedOnAll: false, + }, + reason: { + code: 2, + codeString: "CONTRACT_ADDRESS_INVALID", + message: "Contract address 0xabcd is invalid", + }, + status: "INVALID", }, - status: "INVALID", - }); + ]); }); it("should return an invalid fragment when document has invalid ens name certificate store", async () => { - const fragment = await openAttestationEthereumDocumentStoreIssued.verify( + const fragment = await verify( { ...documentRopstenNotIssuedWithCertificateStore, data: { @@ -150,33 +125,35 @@ describe("openAttestationEthereumDocumentStoreIssued", () => { network: "ropsten", } ); - expect(fragment).toStrictEqual({ - name: "OpenAttestationEthereumDocumentStoreIssued", - type: "DOCUMENT_STATUS", - data: { - details: [ - { - address: "0xomgthisisnotgood", - issued: false, - reason: { - code: 2, - codeString: "CONTRACT_ADDRESS_INVALID", - message: "Contract address 0xomgthisisnotgood is invalid", + expect(fragment).toStrictEqual([ + { + name: "OpenAttestationEthereumDocumentStoreIssued", + type: "DOCUMENT_STATUS", + data: { + details: [ + { + address: "0xomgthisisnotgood", + issued: false, + reason: { + code: 2, + codeString: "CONTRACT_ADDRESS_INVALID", + message: "Contract address 0xomgthisisnotgood is invalid", + }, }, - }, - ], - issuedOnAll: false, - }, - reason: { - code: 2, - codeString: "CONTRACT_ADDRESS_INVALID", - message: "Contract address 0xomgthisisnotgood is invalid", + ], + issuedOnAll: false, + }, + reason: { + code: 2, + codeString: "CONTRACT_ADDRESS_INVALID", + message: "Contract address 0xomgthisisnotgood is invalid", + }, + status: "INVALID", }, - status: "INVALID", - }); + ]); }); it("should return an invalid fragment when document has invalid certificate store with bad checksum", async () => { - const fragment = await openAttestationEthereumDocumentStoreIssued.verify( + const fragment = await verify( { ...documentRopstenNotIssuedWithCertificateStore, data: { @@ -194,98 +171,98 @@ describe("openAttestationEthereumDocumentStoreIssued", () => { network: "ropsten", } ); - expect(fragment).toStrictEqual({ - name: "OpenAttestationEthereumDocumentStoreIssued", - type: "DOCUMENT_STATUS", - data: { - details: [ - { - address: "0x8Fc57204c35fb9317D91285eF52D6b892EC08cd3", - issued: false, - reason: { - code: 2, - codeString: "CONTRACT_ADDRESS_INVALID", - message: "Contract address 0x8Fc57204c35fb9317D91285eF52D6b892EC08cd3 is invalid", + expect(fragment).toStrictEqual([ + { + name: "OpenAttestationEthereumDocumentStoreIssued", + type: "DOCUMENT_STATUS", + data: { + details: [ + { + address: "0x8Fc57204c35fb9317D91285eF52D6b892EC08cd3", + issued: false, + reason: { + code: 2, + codeString: "CONTRACT_ADDRESS_INVALID", + message: "Contract address 0x8Fc57204c35fb9317D91285eF52D6b892EC08cd3 is invalid", + }, }, - }, - ], - issuedOnAll: false, - }, - reason: { - code: 2, - codeString: "CONTRACT_ADDRESS_INVALID", - message: "Contract address 0x8Fc57204c35fb9317D91285eF52D6b892EC08cd3 is invalid", + ], + issuedOnAll: false, + }, + reason: { + code: 2, + codeString: "CONTRACT_ADDRESS_INVALID", + message: "Contract address 0x8Fc57204c35fb9317D91285eF52D6b892EC08cd3 is invalid", + }, + status: "INVALID", }, - status: "INVALID", - }); + ]); }); it("should return an invalid fragment when document with certificate store has not been issued", async () => { - const fragment = await openAttestationEthereumDocumentStoreIssued.verify( - documentRopstenNotIssuedWithCertificateStore, + const fragment = await verify(documentRopstenNotIssuedWithCertificateStore, { + network: "ropsten", + }); + expect(fragment).toStrictEqual([ { - network: "ropsten", - } - ); - expect(fragment).toStrictEqual({ - name: "OpenAttestationEthereumDocumentStoreIssued", - type: "DOCUMENT_STATUS", - data: { - details: [ - { - address: "0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", - issued: false, - reason: { - code: 1, - codeString: "DOCUMENT_NOT_ISSUED", - message: - "Certificate 0x2e97b28b1cb7ca50179af42f1f5581591251a2d93dd6dac75fafc8a69077f4ed has not been issued under contract 0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + name: "OpenAttestationEthereumDocumentStoreIssued", + type: "DOCUMENT_STATUS", + data: { + details: [ + { + address: "0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + issued: false, + reason: { + code: 1, + codeString: "DOCUMENT_NOT_ISSUED", + message: + "Certificate 0x2e97b28b1cb7ca50179af42f1f5581591251a2d93dd6dac75fafc8a69077f4ed has not been issued under contract 0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + }, }, - }, - ], - issuedOnAll: false, - }, - reason: { - code: 1, - codeString: "DOCUMENT_NOT_ISSUED", - message: - "Certificate 0x2e97b28b1cb7ca50179af42f1f5581591251a2d93dd6dac75fafc8a69077f4ed has not been issued under contract 0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + ], + issuedOnAll: false, + }, + reason: { + code: 1, + codeString: "DOCUMENT_NOT_ISSUED", + message: + "Certificate 0x2e97b28b1cb7ca50179af42f1f5581591251a2d93dd6dac75fafc8a69077f4ed has not been issued under contract 0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + }, + status: "INVALID", }, - status: "INVALID", - }); + ]); }); it("should return an invalid fragment when document with document store has not been issued", async () => { - const fragment = await openAttestationEthereumDocumentStoreIssued.verify( - documentRopstenNotIssuedWithDocumentStore, + const fragment = await verify(documentRopstenNotIssuedWithDocumentStore, { + network: "ropsten", + }); + expect(fragment).toStrictEqual([ { - network: "ropsten", - } - ); - expect(fragment).toStrictEqual({ - name: "OpenAttestationEthereumDocumentStoreIssued", - type: "DOCUMENT_STATUS", - data: { - details: [ - { - address: "0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", - issued: false, - reason: { - code: 1, - codeString: "DOCUMENT_NOT_ISSUED", - message: - "Certificate 0xda7a25d51e62bc50e1c7cfa17f7be0e5df3428b96f584e5d021f0cd8da97306d has not been issued under contract 0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + name: "OpenAttestationEthereumDocumentStoreIssued", + type: "DOCUMENT_STATUS", + data: { + details: [ + { + address: "0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + issued: false, + reason: { + code: 1, + codeString: "DOCUMENT_NOT_ISSUED", + message: + "Certificate 0xda7a25d51e62bc50e1c7cfa17f7be0e5df3428b96f584e5d021f0cd8da97306d has not been issued under contract 0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + }, }, - }, - ], - issuedOnAll: false, - }, - reason: { - code: 1, - codeString: "DOCUMENT_NOT_ISSUED", - message: - "Certificate 0xda7a25d51e62bc50e1c7cfa17f7be0e5df3428b96f584e5d021f0cd8da97306d has not been issued under contract 0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + ], + issuedOnAll: false, + }, + reason: { + code: 1, + codeString: "DOCUMENT_NOT_ISSUED", + message: + "Certificate 0xda7a25d51e62bc50e1c7cfa17f7be0e5df3428b96f584e5d021f0cd8da97306d has not been issued under contract 0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + }, + status: "INVALID", }, - status: "INVALID", - }); + ]); }); it("should return a valid fragment when document with certificate store has been issued", async () => { const fragment = await openAttestationEthereumDocumentStoreIssued.verify( @@ -375,10 +352,45 @@ describe("openAttestationEthereumDocumentStoreIssued", () => { status: "INVALID", }); }); + it("should return a skipped fragment when document uses token registry", async () => { + const test = await verify(documentRopstenNotIssuedWithTokenRegistry, { + network: "ropsten", + }); + expect(test).toStrictEqual([ + { + name: "OpenAttestationEthereumDocumentStoreIssued", + reason: { + code: 4, + codeString: "SKIPPED", + message: + 'Document issuers doesn\'t have "documentStore" or "certificateStore" property or DOCUMENT_STORE method', + }, + status: "SKIPPED", + type: "DOCUMENT_STATUS", + }, + ]); + }); + it("should return a skipped fragment when document uses document store but is self signed", async () => { + const test = await verify(documentRopstenValidWithDocumentStoreAndSignature, { + network: "ropsten", + }); + expect(test).toStrictEqual([ + { + name: "OpenAttestationEthereumDocumentStoreIssued", + reason: { + code: 4, + codeString: "SKIPPED", + message: "Document uses signed proof", + }, + status: "SKIPPED", + type: "DOCUMENT_STATUS", + }, + ]); + }); }); describe("v3", () => { it("should return an invalid fragment when document has document store that does not exist", async () => { - const fragment = await openAttestationEthereumDocumentStoreIssued.verify( + const fragment = await verify( { ...documentRopstenNotIssued, data: { @@ -393,74 +405,98 @@ describe("openAttestationEthereumDocumentStoreIssued", () => { network: "ropsten", } ); - expect(fragment).toStrictEqual({ - name: "OpenAttestationEthereumDocumentStoreIssued", - type: "DOCUMENT_STATUS", - data: { - details: { - address: "0x0000000000000000000000000000000000000000", - issued: false, - reason: { - code: 404, - codeString: "CONTRACT_NOT_FOUND", - message: "Contract 0x0000000000000000000000000000000000000000 was not found", + expect(fragment).toStrictEqual([ + { + name: "OpenAttestationEthereumDocumentStoreIssued", + type: "DOCUMENT_STATUS", + data: { + details: { + address: "0x0000000000000000000000000000000000000000", + issued: false, + reason: { + code: 404, + codeString: "CONTRACT_NOT_FOUND", + message: "Contract 0x0000000000000000000000000000000000000000 was not found", + }, }, + issuedOnAll: false, }, - issuedOnAll: false, - }, - reason: { - code: 404, - codeString: "CONTRACT_NOT_FOUND", - message: "Contract 0x0000000000000000000000000000000000000000 was not found", + reason: { + code: 404, + codeString: "CONTRACT_NOT_FOUND", + message: "Contract 0x0000000000000000000000000000000000000000 was not found", + }, + status: "INVALID", }, - status: "INVALID", - }); + ]); }); it("should return an invalid fragment when document with document store has not been issued", async () => { - const fragment = await openAttestationEthereumDocumentStoreIssued.verify(documentRopstenNotIssued, { + const fragment = await verify(documentRopstenNotIssued, { network: "ropsten", }); - expect(fragment).toStrictEqual({ - name: "OpenAttestationEthereumDocumentStoreIssued", - type: "DOCUMENT_STATUS", - data: { - details: { - address: "0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", - issued: false, - reason: { - code: 1, - codeString: "DOCUMENT_NOT_ISSUED", - message: - "Certificate 0x76cb959f49db0cffc05107af4a3ecef14092fd445d9acb0c2e7e27908d262142 has not been issued under contract 0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + expect(fragment).toStrictEqual([ + { + name: "OpenAttestationEthereumDocumentStoreIssued", + type: "DOCUMENT_STATUS", + data: { + details: { + address: "0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + issued: false, + reason: { + code: 1, + codeString: "DOCUMENT_NOT_ISSUED", + message: + "Certificate 0x76cb959f49db0cffc05107af4a3ecef14092fd445d9acb0c2e7e27908d262142 has not been issued under contract 0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + }, }, + issuedOnAll: false, }, - issuedOnAll: false, - }, - reason: { - code: 1, - codeString: "DOCUMENT_NOT_ISSUED", - message: - "Certificate 0x76cb959f49db0cffc05107af4a3ecef14092fd445d9acb0c2e7e27908d262142 has not been issued under contract 0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + reason: { + code: 1, + codeString: "DOCUMENT_NOT_ISSUED", + message: + "Certificate 0x76cb959f49db0cffc05107af4a3ecef14092fd445d9acb0c2e7e27908d262142 has not been issued under contract 0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + }, + status: "INVALID", }, - status: "INVALID", - }); + ]); }); it("should return a valid fragment when document with document store has been issued", async () => { - const fragment = await openAttestationEthereumDocumentStoreIssued.verify(documentRopstenValidWithDocumentStore, { + const fragment = await verify(documentRopstenValidWithDocumentStore, { network: "ropsten", }); - expect(fragment).toStrictEqual({ - name: "OpenAttestationEthereumDocumentStoreIssued", - type: "DOCUMENT_STATUS", - data: { - details: { - address: "0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", - issued: true, + expect(fragment).toStrictEqual([ + { + name: "OpenAttestationEthereumDocumentStoreIssued", + type: "DOCUMENT_STATUS", + data: { + details: { + address: "0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + issued: true, + }, + issuedOnAll: true, }, - issuedOnAll: true, + status: "VALID", }, - status: "VALID", + ]); + }); + it("should return a skipped fragment when document uses token registry", async () => { + const test = await verify(documentRopstenValidWithTokenRegistry, { + network: "ropsten", }); + expect(test).toStrictEqual([ + { + name: "OpenAttestationEthereumDocumentStoreIssued", + reason: { + code: 4, + codeString: "SKIPPED", + message: + 'Document issuers doesn\'t have "documentStore" or "certificateStore" property or DOCUMENT_STORE method', + }, + status: "SKIPPED", + type: "DOCUMENT_STATUS", + }, + ]); }); }); }); diff --git a/src/verifiers/documentStoreIssued/openAttestationEthereumDocumentStoreIssued.ts b/src/verifiers/documentStoreIssued/openAttestationEthereumDocumentStoreIssued.ts index c0b766a0..a620ee43 100644 --- a/src/verifiers/documentStoreIssued/openAttestationEthereumDocumentStoreIssued.ts +++ b/src/verifiers/documentStoreIssued/openAttestationEthereumDocumentStoreIssued.ts @@ -1,4 +1,4 @@ -import { utils, getData, v2, v3, WrappedDocument } from "@govtechsg/open-attestation"; +import { utils, getData, v2, v3, WrappedDocument, SignedWrappedDocument } from "@govtechsg/open-attestation"; import { VerificationFragmentType, Verifier } from "../../types/core"; import { OpenAttestationEthereumDocumentStoreIssuedCode } from "../../types/error"; import { @@ -16,9 +16,11 @@ interface Status { const name = "OpenAttestationEthereumDocumentStoreIssued"; const type: VerificationFragmentType = "DOCUMENT_STATUS"; export const openAttestationEthereumDocumentStoreIssued: Verifier< - WrappedDocument | WrappedDocument + | WrappedDocument + | WrappedDocument + | SignedWrappedDocument > = { - skip: () => { + skip: (document) => { return Promise.resolve({ status: "SKIPPED", type, @@ -27,11 +29,16 @@ export const openAttestationEthereumDocumentStoreIssued: Verifier< code: OpenAttestationEthereumDocumentStoreIssuedCode.SKIPPED, codeString: OpenAttestationEthereumDocumentStoreIssuedCode[OpenAttestationEthereumDocumentStoreIssuedCode.SKIPPED], - message: `Document issuers doesn't have "documentStore" or "certificateStore" property or ${v3.Method.DocumentStore} method`, + message: utils.isSignedWrappedV2Document(document) + ? "Document uses signed proof" + : `Document issuers doesn't have "documentStore" or "certificateStore" property or ${v3.Method.DocumentStore} method`, }, }); }, test: (document) => { + if (utils.isSignedWrappedV2Document(document)) { + return false; + } if (utils.isWrappedV3Document(document)) { const documentData = getData(document); return documentData.proof.method === v3.Method.DocumentStore; diff --git a/src/verify.v2.integration.test.ts b/src/verify.v2.integration.test.ts index a788325a..f46c9ba0 100644 --- a/src/verify.v2.integration.test.ts +++ b/src/verify.v2.integration.test.ts @@ -381,7 +381,7 @@ describe("verify(integration)", () => { reason: { code: 4, codeString: "SKIPPED", - message: `Document issuers doesn't have "documentStore" or "certificateStore" property or DOCUMENT_STORE method`, + message: `Document uses signed proof`, }, }, { @@ -448,7 +448,7 @@ describe("verify(integration)", () => { reason: { code: 4, codeString: "SKIPPED", - message: `Document issuers doesn't have "documentStore" or "certificateStore" property or DOCUMENT_STORE method`, + message: `Document uses signed proof`, }, }, { diff --git a/test/fixtures/v2/documentRopstenValidWithDocumentStoreAndSignature.ts b/test/fixtures/v2/documentRopstenValidWithDocumentStoreAndSignature.ts new file mode 100644 index 00000000..94b4ae5e --- /dev/null +++ b/test/fixtures/v2/documentRopstenValidWithDocumentStoreAndSignature.ts @@ -0,0 +1,77 @@ +import { ProofPurpose, ProofType, SchemaId, SignedWrappedDocument, v2 } from "@govtechsg/open-attestation"; + +interface CustomDocument extends v2.OpenAttestationDocument { + recipient: { + name: string; + address: { + street: string; + country: string; + }; + }; + consignment: any; + declaration: any; +} +export const documentRopstenValidWithDocumentStoreAndSignature: SignedWrappedDocument = { + version: SchemaId.v2, + schema: "tradetrust/1.0", + data: { + id: "7c89df24-c28d-4807-a1cd-abbc917f14ec:string:SGCNM21566325", + $template: { + name: "cde68ddb-5d1b-444c-a40d-708575706884:string:CERTIFICATE_OF_NON_MANIPULATION", + type: "16586a2a-fbb4-4afb-a7c5-3dac13b8663e:string:EMBEDDED_RENDERER", + url: "d1d00871-c7bb-4d8f-b3ad-2f51fac760f7:string:https://demo-cnm.openattestation.com", + }, + issuers: [ + { + name: "9f2c0997-4913-46e9-8b35-3b4b48ad0d93:string:DEMO STORE", + documentStore: "93aef98e-b830-4c45-89f8-d38fc66a68fb:string:0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3", + identityProof: { + type: "e73b9b80-2ce0-49c6-bec4-7d814e4c58f8:string:DNS-TXT", + location: "9b7231eb-e707-4417-b2a0-9ecbc88f312a:string:example.tradetrust.io", + }, + }, + ], + recipient: { + name: "881f0e3b-eb60-462d-9032-d1f05b3d376a:string:SG FREIGHT", + address: { + street: "300747db-f71e-4bdc-a973-63a739335830:string:101 ORCHARD ROAD", + country: "44ca8729-c8f9-4c56-a7ba-d0995b8e19dc:string:SINGAPORE", + }, + }, + consignment: { + description: "758d090e-9933-4ba9-bbc2-8c131a18a81d:string:16667 CARTONS OF RED WINE", + quantity: { + value: "8fd8f4ba-bec7-4a73-ae6a-14e78fa0c716:number:5000", + unit: "ef64db97-2f27-43fa-8ecd-346dc163e678:string:LITRES", + }, + countryOfOrigin: "551e50e9-f1ec-4da0-ac05-7d75a76661d5:string:AUSTRALIA", + outwardBillNo: "8748ef72-9c6a-4c57-b059-d5e87c3fa4b0:string:AQSIQ170923130", + dateOfDischarge: "2a0bbd3d-6fa2-4b77-87f3-91febc8ceba6:string:2018-01-26", + dateOfDeparture: "c1d657a3-960d-4f79-9483-44e8929892f7:string:2018-01-30", + countryOfFinalDestination: "8dcdff63-d762-41f4-82a0-6167761c21a0:string:CHINA", + outgoingVehicleNo: "c2542c68-1e5f-4ef2-8dfd-a0a7f68b0a1e:string:COSCO JAPAN 074E/30-JAN", + }, + declaration: { + name: "878d8a71-0398-4f99-8866-b92818112eb0:string:PETER LEE", + designation: "1787737a-944e-4a62-8f7e-ad2313403b6e:string:SHIPPING MANAGER", + date: "07ab2cc7-664b-4c15-930b-aff8ae1e06a9:string:2018-01-28", + }, + }, + privacy: { + obfuscatedData: [], + }, + signature: { + type: "SHA3MerkleProof", + targetHash: "f079c4321fe7c1990c338167a9776299d523e5097309af340f66412d17e8da28", + proof: [], + merkleRoot: "f079c4321fe7c1990c338167a9776299d523e5097309af340f66412d17e8da28", + }, + proof: { + type: ProofType.EcdsaSecp256k1Signature2019, + created: "2020-06-03T07:12:05.258Z", + proofPurpose: ProofPurpose.AssertionMethod, + verificationMethod: "0x14791697260E4c9A71f18484C9f997B308e59325", + signature: + "0xfede189af7e851fc84e8704ff1e20267997672ae54040ddcb8a53295b46b623c3ffe0980d46d95a783786896e2e28a05fb0a07e1a2b609a5edf1cb9b05d380741b", + }, +};