mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-08 00:38:39 +09:00
Rename Toolkit's webextensions component directory to better reflect what it is.
This commit is contained in:
parent
6955450f7a
commit
d7d16e7fbb
242 changed files with 4 additions and 2 deletions
|
|
@ -1,321 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ExtensionManagement"];
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionUtils",
|
||||
"resource://gre/modules/ExtensionUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "console", () => ExtensionUtils.getConsole());
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "UUIDMap", () => {
|
||||
let {UUIDMap} = Cu.import("resource://gre/modules/Extension.jsm", {});
|
||||
return UUIDMap;
|
||||
});
|
||||
|
||||
/*
|
||||
* This file should be kept short and simple since it's loaded even
|
||||
* when no extensions are running.
|
||||
*/
|
||||
|
||||
// Keep track of frame IDs for content windows. Mostly we can just use
|
||||
// the outer window ID as the frame ID. However, the API specifies
|
||||
// that top-level windows have a frame ID of 0. So we need to keep
|
||||
// track of which windows are top-level. This code listens to messages
|
||||
// from ExtensionContent to do that.
|
||||
var Frames = {
|
||||
// Window IDs of top-level content windows.
|
||||
topWindowIds: new Set(),
|
||||
|
||||
init() {
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.mm.addMessageListener("Extension:TopWindowID", this);
|
||||
Services.mm.addMessageListener("Extension:RemoveTopWindowID", this, true);
|
||||
},
|
||||
|
||||
isTopWindowId(windowId) {
|
||||
return this.topWindowIds.has(windowId);
|
||||
},
|
||||
|
||||
// Convert an outer window ID to a frame ID. An outer window ID of 0
|
||||
// is invalid.
|
||||
getId(windowId) {
|
||||
if (this.isTopWindowId(windowId)) {
|
||||
return 0;
|
||||
}
|
||||
if (windowId == 0) {
|
||||
return -1;
|
||||
}
|
||||
return windowId;
|
||||
},
|
||||
|
||||
// Convert an outer window ID for a parent window to a frame
|
||||
// ID. Outer window IDs follow the same convention that
|
||||
// |window.top.parent === window.top|. The API works differently,
|
||||
// giving a frame ID of -1 for the the parent of a top-level
|
||||
// window. This function handles the conversion.
|
||||
getParentId(parentWindowId, windowId) {
|
||||
if (parentWindowId == windowId) {
|
||||
// We have a top-level window.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Not a top-level window. Just return the ID as normal.
|
||||
return this.getId(parentWindowId);
|
||||
},
|
||||
|
||||
receiveMessage({name, data}) {
|
||||
switch (name) {
|
||||
case "Extension:TopWindowID":
|
||||
// FIXME: Need to handle the case where the content process
|
||||
// crashes. Right now we leak its top window IDs.
|
||||
this.topWindowIds.add(data.windowId);
|
||||
break;
|
||||
|
||||
case "Extension:RemoveTopWindowID":
|
||||
this.topWindowIds.delete(data.windowId);
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
||||
Frames.init();
|
||||
|
||||
var APIs = {
|
||||
apis: new Map(),
|
||||
|
||||
register(namespace, schema, script) {
|
||||
if (this.apis.has(namespace)) {
|
||||
throw new Error(`API namespace already exists: ${namespace}`);
|
||||
}
|
||||
|
||||
this.apis.set(namespace, {schema, script});
|
||||
},
|
||||
|
||||
unregister(namespace) {
|
||||
if (!this.apis.has(namespace)) {
|
||||
throw new Error(`API namespace does not exist: ${namespace}`);
|
||||
}
|
||||
|
||||
this.apis.delete(namespace);
|
||||
},
|
||||
};
|
||||
|
||||
function getURLForExtension(id, path = "") {
|
||||
let uuid = UUIDMap.get(id, false);
|
||||
if (!uuid) {
|
||||
Cu.reportError(`Called getURLForExtension on unmapped extension ${id}`);
|
||||
return null;
|
||||
}
|
||||
return `moz-extension://${uuid}/${path}`;
|
||||
}
|
||||
|
||||
// This object manages various platform-level issues related to
|
||||
// moz-extension:// URIs. It lives here so that it can be used in both
|
||||
// the parent and child processes.
|
||||
//
|
||||
// moz-extension URIs have the form moz-extension://uuid/path. Each
|
||||
// extension has its own UUID, unique to the machine it's installed
|
||||
// on. This is easier and more secure than using the extension ID,
|
||||
// since it makes it slightly harder to fingerprint for extensions if
|
||||
// each user uses different URIs for the extension.
|
||||
var Service = {
|
||||
initialized: false,
|
||||
|
||||
// Map[uuid -> extension].
|
||||
// extension can be an Extension (parent process) or BrowserExtensionContent (child process).
|
||||
uuidMap: new Map(),
|
||||
|
||||
init() {
|
||||
let aps = Cc["@mozilla.org/addons/policy-service;1"].getService(Ci.nsIAddonPolicyService);
|
||||
aps = aps.wrappedJSObject;
|
||||
this.aps = aps;
|
||||
aps.setExtensionURILoadCallback(this.extensionURILoadableByAnyone.bind(this));
|
||||
aps.setExtensionURIToAddonIdCallback(this.extensionURIToAddonID.bind(this));
|
||||
},
|
||||
|
||||
// Called when a new extension is loaded.
|
||||
startupExtension(uuid, uri, extension) {
|
||||
if (!this.initialized) {
|
||||
this.initialized = true;
|
||||
this.init();
|
||||
}
|
||||
|
||||
// Create the moz-extension://uuid mapping.
|
||||
let handler = Services.io.getProtocolHandler("moz-extension");
|
||||
handler.QueryInterface(Ci.nsISubstitutingProtocolHandler);
|
||||
handler.setSubstitution(uuid, uri);
|
||||
|
||||
this.uuidMap.set(uuid, extension);
|
||||
this.aps.setAddonHasPermissionCallback(extension.id, extension.hasPermission.bind(extension));
|
||||
this.aps.setAddonLoadURICallback(extension.id, this.checkAddonMayLoad.bind(this, extension));
|
||||
this.aps.setAddonLocalizeCallback(extension.id, extension.localize.bind(extension));
|
||||
this.aps.setAddonCSP(extension.id, extension.manifest.content_security_policy);
|
||||
this.aps.setBackgroundPageUrlCallback(uuid, this.generateBackgroundPageUrl.bind(this, extension));
|
||||
},
|
||||
|
||||
// Called when an extension is unloaded.
|
||||
shutdownExtension(uuid) {
|
||||
let extension = this.uuidMap.get(uuid);
|
||||
this.uuidMap.delete(uuid);
|
||||
this.aps.setAddonHasPermissionCallback(extension.id, null);
|
||||
this.aps.setAddonLoadURICallback(extension.id, null);
|
||||
this.aps.setAddonLocalizeCallback(extension.id, null);
|
||||
this.aps.setAddonCSP(extension.id, null);
|
||||
this.aps.setBackgroundPageUrlCallback(uuid, null);
|
||||
|
||||
let handler = Services.io.getProtocolHandler("moz-extension");
|
||||
handler.QueryInterface(Ci.nsISubstitutingProtocolHandler);
|
||||
handler.setSubstitution(uuid, null);
|
||||
},
|
||||
|
||||
// Return true if the given URI can be loaded from arbitrary web
|
||||
// content. The manifest.json |web_accessible_resources| directive
|
||||
// determines this.
|
||||
extensionURILoadableByAnyone(uri) {
|
||||
let uuid = uri.host;
|
||||
let extension = this.uuidMap.get(uuid);
|
||||
if (!extension || !extension.webAccessibleResources) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let path = uri.QueryInterface(Ci.nsIURL).filePath;
|
||||
if (path.length > 0 && path[0] == "/") {
|
||||
path = path.substr(1);
|
||||
}
|
||||
return extension.webAccessibleResources.matches(path);
|
||||
},
|
||||
|
||||
// Checks whether a given extension can load this URI (typically via
|
||||
// an XML HTTP request). The manifest.json |permissions| directive
|
||||
// determines this.
|
||||
checkAddonMayLoad(extension, uri) {
|
||||
return extension.whiteListedHosts.matchesIgnoringPath(uri);
|
||||
},
|
||||
|
||||
generateBackgroundPageUrl(extension) {
|
||||
let background_scripts = extension.manifest.background &&
|
||||
extension.manifest.background.scripts;
|
||||
if (!background_scripts) {
|
||||
return;
|
||||
}
|
||||
let html = "<!DOCTYPE html>\n<body>\n";
|
||||
for (let script of background_scripts) {
|
||||
script = script.replace(/"/g, """);
|
||||
html += `<script src="${script}"></script>\n`;
|
||||
}
|
||||
html += "</body>\n</html>\n";
|
||||
return "data:text/html;charset=utf-8," + encodeURIComponent(html);
|
||||
},
|
||||
|
||||
// Finds the add-on ID associated with a given moz-extension:// URI.
|
||||
// This is used to set the addonId on the originAttributes for the
|
||||
// nsIPrincipal attached to the URI.
|
||||
extensionURIToAddonID(uri) {
|
||||
let uuid = uri.host;
|
||||
let extension = this.uuidMap.get(uuid);
|
||||
return extension ? extension.id : undefined;
|
||||
},
|
||||
};
|
||||
|
||||
// API Levels Helpers
|
||||
|
||||
// Find the add-on associated with this document via the
|
||||
// principal's originAttributes. This value is computed by
|
||||
// extensionURIToAddonID, which ensures that we don't inject our
|
||||
// API into webAccessibleResources or remote web pages.
|
||||
function getAddonIdForWindow(window) {
|
||||
return Cu.getObjectPrincipal(window).originAttributes.addonId;
|
||||
}
|
||||
|
||||
const API_LEVELS = Object.freeze({
|
||||
NO_PRIVILEGES: 0,
|
||||
CONTENTSCRIPT_PRIVILEGES: 1,
|
||||
FULL_PRIVILEGES: 2,
|
||||
});
|
||||
|
||||
// Finds the API Level ("FULL_PRIVILEGES", "CONTENTSCRIPT_PRIVILEGES", "NO_PRIVILEGES")
|
||||
// with a given a window object.
|
||||
function getAPILevelForWindow(window, addonId) {
|
||||
const {NO_PRIVILEGES, CONTENTSCRIPT_PRIVILEGES, FULL_PRIVILEGES} = API_LEVELS;
|
||||
|
||||
// Non WebExtension URLs and WebExtension URLs from a different extension
|
||||
// has no access to APIs.
|
||||
if (!addonId || getAddonIdForWindow(window) != addonId) {
|
||||
return NO_PRIVILEGES;
|
||||
}
|
||||
|
||||
// Extension pages running in the content process always defaults to
|
||||
// "content script API level privileges".
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
return CONTENTSCRIPT_PRIVILEGES;
|
||||
}
|
||||
|
||||
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDocShell);
|
||||
|
||||
// Handling of ExtensionPages running inside sub-frames.
|
||||
if (docShell.sameTypeParent) {
|
||||
let parentWindow = docShell.sameTypeParent.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
|
||||
// The option page iframe embedded in the about:addons tab should have
|
||||
// full API level privileges. (see Bug 1256282 for rationale)
|
||||
let parentDocument = parentWindow.document;
|
||||
let parentIsSystemPrincipal = Services.scriptSecurityManager
|
||||
.isSystemPrincipal(parentDocument.nodePrincipal);
|
||||
if (parentDocument.location.href == "about:addons" && parentIsSystemPrincipal) {
|
||||
return FULL_PRIVILEGES;
|
||||
}
|
||||
|
||||
// The addon iframes embedded in a addon page from with the same addonId
|
||||
// should have the same privileges of the sameTypeParent.
|
||||
// (see Bug 1258347 for rationale)
|
||||
let parentSameAddonPrivileges = getAPILevelForWindow(parentWindow, addonId);
|
||||
if (parentSameAddonPrivileges > NO_PRIVILEGES) {
|
||||
return parentSameAddonPrivileges;
|
||||
}
|
||||
|
||||
// In all the other cases, WebExtension URLs loaded into sub-frame UI
|
||||
// will have "content script API level privileges".
|
||||
// (see Bug 1214658 for rationale)
|
||||
return CONTENTSCRIPT_PRIVILEGES;
|
||||
}
|
||||
|
||||
// WebExtension URLs loaded into top frames UI could have full API level privileges.
|
||||
return FULL_PRIVILEGES;
|
||||
}
|
||||
|
||||
this.ExtensionManagement = {
|
||||
startupExtension: Service.startupExtension.bind(Service),
|
||||
shutdownExtension: Service.shutdownExtension.bind(Service),
|
||||
|
||||
registerAPI: APIs.register.bind(APIs),
|
||||
unregisterAPI: APIs.unregister.bind(APIs),
|
||||
|
||||
getFrameId: Frames.getId.bind(Frames),
|
||||
getParentFrameId: Frames.getParentId.bind(Frames),
|
||||
|
||||
getURLForExtension,
|
||||
|
||||
// exported API Level Helpers
|
||||
getAddonIdForWindow,
|
||||
getAPILevelForWindow,
|
||||
API_LEVELS,
|
||||
|
||||
APIs,
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue