Skip to content

Commit 51de3ca

Browse files
authored
Merge pull request #1583 from oasisprotocol/lw/strict-permissions-policy
Add strict Permissions-Policy header
2 parents 8d13573 + 84b30f3 commit 51de3ca

11 files changed

Lines changed: 100 additions & 14 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ docker-compose up -d
129129
REACT_APP_LOCALNET=1 REACT_APP_BACKEND=oasismonitor yarn start
130130
yarn cypress:run
131131

132-
# Manually check that content-security-policy in ./internals/getCsp.js doesn't
132+
# Manually check that content-security-policy in getPermissionHeaders.js doesn't
133133
# break any functionality
134134
yarn --silent print-csp
135135
yarn start:prod

docs/release-process.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,12 @@ Manually deploy `./build/` folder by following <https://github.com/oasisprotocol
2222

2323
Verify deployed version by opening the page in incognito (no cache) - it is displayed in the footer.
2424

25-
Update Content-Security-Policy header.
25+
Update Content-Security-Policy and Permissions-Policy headers.
2626

2727
```sh
28-
yarn print-csp
29-
30-
# See old deployed CSP
31-
curl --head https://wallet.stg.oasis.io/ -s | grep content-security-policy
32-
curl --head https://wallet.oasis.io/ -s | grep content-security-policy
28+
# See old deployed headers
29+
curl --head https://wallet.stg.oasis.io/ -s | grep "content-security-policy\|permissions-policy"
30+
curl --head https://wallet.oasis.io/ -s | grep "content-security-policy\|permissions-policy"
3331
```
3432

3533

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,42 @@ const getCsp = ({ isExtension } = { isExtension: false }) =>
5353
.join(' ')
5454
.replace(/ ;/g, ';')
5555

56-
module.exports = { getCsp }
56+
// Generated with https://www.permissionspolicy.com/
57+
const getPermissionsPolicy = () =>
58+
`
59+
accelerometer=*,
60+
ambient-light-sensor=*,
61+
autoplay=(),
62+
bluetooth=(self),
63+
camera=*,
64+
cross-origin-isolated=(),
65+
display-capture=(),
66+
document-domain=(),
67+
encrypted-media=*,
68+
execution-while-not-rendered=(),
69+
execution-while-out-of-viewport=(),
70+
fullscreen=(self "https://global.transak.com" "https://global-stg.transak.com"),
71+
geolocation=(),
72+
gyroscope=*,
73+
keyboard-map=(),
74+
magnetometer=*,
75+
microphone=*,
76+
midi=(),
77+
navigation-override=(),
78+
payment=("https://global.transak.com" "https://global-stg.transak.com"),
79+
picture-in-picture=(),
80+
publickey-credentials-get=*,
81+
screen-wake-lock=(),
82+
sync-xhr=(),
83+
usb=(self),
84+
web-share=*,
85+
xr-spatial-tracking=()
86+
`
87+
.trim()
88+
.split('\n')
89+
.map(line => line.trim())
90+
.filter(line => !!line)
91+
.join(' ')
92+
.replace(/ ,/g, ',')
93+
94+
module.exports = { getCsp, getPermissionsPolicy }

internals/scripts/build-ext.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// @ts-check
22
const execSync = require('child_process').execSync
3-
const { getCsp } = require('../getCsp.js')
3+
const { getCsp } = require('../getPermissionHeaders.js')
44
const { buildDatetime, buildSha, buildVersion } = require('../getBuildData')
55

66
process.env.REACT_APP_BUILD_DATETIME = buildDatetime

internals/scripts/build-web.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// @ts-check
22
const execSync = require('child_process').execSync
3-
const { getCsp } = require('../getCsp.js')
3+
const { getCsp } = require('../getPermissionHeaders.js')
44
const { buildDatetime, buildSha, buildVersion } = require('../getBuildData')
55

66
process.env.REACT_APP_BUILD_DATETIME = buildDatetime

internals/scripts/print-csp.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
// @ts-check
2-
const { getCsp } = require('../getCsp.js')
2+
const { getCsp } = require('../getPermissionHeaders.js')
33
console.log(getCsp())
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
// @ts-check
2-
const { getCsp } = require('../getCsp.js')
2+
const { getCsp } = require('../getPermissionHeaders.js')
33
console.log(getCsp({ isExtension: true }))

internals/scripts/serve-prod.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
const path = require('path')
33
const http = require('http')
44
const serveHandler = require('serve-handler')
5-
const { getCsp } = require('../getCsp.js')
5+
const { getCsp, getPermissionsPolicy } = require('../getPermissionHeaders.js')
66
const csp = getCsp()
7+
const permissionsPolicy = getPermissionsPolicy()
78
console.log(`Content-Security-Policy: ${csp}\n`)
9+
console.log(`Permissions-Policy: ${permissionsPolicy}\n`)
810

911
const root = path.resolve(__dirname, '../..')
1012

@@ -27,6 +29,10 @@ const server = http.createServer((request, response) => {
2729
key: 'Content-Security-Policy',
2830
value: csp,
2931
},
32+
{
33+
key: 'Permissions-Policy',
34+
value: permissionsPolicy,
35+
},
3036
],
3137
},
3238
],

playwright/tests/fiat.spec.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ test.beforeEach(async ({ page }) => {
1919
})
2020
await expect(page.getByTestId('account-selector')).toBeVisible()
2121
await page.getByRole('link', { name: 'Buy' }).click()
22-
await expect(page.getByText('Buy ROSE')).toBeVisible()
22+
await expect(page.getByRole('heading', { name: 'Buy ROSE' })).toBeVisible()
2323
})
2424

2525
test.describe('Fiat on-ramp', () => {
@@ -94,4 +94,31 @@ test.describe('Fiat on-ramp', () => {
9494
.click()
9595
await expect(page).toHaveURL('https://phishing-wallet.com/')
9696
})
97+
98+
test('Permissions-Policy should contain Transak permissions', async ({ page, baseURL }) => {
99+
expect(baseURL).toBe('http://localhost:5000')
100+
expect((await page.request.head('/')).headers()).toHaveProperty('permissions-policy')
101+
const permissionsPolicy = (await page.request.head('/'))
102+
.headers()
103+
['permissions-policy'].split(',')
104+
.map(rule => rule.trim())
105+
106+
await page
107+
.getByText(
108+
'I understand that I’m using a third-party solution and Oasis* does not carry any responsibility over the usage of this solution.',
109+
)
110+
.click()
111+
112+
const transakPermissions = await page.locator('iframe').getAttribute('allow')
113+
expect(transakPermissions).toBeTruthy()
114+
115+
for (const permission of transakPermissions!.split(';').map(permission => permission.trim())) {
116+
expect(permissionsPolicy.find(rule => rule.startsWith(`${permission}=`))).toContain(
117+
'https://global.transak.com',
118+
)
119+
expect(permissionsPolicy.find(rule => rule.startsWith(`${permission}=`))).toContain(
120+
'https://global-stg.transak.com',
121+
)
122+
}
123+
})
97124
})

playwright/tests/ledger.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { test, expect } from '@playwright/test'
2+
import { expectNoErrorsInConsole } from '../utils/expectNoErrorsInConsole'
3+
4+
test.describe('Ledger', () => {
5+
test('Permissions-Policy should allow USB', async ({ page, baseURL }) => {
6+
expect(baseURL).toBe('http://localhost:5000')
7+
expect((await page.request.head('/')).headers()).toHaveProperty('permissions-policy')
8+
await expectNoErrorsInConsole(page)
9+
10+
await page.goto('/open-wallet/ledger')
11+
await page.getByRole('button', { name: 'Select accounts to open' }).click()
12+
await expect(page.getByText('error').or(page.getByText('fail'))).toBeHidden()
13+
})
14+
})

0 commit comments

Comments
 (0)