diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d181bb..98b3510 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 16.13 - name: install run: npm ci || npm install - name: build @@ -37,6 +40,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 16 - name: install run: npm ci || npm install - name: build diff --git a/index.ts b/index.ts index 634dbb2..dd50b7b 100644 --- a/index.ts +++ b/index.ts @@ -133,3 +133,24 @@ export function _isUrlPermittedByManifest( const originsRegex = patternToRegex(...manifestPermissions.origins); return originsRegex.test(origin); } + +export function dropOverlappingPermissions({origins, permissions}: chrome.permissions.Permissions): chrome.permissions.Permissions { + const result: chrome.permissions.Permissions = {}; + if (origins) { + if (origins.includes('')) { + result.origins = ['']; + } else if (origins.includes('*://*/*')) { + result.origins = ['*://*/*']; + } else { + result.origins = origins.filter(possibleSubset => !origins.some(possibleSuperset => + possibleSubset !== possibleSuperset && patternToRegex(possibleSuperset).test(possibleSubset), + )); + } + } + + if (permissions) { + result.permissions = [...permissions]; + } + + return result; +} diff --git a/package.json b/package.json index e5e798a..1785dbe 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,6 @@ "@sindresorhus/tsconfig": "^2.0.0", "ava": "^4.0.1", "typescript": "^4.5.5", - "xo": "^0.47.0" + "xo": "^0.48.0" } } diff --git a/readme.md b/readme.md index 22dcdbd..b7c7bdf 100644 --- a/readme.md +++ b/readme.md @@ -130,6 +130,12 @@ Difference from `chrome.permissions.getAll`: Same as `getManifestPermissions` but it doesn't return a Promise. +### dropOverlappingPermissions(permissions) + +`*://*/*` includes every URL also matched by `https://fregante.com/*`, so the latter is overlapping. + +This function accepts a [`Permissions`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/permissions/Permissions) object and it drops any permissions that are overlapping. Currently this only applies to origin permissions. + ### isUrlPermittedByManifest(url) Check whether a specific URL is statically permitted by the manifest, whether in the `permissions` array or in a content script. Like `chrome.permissions.contains` except: diff --git a/test/index.js b/test/index.js index d8c25ab..e9d9bed 100644 --- a/test/index.js +++ b/test/index.js @@ -3,6 +3,7 @@ import { _getManifestPermissionsSync, _getAdditionalPermissions, _isUrlPermittedByManifest, + dropOverlappingPermissions, } from '../index.js'; import manifest from './fixtures/manifest.json'; @@ -60,6 +61,69 @@ test('getAdditionalPermissions after added permissions, loose origin check', t = }); }); +test('dropOverlappingPermissions', t => { + t.deepEqual(dropOverlappingPermissions({ + origins: [ + 'https://*.example.com/*', + '', + 'https://fregante.com/*', + '*://*/*', + ], + }), { + origins: [ + '', + ], + }, ' should catch all'); + + t.deepEqual(dropOverlappingPermissions({ + origins: [ + 'https://*.example.com/*', + '*://*/*', + 'https://fregante.com/*', + ], + }), { + origins: ['*://*/*'], + }, '*://*/* should catch all'); + + t.deepEqual(dropOverlappingPermissions({ + origins: [ + 'http://*.example.com/*', + 'https://*/*', + 'https://fregante.com/*', + ], + }), { + origins: [ + 'http://*.example.com/*', + 'https://*/*', + ], + }, 'https://*/* should drop all other https origins'); + + t.deepEqual(dropOverlappingPermissions({ + origins: [ + 'https://git.example.com/*', + 'https://*.example.com/*', + 'https://example.com/*', + 'https://fregante.com/*', + ], + }), { + origins: [ + 'https://*.example.com/*', + 'https://fregante.com/*', + ], + }, 'A subdomain star should drop all other same-domain origins'); + + t.deepEqual(dropOverlappingPermissions({ + origins: [ + 'https://git.example.com/*', + 'https://git.example.com/fregante/*', + ], + }), { + origins: [ + 'https://git.example.com/*', + ], + }, 'A pathname star should drop all other same-origin origins'); +}); + // This is identical to the internal _getManifestPermissionsSync, which is already tested test('selectAdditionalPermissions', t => { t.pass();