mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-04 04:58:00 +00:00
bug 836922 - (CSP) remove intersectWith once multiple policies are supported. r=grobinson
This commit is contained in:
parent
533fe16a0b
commit
11eccea08a
@ -465,8 +465,8 @@ CSPRep.fromString = function(aStr, self, docRequest, csp, reportOnly) {
|
||||
return CSPRep.fromString("default-src 'none'");
|
||||
}
|
||||
|
||||
// return a fully-open policy to be intersected with the contents of the
|
||||
// policy-uri when it returns
|
||||
// return a fully-open policy to be used until the contents of the
|
||||
// policy-uri come back.
|
||||
return CSPRep.fromString("default-src *");
|
||||
}
|
||||
|
||||
@ -723,8 +723,8 @@ CSPRep.fromStringSpecCompliant = function(aStr, self, docRequest, csp, reportOnl
|
||||
return CSPRep.fromStringSpecCompliant("default-src 'none'");
|
||||
}
|
||||
|
||||
// return a fully-open policy to be intersected with the contents of the
|
||||
// policy-uri when it returns
|
||||
// return a fully-open policy to be used until the contents of the
|
||||
// policy-uri come back
|
||||
return CSPRep.fromStringSpecCompliant("default-src *");
|
||||
}
|
||||
|
||||
@ -843,120 +843,6 @@ CSPRep.prototype = {
|
||||
return this._specCompliant;
|
||||
},
|
||||
|
||||
/**
|
||||
* Intersects with another CSPRep, deciding the subset policy
|
||||
* that should be enforced, and returning a new instance.
|
||||
* This assumes that either both CSPReps are specCompliant or they are both
|
||||
* not.
|
||||
* @param aCSPRep
|
||||
* a CSPRep instance to use as "other" CSP
|
||||
* @returns
|
||||
* a new CSPRep instance of the intersection
|
||||
*/
|
||||
intersectWith:
|
||||
function cspsd_intersectWith(aCSPRep) {
|
||||
var newRep = new CSPRep();
|
||||
|
||||
let DIRS = aCSPRep._specCompliant ? CSPRep.SRC_DIRECTIVES_NEW :
|
||||
CSPRep.SRC_DIRECTIVES_OLD;
|
||||
|
||||
// one or more of the two CSPReps may not have any given directive. In
|
||||
// these cases, we need to pick "all" or "none" based on the type of CSPRep
|
||||
// (spec compliant or not).
|
||||
let thisHasDefault = this._directives.hasOwnProperty(DIRS.DEFAULT_SRC),
|
||||
thatHasDefault = aCSPRep._directives.hasOwnProperty(DIRS.DEFAULT_SRC);
|
||||
for (var dir in DIRS) {
|
||||
let dirv = DIRS[dir];
|
||||
let thisHasDir = this._directives.hasOwnProperty(dirv),
|
||||
thatHasDir = aCSPRep._directives.hasOwnProperty(dirv);
|
||||
|
||||
|
||||
// if both specific src directives are absent, skip this (new policy will
|
||||
// rely on default-src)
|
||||
if (!thisHasDir && !thatHasDir) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// frame-ancestors is a special case; it doesn't fall back to
|
||||
// default-src, so only add it to newRep if one or both of the policies
|
||||
// have it.
|
||||
if (dirv === DIRS.FRAME_ANCESTORS) {
|
||||
if (thisHasDir && thatHasDir) {
|
||||
// both have frame-ancestors, intersect them.
|
||||
newRep._directives[dirv] =
|
||||
aCSPRep._directives[dirv].intersectWith(this._directives[dirv]);
|
||||
} else if (thisHasDir || thatHasDir) {
|
||||
// one or the other has frame-ancestors, copy it.
|
||||
newRep._directives[dirv] =
|
||||
( thisHasDir ? this : aCSPRep )._directives[dirv].clone();
|
||||
}
|
||||
}
|
||||
else if (aCSPRep._specCompliant) {
|
||||
// CSP 1.0 doesn't require default-src, so an intersection only makes
|
||||
// sense if there is a default-src or both policies have the directive.
|
||||
|
||||
if (!thisHasDir && !thisHasDefault) {
|
||||
// only aCSPRep has a relevant directive
|
||||
newRep._directives[dirv] = aCSPRep._directives[dirv].clone();
|
||||
}
|
||||
else if (!thatHasDir && !thatHasDefault) {
|
||||
// only "this" has a relevant directive
|
||||
newRep._directives[dirv] = this._directives[dirv].clone();
|
||||
}
|
||||
else {
|
||||
// both policies have a relevant directive (may be default-src)
|
||||
var isect1 = thisHasDir ?
|
||||
this._directives[dirv] :
|
||||
this._directives[DIRS.DEFAULT_SRC];
|
||||
var isect2 = thatHasDir ?
|
||||
aCSPRep._directives[dirv] :
|
||||
aCSPRep._directives[DIRS.DEFAULT_SRC];
|
||||
newRep._directives[dirv] = isect1.intersectWith(isect2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// pre-1.0 CSP requires a default-src, so we can assume it's here
|
||||
// (since the parser created one).
|
||||
var isect1 = thisHasDir ?
|
||||
this._directives[dirv] :
|
||||
this._directives[DIRS.DEFAULT_SRC];
|
||||
var isect2 = thatHasDir ?
|
||||
aCSPRep._directives[dirv] :
|
||||
aCSPRep._directives[DIRS.DEFAULT_SRC];
|
||||
newRep._directives[dirv] = isect1.intersectWith(isect2);
|
||||
}
|
||||
}
|
||||
|
||||
// REPORT_URI
|
||||
var reportURIDir = CSPRep.URI_DIRECTIVES.REPORT_URI;
|
||||
if (this._directives[reportURIDir] && aCSPRep._directives[reportURIDir]) {
|
||||
newRep._directives[reportURIDir] =
|
||||
this._directives[reportURIDir].concat(aCSPRep._directives[reportURIDir]);
|
||||
}
|
||||
else if (this._directives[reportURIDir]) {
|
||||
// blank concat makes a copy of the string.
|
||||
newRep._directives[reportURIDir] = this._directives[reportURIDir].concat();
|
||||
}
|
||||
else if (aCSPRep._directives[reportURIDir]) {
|
||||
// blank concat makes a copy of the string.
|
||||
newRep._directives[reportURIDir] = aCSPRep._directives[reportURIDir].concat();
|
||||
}
|
||||
|
||||
newRep._allowEval = this.allowsEvalInScripts
|
||||
&& aCSPRep.allowsEvalInScripts;
|
||||
|
||||
newRep._allowInlineScripts = this.allowsInlineScripts
|
||||
&& aCSPRep.allowsInlineScripts;
|
||||
|
||||
newRep._allowInlineStyles = this.allowsInlineStyles
|
||||
&& aCSPRep.allowsInlineStyles;
|
||||
|
||||
newRep._innerWindowID = this._innerWindowID ?
|
||||
this._innerWindowID : aCSPRep._innerWindowID;
|
||||
|
||||
return newRep;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if "eval" is enabled through the "eval" keyword.
|
||||
*/
|
||||
@ -1199,62 +1085,6 @@ CSPSourceList.prototype = {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Intersects with another CSPSourceList, deciding the subset directive
|
||||
* that should be enforced, and returning a new instance.
|
||||
* @param that
|
||||
* the other CSPSourceList to intersect "this" with
|
||||
* @returns
|
||||
* a new instance of a CSPSourceList representing the intersection
|
||||
*/
|
||||
intersectWith:
|
||||
function cspsd_intersectWith(that) {
|
||||
|
||||
var newCSPSrcList = null;
|
||||
|
||||
if (!that) return this.clone();
|
||||
|
||||
if (this.isNone() || that.isNone())
|
||||
newCSPSrcList = CSPSourceList.fromString("'none'", this._CSPRep);
|
||||
|
||||
if (this.isAll()) newCSPSrcList = that.clone();
|
||||
if (that.isAll()) newCSPSrcList = this.clone();
|
||||
|
||||
if (!newCSPSrcList) {
|
||||
// the shortcuts didn't apply, must do intersection the hard way.
|
||||
// -- find only common sources
|
||||
|
||||
// XXX (sid): we should figure out a better algorithm for this.
|
||||
// This is horribly inefficient.
|
||||
var isrcs = [];
|
||||
for (var i in this._sources) {
|
||||
for (var j in that._sources) {
|
||||
var s = that._sources[j].intersectWith(this._sources[i]);
|
||||
if (s) {
|
||||
isrcs.push(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Next, remove duplicates
|
||||
dup: for (var i = 0; i < isrcs.length; i++) {
|
||||
for (var j = 0; j < i; j++) {
|
||||
if (isrcs[i].equals(isrcs[j])) {
|
||||
isrcs.splice(i, 1);
|
||||
i--;
|
||||
continue dup;
|
||||
}
|
||||
}
|
||||
}
|
||||
newCSPSrcList = new CSPSourceList();
|
||||
newCSPSrcList._sources = isrcs;
|
||||
}
|
||||
|
||||
if ((!newCSPSrcList._CSPRep) && that._CSPRep) {
|
||||
newCSPSrcList._CSPRep = that._CSPRep;
|
||||
}
|
||||
return newCSPSrcList;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1668,93 +1498,6 @@ CSPSource.prototype = {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines the intersection of two sources.
|
||||
* Returns a null object if intersection generates no
|
||||
* hosts that satisfy it.
|
||||
* @param that
|
||||
* the other CSPSource to intersect "this" with
|
||||
* @returns
|
||||
* a new instance of a CSPSource representing the intersection
|
||||
*/
|
||||
intersectWith:
|
||||
function(that) {
|
||||
var newSource = new CSPSource();
|
||||
|
||||
// 'self' is not part of the intersection. Intersect the raw values from
|
||||
// the source, self must be set by someone creating this source.
|
||||
// When intersecting, we take the more specific of the two: if one scheme,
|
||||
// host or port is undefined, the other is taken. (This is contrary to
|
||||
// when "permits" is called -- there, the value of 'self' is looked at
|
||||
// when a scheme, host or port is undefined.)
|
||||
|
||||
// port
|
||||
if (!this.port)
|
||||
newSource._port = that.port;
|
||||
else if (!that.port)
|
||||
newSource._port = this.port;
|
||||
else if (this.port === "*")
|
||||
newSource._port = that.port;
|
||||
else if (that.port === "*")
|
||||
newSource._port = this.port;
|
||||
else if (that.port === this.port)
|
||||
newSource._port = this.port;
|
||||
else {
|
||||
let msg = CSPLocalizer.getFormatStr("notIntersectPort",
|
||||
[this.toString(), that.toString()]);
|
||||
cspError(this._CSPRep, msg);
|
||||
return null;
|
||||
}
|
||||
|
||||
// scheme
|
||||
if (!this.scheme)
|
||||
newSource._scheme = that.scheme;
|
||||
else if (!that.scheme)
|
||||
newSource._scheme = this.scheme;
|
||||
if (this.scheme === "*")
|
||||
newSource._scheme = that.scheme;
|
||||
else if (that.scheme === "*")
|
||||
newSource._scheme = this.scheme;
|
||||
else if (that.scheme === this.scheme)
|
||||
newSource._scheme = this.scheme;
|
||||
else {
|
||||
var msg = CSPLocalizer.getFormatStr("notIntersectScheme",
|
||||
[this.toString(), that.toString()]);
|
||||
cspError(this._CSPRep, msg);
|
||||
return null;
|
||||
}
|
||||
|
||||
// NOTE: Both sources must have a host, if they don't, something funny is
|
||||
// going on. The fromString() factory method should have set the host to
|
||||
// * if there's no host specified in the input. Regardless, if a host is
|
||||
// not present either the scheme is hostless or any host should be allowed.
|
||||
// This means we can use the other source's host as the more restrictive
|
||||
// host expression, or if neither are present, we can use "*", but the
|
||||
// error should still be reported.
|
||||
|
||||
// host
|
||||
if (this.host && that.host) {
|
||||
newSource._host = this.host.intersectWith(that.host);
|
||||
} else if (this.host) {
|
||||
let msg = CSPLocalizer.getFormatStr("intersectingSourceWithUndefinedHost",
|
||||
[that.toString()]);
|
||||
cspError(this._CSPRep, msg);
|
||||
newSource._host = this.host.clone();
|
||||
} else if (that.host) {
|
||||
let msg = CSPLocalizer.getFormatStr("intersectingSourceWithUndefinedHost",
|
||||
[this.toString()]);
|
||||
cspError(this._CSPRep, msg);
|
||||
newSource._host = that.host.clone();
|
||||
} else {
|
||||
let msg = CSPLocalizer.getFormatStr("intersectingSourcesWithUndefinedHosts",
|
||||
[this.toString(), that.toString()]);
|
||||
cspError(this._CSPRep, msg);
|
||||
newSource._host = CSPHost.fromString("*");
|
||||
}
|
||||
|
||||
return newSource;
|
||||
},
|
||||
|
||||
/**
|
||||
* Compares one CSPSource to another.
|
||||
*
|
||||
@ -1903,36 +1646,6 @@ CSPHost.prototype = {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines the intersection of two Hosts.
|
||||
* Basically, they must be the same, or one must have a wildcard.
|
||||
* @param that
|
||||
* the other CSPHost to intersect "this" with
|
||||
* @returns
|
||||
* a new instance of a CSPHost representing the intersection
|
||||
* (or null, if they can't be intersected)
|
||||
*/
|
||||
intersectWith:
|
||||
function(that) {
|
||||
if (!(this.permits(that) || that.permits(this))) {
|
||||
// host definitions cannot co-exist without a more general host
|
||||
// ... one must be a subset of the other, or intersection makes no sense.
|
||||
return null;
|
||||
}
|
||||
|
||||
// pick the more specific one, if both are same length.
|
||||
if (this._segments.length == that._segments.length) {
|
||||
// *.a vs b.a : b.a
|
||||
return (this._segments[0] === "*") ? that.clone() : this.clone();
|
||||
}
|
||||
|
||||
// different lengths...
|
||||
// *.b.a vs *.a : *.b.a
|
||||
// *.b.a vs d.c.b.a : d.c.b.a
|
||||
return (this._segments.length > that._segments.length) ?
|
||||
this.clone() : that.clone();
|
||||
},
|
||||
|
||||
/**
|
||||
* Compares one CSPHost to another.
|
||||
*
|
||||
|
@ -141,15 +141,6 @@ test(
|
||||
do_check_true( h2.permits("a.b.c")); //"CSPHost a.b.c should allow string a.b.c"
|
||||
});
|
||||
|
||||
test(
|
||||
function test_CSPHost_intersectWith() {
|
||||
var h = CSPHost.fromString("*.b.c");
|
||||
//"*.a.b.c ^ *.b.c should be *.a.b.c"
|
||||
do_check_eq("*.a.b.c", h.intersectWith(CSPHost.fromString("*.a.b.c")).toString());
|
||||
|
||||
//"*.b.c ^ *.d.e should not work (null)"
|
||||
do_check_eq(null, h.intersectWith(CSPHost.fromString("*.d.e")));
|
||||
});
|
||||
|
||||
///////////////////// Test the Source object //////////////////////
|
||||
|
||||
@ -317,42 +308,6 @@ test(
|
||||
do_check_false(wildcardHostSourceList.permits("http://barbaz.com"));
|
||||
});
|
||||
|
||||
test(
|
||||
function test_CSPSourceList_intersect() {
|
||||
// for this test, 'self' values are irrelevant
|
||||
// policy a /\ policy b intersects policies, not context (where 'self'
|
||||
// values come into play)
|
||||
var nullSourceList = CSPSourceList.fromString("'none'");
|
||||
var simpleSourceList = CSPSourceList.fromString("http://a.com");
|
||||
var doubleSourceList = CSPSourceList.fromString("https://foo.com http://bar.com:88");
|
||||
var singleFooSourceList = CSPSourceList.fromString("https://foo.com");
|
||||
var allSourceList = CSPSourceList.fromString("*");
|
||||
|
||||
//"Intersection of one source with 'none' source list should be none.");
|
||||
do_check_true(nullSourceList.intersectWith(simpleSourceList).isNone());
|
||||
//"Intersection of two sources with 'none' source list should be none.");
|
||||
do_check_true(nullSourceList.intersectWith(doubleSourceList).isNone());
|
||||
//"Intersection of '*' with 'none' source list should be none.");
|
||||
do_check_true(nullSourceList.intersectWith(allSourceList).isNone());
|
||||
|
||||
//"Intersection of one source with '*' source list should be one source.");
|
||||
do_check_equivalent(allSourceList.intersectWith(simpleSourceList),
|
||||
simpleSourceList);
|
||||
//"Intersection of two sources with '*' source list should be two sources.");
|
||||
do_check_equivalent(allSourceList.intersectWith(doubleSourceList),
|
||||
doubleSourceList);
|
||||
|
||||
//"Non-overlapping source lists should intersect to 'none'");
|
||||
do_check_true(simpleSourceList.intersectWith(doubleSourceList).isNone());
|
||||
|
||||
//"subset and superset should intersect to subset.");
|
||||
do_check_equivalent(singleFooSourceList,
|
||||
doubleSourceList.intersectWith(singleFooSourceList));
|
||||
|
||||
//TODO: write more tests?
|
||||
|
||||
});
|
||||
|
||||
///////////////////// Test the Whole CSP rep object //////////////////////
|
||||
|
||||
test(
|
||||
|
Loading…
x
Reference in New Issue
Block a user