diff --git a/package-lock.json b/package-lock.json index 9eb61bd1..14b2ac2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0-development", "license": "Apache-2.0", "dependencies": { - "@govtechsg/dnsprove": "^2.6.2", + "@govtechsg/dnsprove": "^2.8.0", "@govtechsg/open-attestation": "^6.10.0-beta.3", "axios": "^1.6.2", "debug": "^4.3.1", @@ -3511,13 +3511,13 @@ } }, "node_modules/@govtechsg/dnsprove": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@govtechsg/dnsprove/-/dnsprove-2.6.2.tgz", - "integrity": "sha512-BVqvHAvUg863a7F29oT1TVYAWsXHztlaxAlRmRunStbsmPYaw9CNasE7PUDxfJ8V8fL5J1smqJ6SCdxBmAG0+w==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@govtechsg/dnsprove/-/dnsprove-2.8.0.tgz", + "integrity": "sha512-QfusJBiKnw1kdOEAW1TgdwpU29Fq1sEwtWWz8UkgkZJbqZJE9cm6mraah3VoDCTe2ljzJd/Tjx0sC2zl421cJQ==", "dependencies": { - "axios": "^1.6.1", + "axios": "^1.6.3", "debug": "^4.3.1", - "runtypes": "^6.3.0" + "runtypes": "^6.7.0" } }, "node_modules/@govtechsg/document-store-ethers-v5": { @@ -6130,11 +6130,11 @@ } }, "node_modules/axios": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", - "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", "dependencies": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -9416,9 +9416,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", diff --git a/package.json b/package.json index aee4686a..d5d3f832 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "@govtechsg/dnsprove": "^2.6.2", + "@govtechsg/dnsprove": "^2.8.0", "@govtechsg/open-attestation": "^6.10.0-beta.3", "axios": "^1.6.2", "debug": "^4.3.1", diff --git a/src/common/utils.ts b/src/common/utils.ts index c6e9c7fe..59bb66e8 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -40,7 +40,7 @@ export const getDefaultProvider = (options: VerificationBuilderOptionsWithNetwor // getProvider is a function to get an existing provider or to get a Default provider, when given the options export const getProvider = (options: VerificationBuilderOptions): providers.Provider => { - return options.provider ?? getDefaultProvider(options); + return options.provider ?? getDefaultProvider(options as VerificationBuilderOptionsWithNetwork); }; /** diff --git a/src/types/core.ts b/src/types/core.ts index 5448f9d8..1bc60feb 100644 --- a/src/types/core.ts +++ b/src/types/core.ts @@ -1,4 +1,5 @@ import { WrappedDocument, SignedWrappedDocument, v2, v3, v4 } from "@govtechsg/open-attestation"; +import type { CustomDnsResolver } from "@govtechsg/dnsprove"; import { Resolver } from "did-resolver"; import { providers } from "ethers"; import { Reason } from "./error"; @@ -8,23 +9,36 @@ import { Reason } from "./error"; */ export type PromiseCallback = (promises: Promise[]) => void; -export interface VerificationBuilderOptionsWithProvider { +export type CustomDnsResolverOption = { + dnsResolvers?: CustomDnsResolver[]; +}; + +export type VerificationBuilderOptionsWithProvider = { provider: providers.Provider; resolver?: Resolver; -} +} & CustomDnsResolverOption; -export interface VerificationBuilderOptionsWithNetwork { +export type VerificationBuilderOptionsWithNetwork = { network: string; resolver?: Resolver; provider?: never; -} +} & CustomDnsResolverOption; -export type VerificationBuilderOptions = VerificationBuilderOptionsWithProvider | VerificationBuilderOptionsWithNetwork; +export type VerificationBuilderOptionsDnsDid = { + resolver?: Resolver; + network?: never; + provider?: never; +} & CustomDnsResolverOption; + +export type VerificationBuilderOptions = + | VerificationBuilderOptionsWithProvider + | VerificationBuilderOptionsWithNetwork + | VerificationBuilderOptionsDnsDid; -export interface VerifierOptions { +export type VerifierOptions = { provider: providers.Provider; resolver?: Resolver; -} +} & CustomDnsResolverOption; /** * A verification fragment is the result of a verification diff --git a/src/verifiers/issuerIdentity/dnsDid/dnsDidProof.ts b/src/verifiers/issuerIdentity/dnsDid/dnsDidProof.ts index 70b93987..ead476dc 100644 --- a/src/verifiers/issuerIdentity/dnsDid/dnsDidProof.ts +++ b/src/verifiers/issuerIdentity/dnsDid/dnsDidProof.ts @@ -1,6 +1,6 @@ import { getData, utils, v2, v3, v4 } from "@govtechsg/open-attestation"; -import { getDnsDidRecords } from "@govtechsg/dnsprove"; -import { VerificationFragmentType, Verifier } from "../../../types/core"; +import { CustomDnsResolver, getDnsDidRecords } from "@govtechsg/dnsprove"; +import { VerificationFragmentType, Verifier, VerifierOptions } from "../../../types/core"; import { OpenAttestationDnsDidCode } from "../../../types/error"; import { withCodedErrorHandler } from "../../../common/errorHandler"; import { CodedError } from "../../../common/error"; @@ -43,11 +43,13 @@ const test: VerifierType["test"] = (document) => { const verifyIssuerDnsDid = async ({ key, location, + dnsResolvers, }: { key: string; location: string; + dnsResolvers?: CustomDnsResolver[]; }): Promise => { - const records = await getDnsDidRecords(location); + const records = await getDnsDidRecords(location, dnsResolvers); return { location, key, @@ -56,7 +58,8 @@ const verifyIssuerDnsDid = async ({ }; const verifyV2 = async ( - document: v2.SignedWrappedDocument + document: v2.SignedWrappedDocument, + options?: VerifierOptions ): Promise => { const documentData = getData(document); const deferredVerificationStatus: Promise[] = documentData.issuers.map((issuer) => { @@ -86,7 +89,7 @@ const verifyV2 = async ( OpenAttestationDnsDidCode.MALFORMED_IDENTITY_PROOF, OpenAttestationDnsDidCode[OpenAttestationDnsDidCode.MALFORMED_IDENTITY_PROOF] ); - return verifyIssuerDnsDid({ key, location }); + return verifyIssuerDnsDid({ key, location, dnsResolvers: options?.dnsResolvers }); }); const verificationStatus = await Promise.all(deferredVerificationStatus); @@ -113,7 +116,8 @@ const verifyV2 = async ( }; const verifyV3 = async ( - document: v3.SignedWrappedDocument + document: v3.SignedWrappedDocument, + options?: VerifierOptions ): Promise => { if (!utils.isSignedWrappedV3Document(document)) throw new CodedError( @@ -123,7 +127,7 @@ const verifyV3 = async ( ); const location = document.openAttestationMetadata.identityProof.identifier; const { key } = document.proof; - const verificationStatus = await verifyIssuerDnsDid({ key, location }); + const verificationStatus = await verifyIssuerDnsDid({ key, location, dnsResolvers: options?.dnsResolvers }); if (ValidDnsDidVerificationStatus.guard(verificationStatus)) { return { @@ -147,7 +151,8 @@ const verifyV3 = async ( }; const verifyV4 = async ( - document: v4.SignedWrappedDocument + document: v4.SignedWrappedDocument, + options?: VerifierOptions ): Promise => { if (!utils.isSignedWrappedV4Document(document)) throw new CodedError( @@ -157,7 +162,7 @@ const verifyV4 = async ( ); const location = document.issuer.identityProof.identifier; const { key } = document.proof; - const verificationStatus = await verifyIssuerDnsDid({ key, location }); + const verificationStatus = await verifyIssuerDnsDid({ key, location, dnsResolvers: options?.dnsResolvers }); if (ValidDnsDidVerificationStatus.guard(verificationStatus)) { return { @@ -180,10 +185,10 @@ const verifyV4 = async ( }; }; -const verify: VerifierType["verify"] = async (document) => { - if (utils.isSignedWrappedV2Document(document)) return verifyV2(document); - else if (utils.isSignedWrappedV3Document(document)) return verifyV3(document); - else if (utils.isSignedWrappedV4Document(document)) return verifyV4(document); +const verify: VerifierType["verify"] = async (document, options) => { + if (utils.isSignedWrappedV2Document(document)) return verifyV2(document, options); + else if (utils.isSignedWrappedV3Document(document)) return verifyV3(document, options); + else if (utils.isSignedWrappedV4Document(document)) return verifyV4(document, options); throw new CodedError( "Document does not match either v2, v3 or v4 formats. Consider using `utils.diagnose` from open-attestation to find out more.", OpenAttestationDnsDidCode.UNRECOGNIZED_DOCUMENT, diff --git a/src/verifiers/issuerIdentity/dnsTxt/openAttestationDnsTxt.ts b/src/verifiers/issuerIdentity/dnsTxt/openAttestationDnsTxt.ts index 4a5b68ba..4afeca4e 100644 --- a/src/verifiers/issuerIdentity/dnsTxt/openAttestationDnsTxt.ts +++ b/src/verifiers/issuerIdentity/dnsTxt/openAttestationDnsTxt.ts @@ -28,7 +28,7 @@ const resolveIssuerIdentity = async ( options: VerifierOptions ): Promise => { const network = await options.provider.getNetwork(); - const records = await getDocumentStoreRecords(location); + const records = await getDocumentStoreRecords(location, options.dnsResolvers); const matchingRecord = records.find( (record) => record.addr.toLowerCase() === smartContractAddress.toLowerCase() && diff --git a/src/verifiers/verificationBuilder.ts b/src/verifiers/verificationBuilder.ts index e1a3c3e0..3f61a4c3 100644 --- a/src/verifiers/verificationBuilder.ts +++ b/src/verifiers/verificationBuilder.ts @@ -32,6 +32,7 @@ export const verificationBuilder = const verifierOptions: VerifierOptions = { provider: getProvider(builderOptions), resolver: builderOptions.resolver, + dnsResolvers: builderOptions.dnsResolvers, }; const promises = verifiers.map((verifier) => { if (verifier.test(document, verifierOptions)) {