From e1bcebff4e1afc62bb61f6bc7e19f33403b1805f Mon Sep 17 00:00:00 2001 From: cavacado Date: Mon, 11 Sep 2023 14:58:40 +0800 Subject: [PATCH] chore: v4 compatibility --- .../DocumentStatus/DocumentStatus.tsx | 17 +++++-- src/test/fixture/did/v4/did-signed.json | 50 +++++++++++++++++++ src/utils/shared.test.ts | 13 ++++- src/utils/shared.ts | 16 ++++-- 4 files changed, 87 insertions(+), 9 deletions(-) create mode 100644 src/test/fixture/did/v4/did-signed.json diff --git a/src/components/DocumentStatus/DocumentStatus.tsx b/src/components/DocumentStatus/DocumentStatus.tsx index bb0877d6b..0f3b34f48 100644 --- a/src/components/DocumentStatus/DocumentStatus.tsx +++ b/src/components/DocumentStatus/DocumentStatus.tsx @@ -2,7 +2,7 @@ import { VerificationFragment, VerificationFragmentWithData, utils } from "@govt import React, { FunctionComponent } from "react"; import { StatusChecks } from "./StatusChecks"; import { useSelector } from "react-redux"; -import { utils as oaUtils, WrappedDocument, v3 } from "@govtechsg/open-attestation"; +import { utils as oaUtils, WrappedDocument, v3, v4 } from "@govtechsg/open-attestation"; import { RootState } from "../../reducers"; import { WrappedOrSignedOpenAttestationDocument } from "../../utils/shared"; @@ -49,6 +49,10 @@ export const getV3IdentityVerificationText = (document: WrappedDocument): string => { + return document.issuer.id.toUpperCase(); +}; + interface IssuedByProps { title?: string; verificationStatus: VerificationFragment[]; @@ -56,9 +60,14 @@ interface IssuedByProps { } export const IssuedBy: FunctionComponent = ({ title = "Issued by", verificationStatus, document }) => { - const formattedDomainNames = oaUtils.isWrappedV2Document(document) - ? getV2FormattedDomainNames(verificationStatus) - : getV3IdentityVerificationText(document); + let formattedDomainNames; + if (oaUtils.isWrappedV2Document(document)) { + formattedDomainNames = getV2FormattedDomainNames(verificationStatus); + } else if (oaUtils.isWrappedV3Document(document)) { + formattedDomainNames = getV3IdentityVerificationText(document); + } else { + formattedDomainNames = getV4IdentityVerificationText(document); + } return (

{title} diff --git a/src/test/fixture/did/v4/did-signed.json b/src/test/fixture/did/v4/did-signed.json new file mode 100644 index 000000000..f2efde6d6 --- /dev/null +++ b/src/test/fixture/did/v4/did-signed.json @@ -0,0 +1,50 @@ +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schemata.openattestation.com/com/openattestation/4.0/alpha-context.json" + ], + "type": ["VerifiableCredential", "OpenAttestationCredential"], + "validFrom": "2021-03-08T12:00:00+08:00", + "name": "Republic of Singapore Driving Licence", + "issuer": { + "id": "did:ethr:0xB26B4941941C51a4885E5B7D3A1B861E54405f90", + "type": "OpenAttestationIssuer", + "name": "Government Technology Agency of Singapore (GovTech)", + "identityProof": { "identityProofType": "DNS-DID", "identifier": "example.openattestation.com" } + }, + "credentialStatus": { "type": "OpenAttestationCredentialStatus", "credentialStatusType": "NONE" }, + "renderMethod": { + "type": "OpenAttestationRenderMethod", + "renderMethodType": "EMBEDDED_RENDERER", + "name": "GOVTECH_DEMO", + "url": "https://demo-renderer.openattestation.com" + }, + "credentialSubject": { + "id": "urn:uuid:a013fb9d-bb03-4056-b696-05575eceaf42", + "type": ["DriversLicense"], + "name": "John Doe", + "licenses": [ + { + "class": "3", + "description": "Motor cars with unladen weight <= 3000kg", + "effectiveDate": "2013-05-16T00:00:00+08:00" + }, + { + "class": "3A", + "description": "Motor cars with unladen weight <= 3000kg", + "effectiveDate": "2013-05-16T00:00:00+08:00" + } + ] + }, + "proof": { + "type": "OpenAttestationMerkleProofSignature2018", + "proofPurpose": "assertionMethod", + "targetHash": "adb16863b9b92f1f46d67f518f853092404dc1322ffb61b45a831ee113f4ea99", + "proofs": [], + "merkleRoot": "adb16863b9b92f1f46d67f518f853092404dc1322ffb61b45a831ee113f4ea99", + "salts": "W3sidmFsdWUiOiJkYTlkMTE5MTMxOWRjOTM4ZTQ2ZjZhYmMzMjU1NTM5NGYwYzEzNDIyMGUwYjgyMDY0NzBhYjlmNmYxN2QyZTJlIiwicGF0aCI6IkBjb250ZXh0WzBdIn0seyJ2YWx1ZSI6IjhhZDM5Njg2NGIwNGI5ZjYxY2I3ODNjY2M1YWEyNTYxODgxYmRiODZmZmI5ZmNjZjViYTQ1YzUyN2MwZGFmMGMiLCJwYXRoIjoiQGNvbnRleHRbMV0ifSx7InZhbHVlIjoiMjYwNDllNWExODQ4MDVlYTUxNjQ4OTM3OGI0NDZhNTdiMjdlZWU0YmFhN2VmYjBkNWM3OTcwMGMzZDI5OGM5MyIsInBhdGgiOiJ0eXBlWzBdIn0seyJ2YWx1ZSI6IjU3N2M2ZGUzMzYzZmE1ZjA2ZDc5NjQyMjAxNTk3ODkzYzdmNDg3NWZlYzFiZTYyOWIxZWRkNTdhZWFlOTE3YzkiLCJwYXRoIjoidHlwZVsxXSJ9LHsidmFsdWUiOiI0NmMyOTY5MTVkZWVhNDMwMDNmY2ZmNjc3NzUxNTc3Zjg2MTdlODliYjBjNDhiNzIwMTdlMzRkOWNhNTM0ZGNlIiwicGF0aCI6InZhbGlkRnJvbSJ9LHsidmFsdWUiOiIwZWQ1Yzg0OTBlYjg2YWM5YmEyNGJlYzc3OTE2MThhZWZjZGE2M2M3OGNmZDJlMTdjMWNlNDRmNzVmZjU3NjljIiwicGF0aCI6Im5hbWUifSx7InZhbHVlIjoiMzEyNGUxNzc4Y2EzYTc2ZmI0MjUxNGExMmIzNDYzYmY4ZmY4NjNiNDdiZTExNDYyY2RiMGRiNzRmMzk1ZjViYiIsInBhdGgiOiJpc3N1ZXIuaWQifSx7InZhbHVlIjoiYTJmNTJhNTdmMWM5MDJhYzQ5MmJiNzc0YTQzOTIxYjk2NWJlM2VmZjRjNTBjMDhiNDhhNjJkOGZkNjNhMWQ1NCIsInBhdGgiOiJpc3N1ZXIudHlwZSJ9LHsidmFsdWUiOiI0NGZhZWFhNmIxYmZlZmI0NGM4NzJlYzI2Nzc4OWNkNzUwM2U3YTQ1YjZjMDdmMmE0MmJkMDE5OWU1NzI0ZjM1IiwicGF0aCI6Imlzc3Vlci5uYW1lIn0seyJ2YWx1ZSI6IjJjNzg1Y2NhOGMyODdhZjhmOGM1NWM4MmJkODI3ZGY4M2YyZDIxY2M4MTVhZWJlYTg5MmVjOTZmNGRmMzVkNzAiLCJwYXRoIjoiaXNzdWVyLmlkZW50aXR5UHJvb2YuaWRlbnRpdHlQcm9vZlR5cGUifSx7InZhbHVlIjoiOWM0OWNiOGQ1Njc2NjljOTEzMDEwYzE3MmI2YmM5N2Q4MTVlOWZlOGY3Mjg2ZWE0NzA3NWVhNDQxYzc4NmYwMyIsInBhdGgiOiJpc3N1ZXIuaWRlbnRpdHlQcm9vZi5pZGVudGlmaWVyIn0seyJ2YWx1ZSI6IjJjZDcxMmFlZTdjZDlkZmI1NjBmYzBjNWVjZmZhY2FkYzkzYmYzZmI1MGRhYTgyYTk2ZTQzYjA5OGU2OTg4YTEiLCJwYXRoIjoiY3JlZGVudGlhbFN0YXR1cy50eXBlIn0seyJ2YWx1ZSI6ImM4MmUwNmU1NWI1YTY2YmUwNTk5NjVjZDI5YTUzZWE1ODg0YjM3NjU0NWE4ZmMwMzNiMTEwNWE0MzMyMWI5ZjAiLCJwYXRoIjoiY3JlZGVudGlhbFN0YXR1cy5jcmVkZW50aWFsU3RhdHVzVHlwZSJ9LHsidmFsdWUiOiJiNzBkMTU5MmU4ZTk3NDlkNGU5ZTEzNjg5NTgxNjhlY2MxZWQ2ODE5NWQzMmE4YmI1MDdlOTc3NGU3ZjkxMGFlIiwicGF0aCI6InJlbmRlck1ldGhvZC50eXBlIn0seyJ2YWx1ZSI6IjIxMGI0NGNjYTdmYzZkOTY4ZDk2ZmVjZWY3MGQzNTU1ZDY5MjViYWEwNjA4ZTczMDM3YjBiOGI5Njc4MTQ0ZGEiLCJwYXRoIjoicmVuZGVyTWV0aG9kLnJlbmRlck1ldGhvZFR5cGUifSx7InZhbHVlIjoiODQyZDBhZTQ1ZTI5N2U1YzgyMmJhZWVjMGMxNDg5MGYyNzkwZjNhNzY1M2JkMTAwNzI5YWJiNTM5NzAxMGY3NCIsInBhdGgiOiJyZW5kZXJNZXRob2QubmFtZSJ9LHsidmFsdWUiOiI4ZDIyYmIwMzJlMjg1N2RlYTk3NDU4ZWZmMjQ5ODgxZGZiZmE2MmUxNDU0MzBkZTdmNWIzZThkNWM5NGVjNmY4IiwicGF0aCI6InJlbmRlck1ldGhvZC51cmwifSx7InZhbHVlIjoiNGJiNWMyMzliNzBmZmI2NDkwYmY4MmQwZTBjODQ3ZWE0YWIyYTQyYWU1MmZjMDljZjA0ZjFiMTg1YjQ5ODFmMyIsInBhdGgiOiJjcmVkZW50aWFsU3ViamVjdC5pZCJ9LHsidmFsdWUiOiJkOGJmNmI3NzRlNjY0MGU2MWIwMmY4MmIzNTM5Y2RhMjdjODkyNmVlNjI0ZDE1ODZlOTZlMzhjZjNkMWQ0MjY1IiwicGF0aCI6ImNyZWRlbnRpYWxTdWJqZWN0LnR5cGVbMF0ifSx7InZhbHVlIjoiYTViNjg5NThkOTNiZmM3Y2M0ZDYzM2IxODViZTRlZGNmMGFmZTkwOGRhYjIwOTI3N2RhOGQ3Nzg2ZTc0MjQ3ZCIsInBhdGgiOiJjcmVkZW50aWFsU3ViamVjdC5uYW1lIn0seyJ2YWx1ZSI6IjNlMjUyNTkwMmI1MDY3ZjZiMjNhZGFjYmNmMzdiOTBjNTY1N2ViZWY1ZTQwZmQ2ZTNlMGM1N2QyYjBhODFlMmYiLCJwYXRoIjoiY3JlZGVudGlhbFN1YmplY3QubGljZW5zZXNbMF0uY2xhc3MifSx7InZhbHVlIjoiODViZDZjYzhkODI4OTRlNWI0OGQ2NmI5ZTM2NGU4MTRhMzIxMWM4ODI0NGVhNmFlZDhkZTYzNWQ1YmFhODljMCIsInBhdGgiOiJjcmVkZW50aWFsU3ViamVjdC5saWNlbnNlc1swXS5kZXNjcmlwdGlvbiJ9LHsidmFsdWUiOiJiZWRlZDA0Yjk1MDEzZjBkNjgzZjZmNGI1YmI2ZDBjNjRjMDM0MjUxYjYwOWQwOTNkZGM0ZDE0Njg2MWJkMjVlIiwicGF0aCI6ImNyZWRlbnRpYWxTdWJqZWN0LmxpY2Vuc2VzWzBdLmVmZmVjdGl2ZURhdGUifSx7InZhbHVlIjoiYzQ2ZTBhMzkyYTExMmM1NjRkNDdmODQ5NmFhMGRiYmZmZTg1NGEwNDQxODAxZmYxNzYyNzBiYmMyYmUxN2MwOSIsInBhdGgiOiJjcmVkZW50aWFsU3ViamVjdC5saWNlbnNlc1sxXS5jbGFzcyJ9LHsidmFsdWUiOiJjMGYzMWI2MGYyMjVkZTg1M2YzNzAyYzk4Y2E1OTk0Y2EzNTcyNmUwZTAyNGZkNzRkMWUwZTM1NzZiYjRhNmZlIiwicGF0aCI6ImNyZWRlbnRpYWxTdWJqZWN0LmxpY2Vuc2VzWzFdLmRlc2NyaXB0aW9uIn0seyJ2YWx1ZSI6IjY0YTUxYjRkMmE3OWMyZTI5NTdkOTg0MDkwN2Q3MGEzMzY4NDRiN2QyYzNlNmE5NDk3NzY1NGUwM2RkMzk1ZWMiLCJwYXRoIjoiY3JlZGVudGlhbFN1YmplY3QubGljZW5zZXNbMV0uZWZmZWN0aXZlRGF0ZSJ9XQ==", + "privacy": { "obfuscated": [] }, + "key": "did:ethr:0xB26B4941941C51a4885E5B7D3A1B861E54405f90#controller", + "signature": "0xf5743ee83429b0ff71ca40d61f59b9c26f1fc220c2e9a4620bc73128acc0bb2b74764c561058327b19c6992ae6c2a543dd40c7c7e359df48a209477e3cea5bbe1c" + } +} diff --git a/src/utils/shared.test.ts b/src/utils/shared.test.ts index 7fcc8f21c..511962b79 100644 --- a/src/utils/shared.test.ts +++ b/src/utils/shared.test.ts @@ -1,8 +1,9 @@ import v3DID from "../test/fixture/did/dns-did-signed.json"; import v2DID from "../test/fixture/did/dns-did-verified.json"; +import v4DID from "../test/fixture/did/v4/did-signed.json"; import invoiceV2 from "../test/fixture/local/v2/invoice.json"; import invoiceV3 from "../test/fixture/local/v3/invoice.json"; -import { getChainId, WrappedOrSignedOpenAttestationDocument } from "./shared"; +import { getAttachments, getChainId, getTemplateUrl, WrappedOrSignedOpenAttestationDocument } from "./shared"; describe("getChainId for v2 document", () => { it("should return the correct chainId for sepolia", () => { @@ -115,3 +116,13 @@ describe("getChainId for v3 document", () => { expect(getChainId(v3DID as unknown as WrappedOrSignedOpenAttestationDocument)).toStrictEqual(undefined); }); }); + +describe("getTemplateUrl for v4", () => { + expect(getTemplateUrl(v4DID as WrappedOrSignedOpenAttestationDocument)).toBe( + "https://demo-renderer.openattestation.com" + ); +}); + +describe("getAttachments for v4", () => { + expect(getAttachments(v4DID as WrappedOrSignedOpenAttestationDocument)).toStrictEqual([]); +}); diff --git a/src/utils/shared.ts b/src/utils/shared.ts index 2bce7c1c4..ac707530f 100644 --- a/src/utils/shared.ts +++ b/src/utils/shared.ts @@ -14,8 +14,10 @@ export const getTemplateUrl = (rawDocument: WrappedOrSignedOpenAttestationDocume if (utils.isWrappedV2Document(rawDocument)) { const documentData = getData(rawDocument); return typeof documentData.$template === "object" ? documentData.$template.url : undefined; - } else { + } else if (utils.isWrappedV3Document(rawDocument)) { return rawDocument.openAttestationMetadata.template?.url; + } else { + return rawDocument.renderMethod?.url; } }; @@ -23,7 +25,7 @@ export const getAttachments = (rawDocument: WrappedOrSignedOpenAttestationDocume if (utils.isWrappedV2Document(rawDocument)) { const documentData = getData(rawDocument); return documentData.attachments; - } else { + } else if (utils.isWrappedV3Document(rawDocument)) { return rawDocument.attachments?.map((attachment: v3.Attachment) => { return { data: attachment.data, @@ -31,6 +33,9 @@ export const getAttachments = (rawDocument: WrappedOrSignedOpenAttestationDocume type: attachment.mimeType, }; }); + } else { + // attachments not included in v4 schema for now. + return []; } }; @@ -44,7 +49,7 @@ export const getChainId = (rawDocument: WrappedOrSignedOpenAttestationDocument): throw new Error("Invalid Document, please use a valid document."); }; - const processChainId = (document: OpenAttestationDocument): number | undefined => { + function processChainId(document: v2.OpenAttestationDocument | v3.OpenAttestationDocument): number | undefined { if (document.network) { // Check for current blockchain, "ETH" or "MATIC", and chainId, if need cater for other blockchain and network, update this accordingly. if (AvailableBlockChains.includes(document.network.chain) && document.network.chainId) { @@ -60,7 +65,7 @@ export const getChainId = (rawDocument: WrappedOrSignedOpenAttestationDocument): "You are using an older version of Open-Attestation Document, to use the auto network feature, please use an updated version. Otherwise, please make sure that you select the correct network." ); return undefined; - }; + } if (utils.isWrappedV2Document(rawDocument)) { const documentData = getData(rawDocument); @@ -73,5 +78,8 @@ export const getChainId = (rawDocument: WrappedOrSignedOpenAttestationDocument): const identityProofType = rawDocument.openAttestationMetadata.identityProof.type; if (identityProofType === "DNS-DID" || identityProofType === "DID") return undefined; return processChainId(rawDocument); + } else { + // for now v4 is only DID method so ignore chainID + return undefined; } };