{"_id":"@dgcgovkh/digitalstamp-oaverify","_rev":"1-7b21e562596c8217926b839d82ca8c67","name":"@dgcgovkh/digitalstamp-oaverify","dist-tags":{"latest":"0.0.2"},"versions":{"0.0.1":{"name":"@dgcgovkh/digitalstamp-oaverify","version":"0.0.1","author":"","license":"Apache-2.0","_id":"@dgcgovkh/digitalstamp-oaverify@0.0.1","maintainers":[{"name":"krisnadev","email":"trykrisnapcu@gmail.com"},{"name":"seanghay","email":"seanghay.dev@gmail.com"}],"dist":{"shasum":"2e8896c33170f177ee48f8bd85f0bebdccbfbe25","tarball":"https://registry.npmjs.org/@dgcgovkh/digitalstamp-oaverify/-/digitalstamp-oaverify-0.0.1.tgz","fileCount":47,"integrity":"sha512-hPqryMs3BYMvVPM9598jilg52jr5kOoZfZ0Nh3EUo+r9sFPt0o2bq+AyV4UcVxlE8bluzD4LXX/sM4NonknNBA==","signatures":[{"sig":"MEUCIQDo9A9OT8O8JD2Vz9DSD/GfPll1aA0lGuCyi8aph4XjkwIgHYL9MRudMgedykgOSbdG4LfK+WQqvBU08FaPXXml8OI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":5358620},"main":"dist/index.js","snyk":true,"types":"dist/types/index.d.ts","unpkg":"dist/index.umd.js","config":{"commitizen":{"path":"node_modules/@commitlint/prompt"}},"module":"dist/index.module.js","exports":{"types":"./dist/types/index.d.ts","import":"./dist/index.modern.mjs","default":"./dist/index.modern.mjs","require":"./dist/index.js"},"gitHead":"5b2579e2541b2575a5de9b9877cdfc13c23ed651","scripts":{"lint":"eslint . --ext .ts --max-warnings 0","test":"NODE_OPTIONS=--max-old-space-size=2048 jest","build":"npm run clean && microbundle --tsconfig tsconfig.prod.json","clean":"rm -rf dist/","commit":"git-cz","prepare":"npm run snyk-protect","test:ci":"jest --runInBand","lint:fix":"npm run lint -- --fix","test:watch":"jest --watch","generate:v3":"DEBUG=oa-verify* ts-node scripts/generate.v3.ts","commit:retry":"npm run commit -- --retry","snyk-protect":"snyk-protect"},"_npmUser":{"name":"krisnadev","email":"trykrisnapcu@gmail.com"},"prettier":{"printWidth":120},"repository":{"url":"","type":"git"},"_npmVersion":"10.5.0","description":"Using the [OpenAttestation (Verify)](https://github.com/Open-Attestation/oa-verify) repository as the codebase for the `npm` module, you can verify [wrapped documents](https://www.openattestation.com/docs/lib-section/remote-files/open-attestation#wrapping","directories":{},"_nodeVersion":"20.12.1","dependencies":{"axios":"^1.6.2","debug":"^4.3.1","ethers":"^5.7.2","runtypes":"^6.3.0","node-cache":"^5.1.2","did-resolver":"^4.1.0","web-did-resolver":"^2.0.27","ethr-did-resolver":"^8.1.2","@govtechsg/open-attestation":"^6.9.0","@dgcgovkh/digitalstamp-dnsprove":"^0.0.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"msw":"^0.28.2","jest":"^26.6.3","husky":"^8.0.3","eslint":"^7.25.0","git-cz":"^4.9.0","ts-jest":"^26.5.5","prettier":"^2.2.1","commitizen":"^4.3.0","typescript":"^4.9.5","@types/jest":"^26.0.23","ajv-formats":"^2.1.1","microbundle":"^0.15.1","@types/debug":"^4.1.5","@snyk/protect":"^1.1257.0","@commitlint/cli":"^18.4.3","semantic-release":"^22.0.8","@commitlint/prompt":"^18.4.3","eslint-plugin-jest":"^24.3.6","eslint-plugin-import":"^2.22.1","jest-watch-typeahead":"^0.6.3","eslint-config-prettier":"^8.3.0","eslint-plugin-prettier":"^3.4.0","@typescript-eslint/parser":"^4.22.0","@commitlint/config-conventional":"^18.4.3","@typescript-eslint/eslint-plugin":"^4.22.0","@govtechsg/document-store-ethers-v5":"^4.1.0"},"_npmOperationalInternal":{"tmp":"tmp/digitalstamp-oaverify_0.0.1_1724319216171_0.35117409891261797","host":"s3://npm-registry-packages"}},"0.0.2":{"name":"@dgcgovkh/digitalstamp-oaverify","version":"0.0.2","description":"Using the [OpenAttestation (Verify)](https://github.com/Open-Attestation/oa-verify) repository as the codebase for the `npm` module, you can verify [wrapped documents](https://www.openattestation.com/docs/lib-section/remote-files/open-attestation#wrapping","main":"dist/index.js","unpkg":"dist/index.umd.js","module":"dist/index.module.js","types":"dist/types/index.d.ts","exports":{"require":"./dist/index.js","import":"./dist/index.modern.mjs","default":"./dist/index.modern.mjs","types":"./dist/types/index.d.ts"},"scripts":{"build":"npm run clean && microbundle --tsconfig tsconfig.prod.json","clean":"rm -rf dist/","commit":"git-cz","commit:retry":"npm run commit -- --retry","test:ci":"jest --runInBand","test":"NODE_OPTIONS=--max-old-space-size=2048 jest","test:watch":"jest --watch","lint":"eslint . --ext .ts --max-warnings 0","lint:fix":"npm run lint -- --fix","snyk-protect":"snyk-protect","prepare":"npm run snyk-protect","generate:v3":"DEBUG=oa-verify* ts-node scripts/generate.v3.ts"},"author":"","license":"Apache-2.0","dependencies":{"@dgcgovkh/digitalstamp-dnsprove":"^0.0.2","@govtechsg/open-attestation":"^6.9.0","axios":"^1.6.2","debug":"^4.3.1","did-resolver":"^4.1.0","ethers":"^5.7.2","ethr-did-resolver":"^8.1.2","node-cache":"^5.1.2","runtypes":"^6.3.0","web-did-resolver":"^2.0.27"},"devDependencies":{"@commitlint/cli":"^18.4.3","@commitlint/config-conventional":"^18.4.3","@commitlint/prompt":"^18.4.3","@govtechsg/document-store-ethers-v5":"^4.1.0","@snyk/protect":"^1.1257.0","@types/debug":"^4.1.5","@types/jest":"^26.0.23","@typescript-eslint/eslint-plugin":"^4.22.0","@typescript-eslint/parser":"^4.22.0","ajv-formats":"^2.1.1","commitizen":"^4.3.0","eslint":"^7.25.0","eslint-config-prettier":"^8.3.0","eslint-plugin-import":"^2.22.1","eslint-plugin-jest":"^24.3.6","eslint-plugin-prettier":"^3.4.0","git-cz":"^4.9.0","husky":"^8.0.3","jest":"^26.6.3","jest-watch-typeahead":"^0.6.3","microbundle":"^0.15.1","msw":"^0.28.2","prettier":"^2.2.1","semantic-release":"^22.0.8","ts-jest":"^26.5.5","typescript":"^4.9.5"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":""},"config":{"commitizen":{"path":"node_modules/@commitlint/prompt"}},"prettier":{"printWidth":120},"snyk":true,"_id":"@dgcgovkh/digitalstamp-oaverify@0.0.2","gitHead":"5b2579e2541b2575a5de9b9877cdfc13c23ed651","_nodeVersion":"20.12.1","_npmVersion":"10.5.0","dist":{"integrity":"sha512-s4tJ0PaDBjDEEZ/2Li5k63EucoVgCLTTlxpfr/GpexQ7SLawOrKCMW6x4lUsVqll79E2VthaEpY99QQcxqoBMQ==","shasum":"6218c51f072523973d73285c4178147865aa4456","tarball":"https://registry.npmjs.org/@dgcgovkh/digitalstamp-oaverify/-/digitalstamp-oaverify-0.0.2.tgz","fileCount":47,"unpackedSize":5358800,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBJHHtu8loTvmr7fzGtidzrUsoUHwqmy2wS/VgGegW7VAiEAwvKzzk5KAk9lhMIulXEDo0ePAY8+blLcC/R0ihrhVbI="}]},"_npmUser":{"name":"krisnadev","email":"trykrisnapcu@gmail.com"},"directories":{},"maintainers":[{"name":"krisnadev","email":"trykrisnapcu@gmail.com"},{"name":"seanghay","email":"seanghay.dev@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/digitalstamp-oaverify_0.0.2_1724343267180_0.2887316343443884"},"_hasShrinkwrap":false}},"time":{"created":"2024-08-22T09:33:36.052Z","modified":"2024-08-22T16:14:27.700Z","0.0.1":"2024-08-22T09:33:36.432Z","0.0.2":"2024-08-22T16:14:27.508Z"},"license":"Apache-2.0","repository":{"type":"git","url":""},"description":"Using the [OpenAttestation (Verify)](https://github.com/Open-Attestation/oa-verify) repository as the codebase for the `npm` module, you can verify [wrapped documents](https://www.openattestation.com/docs/lib-section/remote-files/open-attestation#wrapping","maintainers":[{"name":"krisnadev","email":"trykrisnapcu@gmail.com"},{"name":"seanghay","email":"seanghay.dev@gmail.com"}],"readme":"# OpenAttestation (Verify)\r\n\r\nUsing the [OpenAttestation (Verify)](https://github.com/Open-Attestation/oa-verify) repository as the codebase for the `npm` module, you can verify [wrapped documents](https://www.openattestation.com/docs/lib-section/remote-files/open-attestation#wrapping-documents) programmatically. This is useful if you are building your own API or web components. The following are common use cases where you will need this module:\r\n\r\n- [Verifying a document](#verifying-a-document)\r\n- [Building a custom verifier](#custom-verification)\r\n- [Adding custom validation](#custom-validation)\r\n\r\nThis module does not provide the following functionalities:\r\n\r\n- Programmatic wrapping of OA documents (refer to [OpenAttestation](https://www.openattestation.com/docs/lib-section/remote-files/open-attestation#wrapping-documents))\r\n- Encryption or decryption of OA documents (refer to [OpenAttestation (Encryption)](https://www.openattestation.com/docs/lib-section/remote-files/open-attestation-encryption))\r\n- Programmatic issuance or revocation of any document on the Ethereum blockchain\r\n\r\n## Verification flow\r\n\r\nIn brief, the verification flow runs three checks on the document:\r\n\r\n1. The document integrity check\r\n1. The issuance status check\r\n1. The issuance identity check\r\n\r\nOnly when it passes all three checks, will it count as a valid OA document.\r\n\r\n### Ethereum\r\n\r\nThe diagram below shows the verification flow on OA documents issued using the Ethereum method:\r\n\r\n![Verify OA documents issued using Ethereum](https://raw.githubusercontent.com/Open-Attestation/oa-verify/master/diagram/verifiable-docs-eth.light.svg)\r\n\r\n### DID\r\n\r\nThe diagram below shows the verification flow on OA documents issued using the DID method:\r\n\r\n![Verify OA documents issued using DID](https://raw.githubusercontent.com/Open-Attestation/oa-verify/master/diagram/verifiable-docs-did.light.svg)\r\n\r\n## Installation\r\n\r\nTo install OpenAttestation (Verify) on your machine, run the command below:\r\n\r\n```bash\r\nnpm i @dgcgovkh/digitalstamp-oaverify\r\n```\r\n\r\n## Usage\r\n\r\n### Verifying a document\r\n\r\nA verification happens on a wrapped document, which performs the following checks:\r\n\r\n- Has the document been tampered with?\r\n- Is the issuance state of the document valid?\r\n- Is the document issuer identity valid? (See [identity proof](https://www.openattestation.com/docs/verify-section/issuance-identity))\r\n\r\nThe verification requires a wrapped document created using [OpenAttestation](https://www.openattestation.com/docs/lib-section/remote-files/open-attestation). The following shows an example of a wrapped document, which is valid and has been issued on the Sepolia network.\r\n\r\n```json\r\n{\r\n  \"version\": \"https://schema.openattestation.com/2.0/schema.json\",\r\n  \"data\": {\r\n    \"billFrom\": {},\r\n    \"billTo\": { \"company\": {} },\r\n    \"$template\": {\r\n      \"type\": \"f76f4d39-8d23-455b-96ba-5889e0233641:string:EMBEDDED_RENDERER\",\r\n      \"name\": \"575f0624-7f43-484c-9285-edd1ae96ebc6:string:INVOICE\",\r\n      \"url\": \"fb61f072-64e9-4c2f-83bf-ae68fd911414:string:https://generic-templates.tradetrust.io\"\r\n    },\r\n    \"issuers\": [\r\n      {\r\n        \"name\": \"ed121e9e-8f70-4a01-a422-4509d837c13f:string:Demo Issuer\",\r\n        \"documentStore\": \"08948d61-9392-459f-b476-e3c51961f04b:string:0x49b2969bF0E4aa822023a9eA2293b24E4518C1DD\",\r\n        \"identityProof\": {\r\n          \"type\": \"61c13b84-181a-43aa-85f5-dfe89e4b6963:string:DNS-TXT\",\r\n          \"location\": \"d7ba5e33-cf5f-4fcc-a4b7-3e6e17324966:string:demo-tradetrust.openattestation.com\"\r\n        },\r\n        \"revocation\": {\r\n          \"type\": \"23d47c6b-4384-4c31-90ca-8284602f6b3e:string:NONE\"\r\n        }\r\n      }\r\n    ],\r\n    \"links\": {\r\n      \"self\": {\r\n        \"href\": \"121c55c0-864d-4e54-a1f0-86bec4b9a050:string:https://action.openattestation.com?q=%7B%22type%22%3A%22DOCUMENT%22%2C%22payload%22%3A%7B%22uri%22%3A%22https%3A%2F%2Ftradetrust-functions.netlify.app%2F.netlify%2Ffunctions%2Fstorage%2Faea9cb1a-816a-4fd7-b3a9-84924dc9a9e9%22%2C%22key%22%3A%22d80b453e53bb26d3b36efe65f18f0482f52d97cffad6f6c9c195d10e165b9a83%22%2C%22permittedActions%22%3A%5B%22STORE%22%5D%2C%22redirect%22%3A%22https%3A%2F%2Fdev.tradetrust.io%2F%22%2C%22chainId%22%3A%225%22%7D%7D\"\r\n      }\r\n    },\r\n    \"network\": {\r\n      \"chain\": \"05eb1707-5426-41d8-8fde-bc48ff0f2182:string:ETH\",\r\n      \"chainId\": \"ae505425-2df7-4597-87d2-037418d7bcbf:string:5\"\r\n    }\r\n  },\r\n  \"signature\": {\r\n    \"type\": \"SHA3MerkleProof\",\r\n    \"targetHash\": \"f292056ed5e5535400cec63b78a84ec384d2d77117e1606a17644e7b97a03cac\",\r\n    \"proof\": [],\r\n    \"merkleRoot\": \"f292056ed5e5535400cec63b78a84ec384d2d77117e1606a17644e7b97a03cac\"\r\n  }\r\n}\r\n```\r\n\r\nTo perform the verification checks on the document, use the following code:\r\n\r\n```ts\r\n// index.ts\r\nimport { isValid, verify } from \"@dgcgovkh/digitalstamp-oaverify\";\r\nimport * as document from \"./document.json\";\r\n\r\nconst fragments = await verify(document as any);\r\n\r\nconsole.log(isValid(fragments)); // output true\r\n```\r\n\r\n### Custom verification\r\n\r\nBy default, the provided `verify` method performs multiple checks on a document.\r\n\r\n- The type `DOCUMENT_STATUS` runs these verifiers:\r\n\r\n  - `OpenAttestationEthereumDocumentStoreStatus`\r\n  - `OpenAttestationEthereumTokenRegistryStatus`\r\n  - `DidSignedDocumentStatus`\r\n\r\n- The type `DOCUMENT_INTEGRITY` runs this verifier:\r\n\r\n  - `OpenAttestationHash`\r\n\r\n- The type `ISSUER_IDENTITY` runs these verifiers:\r\n  - `OpenAttestationDnsTxt`\r\n  - `DnsDidProof`\r\n\r\nAll those verifiers are exported as `openAttestationVerifiers`\r\n\r\nYou can build your own verification method based on the default exported verifiers:\r\n\r\n```ts\r\n// creating your own verification method using default exported verifiers\r\nimport { verificationBuilder, openAttestationVerifiers } from \"@dgcgovkh/digitalstamp-oaverify\";\r\n\r\nconst verify1 = verificationBuilder(openAttestationVerifiers, { network: \"sepolia\" }); // this verification is equivalent to the one exported by the library\r\n\r\nconst verify2 = verificationBuilder([openAttestationVerifiers[0], openAttestationVerifiers[1]], {\r\n  network: \"sepolia\",\r\n}); // this verification only runs 2 verifiers\r\n```\r\n\r\nYou can also build your own verification method based on the custom verifiers:\r\n\r\n```ts\r\n// creating your own verification using custom verifier\r\nimport { verificationBuilder, openAttestationVerifiers, Verifier } from \"@dgcgovkh/digitalstamp-oaverify\";\r\nconst customVerifier: Verifier<any> = {\r\n  skip: () => {\r\n    // returns a SkippedVerificationFragment if the verifier should be skipped or throws an error if it should always run\r\n  },\r\n  test: () => {\r\n    // returns true or false\r\n  },\r\n  verify: async (document) => {\r\n    // performs checks and returns a fragment\r\n  },\r\n};\r\n\r\n// creates your own verify function with all verifiers and your custom one\r\nconst verify = verificationBuilder([...openAttestationVerifiers, customVerifier], { network: \"sepolia\" });\r\n```\r\n\r\nRefer to the [Extending custom verification](#extending-custom-verification) section to find out more on how to create your own custom verifier.\r\n\r\n### Custom validation\r\n\r\nFragments will be produced after verifying a document. Each fragment will determine if the individual type mentioned [here](#custom-verification) is valid or not, and will collectively prove the validity of the document.\r\n\r\nThe `isValid` function will execute over fragments and determine if the fragments produced a valid result. By default, the function will return `true` if a document fulfils all the following conditions:\r\n\r\n- The document has NOT been tampered.\r\n- AND The document has been issued.\r\n- AND The document has NOT been revoked.\r\n- AND The issuer identity is valid.\r\n\r\nIn the function, a list of types also checks for as a second parameter.\r\n\r\n```ts\r\n// index.ts\r\nimport { isValid, openAttestationVerifiers, verificationBuilder } from \"@dgcgovkh/digitalstamp-oaverify\";\r\nimport * as document from \"./document.json\";\r\n\r\nconst verify = verificationBuilder(openAttestationVerifiers, {\r\n  network: \"mainnet\",\r\n});\r\n\r\nconst fragments = await verify(document as any);\r\n\r\nconsole.log(isValid(fragments, [\"DOCUMENT_INTEGRITY\"])); // output true\r\nconsole.log(isValid(fragments, [\"DOCUMENT_STATUS\"])); // output false\r\nconsole.log(isValid(fragments, [\"ISSUER_IDENTITY\"])); // output false\r\nconsole.log(isValid(fragments)); // output false\r\n```\r\n\r\nThe following explains what the functions return with reasons:\r\n\r\n- `isValid(fragments, [\"DOCUMENT_INTEGRITY\"])` returns `true` because the integrity of the document is not dependent on the network where it has been published.\r\n- `isValid(fragments, [\"DOCUMENT_STATUS\"])` returns `false` because the document has not been published on the Ethereum main network.\r\n- `isValid(fragments, [\"ISSUER_IDENTITY\"])` returns `false` because there is no [DNS TXT record](https://www.openattestation.com/docs/ethereum-section/dns-proof) associated with the Ethereum main network's document store.\r\n- `isValid(fragments)` returns `false` because at least one of the above returns false.\r\n\r\n### Listening to an individual verification method\r\n\r\nThe `verify` function provides an option that listens to individual verification methods. It can be useful if you want, for instance, to provide individual loaders on your UI.\r\n\r\nThe following is a code example with that option:\r\n\r\n```ts\r\n// index.ts\r\nimport { isValid, openAttestationVerifiers, verificationBuilder } from \"@dgcgovkh/digitalstamp-oaverify\";\r\nimport * as document from \"./document.json\";\r\n\r\nconst verify = verificationBuilder(openAttestationVerifiers, {\r\n  network: \"sepolia\",\r\n});\r\n\r\nconst promisesCallback = (verificationMethods: any) => {\r\n  for (const verificationMethod of verificationMethods) {\r\n    verificationMethod.then((fragment: any) => {\r\n      console.log(`${fragment.name} has been resolved with status ${fragment.status}`);\r\n    });\r\n  }\r\n};\r\n\r\nconst fragments = await verify(document as any, promisesCallBack);\r\n\r\nconsole.log(isValid(fragments)); // output true\r\n```\r\n\r\n---\r\n\r\n## Advanced usage\r\n\r\n### Extending custom verification\r\n\r\nExtending from the [Custom verification](#custom-verification) section, you will learn how to write custom verification methods and how to distribute your own verifier.\r\n\r\n#### Building a custom verification method\r\n\r\nYou will write a verification method with the following rules:\r\n\r\n1. It must run only on documents with their version equal to `https://schema.openattestation.com/2.0/schema.json`\r\n\r\n1. It must return a valid fragment, only if the document data hold a `name` property with the value `Certificate of Completion`\r\n\r\n##### Document version\r\n\r\nThis is where `skip` and `test` methods are needed. You will use the `test` method to return when the verification method was running and the `skip` method to explain why it wasn't:\r\n\r\n```ts\r\n// index.ts\r\nimport { verificationBuilder, openAttestationVerifiers, Verifier, isValid } from \"@dgcgovkh/digitalstamp-oaverify\";\r\nimport { getData } from \"@govtechsg/open-attestation\";\r\nimport * as document from \"./document.json\";\r\n\r\nconst customVerifier: Verifier<any> = {\r\n  skip: async () => {\r\n    return {\r\n      status: \"SKIPPED\",\r\n      type: \"DOCUMENT_INTEGRITY\",\r\n      name: \"CustomVerifier\",\r\n      reason: {\r\n        code: 0,\r\n        codeString: \"SKIPPED\",\r\n        message: `Document doesn't have version equal to 'https://schema.openattestation.com/2.0/schema.json'`,\r\n      },\r\n    };\r\n  },\r\n  test: () => document.version === \"https://schema.openattestation.com/2.0/schema.json\",\r\n};\r\n```\r\n\r\n> **Note:** Use the `DOCUMENT_INTEGRITY` type to check the document content.\r\n\r\n##### The `name` property\r\n\r\nOnce you have decided `when` the verification method will run, you need to write the logic of the verifier in the `verify` method. You will use the [getData](https://www.openattestation.com/docs/lib-section/remote-files/open-attestation#retrieving-the-document-data) utility to access the document data and return the appropriate fragment depending on the content:\r\n\r\n```ts\r\n// index.ts\r\nimport { verificationBuilder, openAttestationVerifiers, Verifier, isValid } from \"@dgcgovkh/digitalstamp-oaverify\";\r\nimport { getData } from \"@govtechsg/open-attestation\";\r\nimport * as document from \"./document.json\";\r\n\r\nconst customVerifier: Verifier<any> = {\r\n  skip: async () => {\r\n    /* content has been defined in the section above */\r\n  },\r\n  test: () => /* content has been defined in the section above */,\r\n  verify: async (document: any) => {\r\n    const documentData = getData(document);\r\n    if (documentData.name !== \"Certificate of Completion\") {\r\n      return {\r\n        type: \"DOCUMENT_INTEGRITY\",\r\n        name: \"CustomVerifier\",\r\n        data: documentData.name,\r\n        reason: {\r\n          code: 1,\r\n          codeString: \"INVALID_NAME\",\r\n          message: `Document name is ${documentData.name}`,\r\n        },\r\n        status: \"INVALID\",\r\n      };\r\n    }\r\n    return {\r\n      type: \"DOCUMENT_INTEGRITY\",\r\n      name: \"CustomVerifier\",\r\n      data: documentData.name,\r\n      status: \"VALID\",\r\n    };\r\n  },\r\n};\r\n```\r\n\r\n#### Building a custom verify method\r\n\r\nThe `verify` function is built to run a list of verification methods. Each verifier will produce a fragment that determines if the document is valid. OpenAttestation has its own set of verification methods in `openAttestationVerifiers`.\r\n\r\nUsing the `verificationBuilder` function, you can create custom verification methods and reuse the default method exported from the library.\r\n\r\nExtending from the [Custom verification](#custom-verification) section, you will build a new verifier using the custom verification method below:\r\n\r\n```ts\r\n// index.ts\r\nimport { verificationBuilder, openAttestationVerifiers, Verifier, isValid } from \"@dgcgovkh/digitalstamp-oaverify\";\r\nimport { getData } from \"@govtechsg/open-attestation\";\r\nimport document from \"./document.json\";\r\n\r\n// based on the test condition specified below, your custom verifier will only check documentData.name if document.version is equal to https://schema.openattestation.com/2.0/schema.json\r\nconst customVerifier: Verifier<any> = {\r\n  skip: async () => {\r\n    return {\r\n      status: \"SKIPPED\",\r\n      type: \"DOCUMENT_INTEGRITY\",\r\n      name: \"CustomVerifier\",\r\n      reason: {\r\n        code: 0,\r\n        codeString: \"SKIPPED\",\r\n        message: `Document doesn't have version equal to 'https://schema.openattestation.com/2.0/schema.json'`,\r\n      },\r\n    };\r\n  },\r\n  test: () => document.version === \"https://schema.openattestation.com/2.0/schema.json\",\r\n  verify: async (document: any) => {\r\n    const documentData = getData(document);\r\n    if (documentData.name !== \"Certificate of Completion\") {\r\n      return {\r\n        type: \"DOCUMENT_INTEGRITY\",\r\n        name: \"CustomVerifier\",\r\n        data: documentData.name,\r\n        reason: {\r\n          code: 1,\r\n          codeString: \"INVALID_NAME\",\r\n          message: `Document name is ${documentData.name}`,\r\n        },\r\n        status: \"INVALID\",\r\n      };\r\n    }\r\n    return {\r\n      type: \"DOCUMENT_INTEGRITY\",\r\n      name: \"CustomVerifier\",\r\n      data: documentData.name,\r\n      status: \"VALID\",\r\n    };\r\n  },\r\n};\r\n\r\n// create your own verify function with all verifiers and your custom one\r\nconst verify = verificationBuilder([...openAttestationVerifiers, customVerifier], { network: \"sepolia\" });\r\n\r\nconst fragments = await verify(document);\r\n\r\nconsole.log(isValid(fragments)); // return false\r\nconsole.log(fragments.find((fragment: any) => fragment.name === \"CustomVerifier\")); // display the details on our specific verifier\r\n```\r\n\r\nThe document you [created](#verifying-a-document) is not valid according to your own verifier, because the `name` property does not exist. Test again with the following document:\r\n\r\n```json\r\n{\r\n  \"version\": \"https://schema.openattestation.com/2.0/schema.json\",\r\n  \"data\": {\r\n    \"name\": \"66e35a92-9e97-4ffc-b94e-769773dd7535:string:Certificate of Completion\",\r\n    \"issuers\": [\r\n      {\r\n        \"documentStore\": \"375a13f9-ca3d-4a1f-a0c9-1fa92e43a3ec:string:0x8Fc57204c35fb9317D91285eF52D6b892EC08cD3\",\r\n        \"name\": \"448c7f62-3a93-4792-a157-fabcbf15b91a:string:University of Blockchain\",\r\n        \"identityProof\": {\r\n          \"type\": \"dcfc17e0-a178-4bb8-b0fb-6a2cfddb8f2f:string:DNS-TXT\",\r\n          \"location\": \"e3f54dbf-bb51-41bb-9511-e01a5c07ea86:string:example.openattestation.com\"\r\n        }\r\n      }\r\n    ]\r\n  },\r\n  \"privacy\": { \"obfuscatedData\": [] },\r\n  \"signature\": {\r\n    \"type\": \"SHA3MerkleProof\",\r\n    \"targetHash\": \"975887a864e11fbe27e90f4759c44db90193abc237dede81cd3cd7ca45c46522\",\r\n    \"proof\": [],\r\n    \"merkleRoot\": \"975887a864e11fbe27e90f4759c44db90193abc237dede81cd3cd7ca45c46522\"\r\n  }\r\n}\r\n```\r\n\r\n### Environment variables\r\n\r\n- `PROVIDER_API_KEY`: You can provide your own PROVIDER API key.\r\n- `PROVIDER_ENDPOINT_URL`: You can provide your preferred JSON-RPC HTTP API URL.\r\n- `PROVIDER_NETWORK`: You can specify the network to use, i.e. \"homestead\", \"mainnet\", or \"sepolia\".\r\n- `PROVIDER_ENDPOINT_TYPE`: You can specify the provider to use, i.e. \"infura\", \"alchemy\", or \"jsonrpc\".\r\n\r\n  - Supported providers include:\r\n    - Infura\r\n    - EtherScan\r\n    - Alchemy\r\n    - JSON-RPC\r\n\r\n### Switching network\r\n\r\nYou may build the verifier to check against a custom network with either way:\r\n\r\n1. Providing your own Web3 provider\r\n\r\n2. Specifying the network name\r\n\r\n   In this way, the provider will be using the default one.\r\n\r\n#### Provider\r\n\r\nThe following code example shows how you can specify a custom provider:\r\n\r\n```ts\r\nconst verify = verificationBuilder(openAttestationVerifiers, { provider: customProvider });\r\n```\r\n\r\n#### Network\r\n\r\nThe following code example shows how you can specify the network:\r\n\r\n```ts\r\nconst verify = verificationBuilder(openAttestationVerifiers, { network: \"sepolia\" });\r\n```\r\n\r\n### Specifying the resolver\r\n\r\nUsing the exposed `createResolver` method, you can easily create custom resolvers to resolve DIDs:\r\n\r\n```ts\r\nimport { createResolver, verificationBuilder, openAttestationVerifiers } from \"@dgcgovkh/digitalstamp-oaverify\";\r\n\r\nconst resolver = createResolver({\r\n  networks: [{ name: \"my-network\", rpcUrl: \"https://my-private-chain/besu\", registry: \"0xaE5a9b9...\" }],\r\n});\r\n\r\nconst verify = verificationBuilder(openAttestationVerifiers, { resolver });\r\n```\r\n\r\nAt the moment, `oa-verify` supports two DID resolvers:\r\n\r\n- [web-did-resolver](https://github.com/decentralized-identity/web-did-resolver#readme)\r\n- [ethr-did-resolver](https://github.com/decentralized-identity/ethr-did-resolver)\r\n\r\n---\r\n\r\n## Provider\r\n\r\nYou can generate a provider using the provider generator, which supports these providers:\r\n\r\n- `INFURA`\r\n- `ALCHEMY`\r\n- `ETHERSCAN`\r\n- `JsonRPC`\r\n\r\nIt requires a set of options:\r\n\r\n- `network`: Specified as a **string** for a common network name, i.e. \"homestead\", \"mainnet\", or \"sepolia\"\r\n- `provider`: Specified as a **string**, i.e. \"infura\", \"alchemy\", or \"jsonrpc\"\r\n- `url`: Specified as a **string**, which is being used to connect to a JSON-RPC HTTP API\r\n- `apiKey`: Specified as a **string** to be used together with the provider. If no value is provided, a default shared API key will be used, which may result in reduced performance and throttled requests.\r\n\r\n### Example\r\n\r\nThe following shows a basic use case of `provider`:\r\n\r\n```ts\r\nimport { utils } from \"@dgcgovkh/digitalstamp-oaverify\";\r\nconst provider = utils.generateProvider();\r\n// This will generate an infura provider using the default values.\r\n```\r\n\r\n#### Alternate method 1\r\n\r\nThis method uses the environment variables:\r\n\r\n```ts\r\n// environment file\r\nPROVIDER_NETWORK = \"sepolia\";\r\nPROVIDER_ENDPOINT_TYPE = \"infura\";\r\nPROVIDER_ENDPOINT_URL = \"http://jsonrpc.com\";\r\nPROVIDER_API_KEY = \"ajdh1j23\";\r\n\r\n// provider file\r\nimport { utils } from \"@dgcgovkh/digitalstamp-oaverify\";\r\nconst provider = utils.generateProvider();\r\n// This will use the environment variables declared in the files automatically.\r\n```\r\n\r\n#### Alternate method 2\r\n\r\nThis method passes in the values as parameters:\r\n\r\n```ts\r\nimport { utils } from \"@dgcgovkh/digitalstamp-oaverify\";\r\nconst providerOptions = {\r\n  network: \"sepolia\",\r\n  providerType: \"infura\",\r\n  apiKey: \"abdfddsfe23232\",\r\n};\r\nconst provider = utils.generateProvider(providerOptions);\r\n// This will generate a provider based on the options provided.\r\n// Note: Using this declaration will override all environment variables and default values.\r\n```\r\n\r\n---\r\n\r\n## Utils and types\r\n\r\n### Overview\r\n\r\nVarious utilities and types are available to assert the correctness of fragments. Each verification method exports types for the fragment and the data associated with the fragment.\r\n\r\n- Fragment types are available in four flavors: `VALID`, `INVALID`, `SKIPPED`, and `ERROR`.\r\n- `VALID` and `INVALID` fragment data are available in two flavors most of the time, one for each version of `OpenAttestation` (V2 or V3).\r\n\r\nThis library provides types and utilities to:\r\n\r\n- Get a specific fragment from all fragments returned by the `verify` method.\r\n- Narrow down to a specific type of fragment.\r\n- Narrow down to specific data from the fragment.\r\n\r\n### Example\r\n\r\nThe following code example shows the usage:\r\n\r\n```ts\r\nimport { utils } from \"@dgcgovkh/digitalstamp-oaverify\";\r\nconst fragments = verify(documentValidWithCertificateStore, { network: \"sepolia\" });\r\n// return the correct fragment, correctly typed\r\nconst fragment = utils.getOpenAttestationEthereumTokenRegistryStatusFragment(fragments);\r\n\r\nif (utils.isValidFragment(fragment)) {\r\n  // guard to narrow to the valid fragment type\r\n  const { data } = fragment;\r\n  if (ValidTokenRegistryDataV2.guard(data)) {\r\n    // data is correctly typed here\r\n  }\r\n}\r\n```\r\n\r\n> **Note:** In the example above, it may be unnecessary to use `utils.isValidFragment`, as it's possible to use `ValidTokenRegistryDataV2.guard` directly over the data.\r\n\r\n### List of utilities\r\n\r\n- `getOpenAttestationHashFragment`\r\n- `getOpenAttestationDidSignedDocumentStatusFragment`\r\n- `getOpenAttestationEthereumDocumentStoreStatusFragment`\r\n- `getOpenAttestationEthereumTokenRegistryStatusFragment`\r\n- `getOpenAttestationDidIdentityProofFragment`\r\n- `getOpenAttestationDnsDidIdentityProofFragment`\r\n- `getOpenAttestationDnsTxtIdentityProofFragment`\r\n- `getDocumentIntegrityFragments`\r\n- `getDocumentStatusFragments`\r\n- `getIssuerIdentityFragments`\r\n- `isValidFragment`: Type guard to filter only the `VALID` fragment type\r\n- `isInvalidFragment`: Type guard to filter only the `INVALID` fragment type\r\n- `isErrorFragment`: Type guard to filter only the `ERROR` fragment type\r\n- `isSkippedFragment`: Type guard to filter only the `SKIPPED` fragment type\r\n\r\n---\r\n\r\n## Verification method\r\n\r\n| Name                                       | Type               | Description                                                                  | Present in default verifier? |\r\n| ------------------------------------------ | ------------------ | ---------------------------------------------------------------------------- | ---------------------------- |\r\n| OpenAttestationHash                        | DOCUMENT_INTEGRITY | Verify that merkle root and target hash matches the certificate              | Yes                          |\r\n| OpenAttestationDidSignedDocumentStatus     | DOCUMENT_STATUS    | Verify the validity of the signature of a DID signed certificate             | Yes                          |\r\n| OpenAttestationEthereumDocumentStoreStatus | DOCUMENT_STATUS    | Verify the certificate has been issued to the document store and not revoked | Yes                          |\r\n| OpenAttestationEthereumTokenRegistryStatus | DOCUMENT_STATUS    | Verify the certificate has been issued to the token registry and not revoked | Yes                          |\r\n| OpenAttestationDidIdentityProof            | ISSUER_IDENTITY    | Verify identity of DID (similar to OpenAttestationDidSignedDocumentStatus)   | No                           |\r\n| OpenAttestationDnsDidIdentityProof         | ISSUER_IDENTITY    | Verify identify of DID certificate using DNS-TXT                             | Yes                          |\r\n| OpenAttestationDnsTxtIdentityProof         | ISSUER_IDENTITY    | Verify identify of document store certificate using DNS-TXT                  | Yes                          |\r\n\r\n---\r\n\r\n## Development\r\n\r\nTo run tests, use the following command:\r\n\r\n```\r\nnpm run test\r\n```\r\n\r\nTo generate test documents (for V3), use the script at `scripts/generate.v3.ts` and run the following command:\r\n\r\n```\r\nnpm run generate:v3\r\n```\r\n\r\n## License\r\n\r\nOpenAttestation (Verify) is under the [Apache license, version 2.0](https://www.apache.org/licenses/LICENSE-2.0).\r\n\r\n## Additional information\r\n\r\n- For more information on the verification SDK implementation, follow the [Verifier ADR](https://github.com/Open-Attestation/adr/blob/master/verifier.md).\r\n- If you find a bug, have a question, or want to share an idea, reach us at our [Github repository](https://github.com/Open-Attestation/oa-verify).\r\n","readmeFilename":"README.md"}