From 178a64ed72b06bc7660589b35efa0f6de873fbf0 Mon Sep 17 00:00:00 2001 From: Sam Hellawell Date: Fri, 10 Nov 2023 16:52:51 +0000 Subject: [PATCH 1/2] Remove Axios in favor of fetch Signed-off-by: Sam Hellawell --- package.json | 3 +- src/modules/schema.js | 4 +-- src/resolver/did/universal-resolver.js | 8 +++--- src/utils/json-fetch.js | 28 +++++++++++++++++++ src/utils/vc/document-loader.js | 4 +-- tests/cached-document-loader.js | 4 +-- ...g-and-presentation-with-2-subjects.test.js | 6 ++-- tests/integration/issuing.test.js | 6 ++-- tests/mocks/axios.js | 17 ----------- tests/mocks/fetch.js | 27 ++++++++++++++++++ tests/unit/issuing.test.js | 6 ++-- tests/unit/presigned-validation.test.js | 6 ++-- tests/unit/schema.test.js | 2 +- yarn.lock | 10 +------ 14 files changed, 80 insertions(+), 51 deletions(-) create mode 100644 src/utils/json-fetch.js delete mode 100644 tests/mocks/axios.js create mode 100644 tests/mocks/fetch.js diff --git a/package.json b/package.json index fc45a6769..a13add5bc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@docknetwork/sdk", - "version": "6.8.0", + "version": "6.8.1", "main": "index.js", "license": "MIT", "repository": { @@ -104,7 +104,6 @@ "@juanelas/base64": "^1.0.5", "@polkadot/api": "9.7.1", "@transmute/json-web-signature": "^0.7.0-unstable.80", - "axios": "0.27.2", "base64url": "3.0.1", "blake2b": "2.1.4", "bs58": "5.0.0", diff --git a/src/modules/schema.js b/src/modules/schema.js index a1fc56cf9..6470fadf5 100644 --- a/src/modules/schema.js +++ b/src/modules/schema.js @@ -1,6 +1,5 @@ import { canonicalize } from 'json-canonicalize'; import { validate } from 'jsonschema'; -import axios from 'axios'; import { hexDIDToQualified } from '../utils/did'; import { getSignatureFromKeyringPair } from '../utils/misc'; @@ -12,6 +11,7 @@ import { // Supported schemas import JSONSchema07 from '../utils/vc/schemas/schema-draft-07'; +import jsonFetch from '../utils/json-fetch'; export default class Schema { /** @@ -165,7 +165,7 @@ export default class Schema { return JSONSchema07; } // Fetch the URI and expect a JSON response - const { data: doc } = await axios.get(schemaUrl); + const doc = await jsonFetch(schemaUrl); if (typeof doc === 'object') { return doc; } diff --git a/src/resolver/did/universal-resolver.js b/src/resolver/did/universal-resolver.js index 19b06cadb..8707629ef 100644 --- a/src/resolver/did/universal-resolver.js +++ b/src/resolver/did/universal-resolver.js @@ -1,6 +1,6 @@ -import axios from 'axios'; import { NoDIDError } from '../../utils/did'; import { Resolver, WILDCARD } from '../generic'; +import jsonFetch from '../../utils/json-fetch'; /** * Resolves `DID`s with wildcard method: `did:*:`. @@ -36,7 +36,7 @@ export default class UniversalResolver extends Resolver { hashIndex === -1 ? did : did.slice(0, hashIndex).trim(), ); try { - const resp = await axios.get(`${this.idUrl}${encodedDid}`, { + const resp = await jsonFetch(`${this.idUrl}${encodedDid}`, { headers: { Accept: 'application/ld+json;profile="https://w3id.org/did-resolution"', @@ -44,9 +44,9 @@ export default class UniversalResolver extends Resolver { }); // Sometimes didDocument doesnt exist, if so return data as document - return resp.data.didDocument || resp.data; + return resp.didDocument || resp; } catch (error) { - if (error.isAxiosError) { + if (error.statusCode === 404) { throw new NoDIDError(did); } diff --git a/src/utils/json-fetch.js b/src/utils/json-fetch.js new file mode 100644 index 000000000..b6f058494 --- /dev/null +++ b/src/utils/json-fetch.js @@ -0,0 +1,28 @@ +export class JSONFetchError extends Error { + constructor(message, statusCode) { + super(message); + + this.statusCode = statusCode; + } +} + +export default async function jsonFetch(url, options) { + let response; + try { + response = await fetch(url, options); + } catch (e) { + throw new Error(`Fetch failed for URL: ${url}`); + } + if (response.ok) { + let doc; + try { + doc = await response.json(); + } catch (e) { + throw new Error(`URL: ${url} is not JSON`); + } + return doc; + } else { + // Handle the case when the fetch request fails (e.g., non-2xx response status) + throw new JSONFetchError('Failed to fetch data', response.status); + } +} diff --git a/src/utils/vc/document-loader.js b/src/utils/vc/document-loader.js index d651d9507..6199071a6 100644 --- a/src/utils/vc/document-loader.js +++ b/src/utils/vc/document-loader.js @@ -1,6 +1,6 @@ -import axios from 'axios'; import cachedUris from './contexts'; import Resolver from "../../resolver/generic/resolver"; // eslint-disable-line +import jsonFetch from '../json-fetch'; function parseEmbeddedDataURI(embedded) { // Strip new lines @@ -63,7 +63,7 @@ function documentLoader(resolver = null) { if (cachedData) { document = cachedData; } else { - const { data: doc } = await axios.get(uriString); + const doc = await jsonFetch(uriString); cachedUris.set(cacheKey, doc); document = doc; } diff --git a/tests/cached-document-loader.js b/tests/cached-document-loader.js index a865b1cf4..32a7ba081 100644 --- a/tests/cached-document-loader.js +++ b/tests/cached-document-loader.js @@ -1,6 +1,6 @@ -import axios from 'axios'; import contexts from '../src/utils/vc/contexts'; import network_cache from './network-cache'; +import jsonFetch from '../src/utils/json-fetch'; // global document cache, replaces the internet and acts as a did method const documentRegistry = {}; @@ -17,7 +17,7 @@ export async function documentLoader(url) { if (!(url.startsWith('http://') || url.startsWith('https://'))) { throw new Error(`failed to resolve ${url}`); } - documentRegistry[url] = (await axios.get(url)).data; + documentRegistry[url] = await jsonFetch(url); console.warn( 'Unit test is making web requests. This is slow. Please update ./test/network-cache.js', 'with: ', diff --git a/tests/integration/issuing-and-presentation-with-2-subjects.test.js b/tests/integration/issuing-and-presentation-with-2-subjects.test.js index 4149b365f..7fa99e6d0 100644 --- a/tests/integration/issuing-and-presentation-with-2-subjects.test.js +++ b/tests/integration/issuing-and-presentation-with-2-subjects.test.js @@ -1,7 +1,7 @@ -// Mock axios +// Mock fetch import { randomAsHex } from '@polkadot/util-crypto'; import jsonld from 'jsonld'; -import mockAxios from '../mocks/axios'; +import mockFetch from '../mocks/fetch'; import { createNewDockDID, @@ -18,7 +18,7 @@ import { import { getKeyDoc } from '../../src/utils/vc/helpers'; import { createPresentation } from '../create-presentation'; -mockAxios(); +mockFetch(); // DID and seed for const issuerDID = createNewDockDID(); diff --git a/tests/integration/issuing.test.js b/tests/integration/issuing.test.js index ca696eb3f..85fd1b675 100644 --- a/tests/integration/issuing.test.js +++ b/tests/integration/issuing.test.js @@ -1,6 +1,6 @@ -// Mock axios +// Mock fetch import { randomAsHex } from '@polkadot/util-crypto'; -import mockAxios from '../mocks/axios'; +import mockFetch from '../mocks/fetch'; import { createNewDockDID } from '../../src/utils/did'; @@ -15,7 +15,7 @@ import { generateEcdsaSecp256k1Keypair } from '../../src/utils/misc'; import { issueCredential, verifyCredential } from '../../src/utils/vc/index'; import { getKeyDoc } from '../../src/utils/vc/helpers'; -mockAxios(); +mockFetch(); // 1st issuer's DID. const issuer1DID = createNewDockDID(); diff --git a/tests/mocks/axios.js b/tests/mocks/axios.js deleted file mode 100644 index 11d4d8171..000000000 --- a/tests/mocks/axios.js +++ /dev/null @@ -1,17 +0,0 @@ -import axios from 'axios'; -import networkCache from '../network-cache'; - -jest.mock('axios'); - -export default function mockAxios() { - axios.get.mockImplementation(async (url) => { - if (networkCache[url]) { - return { - data: networkCache[url], - }; - } - - console.error(`Test should cache this URL: ${url}`); - throw new Error(`Test should cache this URL: ${url}`); - }); -} diff --git a/tests/mocks/fetch.js b/tests/mocks/fetch.js new file mode 100644 index 000000000..2c34f21f5 --- /dev/null +++ b/tests/mocks/fetch.js @@ -0,0 +1,27 @@ +import networkCache from '../network-cache'; + +// Mock the global fetch function +global.fetch = jest.fn(); + +// Function to set up a mock response for fetch +const mockFetchResponse = (status, data) => { + const response = new Response(JSON.stringify(data), { + status, + headers: { + 'Content-type': 'application/json', + }, + }); + return Promise.resolve(response); +}; + +export default function mockFetch() { + // Set up a mock response for all GET requests + fetch.mockImplementation((url) => { + if (networkCache[url]) { + return mockFetchResponse(200, networkCache[url]); + } + + console.error(`Test should cache this URL: ${url}`); + throw new Error(`Test should cache this URL: ${url}`); + }); +} diff --git a/tests/unit/issuing.test.js b/tests/unit/issuing.test.js index f96bff8e4..010262921 100644 --- a/tests/unit/issuing.test.js +++ b/tests/unit/issuing.test.js @@ -1,5 +1,5 @@ -// Mock axios -import mockAxios from '../mocks/axios'; +// Mock fetch +import mockFetch from '../mocks/fetch'; import { issueCredential, @@ -12,7 +12,7 @@ import VerifiableCredential from '../../src/verifiable-credential'; import VerifiablePresentation from '../../src/verifiable-presentation'; import testingKeys from '../test-keys'; -mockAxios(); +mockFetch(); // Test constants const issuanceDate = '2020-04-15T09:05:35Z'; diff --git a/tests/unit/presigned-validation.test.js b/tests/unit/presigned-validation.test.js index 82e095c0f..b78c31818 100644 --- a/tests/unit/presigned-validation.test.js +++ b/tests/unit/presigned-validation.test.js @@ -1,11 +1,11 @@ -// Mock axios -import mockAxios from '../mocks/axios'; +// Mock fetch +import mockFetch from '../mocks/fetch'; import { verifyCredential, } from '../../src/utils/vc/index'; -mockAxios(); +mockFetch(); const controllerUrl = 'https://gist.githubusercontent.com/lovesh/312d407e3a16be0e7d5e43169e824958/raw'; const keyUrl = 'https://gist.githubusercontent.com/lovesh/67bdfd354cfaf4fb853df4d6713f4610/raw'; diff --git a/tests/unit/schema.test.js b/tests/unit/schema.test.js index bf097ee42..b6774748d 100644 --- a/tests/unit/schema.test.js +++ b/tests/unit/schema.test.js @@ -1,4 +1,4 @@ -// Mock axios +// Mock fetch import { cryptoWaitReady } from '@polkadot/util-crypto'; import VerifiableCredential from '../../src/verifiable-credential'; diff --git a/yarn.lock b/yarn.lock index b56e5b6d0..073b4768d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4733,14 +4733,6 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== -axios@0.27.2: - version "0.27.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" - integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== - dependencies: - follow-redirects "^1.14.9" - form-data "^4.0.0" - b4a@^1.0.1: version "1.6.1" resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.1.tgz#9effac93a469a868d024e16fd77162c653544cbd" @@ -7086,7 +7078,7 @@ fn.name@1.x.x: resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -follow-redirects@^1.14.9, follow-redirects@^1.5.1: +follow-redirects@^1.5.1: version "1.15.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== From 0f0dafb84dac516b61c329cee1c09622bcaf44ba Mon Sep 17 00:00:00 2001 From: Sam Hellawell Date: Fri, 10 Nov 2023 22:02:24 +0000 Subject: [PATCH 2/2] protocol blob detect --- src/utils/json-fetch.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils/json-fetch.js b/src/utils/json-fetch.js index b6f058494..da2a88586 100644 --- a/src/utils/json-fetch.js +++ b/src/utils/json-fetch.js @@ -7,6 +7,10 @@ export class JSONFetchError extends Error { } export default async function jsonFetch(url, options) { + if (url.startsWith('blob:')) { + throw new Error('Unsupported protocol blob:'); + } + let response; try { response = await fetch(url, options);