mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Make browser-policy-content tell webapp about inline script policy.
This avoids the need for webapp to probe for browser-policy without weak-depending on it.
This commit is contained in:
@@ -94,6 +94,11 @@ var setDefaultPolicy = function () {
|
||||
"style-src 'self' 'unsafe-inline';");
|
||||
};
|
||||
|
||||
var setWebAppInlineScripts = function (value) {
|
||||
if (! BrowserPolicy._runningTest())
|
||||
WebAppInternals.setInlineScriptsAllowed(value);
|
||||
};
|
||||
|
||||
_.extend(BrowserPolicy.content, {
|
||||
// Exported for tests and browser-policy-common.
|
||||
_constructCsp: function () {
|
||||
@@ -123,6 +128,9 @@ _.extend(BrowserPolicy.content, {
|
||||
setPolicy: function (csp) {
|
||||
cachedCsp = null;
|
||||
parseCsp(csp);
|
||||
setWebAppInlineScripts(
|
||||
BrowserPolicy.content._keywordAllowed("script-src", unsafeInline)
|
||||
);
|
||||
},
|
||||
|
||||
_keywordAllowed: function (directive, keyword) {
|
||||
@@ -130,29 +138,17 @@ _.extend(BrowserPolicy.content, {
|
||||
_.indexOf(cspSrcs[directive], keyword) !== -1);
|
||||
},
|
||||
|
||||
// Used by webapp to determine whether we need an extra round trip for
|
||||
// __meteor_runtime_config__. If we're in a test run, we should always return
|
||||
// true, since CSP headers are never sent on tests -- unless the
|
||||
// _calledFromTests flag is set, in which case a test is testing what
|
||||
// inlineScriptsAllowed() would return if we weren't in a test. Wphew.
|
||||
// XXX maybe this test interface could be cleaned up
|
||||
inlineScriptsAllowed: function (_calledFromTests) {
|
||||
if (BrowserPolicy._runningTest() && ! _calledFromTests)
|
||||
return true;
|
||||
|
||||
return BrowserPolicy.content._keywordAllowed("script-src",
|
||||
unsafeInline);
|
||||
},
|
||||
|
||||
// Helpers for creating content security policies
|
||||
|
||||
allowInlineScripts: function () {
|
||||
prepareForCspDirective("script-src");
|
||||
cspSrcs["script-src"].push(unsafeInline);
|
||||
setWebAppInlineScripts(true);
|
||||
},
|
||||
disallowInlineScripts: function () {
|
||||
prepareForCspDirective("script-src");
|
||||
removeCspSrc("script-src", unsafeInline);
|
||||
setWebAppInlineScripts(false);
|
||||
},
|
||||
allowEval: function () {
|
||||
prepareForCspDirective("script-src");
|
||||
@@ -189,6 +185,7 @@ _.extend(BrowserPolicy.content, {
|
||||
cspSrcs = {
|
||||
"default-src": []
|
||||
};
|
||||
setWebAppInlineScripts(false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -210,14 +207,23 @@ _.each(["script", "object", "img", "media",
|
||||
var allowDataMethodName = "allow" + methodResource + "DataUrl";
|
||||
var allowSelfMethodName = "allow" + methodResource + "SameOrigin";
|
||||
|
||||
var disallow = function () {
|
||||
cachedCsp = null;
|
||||
cspSrcs[directive] = [];
|
||||
};
|
||||
|
||||
BrowserPolicy.content[allowMethodName] = function (src) {
|
||||
prepareForCspDirective(directive);
|
||||
cspSrcs[directive].push(src);
|
||||
};
|
||||
BrowserPolicy.content[disallowMethodName] = function () {
|
||||
cachedCsp = null;
|
||||
cspSrcs[directive] = [];
|
||||
};
|
||||
if (resource === "script") {
|
||||
BrowserPolicy.content[disallowMethodName] = function () {
|
||||
disallow();
|
||||
setWebAppInlineScripts(false);
|
||||
};
|
||||
} else {
|
||||
BrowserPolicy.content[disallowMethodName] = disallow;
|
||||
}
|
||||
BrowserPolicy.content[allowDataMethodName] = function () {
|
||||
prepareForCspDirective(directive);
|
||||
cspSrcs[directive].push("data:");
|
||||
|
||||
@@ -5,5 +5,5 @@ Package.describe({
|
||||
Package.on_use(function (api) {
|
||||
api.imply(["browser-policy-common"], "server");
|
||||
api.add_files("browser-policy-content.js", "server");
|
||||
api.use(["underscore", "browser-policy-common"], "server");
|
||||
api.use(["underscore", "browser-policy-common", "webapp"], "server");
|
||||
});
|
||||
|
||||
@@ -27,7 +27,7 @@ Tinytest.add("browser-policy - csp", function (test) {
|
||||
BrowserPolicy.content._reset();
|
||||
// Default policy
|
||||
test.isTrue(cspsEqual(BrowserPolicy.content._constructCsp(), defaultCsp));
|
||||
test.isTrue(BrowserPolicy.content.inlineScriptsAllowed(true /* tests-only flag */));
|
||||
test.isTrue(BrowserPolicy.content._keywordAllowed("script-src", "'unsafe-inline'"));
|
||||
|
||||
// Redundant whitelisting (inline scripts already allowed in default policy)
|
||||
BrowserPolicy.content.allowInlineScripts();
|
||||
@@ -38,7 +38,7 @@ Tinytest.add("browser-policy - csp", function (test) {
|
||||
test.isTrue(cspsEqual(BrowserPolicy.content._constructCsp(),
|
||||
"default-src 'self'; script-src 'self'; " +
|
||||
"connect-src * 'self'; img-src data: 'self'; style-src 'self' 'unsafe-inline';"));
|
||||
test.isFalse(BrowserPolicy.content.inlineScriptsAllowed(true));
|
||||
test.isFalse(BrowserPolicy.content._keywordAllowed("script-src", "'unsafe-inline'"));
|
||||
|
||||
// Allow eval
|
||||
BrowserPolicy.content.allowEval();
|
||||
@@ -59,26 +59,26 @@ Tinytest.add("browser-policy - csp", function (test) {
|
||||
// Disallow everything
|
||||
BrowserPolicy.content.disallowAll();
|
||||
test.isTrue(cspsEqual(BrowserPolicy.content._constructCsp(), "default-src 'none';"));
|
||||
test.isFalse(BrowserPolicy.content.inlineScriptsAllowed(true));
|
||||
test.isFalse(BrowserPolicy.content._keywordAllowed("script-src", "'unsafe-inline'"));
|
||||
|
||||
// Put inline scripts back in
|
||||
BrowserPolicy.content.allowInlineScripts();
|
||||
test.isTrue(cspsEqual(BrowserPolicy.content._constructCsp(),
|
||||
"default-src 'none'; script-src 'unsafe-inline';"));
|
||||
test.isTrue(BrowserPolicy.content.inlineScriptsAllowed(true));
|
||||
test.isTrue(BrowserPolicy.content._keywordAllowed("script-src", "'unsafe-inline'"));
|
||||
|
||||
// Add 'self' to all content types
|
||||
BrowserPolicy.content.allowSameOriginForAll();
|
||||
test.isTrue(cspsEqual(BrowserPolicy.content._constructCsp(),
|
||||
"default-src 'self'; script-src 'self' 'unsafe-inline';"));
|
||||
test.isTrue(BrowserPolicy.content.inlineScriptsAllowed(true));
|
||||
test.isTrue(BrowserPolicy.content._keywordAllowed("script-src", "'unsafe-inline'"));
|
||||
|
||||
// Disallow all content except same-origin scripts
|
||||
BrowserPolicy.content.disallowAll();
|
||||
BrowserPolicy.content.allowScriptSameOrigin();
|
||||
test.isTrue(cspsEqual(BrowserPolicy.content._constructCsp(),
|
||||
"default-src 'none'; script-src 'self';"));
|
||||
test.isFalse(BrowserPolicy.content.inlineScriptsAllowed(true));
|
||||
test.isFalse(BrowserPolicy.content._keywordAllowed("script-src", "'unsafe-inline'"));
|
||||
|
||||
// Starting with all content same origin, disallowScript() and then allow
|
||||
// inline scripts. Result should be that that only inline scripts can execute,
|
||||
@@ -89,9 +89,11 @@ Tinytest.add("browser-policy - csp", function (test) {
|
||||
BrowserPolicy.content.disallowScript();
|
||||
test.isTrue(cspsEqual(BrowserPolicy.content._constructCsp(),
|
||||
"default-src 'self'; script-src 'none';"));
|
||||
test.isFalse(BrowserPolicy.content._keywordAllowed("script-src", "'unsafe-inline'"));
|
||||
BrowserPolicy.content.allowInlineScripts();
|
||||
test.isTrue(cspsEqual(BrowserPolicy.content._constructCsp(),
|
||||
"default-src 'self'; script-src 'unsafe-inline';"));
|
||||
test.isTrue(BrowserPolicy.content._keywordAllowed("script-src", "'unsafe-inline'"));
|
||||
|
||||
// Starting with all content same origin, allow inline scripts. (Should result
|
||||
// in both same origin and inline scripts allowed.)
|
||||
|
||||
@@ -231,11 +231,8 @@ var runWebAppServer = function () {
|
||||
return;
|
||||
}
|
||||
|
||||
var browserPolicyPackage = Package["browser-policy-common"];
|
||||
if (pathname === "/meteor_runtime_config.js" &&
|
||||
browserPolicyPackage &&
|
||||
browserPolicyPackage.BrowserPolicy.content &&
|
||||
! browserPolicyPackage.BrowserPolicy.content.inlineScriptsAllowed()) {
|
||||
! WebAppInternals.inlineScriptsAllowed()) {
|
||||
res.writeHead(200, { 'Content-type': 'application/javascript' });
|
||||
res.write("__meteor_runtime_config__ = " +
|
||||
JSON.stringify(__meteor_runtime_config__) + ";");
|
||||
@@ -403,10 +400,7 @@ var runWebAppServer = function () {
|
||||
|
||||
// Include __meteor_runtime_config__ in the app html, as an inline script if
|
||||
// it's not forbidden by CSP.
|
||||
var browserPolicyPackage = Package["browser-policy-common"];
|
||||
if (! browserPolicyPackage ||
|
||||
! browserPolicyPackage.BrowserPolicy.content ||
|
||||
browserPolicyPackage.BrowserPolicy.content.inlineScriptsAllowed()) {
|
||||
if (WebAppInternals.inlineScriptsAllowed()) {
|
||||
boilerplateHtml = boilerplateHtml.replace(
|
||||
/##RUNTIME_CONFIG##/,
|
||||
"<script type='text/javascript'>__meteor_runtime_config__ = " +
|
||||
@@ -572,3 +566,14 @@ WebAppInternals.bindToProxy = function (proxyConfig) {
|
||||
};
|
||||
|
||||
runWebAppServer();
|
||||
|
||||
|
||||
var inlineScriptsAllowed = true;
|
||||
|
||||
WebAppInternals.inlineScriptsAllowed = function () {
|
||||
return inlineScriptsAllowed;
|
||||
};
|
||||
|
||||
WebAppInternals.setInlineScriptsAllowed = function (value) {
|
||||
inlineScriptsAllowed = value;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user