diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 9283546fdf..31d4d55a3e 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -44,18 +44,6 @@ jobs: - name: Build, Lint, Test & Typecheck run: yarn nx affected -t build,lint,test,typecheck - - name: Validate Checkout Widgets Hashes - run: | - cd packages/checkout/widgets-lib - mv hashes.json hashes.json.old - yarn updateHashes - if [ -n "$(git diff --exit-code hashes.json)" ]; then - echo "Hashes.json has changed. Please update the hashes.json file and commit the changes." - echo "You can use the following command in the root of the repo to update the hashes.json file:" - echo "yarn workspace @imtbl/checkout-widgets updateHashes" - exit 1 - fi - build-lint-test-examples: name: Build, Lint & Test Examples runs-on: ubuntu-latest-8-cores diff --git a/packages/checkout/sdk/src/sdk.ts b/packages/checkout/sdk/src/sdk.ts index 6f3c379050..212c4db457 100644 --- a/packages/checkout/sdk/src/sdk.ts +++ b/packages/checkout/sdk/src/sdk.ts @@ -247,7 +247,7 @@ export class Checkout { ) { const checkout = this; try { - const cdnUrl = await getWidgetsEsmUrl(validVersion); + const cdnUrl = getWidgetsEsmUrl(validVersion); // WebpackIgnore comment required to prevent webpack modifying the import statement and // breaking the dynamic import in certain applications integrating checkout diff --git a/packages/checkout/sdk/src/widgets/hashUtils.ts b/packages/checkout/sdk/src/widgets/hashUtils.ts deleted file mode 100644 index f54223ff0c..0000000000 --- a/packages/checkout/sdk/src/widgets/hashUtils.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* eslint-disable max-len */ -export async function generateSHA512Hash(url: string): Promise { - // Fetch the content of the remote JavaScript file - const response = await fetch(url); - const content = await response.text(); - - // Convert the content to an ArrayBuffer - const encoder = new TextEncoder(); - const data = encoder.encode(content); - - // Use the Browser WebCrypto SubtleCrypto API to generate a SHA-512 hash - const hashBuffer = await window.crypto.subtle.digest('SHA-512', data); - - // Convert the hash to a Base64 string - const hashArray = Array.from(new Uint8Array(hashBuffer)); - const hashBase64 = btoa(String.fromCharCode(...hashArray)); - - return `sha512-${hashBase64}`; -} - -async function getLatestGitTag(): Promise { - const response = await fetch('https://api.github.com/repos/immutable/ts-immutable-sdk/tags'); - const tags = await response.json(); - return tags[0].name; -} - -export async function validatedHashesUrl(version: string): Promise { - if (version !== 'latest') { - return `https://raw.githubusercontent.com/immutable/ts-immutable-sdk/refs/tags/${version}/packages/checkout/widgets-lib/hashes.json`; - } - - const latestGitTag = await getLatestGitTag(); - return `https://raw.githubusercontent.com/immutable/ts-immutable-sdk/refs/tags/${latestGitTag}/packages/checkout/widgets-lib/hashes.json`; -} diff --git a/packages/checkout/sdk/src/widgets/load.test.ts b/packages/checkout/sdk/src/widgets/load.test.ts index da7e70ad4e..afcaede08c 100644 --- a/packages/checkout/sdk/src/widgets/load.test.ts +++ b/packages/checkout/sdk/src/widgets/load.test.ts @@ -2,15 +2,8 @@ import { SDK_VERSION_MARKER } from '../env'; import { getWidgetsEsmUrl, loadUnresolvedBundle } from './load'; -const SDK_VERSION = SDK_VERSION_MARKER; - -jest.mock('./hashUtils', () => ({ - generateSHA512Hash: jest.fn(async () => 'sha512-abc123'), - // eslint-disable-next-line max-len - validatedHashesUrl: jest.fn(async () => `https://raw.githubusercontent.com/immutable/ts-immutable-sdk/refs/tags/${SDK_VERSION}/packages/checkout/widgets-lib/hashes.json`), -})); - describe('load', () => { + const SDK_VERSION = SDK_VERSION_MARKER; const scriptId = 'immutable-checkout-widgets-bundle'; beforeEach(() => { @@ -18,15 +11,11 @@ describe('load', () => { }); describe('load unresolved bundle', () => { - it('should validate the versioning', async () => { + it('should validate the versioning', () => { const tag = document.createElement('script'); - await loadUnresolvedBundle(tag, scriptId, SDK_VERSION); - + loadUnresolvedBundle(tag, scriptId, SDK_VERSION); expect(document.head.innerHTML).toBe( - '`, ); @@ -34,23 +23,14 @@ describe('load', () => { }); describe('get widgets esm url', () => { - beforeEach(() => { - // @ts-expect-error mocking only json value of fetch response - global.fetch = jest.fn(async () => ({ - json: async () => ({ 'dist/index.js': 'sha512-abc123' }), - })); - }); - - it('should validate the versioning', async () => { - const widgetsEsmUrl = await getWidgetsEsmUrl(SDK_VERSION); - expect(widgetsEsmUrl).toEqual( + it('should validate the versioning', () => { + expect(getWidgetsEsmUrl(SDK_VERSION)).toEqual( `https://cdn.jsdelivr.net/npm/@imtbl/sdk@${SDK_VERSION}/dist/browser/checkout/widgets-esm.js`, ); }); - it('should change version', async () => { - const widgetsEsmUrl = await getWidgetsEsmUrl('1.2.3'); - expect(widgetsEsmUrl).toEqual( + it('should change version', () => { + expect(getWidgetsEsmUrl('1.2.3')).toEqual( 'https://cdn.jsdelivr.net/npm/@imtbl/sdk@1.2.3/dist/browser/checkout/widgets-esm.js', ); }); diff --git a/packages/checkout/sdk/src/widgets/load.ts b/packages/checkout/sdk/src/widgets/load.ts index b008dad878..328a07ef5f 100644 --- a/packages/checkout/sdk/src/widgets/load.ts +++ b/packages/checkout/sdk/src/widgets/load.ts @@ -1,8 +1,7 @@ import { useLocalBundle } from '../env'; -import { generateSHA512Hash, validatedHashesUrl } from './hashUtils'; // Loads the checkout widgets bundle from the CDN and appends the script to the document head -export async function loadUnresolvedBundle( +export function loadUnresolvedBundle( tag: HTMLScriptElement, scriptId: string, validVersion: string, @@ -18,12 +17,6 @@ export async function loadUnresolvedBundle( let cdnUrl = `https://cdn.jsdelivr.net/npm/@imtbl/sdk@${validVersion}/dist/browser/checkout/widgets.js`; if (useLocalBundle()) cdnUrl = `http://${window.location.host}/lib/js/widgets.js`; - if (!useLocalBundle()) { - const integrityHash = await generateSHA512Hash(cdnUrl); - tag.setAttribute('integrity', integrityHash); - tag.setAttribute('crossorigin', 'anonymous'); - } - tag.setAttribute('id', scriptId); tag.setAttribute('data-version', validVersion); tag.setAttribute('src', cdnUrl); @@ -32,27 +25,10 @@ export async function loadUnresolvedBundle( } // Gets the CDN url for the split checkout widgets bundle -export async function getWidgetsEsmUrl( +export function getWidgetsEsmUrl( validVersion: string, -): Promise> { - if (useLocalBundle()) return `http://${window.location.host}/lib/js/index.js`; - - const cdnUrl = `https://cdn.jsdelivr.net/npm/@imtbl/sdk@${validVersion}/dist/browser/checkout/widgets-esm.js`; - - const validHashesUrl = await validatedHashesUrl(validVersion); - - const hash = await generateSHA512Hash(cdnUrl); - - const widgetsEsmHash: string = await fetch(validHashesUrl) - .then((response) => response.json()) - .then((hashes) => hashes['dist/index.js']) - .catch(() => { - throw new Error('Security Error: could not fetch widgets-esm.js hash'); - }); - - if (hash !== widgetsEsmHash) { - throw new Error('Security Error: widgets-esm.js hash mismatch'); - } - +): string { + let cdnUrl = `https://cdn.jsdelivr.net/npm/@imtbl/sdk@${validVersion}/dist/browser/checkout/widgets-esm.js`; + if (useLocalBundle()) cdnUrl = `http://${window.location.host}/lib/js/index.js`; return cdnUrl; } diff --git a/packages/checkout/widgets-lib/.eslintrc.cjs b/packages/checkout/widgets-lib/.eslintrc.cjs index 2639456e54..96bdd2ff19 100644 --- a/packages/checkout/widgets-lib/.eslintrc.cjs +++ b/packages/checkout/widgets-lib/.eslintrc.cjs @@ -1,6 +1,6 @@ module.exports = { "extends": ["../../../.eslintrc"], - "ignorePatterns": ["jest.config.*", "rollup.config.*", "*.js"], + "ignorePatterns": ["jest.config.*", "rollup.config.*"], "parser": "@typescript-eslint/parser", "parserOptions": { "project": "./tsconfig.json", diff --git a/packages/checkout/widgets-lib/hashes.json b/packages/checkout/widgets-lib/hashes.json deleted file mode 100644 index b12e1c1f19..0000000000 --- a/packages/checkout/widgets-lib/hashes.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "dist/widgets.js": "sha512-WMrmg+Xs0GRr3rQ7dOxLMHXw1Co+WH9+LHzhVcV1mh7MIgacX5jmFtWM0DbXszQGBj6KlOe+3W5HiyPvGylGiQ==", - "dist/index.js": "sha512-dQi34NMUtZhRBuxK3a36z3abkfbfX6+BWvmvILVMRzTQRdxq1w+X+DvkNdiFfRyAAAuAvCDGhk1XETGfE0cKKQ==" -} \ No newline at end of file diff --git a/packages/checkout/widgets-lib/package.json b/packages/checkout/widgets-lib/package.json index be00c6d0cf..435af8d09e 100644 --- a/packages/checkout/widgets-lib/package.json +++ b/packages/checkout/widgets-lib/package.json @@ -104,16 +104,15 @@ "build": "yarn clean && NODE_ENV=production rollup --config rollup.config.js", "build:analyse": "yarn build --plugin visualizer", "build:local": "yarn clean && yarn build && mkdir -p ../widgets-sample-app/public/lib/js && cp dist/*.js ../widgets-sample-app/public/lib/js/", + "prepare:examplewidgets": "yarn workspace @examples/sdk-load-widgets-with-nextjs exec mkdir -p tests/utils/local-widgets-js/ && cp $(yarn workspace @imtbl/sdk exec pwd)/dist/browser/checkout/*.js $(yarn workspace @examples/sdk-load-widgets-with-nextjs exec pwd)/tests/utils/local-widgets-js/", "clean": "rimraf ./dist", "d": "rollup --config rollup.config.js", "lint": "eslint ./src --ext .ts,.jsx,.tsx --max-warnings=0", "lint:fix": "eslint ./src --ext .ts,.jsx,.tsx --max-warnings=0 --fix", - "prepare:examplewidgets": "yarn workspace @examples/sdk-load-widgets-with-nextjs exec mkdir -p tests/utils/local-widgets-js/ && cp $(yarn workspace @imtbl/sdk exec pwd)/dist/browser/checkout/*.js $(yarn workspace @examples/sdk-load-widgets-with-nextjs exec pwd)/tests/utils/local-widgets-js/", "start": "yarn clean && NODE_ENV=development rollup --config rollup.config.js --watch", "test": "jest test --passWithNoTests", "test:watch": "jest test --passWithNoTests --watch", - "typecheck": "tsc --customConditions \"default\" --noEmit", - "updateHashes": "yarn run --top-level nx run @imtbl/checkout-widgets:build && node ./updateHashes.js" + "typecheck": "tsc --customConditions \"default\" --noEmit" }, "type": "module", "types": "./dist/index.d.ts" diff --git a/packages/checkout/widgets-lib/updateHashes.js b/packages/checkout/widgets-lib/updateHashes.js deleted file mode 100755 index 22ca342504..0000000000 --- a/packages/checkout/widgets-lib/updateHashes.js +++ /dev/null @@ -1,24 +0,0 @@ -// @ts-check -import { readFileSync, writeFileSync } from "fs" -import { createHash } from "crypto" - -const filesToHash = ["dist/widgets.js", "dist/index.js"] - -filesToHash.forEach(file => { - try { - readFileSync(file) - } catch (e) { - console.error(`File ${file} not found`) - console.error('Please build the Checkout Widgets package') - process.exit(1) - } -}) - -const hashes = filesToHash.reduce((acc, file) => { - const hash = `sha512-${createHash("sha512").update(readFileSync(file - )).digest("base64")}` - acc[file] = hash - return acc -}, {}) - -writeFileSync("hashes.json", JSON.stringify(hashes, null, 2)) \ No newline at end of file diff --git a/sdk/package.json b/sdk/package.json index 28aa1f670d..7158067697 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -178,4 +178,4 @@ }, "type": "module", "types": "./dist/index.d.ts" -} \ No newline at end of file +}