mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1190688: Part 1 - [webext] Implement the activeTab permission. r=billm
This commit is contained in:
parent
ee06b6660a
commit
294c025113
@ -32,6 +32,8 @@ function BrowserAction(options, extension)
|
||||
this.id = makeWidgetId(extension.id) + "-browser-action";
|
||||
this.widget = null;
|
||||
|
||||
this.tabManager = TabManager.for(extension);
|
||||
|
||||
let title = extension.localize(options.default_title || "");
|
||||
let popup = extension.localize(options.default_popup || "");
|
||||
if (popup) {
|
||||
@ -74,6 +76,7 @@ BrowserAction.prototype = {
|
||||
node.addEventListener("command", event => {
|
||||
let tab = tabbrowser.selectedTab;
|
||||
let popup = this.getProperty(tab, "popup");
|
||||
this.tabManager.addActiveTabPermission(tab);
|
||||
if (popup) {
|
||||
this.togglePopup(node, popup);
|
||||
} else {
|
||||
|
@ -43,8 +43,11 @@ var menuBuilder = {
|
||||
for (let [ext, menuItemMap] of contextMenuMap) {
|
||||
let parentMap = new Map();
|
||||
let topLevelItems = new Set();
|
||||
for (let [id, item] of menuItemMap) {
|
||||
dump(id + " : " + item + "\n");
|
||||
for (let entry of menuItemMap) {
|
||||
// We need a closure over |item|, and we don't currently get a
|
||||
// fresh binding per loop if we declare it in the loop head.
|
||||
let [id, item] = entry;
|
||||
|
||||
if (item.enabledForContext(contextData)) {
|
||||
let element;
|
||||
if (item.isMenu) {
|
||||
@ -79,15 +82,13 @@ var menuBuilder = {
|
||||
topLevelItems.add(element);
|
||||
}
|
||||
|
||||
if (item.onclick) {
|
||||
function clickHandlerForItem(item) {
|
||||
return event => {
|
||||
let clickData = item.getClickData(contextData, event);
|
||||
runSafe(item.extContext, item.onclick, clickData);
|
||||
}
|
||||
element.addEventListener("command", event => {
|
||||
item.tabManager.addActiveTabPermission();
|
||||
if (item.onclick) {
|
||||
let clickData = item.getClickData(contextData, event);
|
||||
runSafe(item.extContext, item.onclick, clickData);
|
||||
}
|
||||
element.addEventListener("command", clickHandlerForItem(item));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (topLevelItems.size > 1) {
|
||||
@ -166,6 +167,8 @@ function MenuItem(extension, extContext, createProperties)
|
||||
this.extension = extension;
|
||||
this.extContext = extContext;
|
||||
|
||||
this.tabManager = TabManager.for(extension);
|
||||
|
||||
this.init(createProperties);
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,8 @@ function PageAction(options, extension)
|
||||
this.extension = extension;
|
||||
this.id = makeWidgetId(extension.id) + "-page-action";
|
||||
|
||||
this.tabManager = TabManager.for(extension);
|
||||
|
||||
let title = extension.localize(options.default_title || "");
|
||||
let popup = extension.localize(options.default_popup || "");
|
||||
if (popup) {
|
||||
@ -139,6 +141,8 @@ PageAction.prototype = {
|
||||
let tab = window.gBrowser.selectedTab;
|
||||
let popup = this.tabContext.get(tab).popup;
|
||||
|
||||
this.tabManager.addActiveTabPermission(tab);
|
||||
|
||||
if (popup) {
|
||||
openPanel(this.getButton(window), popup, this.extension);
|
||||
} else {
|
||||
|
@ -457,13 +457,8 @@ extensions.registerAPI((extension, context) => {
|
||||
}
|
||||
|
||||
let result = [];
|
||||
let e = Services.wm.getEnumerator("navigator:browser");
|
||||
while (e.hasMoreElements()) {
|
||||
let window = e.getNext();
|
||||
if (window.document.readyState != "complete") {
|
||||
continue;
|
||||
}
|
||||
let tabs = TabManager.getTabs(extension, window);
|
||||
for (let window of WindowListManager.browserWindows()) {
|
||||
let tabs = TabManager.for(extension).getTabs(window);
|
||||
for (let tab of tabs) {
|
||||
if (matches(window, tab)) {
|
||||
result.push(tab);
|
||||
@ -489,10 +484,16 @@ extensions.registerAPI((extension, context) => {
|
||||
// window IDs and insufficient permissions need to result in a
|
||||
// callback with |lastError| set.
|
||||
innerWindowID: tab.linkedBrowser.innerWindowID,
|
||||
|
||||
matchesHost: extension.whiteListedHosts.serialize(),
|
||||
};
|
||||
|
||||
if (TabManager.for(extension).hasActiveTabPermission(tab)) {
|
||||
// If we have the "activeTab" permission for this tab, ignore
|
||||
// the host whitelist.
|
||||
options.matchesHost = ["<all_urls>"];
|
||||
} else {
|
||||
options.matchesHost = extension.whiteListedHosts.serialize();
|
||||
}
|
||||
|
||||
if (details.code) {
|
||||
options[kind + 'Code'] = details.code;
|
||||
}
|
||||
|
@ -267,7 +267,87 @@ TabContext.prototype = {
|
||||
},
|
||||
};
|
||||
|
||||
// Manages mapping between XUL tabs and extension tab IDs.
|
||||
// Manages tab mappings and permissions for a specific extension.
|
||||
function ExtensionTabManager(extension) {
|
||||
this.extension = extension;
|
||||
|
||||
// A mapping of tab objects to the inner window ID the extension currently has
|
||||
// the active tab permission for. The active permission for a given tab is
|
||||
// valid only for the inner window that was active when the permission was
|
||||
// granted. If the tab navigates, the inner window ID changes, and the
|
||||
// permission automatically becomes stale.
|
||||
//
|
||||
// WeakMap[tab => inner-window-id<int>]
|
||||
this.hasTabPermissionFor = new WeakMap();
|
||||
}
|
||||
|
||||
ExtensionTabManager.prototype = {
|
||||
addActiveTabPermission(tab = TabManager.activeTab) {
|
||||
if (this.extension.hasPermission("activeTab")) {
|
||||
// Note that, unlike Chrome, we don't currently clear this permission with
|
||||
// the tab navigates. If the inner window is revived from BFCache before
|
||||
// we've granted this permission to a new inner window, the extension
|
||||
// maintains its permissions for it.
|
||||
this.hasTabPermissionFor.set(tab, tab.linkedBrowser.innerWindowID);
|
||||
}
|
||||
},
|
||||
|
||||
// Returns true if the extension has the "activeTab" permission for this tab.
|
||||
// This is somewhat more permissive than the generic "tabs" permission, as
|
||||
// checked by |hasTabPermission|, in that it also allows programmatic script
|
||||
// injection without an explicit host permission.
|
||||
hasActiveTabPermission(tab) {
|
||||
// This check is redundant with addTabPermission, but cheap.
|
||||
if (this.extension.hasPermission("activeTab")) {
|
||||
return (this.hasTabPermissionFor.has(tab) &&
|
||||
this.hasTabPermissionFor.get(tab) === tab.linkedBrowser.innerWindowID);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
hasTabPermission(tab) {
|
||||
return this.extension.hasPermission("tabs") || this.hasActiveTabPermission(tab);
|
||||
},
|
||||
|
||||
convert(tab) {
|
||||
let window = tab.ownerDocument.defaultView;
|
||||
let windowActive = window == WindowManager.topWindow;
|
||||
|
||||
let result = {
|
||||
id: TabManager.getId(tab),
|
||||
index: tab._tPos,
|
||||
windowId: WindowManager.getId(window),
|
||||
selected: tab.selected,
|
||||
highlighted: tab.selected,
|
||||
active: tab.selected,
|
||||
pinned: tab.pinned,
|
||||
status: TabManager.getStatus(tab),
|
||||
incognito: PrivateBrowsingUtils.isBrowserPrivate(tab.linkedBrowser),
|
||||
width: tab.linkedBrowser.clientWidth,
|
||||
height: tab.linkedBrowser.clientHeight,
|
||||
};
|
||||
|
||||
if (this.hasTabPermission(tab)) {
|
||||
result.url = tab.linkedBrowser.currentURI.spec;
|
||||
if (tab.linkedBrowser.contentTitle) {
|
||||
result.title = tab.linkedBrowser.contentTitle;
|
||||
}
|
||||
let icon = window.gBrowser.getIcon(tab);
|
||||
if (icon) {
|
||||
result.favIconUrl = icon;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
getTabs(window) {
|
||||
return Array.from(window.gBrowser.tabs, tab => this.convert(tab));
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
// Manages global mappings between XUL tabs and extension tab IDs.
|
||||
global.TabManager = {
|
||||
_tabs: new WeakMap(),
|
||||
_nextId: 1,
|
||||
@ -322,44 +402,26 @@ global.TabManager = {
|
||||
},
|
||||
|
||||
convert(extension, tab) {
|
||||
let window = tab.ownerDocument.defaultView;
|
||||
let windowActive = window == WindowManager.topWindow;
|
||||
let result = {
|
||||
id: this.getId(tab),
|
||||
index: tab._tPos,
|
||||
windowId: WindowManager.getId(window),
|
||||
selected: tab.selected,
|
||||
highlighted: tab.selected,
|
||||
active: tab.selected,
|
||||
pinned: tab.pinned,
|
||||
status: this.getStatus(tab),
|
||||
incognito: PrivateBrowsingUtils.isBrowserPrivate(tab.linkedBrowser),
|
||||
width: tab.linkedBrowser.clientWidth,
|
||||
height: tab.linkedBrowser.clientHeight,
|
||||
};
|
||||
|
||||
if (extension.hasPermission("tabs")) {
|
||||
result.url = tab.linkedBrowser.currentURI.spec;
|
||||
if (tab.linkedBrowser.contentTitle) {
|
||||
result.title = tab.linkedBrowser.contentTitle;
|
||||
}
|
||||
let icon = window.gBrowser.getIcon(tab);
|
||||
if (icon) {
|
||||
result.favIconUrl = icon;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
getTabs(extension, window) {
|
||||
if (!window.gBrowser) {
|
||||
return [];
|
||||
}
|
||||
return Array.map(window.gBrowser.tabs, tab => this.convert(extension, tab));
|
||||
return TabManager.for(extension).convert(tab);
|
||||
},
|
||||
};
|
||||
|
||||
// WeakMap[Extension -> ExtensionTabManager]
|
||||
let tabManagers = new WeakMap();
|
||||
|
||||
// Returns the extension-specific tab manager for the given extension, or
|
||||
// creates one if it doesn't already exist.
|
||||
TabManager.for = function (extension) {
|
||||
if (!tabManagers.has(extension)) {
|
||||
tabManagers.set(extension, new ExtensionTabManager(extension));
|
||||
}
|
||||
return tabManagers.get(extension);
|
||||
};
|
||||
|
||||
extensions.on("shutdown", (type, extension) => {
|
||||
tabManagers.delete(extension);
|
||||
});
|
||||
|
||||
// Manages mapping between XUL windows and extension window IDs.
|
||||
global.WindowManager = {
|
||||
_windows: new WeakMap(),
|
||||
@ -411,7 +473,7 @@ global.WindowManager = {
|
||||
};
|
||||
|
||||
if (getInfo && getInfo.populate) {
|
||||
results.tabs = TabManager.getTabs(extension, window);
|
||||
results.tabs = TabManager.for(extension).getTabs(window);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
Loading…
Reference in New Issue
Block a user