From f0d7c6aad824482db4bc29f6933e6192869001f5 Mon Sep 17 00:00:00 2001 From: Goi Jia Jian Date: Thu, 2 Jul 2020 01:44:48 +0800 Subject: [PATCH 01/11] feat: add google spreadsheets --- package-lock.json | 198 +++++++++++++++++++++++++++++++++++++++++++--- package.json | 1 + src/verify.ts | 6 ++ 3 files changed, 196 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index bbb2cc2..ca5e53a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2242,6 +2242,11 @@ "@types/node": "*" } }, + "@types/google-spreadsheet": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/google-spreadsheet/-/google-spreadsheet-3.0.0.tgz", + "integrity": "sha512-BMsoo/J2yshaLBsMxW/o6Py8rBdDeFHUWQ18Z/WoD8VDBGzsdcNVXMObBxL4szj0FbnSiaqUJ9paJYXMr+GhhQ==" + }, "@types/istanbul-lib-coverage": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", @@ -2429,6 +2434,14 @@ "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", "dev": true }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, "acorn": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", @@ -2968,6 +2981,11 @@ } } }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -2983,6 +3001,11 @@ "integrity": "sha512-l5r9ir56nda3qu14nAXIlyq1MmUSs0meCIaFAh8HwkFwP1F8eToOuS3ah2VAHHcY04jaYD7FpJC5JTXHYRbkzg==", "dev": true }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", @@ -3121,6 +3144,11 @@ "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", "dev": true }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -4489,6 +4517,14 @@ "safer-buffer": "^2.1.0" } }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "electron-to-chromium": { "version": "1.3.322", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz", @@ -5256,6 +5292,11 @@ } } }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, "exec-sh": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", @@ -5367,8 +5408,7 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { "version": "3.0.2", @@ -5562,6 +5602,11 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" + }, "fastq": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", @@ -6399,6 +6444,51 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "gaxios": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.3.4.tgz", + "integrity": "sha512-US8UMj8C5pRnao3Zykc4AAVr+cffoNKRTg9Rsf2GiuZCW69vgJj38VK2PzlPuQU73FZ/nTk9/Av6/JGcE1N9vA==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + }, + "dependencies": { + "agent-base": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz", + "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==", + "requires": { + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + } + } + }, + "gcp-metadata": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-3.5.0.tgz", + "integrity": "sha512-ZQf+DLZ5aKcRpLzYUyBS3yo3N0JSa82lNDO8rj3nMSlovLcz2riKFBsYgDzeXcv75oo5eqB2lx+B14UvPoCRnA==", + "requires": { + "gaxios": "^2.1.0", + "json-bigint": "^0.3.0" + } + }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", @@ -6679,6 +6769,57 @@ } } }, + "google-auth-library": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.10.1.tgz", + "integrity": "sha512-rOlaok5vlpV9rSiUu5EpR0vVpc+PhN62oF4RyX/6++DG1VsaulAFEMlDYBLjJDDPI6OcNOCGAKy9UVB/3NIDXg==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^2.1.0", + "gcp-metadata": "^3.4.0", + "gtoken": "^4.1.0", + "jws": "^4.0.0", + "lru-cache": "^5.0.0" + }, + "dependencies": { + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + } + } + }, + "google-p12-pem": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.4.tgz", + "integrity": "sha512-S4blHBQWZRnEW44OcR7TL9WR+QCqByRvhNDZ/uuQfpxywfupikf/miba8js1jZi6ZOGv5slgSuoshCWh6EMDzg==", + "requires": { + "node-forge": "^0.9.0" + } + }, + "google-spreadsheet": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/google-spreadsheet/-/google-spreadsheet-3.0.11.tgz", + "integrity": "sha512-bkYUdsq4Nwg7klnFevG6MRHXAfGh9gYVymGp001YdtThct5uSIB/41lUOsGzFbQQSR5FcBTwAu9nZVYvaNdv9Q==", + "requires": { + "axios": "^0.19.1", + "google-auth-library": "^5.9.1", + "lodash": "^4.17.15" + }, + "dependencies": { + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } + } + } + }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", @@ -6691,6 +6832,17 @@ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "dev": true }, + "gtoken": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.1.4.tgz", + "integrity": "sha512-VxirzD0SWoFUo5p8RDP8Jt2AGyOmyYcT/pOUgDKJCK+iSw0TMqwrVfY37RXTNmoKwrzmDHSk0GMT9FsgVmnVSA==", + "requires": { + "gaxios": "^2.1.0", + "google-p12-pem": "^2.0.0", + "jws": "^4.0.0", + "mime": "^2.2.0" + } + }, "handlebars": { "version": "4.5.3", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", @@ -8701,6 +8853,14 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-bigint": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.1.tgz", + "integrity": "sha512-DGWnSzmusIreWlEupsUelHrhwmPPE+FiQvg+drKfk2p+bdEYa5mp4PJ8JsCWqae0M2jQNb0HPvnwvf1qOTThzQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -8766,6 +8926,25 @@ "verror": "1.10.0" } }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -9440,7 +9619,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "requires": { "yallist": "^3.0.2" } @@ -9705,8 +9883,7 @@ "mime": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", - "dev": true + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" }, "mime-db": { "version": "1.42.0", @@ -9955,6 +10132,11 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" }, + "node-forge": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz", + "integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==" + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -14872,8 +15054,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-json-parse": { "version": "1.0.1", @@ -17563,8 +17744,7 @@ "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "yaml": { "version": "1.7.2", diff --git a/package.json b/package.json index b359001..535f7ef 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "@govtechsg/oa-verify": "3.4.0", "@govtechsg/open-attestation": "3.9.0", "debug": "4.1.1", + "google-spreadsheet": "3.0.11", "node-fetch": "2.6.0" }, "devDependencies": { diff --git a/src/verify.ts b/src/verify.ts index 8367353..6d0cf08 100644 --- a/src/verify.ts +++ b/src/verify.ts @@ -104,6 +104,12 @@ export const registryVerifier: Verifier< }, verify: async document => { const registry: Registry = await fetch("https://opencerts.io/static/registry.json").then(res => res.json()); + const spreadsheet = new GoogleSpreadsheet("1nhhD3XvHh2Ql_hW27LNw01fC-_I6Azt_XzYiYGhkmAU"); // or use service credential + const apiKey = process.env.GOOGLE_API_KEY; + await spreadsheet.useApiKey(apiKey as string); // handle this later + await spreadsheet.loadInfo(); + const sheet = spreadsheet.sheetsById[103906216]; + console.log(await sheet.getRows()); if (utils.isWrappedV3Document(document)) { const documentData = getData(document); From 74903e6e39288df5ca0c1a21dd1e2e0219816468 Mon Sep 17 00:00:00 2001 From: Goi Jia Jian Date: Fri, 3 Jul 2020 12:07:57 +0800 Subject: [PATCH 02/11] feat: load from gsheet --- src/verify.ts | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/verify.ts b/src/verify.ts index 6d0cf08..47829b8 100644 --- a/src/verify.ts +++ b/src/verify.ts @@ -103,21 +103,50 @@ export const registryVerifier: Verifier< }); }, verify: async document => { - const registry: Registry = await fetch("https://opencerts.io/static/registry.json").then(res => res.json()); + // const registry: Registry = await fetch("https://opencerts.io/static/registry.json").then(res => res.json()); const spreadsheet = new GoogleSpreadsheet("1nhhD3XvHh2Ql_hW27LNw01fC-_I6Azt_XzYiYGhkmAU"); // or use service credential const apiKey = process.env.GOOGLE_API_KEY; await spreadsheet.useApiKey(apiKey as string); // handle this later await spreadsheet.loadInfo(); const sheet = spreadsheet.sheetsById[103906216]; - console.log(await sheet.getRows()); + const rows = await sheet.getRows(); + const registry2: Registry = { + issuers: {} + }; + // Cell method + // await sheet.loadCells("A:H"); + // console.log(sheet.); + // const c = sheet.getCellByA1("C2"); + // console.log(c.value, c.valueType); + + rows.forEach((row: GoogleSpreadsheetRow): void => { + // console.log(row); + const displayCard = row.displayCard === "TRUE"; + + registry2.issuers[row.documentStore] = { + name: row.name, + displayCard: row.displayCard + }; + + if (row.displayCard) { + registry2.issuers[row.documentStore] = { + ...registry2.issuers[row.documentStore], + website: row.website, + email: row.email, + phone: row.phone, + logo: row.logo, + id: row.id + }; + } + }); if (utils.isWrappedV3Document(document)) { const documentData = getData(document); - return storeToFragment(registry, documentData.proof.value); + return storeToFragment(registry2, documentData.proof.value); } const documentData = getData(document); const issuerFragments = documentData.issuers.map(issuer => - storeToFragment(registry, (issuer.documentStore || issuer.certificateStore)!) + storeToFragment(registry2, (issuer.documentStore || issuer.certificateStore)!) ); // if one issuer is valid => fragment status is valid otherwise if all issuers are invalid => invalid const status = issuerFragments.some(fragment => fragment.status === "VALID") ? "VALID" : "INVALID"; From 662d092359377ae549a72196038be2891fb1c5ca Mon Sep 17 00:00:00 2001 From: Goi Jia Jian Date: Fri, 3 Jul 2020 12:39:23 +0800 Subject: [PATCH 03/11] fix: unused var --- src/verify.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/verify.ts b/src/verify.ts index 47829b8..02aff08 100644 --- a/src/verify.ts +++ b/src/verify.ts @@ -125,10 +125,10 @@ export const registryVerifier: Verifier< registry2.issuers[row.documentStore] = { name: row.name, - displayCard: row.displayCard + displayCard }; - if (row.displayCard) { + if (displayCard) { registry2.issuers[row.documentStore] = { ...registry2.issuers[row.documentStore], website: row.website, From 8684e6085b2bfaf80225e6a85f0be770ca0c2759 Mon Sep 17 00:00:00 2001 From: Goi Jia Jian Date: Fri, 3 Jul 2020 12:42:18 +0800 Subject: [PATCH 04/11] fix: unused import --- src/verify.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/verify.ts b/src/verify.ts index 02aff08..4d84ad8 100644 --- a/src/verify.ts +++ b/src/verify.ts @@ -6,7 +6,6 @@ import { VerificationFragmentType, VerificationManagerOptions } from "@govtechsg/oa-verify"; -import fetch from "node-fetch"; import { getData, v2, v3, WrappedDocument, utils } from "@govtechsg/open-attestation"; export interface RegistryEntry { From c1d84a69c99a60ebb2cfacae3ca742c26c6625fa Mon Sep 17 00:00:00 2001 From: Goi Jia Jian Date: Mon, 6 Jul 2020 17:53:54 +0800 Subject: [PATCH 05/11] feat: use Google Sheets v4 API direct --- package-lock.json | 193 ++--------------------------------------- package.json | 1 - src/verify.ts | 60 ++++++------- test/verify.v2.test.ts | 2 +- 4 files changed, 38 insertions(+), 218 deletions(-) diff --git a/package-lock.json b/package-lock.json index ca5e53a..e215b25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2434,14 +2434,6 @@ "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", "dev": true }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, "acorn": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", @@ -2981,11 +2973,6 @@ } } }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" - }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -3001,11 +2988,6 @@ "integrity": "sha512-l5r9ir56nda3qu14nAXIlyq1MmUSs0meCIaFAh8HwkFwP1F8eToOuS3ah2VAHHcY04jaYD7FpJC5JTXHYRbkzg==", "dev": true }, - "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" - }, "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", @@ -3144,11 +3126,6 @@ "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", "dev": true }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -4517,14 +4494,6 @@ "safer-buffer": "^2.1.0" } }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, "electron-to-chromium": { "version": "1.3.322", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz", @@ -5292,11 +5261,6 @@ } } }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, "exec-sh": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", @@ -5408,7 +5372,8 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true }, "extend-shallow": { "version": "3.0.2", @@ -5602,11 +5567,6 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "fast-text-encoding": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", - "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" - }, "fastq": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", @@ -6444,51 +6404,6 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, - "gaxios": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.3.4.tgz", - "integrity": "sha512-US8UMj8C5pRnao3Zykc4AAVr+cffoNKRTg9Rsf2GiuZCW69vgJj38VK2PzlPuQU73FZ/nTk9/Av6/JGcE1N9vA==", - "requires": { - "abort-controller": "^3.0.0", - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.3.0" - }, - "dependencies": { - "agent-base": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz", - "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==", - "requires": { - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" - } - } - }, - "gcp-metadata": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-3.5.0.tgz", - "integrity": "sha512-ZQf+DLZ5aKcRpLzYUyBS3yo3N0JSa82lNDO8rj3nMSlovLcz2riKFBsYgDzeXcv75oo5eqB2lx+B14UvPoCRnA==", - "requires": { - "gaxios": "^2.1.0", - "json-bigint": "^0.3.0" - } - }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", @@ -6769,57 +6684,6 @@ } } }, - "google-auth-library": { - "version": "5.10.1", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.10.1.tgz", - "integrity": "sha512-rOlaok5vlpV9rSiUu5EpR0vVpc+PhN62oF4RyX/6++DG1VsaulAFEMlDYBLjJDDPI6OcNOCGAKy9UVB/3NIDXg==", - "requires": { - "arrify": "^2.0.0", - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^2.1.0", - "gcp-metadata": "^3.4.0", - "gtoken": "^4.1.0", - "jws": "^4.0.0", - "lru-cache": "^5.0.0" - }, - "dependencies": { - "arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" - } - } - }, - "google-p12-pem": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.4.tgz", - "integrity": "sha512-S4blHBQWZRnEW44OcR7TL9WR+QCqByRvhNDZ/uuQfpxywfupikf/miba8js1jZi6ZOGv5slgSuoshCWh6EMDzg==", - "requires": { - "node-forge": "^0.9.0" - } - }, - "google-spreadsheet": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/google-spreadsheet/-/google-spreadsheet-3.0.11.tgz", - "integrity": "sha512-bkYUdsq4Nwg7klnFevG6MRHXAfGh9gYVymGp001YdtThct5uSIB/41lUOsGzFbQQSR5FcBTwAu9nZVYvaNdv9Q==", - "requires": { - "axios": "^0.19.1", - "google-auth-library": "^5.9.1", - "lodash": "^4.17.15" - }, - "dependencies": { - "axios": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", - "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", - "requires": { - "follow-redirects": "1.5.10" - } - } - } - }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", @@ -6832,17 +6696,6 @@ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "dev": true }, - "gtoken": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.1.4.tgz", - "integrity": "sha512-VxirzD0SWoFUo5p8RDP8Jt2AGyOmyYcT/pOUgDKJCK+iSw0TMqwrVfY37RXTNmoKwrzmDHSk0GMT9FsgVmnVSA==", - "requires": { - "gaxios": "^2.1.0", - "google-p12-pem": "^2.0.0", - "jws": "^4.0.0", - "mime": "^2.2.0" - } - }, "handlebars": { "version": "4.5.3", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", @@ -8853,14 +8706,6 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, - "json-bigint": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.1.tgz", - "integrity": "sha512-DGWnSzmusIreWlEupsUelHrhwmPPE+FiQvg+drKfk2p+bdEYa5mp4PJ8JsCWqae0M2jQNb0HPvnwvf1qOTThzQ==", - "requires": { - "bignumber.js": "^9.0.0" - } - }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -8926,25 +8771,6 @@ "verror": "1.10.0" } }, - "jwa": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "requires": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -9619,6 +9445,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "requires": { "yallist": "^3.0.2" } @@ -9883,7 +9710,8 @@ "mime": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true }, "mime-db": { "version": "1.42.0", @@ -10132,11 +9960,6 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" }, - "node-forge": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz", - "integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==" - }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -15054,7 +14877,8 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "safe-json-parse": { "version": "1.0.1", @@ -17744,7 +17568,8 @@ "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true }, "yaml": { "version": "1.7.2", diff --git a/package.json b/package.json index 535f7ef..b359001 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "@govtechsg/oa-verify": "3.4.0", "@govtechsg/open-attestation": "3.9.0", "debug": "4.1.1", - "google-spreadsheet": "3.0.11", "node-fetch": "2.6.0" }, "devDependencies": { diff --git a/src/verify.ts b/src/verify.ts index 4d84ad8..5e7420b 100644 --- a/src/verify.ts +++ b/src/verify.ts @@ -22,6 +22,11 @@ export interface Registry { [key: string]: RegistryEntry; }; } +export interface GoogleSpreadsheetValues { + range: string; + majorDimension: string; + values: string[]; +} export type OpencertsRegistryVerificationFragmentData = Partial & { value: string; status: "VALID" | "INVALID"; @@ -101,51 +106,42 @@ export const registryVerifier: Verifier< } }); }, - verify: async document => { - // const registry: Registry = await fetch("https://opencerts.io/static/registry.json").then(res => res.json()); - const spreadsheet = new GoogleSpreadsheet("1nhhD3XvHh2Ql_hW27LNw01fC-_I6Azt_XzYiYGhkmAU"); // or use service credential - const apiKey = process.env.GOOGLE_API_KEY; - await spreadsheet.useApiKey(apiKey as string); // handle this later - await spreadsheet.loadInfo(); - const sheet = spreadsheet.sheetsById[103906216]; - const rows = await sheet.getRows(); - const registry2: Registry = { + verify: async (document, options) => { + const apiKey = options.googleApiKey || process.env.GOOGLE_API_KEY; + const spreadsheetId = "1nhhD3XvHh2Ql_hW27LNw01fC-_I6Azt_XzYiYGhkmAU"; + const range = "Registry!A:H"; + const data: GoogleSpreadsheetValues = await fetch( + `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values/${range}?valueRenderOption=UNFORMATTED_VALUE&key=${apiKey}` + ).then(res => res.json()); + const registry: Registry = { issuers: {} }; - // Cell method - // await sheet.loadCells("A:H"); - // console.log(sheet.); - // const c = sheet.getCellByA1("C2"); - // console.log(c.value, c.valueType); - - rows.forEach((row: GoogleSpreadsheetRow): void => { - // console.log(row); - const displayCard = row.displayCard === "TRUE"; - - registry2.issuers[row.documentStore] = { - name: row.name, - displayCard + data.values.forEach((row): void => { + // 0: documentStore, 1: name, 2: displayCard, 3: website, 4: email, 5: phone, 6: logo, 7: id, 8: group + registry.issuers[row[0]] = { + name: row[1], + displayCard: /true/i.test(row[2]) }; - if (displayCard) { - registry2.issuers[row.documentStore] = { - ...registry2.issuers[row.documentStore], - website: row.website, - email: row.email, - phone: row.phone, - logo: row.logo, - id: row.id + if (row[2]) { + registry.issuers[row[0]] = { + ...registry.issuers[row[0]], + website: row[3], + email: row[4], + phone: row[5], + logo: row[6], + id: row[7] }; } }); if (utils.isWrappedV3Document(document)) { const documentData = getData(document); - return storeToFragment(registry2, documentData.proof.value); + return storeToFragment(registry, documentData.proof.value); } const documentData = getData(document); const issuerFragments = documentData.issuers.map(issuer => - storeToFragment(registry2, (issuer.documentStore || issuer.certificateStore)!) + storeToFragment(registry, (issuer.documentStore || issuer.certificateStore)!) ); // if one issuer is valid => fragment status is valid otherwise if all issuers are invalid => invalid const status = issuerFragments.some(fragment => fragment.status === "VALID") ? "VALID" : "INVALID"; diff --git a/test/verify.v2.test.ts b/test/verify.v2.test.ts index f222429..66ccf99 100644 --- a/test/verify.v2.test.ts +++ b/test/verify.v2.test.ts @@ -109,7 +109,7 @@ describe("verify", () => { ]); expect(isValid(fragments)).toStrictEqual(true); }); - describe("IDENTITY_ISSUER", () => { + describe.only("IDENTITY_ISSUER", () => { describe("single issuer with certificate store", () => { it("should have valid ISSUER_IDENTITY when document has one issuer that is in registry", async () => { const fragments = await verify(documentWithOneCertificateStoreIssuerInRegistry, options); From 3e96c9870c94c1429b69ad4eb1f282a969a45ed2 Mon Sep 17 00:00:00 2001 From: Goi Jia Jian Date: Mon, 6 Jul 2020 18:15:02 +0800 Subject: [PATCH 06/11] feat: added GoogleApiKey as option --- src/verify.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/verify.ts b/src/verify.ts index 5e7420b..29bf86f 100644 --- a/src/verify.ts +++ b/src/verify.ts @@ -8,6 +8,10 @@ import { } from "@govtechsg/oa-verify"; import { getData, v2, v3, WrappedDocument, utils } from "@govtechsg/open-attestation"; +export interface OpenCertsVerificationManagerOptions extends VerificationManagerOptions { + googleApiKey?: string; +} + export interface RegistryEntry { name: string; displayCard: boolean; @@ -83,7 +87,7 @@ const storeToFragment = ( export const registryVerifier: Verifier< WrappedDocument | WrappedDocument, - VerificationManagerOptions, + OpenCertsVerificationManagerOptions, OpencertsRegistryVerificationFragmentData | OpencertsRegistryVerificationFragmentData[] > = { test: document => { @@ -193,5 +197,5 @@ export const isValid = ( export const verify: ( document: WrappedDocument | WrappedDocument, - options: VerificationManagerOptions + options: OpenCertsVerificationManagerOptions ) => Promise = verificationBuilder([...openAttestationVerifiers, registryVerifier]); From a2790c9548eeb4799da50c522e8cfec37ee6f79c Mon Sep 17 00:00:00 2001 From: Goi Jia Jian Date: Mon, 6 Jul 2020 18:19:35 +0800 Subject: [PATCH 07/11] fix: tests --- test/verify.v2.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/verify.v2.test.ts b/test/verify.v2.test.ts index 66ccf99..f222429 100644 --- a/test/verify.v2.test.ts +++ b/test/verify.v2.test.ts @@ -109,7 +109,7 @@ describe("verify", () => { ]); expect(isValid(fragments)).toStrictEqual(true); }); - describe.only("IDENTITY_ISSUER", () => { + describe("IDENTITY_ISSUER", () => { describe("single issuer with certificate store", () => { it("should have valid ISSUER_IDENTITY when document has one issuer that is in registry", async () => { const fragments = await verify(documentWithOneCertificateStoreIssuerInRegistry, options); From 60c0a75d5ce4d36aa60e1a0af6c8cbacbb8eef14 Mon Sep 17 00:00:00 2001 From: Goi Jia Jian Date: Mon, 6 Jul 2020 18:28:08 +0800 Subject: [PATCH 08/11] chore: remove unused packages --- package-lock.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index e215b25..bbb2cc2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2242,11 +2242,6 @@ "@types/node": "*" } }, - "@types/google-spreadsheet": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/google-spreadsheet/-/google-spreadsheet-3.0.0.tgz", - "integrity": "sha512-BMsoo/J2yshaLBsMxW/o6Py8rBdDeFHUWQ18Z/WoD8VDBGzsdcNVXMObBxL4szj0FbnSiaqUJ9paJYXMr+GhhQ==" - }, "@types/istanbul-lib-coverage": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", From f7c9f369bcda89f0f337affd95d4d22d7ba7349b Mon Sep 17 00:00:00 2001 From: Goi Jia Jian Date: Tue, 7 Jul 2020 02:03:33 +0800 Subject: [PATCH 09/11] fix: temporarily adding dist --- .gitignore | 2 +- dist/index.js | 43 ++++++ dist/ts/src/index.d.ts | 2 + dist/ts/src/util/logger.d.ts | 9 ++ dist/ts/src/verify.d.ts | 37 +++++ dist/ts/test/fixtures/v2/document.d.ts | 23 +++ dist/ts/test/fixtures/v3/document.d.ts | 6 + dist/ts/test/verify.v2.test.d.ts | 1 + dist/ts/test/verify.v3.test.d.ts | 1 + dist/util/logger.js | 32 +++++ dist/verify.js | 187 +++++++++++++++++++++++++ 11 files changed, 342 insertions(+), 1 deletion(-) create mode 100644 dist/index.js create mode 100644 dist/ts/src/index.d.ts create mode 100644 dist/ts/src/util/logger.d.ts create mode 100644 dist/ts/src/verify.d.ts create mode 100644 dist/ts/test/fixtures/v2/document.d.ts create mode 100644 dist/ts/test/fixtures/v3/document.d.ts create mode 100644 dist/ts/test/verify.v2.test.d.ts create mode 100644 dist/ts/test/verify.v3.test.d.ts create mode 100644 dist/util/logger.js create mode 100644 dist/verify.js diff --git a/.gitignore b/.gitignore index 267aee3..7604f62 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ .DS_Store /coverage -/dist +# /dist /node_modules *.log /.idea diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..4c508f0 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,43 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var _exportNames = { + verificationBuilder: true, + openAttestationVerifiers: true, + Verifier: true +}; +Object.defineProperty(exports, "verificationBuilder", { + enumerable: true, + get: function get() { + return _oaVerify.verificationBuilder; + } +}); +Object.defineProperty(exports, "openAttestationVerifiers", { + enumerable: true, + get: function get() { + return _oaVerify.openAttestationVerifiers; + } +}); +Object.defineProperty(exports, "Verifier", { + enumerable: true, + get: function get() { + return _oaVerify.Verifier; + } +}); + +var _oaVerify = require("@govtechsg/oa-verify"); + +var _verify = require("./verify"); + +Object.keys(_verify).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function get() { + return _verify[key]; + } + }); +}); \ No newline at end of file diff --git a/dist/ts/src/index.d.ts b/dist/ts/src/index.d.ts new file mode 100644 index 0000000..9c0de4e --- /dev/null +++ b/dist/ts/src/index.d.ts @@ -0,0 +1,2 @@ +export { verificationBuilder, openAttestationVerifiers, Verifier } from "@govtechsg/oa-verify"; +export * from "./verify"; diff --git a/dist/ts/src/util/logger.d.ts b/dist/ts/src/util/logger.d.ts new file mode 100644 index 0000000..3fdd413 --- /dev/null +++ b/dist/ts/src/util/logger.d.ts @@ -0,0 +1,9 @@ +import debug from "debug"; +export declare const trace: (namespace: string) => debug.Debugger; +export declare const info: (namespace: string) => debug.Debugger; +export declare const error: (namespace: string) => debug.Debugger; +export declare const getLogger: (namespace: string) => { + trace: debug.Debugger; + info: debug.Debugger; + error: debug.Debugger; +}; diff --git a/dist/ts/src/verify.d.ts b/dist/ts/src/verify.d.ts new file mode 100644 index 0000000..9569af8 --- /dev/null +++ b/dist/ts/src/verify.d.ts @@ -0,0 +1,37 @@ +import { Verifier, VerificationFragment, VerificationFragmentType, VerificationManagerOptions } from "@govtechsg/oa-verify"; +import { v2, v3, WrappedDocument } from "@govtechsg/open-attestation"; +export interface OpenCertsVerificationManagerOptions extends VerificationManagerOptions { + googleApiKey?: string; +} +export interface RegistryEntry { + name: string; + displayCard: boolean; + website?: string; + email?: string; + phone?: string; + logo?: string; + id?: string; +} +export interface Registry { + issuers: { + [key: string]: RegistryEntry; + }; +} +export interface GoogleSpreadsheetValues { + range: string; + majorDimension: string; + values: string[]; +} +export declare type OpencertsRegistryVerificationFragmentData = Partial & { + value: string; + status: "VALID" | "INVALID"; +}; +export declare const type = "ISSUER_IDENTITY"; +export declare const name = "OpencertsRegistryVerifier"; +export declare enum OpencertsRegistryCode { + INVALID_IDENTITY = 0, + SKIPPED = 1 +} +export declare const registryVerifier: Verifier | WrappedDocument, OpenCertsVerificationManagerOptions, OpencertsRegistryVerificationFragmentData | OpencertsRegistryVerificationFragmentData[]>; +export declare const isValid: (verificationFragments: VerificationFragment[], types?: VerificationFragmentType[]) => boolean; +export declare const verify: (document: WrappedDocument | WrappedDocument, options: OpenCertsVerificationManagerOptions) => Promise; diff --git a/dist/ts/test/fixtures/v2/document.d.ts b/dist/ts/test/fixtures/v2/document.d.ts new file mode 100644 index 0000000..3f41280 --- /dev/null +++ b/dist/ts/test/fixtures/v2/document.d.ts @@ -0,0 +1,23 @@ +import { v2, WrappedDocument } from "@govtechsg/open-attestation"; +interface CustomDocument extends v2.OpenAttestationDocument { + name: string; + issuedOn: string; + $template: string; + recipient: { + name: string; + }; +} +export declare const documentMainnetValidWithCertificateStore: WrappedDocument; +export declare const documentWithOneCertificateStoreIssuerInRegistry: WrappedDocument; +export declare const documentWithOneCertificateStoreIssuerNotInRegistry: WrappedDocument; +export declare const documentWithOneDocumentStoreIssuerInRegistryAndValidDnsTxt: WrappedDocument; +export declare const documentWithOneDocumentStoreIssuerNotInRegistryAndValidDnsTxt: WrappedDocument; +export declare const documentWithOneDocumentStoreIssuerInRegistryAndInvalidDnsTxt: WrappedDocument; +export declare const documentWithOneDocumentStoreIssuerNotInRegistryAndInvalidDnsTxt: WrappedDocument; +export declare const documentWithTwoCertificateStoreIssuerInRegistry: WrappedDocument; +export declare const documentWithTwoDocumentStoreIssuerInRegistryWithValidDnsTxt: WrappedDocument; +export declare const documentWithTwoDocumentStoreIssuerOneInRegistryWithValidDnsTxtAndSecondInvalid: WrappedDocument; +export declare const documentWithTwoDocumentStoreIssuerNotInRegistryWithoutValidDnsTxt: WrappedDocument; +export declare const documentWithTwoCertificateStoreIssuerWithOneInRegistry: WrappedDocument; +export declare const documentWithTwoCertificateStoreIssuerNotInRegistry: WrappedDocument; +export {}; diff --git a/dist/ts/test/fixtures/v3/document.d.ts b/dist/ts/test/fixtures/v3/document.d.ts new file mode 100644 index 0000000..af4cfa8 --- /dev/null +++ b/dist/ts/test/fixtures/v3/document.d.ts @@ -0,0 +1,6 @@ +import { v3, WrappedDocument } from "@govtechsg/open-attestation"; +export declare const documentWithDocumentStoreIssuerInRegistryAndValidDns: WrappedDocument; +export declare const documentWithDocumentStoreIssuerInRegistryAndInvalidDns: WrappedDocument; +export declare const documentWithDocumentStoreIssuerNotInRegistryAndValidDns: WrappedDocument; +export declare const documentWithDocumentStoreIssuerNotInRegistryAndInvalidDns: WrappedDocument; +export declare const documentRopstenValidWithDocumentStore: WrappedDocument; diff --git a/dist/ts/test/verify.v2.test.d.ts b/dist/ts/test/verify.v2.test.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dist/ts/test/verify.v2.test.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/ts/test/verify.v3.test.d.ts b/dist/ts/test/verify.v3.test.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dist/ts/test/verify.v3.test.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/util/logger.js b/dist/util/logger.js new file mode 100644 index 0000000..7ba3419 --- /dev/null +++ b/dist/util/logger.js @@ -0,0 +1,32 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getLogger = exports.error = exports.info = exports.trace = void 0; + +var _debug = _interopRequireDefault(require("debug")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const logger = (0, _debug.default)("@govtechsg/opencerts-verify"); + +const trace = namespace => logger.extend(`trace:${namespace}`); + +exports.trace = trace; + +const info = namespace => logger.extend(`info:${namespace}`); + +exports.info = info; + +const error = namespace => logger.extend(`error:${namespace}`); + +exports.error = error; + +const getLogger = namespace => ({ + trace: trace(namespace), + info: info(namespace), + error: error(namespace) +}); + +exports.getLogger = getLogger; \ No newline at end of file diff --git a/dist/verify.js b/dist/verify.js new file mode 100644 index 0000000..d2d755b --- /dev/null +++ b/dist/verify.js @@ -0,0 +1,187 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.verify = exports.isValid = exports.registryVerifier = exports.OpencertsRegistryCode = exports.name = exports.type = void 0; + +var _oaVerify = require("@govtechsg/oa-verify"); + +var _nodeFetch = _interopRequireDefault(require("node-fetch")); + +var _openAttestation = require("@govtechsg/open-attestation"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } + +function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } + +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } + +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +const type = "ISSUER_IDENTITY"; +exports.type = type; +const name = "OpencertsRegistryVerifier"; // NEVER EVER REPLACE OR CHANGE A VALUE :) +// code for errors and invalid fragment + +exports.name = name; +let OpencertsRegistryCode; +exports.OpencertsRegistryCode = OpencertsRegistryCode; + +(function (OpencertsRegistryCode) { + OpencertsRegistryCode[OpencertsRegistryCode["INVALID_IDENTITY"] = 0] = "INVALID_IDENTITY"; + OpencertsRegistryCode[OpencertsRegistryCode["SKIPPED"] = 1] = "SKIPPED"; +})(OpencertsRegistryCode || (exports.OpencertsRegistryCode = OpencertsRegistryCode = {})); + +const storeToFragment = (registry, store) => { + const key = Object.keys(registry.issuers).find(k => k.toLowerCase() === store.toLowerCase()); + + if (key) { + return { + status: "VALID", + type, + name, + data: _objectSpread({ + status: "VALID", + value: store + }, registry.issuers[key]) + }; + } + + return { + status: "INVALID", + type, + name, + data: { + value: store, + status: "INVALID", + reason: { + code: OpencertsRegistryCode.INVALID_IDENTITY, + codeString: OpencertsRegistryCode[OpencertsRegistryCode.INVALID_IDENTITY], + message: `Document store ${store} not found in the registry` + } + }, + reason: { + code: OpencertsRegistryCode.INVALID_IDENTITY, + codeString: OpencertsRegistryCode[OpencertsRegistryCode.INVALID_IDENTITY], + message: `Document store ${store} not found in the registry` + } + }; +}; + +const registryVerifier = { + test: document => { + if ((0, _oaVerify.isWrappedV3Document)(document)) { + const documentData = (0, _openAttestation.getData)(document); + return documentData.proof.method === _openAttestation.v3.Method.DocumentStore; + } + + const documentData = (0, _openAttestation.getData)(document); + return documentData.issuers.some(issuer => "documentStore" in issuer || "certificateStore" in issuer); + }, + skip: () => { + return Promise.resolve({ + status: "SKIPPED", + type, + name, + reason: { + code: OpencertsRegistryCode.SKIPPED, + codeString: OpencertsRegistryCode[OpencertsRegistryCode.SKIPPED], + message: `Document issuers doesn't have "documentStore" or "certificateStore" property or ${_openAttestation.v3.Method.DocumentStore} method` + } + }); + }, + verify: function () { + var _verify = _asyncToGenerator(function* (document, options) { + var _issuerFragments$find; + + const apiKey = options.googleApiKey || process.env.GOOGLE_API_KEY; + const spreadsheetId = "1nhhD3XvHh2Ql_hW27LNw01fC-_I6Azt_XzYiYGhkmAU"; + const range = "Registry!A:H"; + const data = yield (0, _nodeFetch.default)(`https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values/${range}?valueRenderOption=UNFORMATTED_VALUE&key=${apiKey}`).then(res => res.json()); + const registry = { + issuers: {} + }; + data.values.forEach(row => { + // 0: documentStore, 1: name, 2: displayCard, 3: website, 4: email, 5: phone, 6: logo, 7: id, 8: group + registry.issuers[row[0]] = { + name: row[1], + displayCard: /true/i.test(row[2]) + }; + + if (row[2]) { + registry.issuers[row[0]] = _objectSpread({}, registry.issuers[row[0]], { + website: row[3], + email: row[4], + phone: row[5], + logo: row[6], + id: row[7] + }); + } + }); + + if ((0, _oaVerify.isWrappedV3Document)(document)) { + const documentData = (0, _openAttestation.getData)(document); + return storeToFragment(registry, documentData.proof.value); + } + + const documentData = (0, _openAttestation.getData)(document); + const issuerFragments = documentData.issuers.map(issuer => storeToFragment(registry, issuer.documentStore || issuer.certificateStore)); // if one issuer is valid => fragment status is valid otherwise if all issuers are invalid => invalid + + const status = issuerFragments.some(fragment => fragment.status === "VALID") ? "VALID" : "INVALID"; + return { + type, + name, + status, + data: issuerFragments.map(fragment => fragment.data), + reason: (_issuerFragments$find = issuerFragments.find(fragment => fragment.reason)) === null || _issuerFragments$find === void 0 ? void 0 : _issuerFragments$find.reason + }; + }); + + function verify(_x, _x2) { + return _verify.apply(this, arguments); + } + + return verify; + }() +}; +exports.registryVerifier = registryVerifier; + +const isValid = (verificationFragments, types = ["DOCUMENT_STATUS", "DOCUMENT_INTEGRITY", "ISSUER_IDENTITY"]) => { + if (verificationFragments.length < 1) { + throw new Error("Please provide at least one verification fragment to check"); + } + + if (types.length < 1) { + throw new Error("Please provide at least one type to check"); + } + + return types.every(currentType => { + var _fragmentForDnsVerifi, _fragmentForDnsVerifi2, _fragmentForDnsVerifi3; + + const verificationFragmentsForType = verificationFragments.filter(fragment => fragment.type === currentType); // return true if at least one fragment is valid + // and all fragments are valid or skipped + + const defaultCheck = verificationFragmentsForType.some(fragment => fragment.status === "VALID") && verificationFragmentsForType.every(fragment => fragment.status === "VALID" || fragment.status === "SKIPPED"); // return defaultCheck if it's true or if type is DOCUMENT_INTEGRITY or DOCUMENT_STATUS + + if (currentType === "DOCUMENT_STATUS" || currentType === "DOCUMENT_INTEGRITY" || defaultCheck) { + return defaultCheck; + } // if default check is false and type is issuer identity we need to perform further checks + + + const fragmentForDnsVerifier = verificationFragmentsForType.find(fragment => fragment.name === "OpenAttestationDnsTxt"); + const fragmentForRegistryVerifier = verificationFragmentsForType.find(fragment => fragment.name === name); + return (fragmentForRegistryVerifier === null || fragmentForRegistryVerifier === void 0 ? void 0 : fragmentForRegistryVerifier.status) === "VALID" || // if registry fragment is valid then issuer identity is valid + (fragmentForDnsVerifier === null || fragmentForDnsVerifier === void 0 ? void 0 : (_fragmentForDnsVerifi = fragmentForDnsVerifier.data) === null || _fragmentForDnsVerifi === void 0 ? void 0 : _fragmentForDnsVerifi.status) === "VALID" || ( // otherwise if there is one issuer and it's dns entry is valid then issuer identity is valid + fragmentForDnsVerifier === null || fragmentForDnsVerifier === void 0 ? void 0 : (_fragmentForDnsVerifi2 = fragmentForDnsVerifier.data) === null || _fragmentForDnsVerifi2 === void 0 ? void 0 : (_fragmentForDnsVerifi3 = _fragmentForDnsVerifi2.every) === null || _fragmentForDnsVerifi3 === void 0 ? void 0 : _fragmentForDnsVerifi3.call(_fragmentForDnsVerifi2, d => d.status === "VALID")) // otherwise if there are multiple issuers and all of them have valid dns entry then issuer identity is valid + ; + }); +}; + +exports.isValid = isValid; +const verify = (0, _oaVerify.verificationBuilder)([..._oaVerify.openAttestationVerifiers, registryVerifier]); +exports.verify = verify; \ No newline at end of file From 7c1760133cf5dc96a3aa3296a422149ee42e29b1 Mon Sep 17 00:00:00 2001 From: Goi Jia Jian Date: Tue, 7 Jul 2020 11:24:18 +0800 Subject: [PATCH 10/11] fix: node-fetch --- src/verify.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/verify.ts b/src/verify.ts index 29bf86f..245d22d 100644 --- a/src/verify.ts +++ b/src/verify.ts @@ -6,6 +6,7 @@ import { VerificationFragmentType, VerificationManagerOptions } from "@govtechsg/oa-verify"; +import fetch from "node-fetch"; import { getData, v2, v3, WrappedDocument, utils } from "@govtechsg/open-attestation"; export interface OpenCertsVerificationManagerOptions extends VerificationManagerOptions { From 2871a5f724e24e23a94941fcc33c76e710ed36db Mon Sep 17 00:00:00 2001 From: Goi Jia Jian Date: Tue, 7 Jul 2020 11:59:10 +0800 Subject: [PATCH 11/11] fix: update dist --- dist/verify.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/verify.js b/dist/verify.js index d2d755b..9d596d3 100644 --- a/dist/verify.js +++ b/dist/verify.js @@ -75,7 +75,7 @@ const storeToFragment = (registry, store) => { const registryVerifier = { test: document => { - if ((0, _oaVerify.isWrappedV3Document)(document)) { + if (_openAttestation.utils.isWrappedV3Document(document)) { const documentData = (0, _openAttestation.getData)(document); return documentData.proof.method === _openAttestation.v3.Method.DocumentStore; } @@ -124,7 +124,7 @@ const registryVerifier = { } }); - if ((0, _oaVerify.isWrappedV3Document)(document)) { + if (_openAttestation.utils.isWrappedV3Document(document)) { const documentData = (0, _openAttestation.getData)(document); return storeToFragment(registry, documentData.proof.value); }