Bug 1368102: Part 4 - Use WebExtensionContentScript to match content scripts. r=mixedpuppy,zombie

MozReview-Commit-ID: 1Ga0259WjC
This commit is contained in:
Kris Maglione
2017-06-03 17:11:08 -07:00
parent f29027b906
commit 861919618a
4 changed files with 88 additions and 118 deletions

View File

@@ -19,8 +19,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
"resource://gre/modules/ExtensionManagement.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
"resource://gre/modules/MessageChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "WebNavigationFrames",
"resource://gre/modules/WebNavigationFrames.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionChild",
"resource://gre/modules/ExtensionChild.jsm");
@@ -39,33 +37,39 @@ XPCOMUtils.defineLazyGetter(this, "getInnerWindowID", () => ExtensionUtils.getIn
const appinfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
const isContentProcess = appinfo.processType == appinfo.PROCESS_TYPE_CONTENT;
function parseScriptOptions(options) {
return {
allFrames: options.all_frames,
matchAboutBlank: options.match_about_blank,
frameID: options.frame_id,
runAt: options.run_at,
matches: new MatchPatternSet(options.matches),
excludeMatches: new MatchPatternSet(options.exclude_matches || []),
includeGlobs: options.include_globs && options.include_globs.map(glob => new MatchGlob(glob)),
excludeGlobs: options.exclude_globs && options.exclude_globs.map(glob => new MatchGlob(glob)),
jsPaths: options.js || [],
cssPaths: options.css || [],
};
}
class ScriptMatcher {
constructor(extension, options) {
constructor(extension, matcher) {
this.extension = extension;
this.options = options;
this.matcher = matcher;
this._script = null;
this.allFrames = options.all_frames;
this.matchAboutBlank = options.match_about_blank;
this.frameId = options.frame_id;
this.runAt = options.run_at;
this.matches = new MatchPatternSet(options.matches);
this.excludeMatches = new MatchPatternSet(options.exclude_matches || []);
this.includeGlobs = options.include_globs && options.include_globs.map(glob => new MatchGlob(glob));
this.excludeGlobs = options.include_globs && options.exclude_globs.map(glob => new MatchGlob(glob));
}
toString() {
return `[Script {js: [${this.options.js}], matchAboutBlank: ${this.matchAboutBlank}, runAt: ${this.runAt}, matches: ${this.options.matches}}]`;
get matchAboutBlank() {
return this.matcher.matchAboutBlank;
}
get script() {
if (!this._script) {
this._script = new ExtensionContent.Script(this.extension.realExtension,
this.options);
this.matcher);
}
return this._script;
}
@@ -78,82 +82,11 @@ class ScriptMatcher {
}
matchesLoadInfo(uri, loadInfo) {
if (!this.matchesURI(uri)) {
return false;
}
if (!this.allFrames && !loadInfo.isTopLevelLoad) {
return false;
}
return true;
}
matchesURI(uri) {
if (!(this.matches.matches(uri))) {
return false;
}
if (this.excludeMatches.matches(uri)) {
return false;
}
if (this.includeGlobs && !this.includeGlobs.some(glob => glob.matches(uri.spec))) {
return false;
}
if (this.excludeGlobs && this.excludeGlobs.some(glob => glob.matches(uri.spec))) {
return false;
}
return true;
return this.matcher.matchesLoadInfo(uri, loadInfo);
}
matchesWindow(window) {
if (!this.allFrames && this.frameId == null && window.parent !== window) {
return false;
}
let uri = window.document.documentURIObject;
let principal = window.document.nodePrincipal;
if (this.matchAboutBlank) {
// When matching top-level about:blank documents,
// allow loading into any with a NullPrincipal.
if (uri.spec === "about:blank" && window === window.parent && principal.isNullPrincipal) {
return true;
}
// When matching about:blank/srcdoc iframes, the checks below
// need to be performed against the "owner" document's URI.
if (["about:blank", "about:srcdoc"].includes(uri.spec)) {
uri = principal.URI;
}
}
// Documents from data: URIs also inherit the principal.
if (Services.netUtils.URIChainHasFlags(uri, Ci.nsIProtocolHandler.URI_INHERITS_SECURITY_CONTEXT)) {
if (!this.matchAboutBlank) {
return false;
}
uri = principal.URI;
}
if (!this.matchesURI(uri)) {
return false;
}
if (this.frameId != null && WebNavigationFrames.getFrameId(window) !== this.frameId) {
return false;
}
// If mozAddonManager is present on this page, don't allow
// content scripts.
if (window.navigator.mozAddonManager !== undefined) {
return false;
}
return true;
return this.matcher.matchesWindow(window);
}
injectInto(window) {
@@ -202,7 +135,18 @@ class ExtensionGlobal {
return ExtensionContent.handleDetectLanguage(this.global, target);
case "Extension:Execute":
let extension = ExtensionManager.get(recipient.extensionId);
let script = new ScriptMatcher(extension, data.options);
let matcher = new WebExtensionContentScript(extension.policy, parseScriptOptions(data.options));
let options = Object.assign(matcher, {
wantReturnValue: data.options.wantReturnValue,
removeCSS: data.options.remove_css,
cssOrigin: data.options.css_origin,
cssCode: data.options.cssCode,
jsCode: data.options.jsCode,
});
let script = new ScriptMatcher(extension, options);
return ExtensionContent.handleExtensionExecute(this.global, target, data.options, script);
case "WebNavigation:GetFrame":
@@ -536,11 +480,11 @@ class StubExtension {
this.whiteListedHosts = new MatchPatternSet(data.whiteListedHosts);
this.webAccessibleResources = data.webAccessibleResources.map(path => new MatchGlob(path));
this.scripts = data.content_scripts.map(scriptData => new ScriptMatcher(this, scriptData));
this._realExtension = null;
this.startup();
this.scripts = this.policy.contentScripts.map(matcher => new ScriptMatcher(this, matcher));
}
startup() {
@@ -548,6 +492,8 @@ class StubExtension {
if (isContentProcess) {
let uri = Services.io.newURI(this.data.resourceURL);
ExtensionManagement.startupExtension(this.uuid, uri, this);
} else {
this.policy = WebExtensionPolicy.getByID(this.id);
}
}