diff --git a/README.md b/README.md index bbb682adbe..163f5a26d9 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ docker-compose up -d REACT_APP_LOCALNET=1 REACT_APP_BACKEND=oasismonitor yarn start yarn cypress:run -# Manually check that content-security-policy in ./internals/getCsp.js doesn't +# Manually check that content-security-policy in getPermissionHeaders.js doesn't # break any functionality yarn --silent print-csp yarn start:prod diff --git a/docs/release-process.md b/docs/release-process.md index 89cad738a1..7bff228e14 100644 --- a/docs/release-process.md +++ b/docs/release-process.md @@ -22,14 +22,12 @@ Manually deploy `./build/` folder by following .join(' ') .replace(/ ;/g, ';') -module.exports = { getCsp } +// Generated with https://www.permissionspolicy.com/ +const getPermissionsPolicy = () => + ` + accelerometer=*, + ambient-light-sensor=*, + autoplay=(), + bluetooth=(self), + camera=*, + cross-origin-isolated=(), + display-capture=(), + document-domain=(), + encrypted-media=*, + execution-while-not-rendered=(), + execution-while-out-of-viewport=(), + fullscreen=(self "https://global.transak.com" "https://global-stg.transak.com"), + geolocation=(), + gyroscope=*, + keyboard-map=(), + magnetometer=*, + microphone=*, + midi=(), + navigation-override=(), + payment=("https://global.transak.com" "https://global-stg.transak.com"), + picture-in-picture=(), + publickey-credentials-get=*, + screen-wake-lock=(), + sync-xhr=(), + usb=(self), + web-share=*, + xr-spatial-tracking=() + ` + .trim() + .split('\n') + .map(line => line.trim()) + .filter(line => !!line) + .join(' ') + .replace(/ ,/g, ',') + +module.exports = { getCsp, getPermissionsPolicy } diff --git a/internals/scripts/build-ext.js b/internals/scripts/build-ext.js index 5f5c32b27a..d82d1a613b 100644 --- a/internals/scripts/build-ext.js +++ b/internals/scripts/build-ext.js @@ -1,6 +1,6 @@ // @ts-check const execSync = require('child_process').execSync -const { getCsp } = require('../getCsp.js') +const { getCsp } = require('../getPermissionHeaders.js') const { buildDatetime, buildSha, buildVersion } = require('../getBuildData') process.env.REACT_APP_BUILD_DATETIME = buildDatetime diff --git a/internals/scripts/build-web.js b/internals/scripts/build-web.js index 9943ed89e5..8350c4cee9 100644 --- a/internals/scripts/build-web.js +++ b/internals/scripts/build-web.js @@ -1,6 +1,6 @@ // @ts-check const execSync = require('child_process').execSync -const { getCsp } = require('../getCsp.js') +const { getCsp } = require('../getPermissionHeaders.js') const { buildDatetime, buildSha, buildVersion } = require('../getBuildData') process.env.REACT_APP_BUILD_DATETIME = buildDatetime diff --git a/internals/scripts/print-csp.js b/internals/scripts/print-csp.js index c40c5dcf9d..0826ac296f 100644 --- a/internals/scripts/print-csp.js +++ b/internals/scripts/print-csp.js @@ -1,3 +1,3 @@ // @ts-check -const { getCsp } = require('../getCsp.js') +const { getCsp } = require('../getPermissionHeaders.js') console.log(getCsp()) diff --git a/internals/scripts/print-extension-csp.js b/internals/scripts/print-extension-csp.js index c72def0859..8c74da563e 100644 --- a/internals/scripts/print-extension-csp.js +++ b/internals/scripts/print-extension-csp.js @@ -1,3 +1,3 @@ // @ts-check -const { getCsp } = require('../getCsp.js') +const { getCsp } = require('../getPermissionHeaders.js') console.log(getCsp({ isExtension: true })) diff --git a/internals/scripts/serve-prod.js b/internals/scripts/serve-prod.js index 6cd5be3db9..797961cc76 100644 --- a/internals/scripts/serve-prod.js +++ b/internals/scripts/serve-prod.js @@ -2,9 +2,11 @@ const path = require('path') const http = require('http') const serveHandler = require('serve-handler') -const { getCsp } = require('../getCsp.js') +const { getCsp, getPermissionsPolicy } = require('../getPermissionHeaders.js') const csp = getCsp() +const permissionsPolicy = getPermissionsPolicy() console.log(`Content-Security-Policy: ${csp}\n`) +console.log(`Permissions-Policy: ${permissionsPolicy}\n`) const root = path.resolve(__dirname, '../..') @@ -27,6 +29,10 @@ const server = http.createServer((request, response) => { key: 'Content-Security-Policy', value: csp, }, + { + key: 'Permissions-Policy', + value: permissionsPolicy, + }, ], }, ], diff --git a/playwright/tests/fiat.spec.ts b/playwright/tests/fiat.spec.ts index 3adfa6386f..80ee5ac62c 100644 --- a/playwright/tests/fiat.spec.ts +++ b/playwright/tests/fiat.spec.ts @@ -19,7 +19,7 @@ test.beforeEach(async ({ page }) => { }) await expect(page.getByTestId('account-selector')).toBeVisible() await page.getByRole('link', { name: 'Buy' }).click() - await expect(page.getByText('Buy ROSE')).toBeVisible() + await expect(page.getByRole('heading', { name: 'Buy ROSE' })).toBeVisible() }) test.describe('Fiat on-ramp', () => { @@ -94,4 +94,31 @@ test.describe('Fiat on-ramp', () => { .click() await expect(page).toHaveURL('https://phishing-wallet.com/') }) + + test('Permissions-Policy should contain Transak permissions', async ({ page, baseURL }) => { + expect(baseURL).toBe('http://localhost:5000') + expect((await page.request.head('/')).headers()).toHaveProperty('permissions-policy') + const permissionsPolicy = (await page.request.head('/')) + .headers() + ['permissions-policy'].split(',') + .map(rule => rule.trim()) + + await page + .getByText( + 'I understand that I’m using a third-party solution and Oasis* does not carry any responsibility over the usage of this solution.', + ) + .click() + + const transakPermissions = await page.locator('iframe').getAttribute('allow') + expect(transakPermissions).toBeTruthy() + + for (const permission of transakPermissions!.split(';').map(permission => permission.trim())) { + expect(permissionsPolicy.find(rule => rule.startsWith(`${permission}=`))).toContain( + 'https://global.transak.com', + ) + expect(permissionsPolicy.find(rule => rule.startsWith(`${permission}=`))).toContain( + 'https://global-stg.transak.com', + ) + } + }) }) diff --git a/playwright/tests/ledger.spec.ts b/playwright/tests/ledger.spec.ts new file mode 100644 index 0000000000..176dee94e1 --- /dev/null +++ b/playwright/tests/ledger.spec.ts @@ -0,0 +1,14 @@ +import { test, expect } from '@playwright/test' +import { expectNoErrorsInConsole } from '../utils/expectNoErrorsInConsole' + +test.describe('Ledger', () => { + test('Permissions-Policy should allow USB', async ({ page, baseURL }) => { + expect(baseURL).toBe('http://localhost:5000') + expect((await page.request.head('/')).headers()).toHaveProperty('permissions-policy') + await expectNoErrorsInConsole(page) + + await page.goto('/open-wallet/ledger') + await page.getByRole('button', { name: 'Select accounts to open' }).click() + await expect(page.getByText('error').or(page.getByText('fail'))).toBeHidden() + }) +}) diff --git a/src/app/pages/FiatOnrampPage/index.tsx b/src/app/pages/FiatOnrampPage/index.tsx index 63195482dc..6fa3cba687 100644 --- a/src/app/pages/FiatOnrampPage/index.tsx +++ b/src/app/pages/FiatOnrampPage/index.tsx @@ -112,6 +112,9 @@ export function FiatOnramp() {