Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add more extensions manifest key options #39673

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/api/extensions.md
Expand Up @@ -40,6 +40,23 @@ We support the following extensions APIs, with some caveats. Other APIs may
additionally be supported, but support for any APIs not listed here is
provisional and may be removed.

### Supported Manifest Keys

- `name`
- `version`
- `author`
- `permissions`
- `content_scripts`
- `default_locale`
- `devtools_page`
- `short_name`
- `host_permissions` (Manifest V3)
- `manifest_version`
- `background` (Manifest V2)
- `minimum_chrome_version`

See [Manifest file format](https://developer.chrome.com/docs/extensions/mv3/manifest/) for more information about the purpose of each possible key.

### `chrome.devtools.inspectedWindow`

All features of this API are supported.
Expand Down
13 changes: 13 additions & 0 deletions shell/common/extensions/api/_manifest_features.json
Expand Up @@ -7,6 +7,10 @@
// well as feature.h, simple_feature.h, and feature_provider.h.

{
"author": {
"channel": "stable",
"extension_types": "all"
},
"content_scripts": {
"channel": "stable",
"extension_types": ["extension"]
Expand All @@ -15,8 +19,17 @@
"channel": "stable",
"extension_types": ["extension"]
},
"host_permissions": {
"channel": "stable",
"extension_types": ["extension"],
"min_manifest_version": 3
},
"minimum_chrome_version": {
"channel": "stable",
"extension_types": ["extension"]
},
"short_name": {
"channel": "stable",
"extension_types": "all"
}
}
63 changes: 62 additions & 1 deletion spec/extensions-spec.ts
Expand Up @@ -69,6 +69,67 @@ describe('chrome extensions', () => {
`)).to.eventually.have.property('id');
});

describe('host_permissions', async () => {
let customSession: Session;
let w: BrowserWindow;

beforeEach(() => {
customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
w = new BrowserWindow({
show: false,
webPreferences: {
session: customSession,
sandbox: true
}
});
});

afterEach(closeAllWindows);

it('recognize malformed host permissions', async () => {
await w.loadURL(url);

const extPath = path.join(fixtures, 'extensions', 'host-permissions', 'malformed');
customSession.loadExtension(extPath);

const warning = await new Promise(resolve => { process.on('warning', resolve); });

const malformedHost = /Permission 'malformed_host' is unknown or URL pattern is malformed/;

expect(warning).to.match(malformedHost);
});

it('can grant special privileges to urls with host permissions', async () => {
const extPath = path.join(fixtures, 'extensions', 'host-permissions', 'privileged-tab-info');
await customSession.loadExtension(extPath);

await w.loadURL(url);

const message = { method: 'query' };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);

const [,, responseString] = await once(w.webContents, 'console-message');
const response = JSON.parse(responseString);

expect(response).to.have.lengthOf(1);

const tab = response[0];
expect(tab).to.have.property('url').that.is.a('string');
expect(tab).to.have.property('title').that.is.a('string');
expect(tab).to.have.property('active').that.is.a('boolean');
expect(tab).to.have.property('autoDiscardable').that.is.a('boolean');
expect(tab).to.have.property('discarded').that.is.a('boolean');
expect(tab).to.have.property('groupId').that.is.a('number');
expect(tab).to.have.property('highlighted').that.is.a('boolean');
expect(tab).to.have.property('id').that.is.a('number');
expect(tab).to.have.property('incognito').that.is.a('boolean');
expect(tab).to.have.property('index').that.is.a('number');
expect(tab).to.have.property('pinned').that.is.a('boolean');
expect(tab).to.have.property('selected').that.is.a('boolean');
expect(tab).to.have.property('windowId').that.is.a('number');
});
});

it('supports minimum_chrome_version manifest key', async () => {
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
const w = new BrowserWindow({
Expand All @@ -81,7 +142,7 @@ describe('chrome extensions', () => {

await w.loadURL('about:blank');

const extPath = path.join(fixtures, 'extensions', 'chrome-too-low-version');
const extPath = path.join(fixtures, 'extensions', 'minimum-chrome-version');
const load = customSession.loadExtension(extPath);
await expect(load).to.eventually.be.rejectedWith(
`Loading extension at ${extPath} failed with: This extension requires Chromium version 999 or greater.`
Expand Down
@@ -0,0 +1,9 @@
{
"name": "malformed",
"version": "0.1",
"manifest_version": 3,
"description": "Extension with invalid host_permissions",
"host_permissions": [
"malformed_host"
]
}
@@ -0,0 +1,6 @@
/* global chrome */

chrome.runtime.onMessage.addListener((_request, _sender, sendResponse) => {
chrome.tabs.query({}).then(sendResponse);
return true;
});
@@ -0,0 +1,11 @@
/* global chrome */

chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => {
sendResponse(request);
});

window.addEventListener('message', () => {
chrome.runtime.sendMessage({ method: 'query' }, response => {
console.log(JSON.stringify(response));
});
}, false);
@@ -0,0 +1,14 @@
{
"name": "privileged-tab-info",
"version": "0.1",
"manifest_version": 3,
"content_scripts": [{
"matches": [ "<all_urls>"],
"js": ["main.js"],
"run_at": "document_start"
}],
"host_permissions": ["http://*/*"],
"background": {
"service_worker": "background.js"
}
}