Skip to content

Commit

Permalink
chore(CSP): WIP, fixes #1923 - add CSP to the payments server
Browse files Browse the repository at this point in the history
  • Loading branch information
LZoog committed Aug 2, 2019
1 parent e30527a commit 300dea0
Show file tree
Hide file tree
Showing 9 changed files with 291 additions and 183 deletions.
6 changes: 4 additions & 2 deletions packages/fxa-content-server/server/bin/fxa-content-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ const fourOhFour = require('../lib/404');
const serverErrorHandler = require('../lib/500');
const localizedRender = require('../lib/localized-render');
const csp = require('../lib/csp');
const cspRulesBlocking = require('../lib/csp/blocking')(config);
const cspRulesReportOnly = require('../lib/csp/report-only')(config);
const cspRulesBlocking = require('../../../fxa-shared/csp/blocking')(config);
const cspRulesReportOnly = require('../../../fxa-shared/csp/report-only')(
config
);

const STATIC_DIRECTORY = path.join(
__dirname,
Expand Down
10 changes: 5 additions & 5 deletions packages/fxa-content-server/tests/server/csp.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
const { registerSuite } = intern.getInterface('object');
const assert = intern.getPlugin('chai').assert;
const config = require('../../server/lib/configuration');
const BlockingRules = require('../../server/lib/csp/blocking');
const path = require('path');
const blockingRules = require('../../../fxa-shared/csp/blocking');
const proxyquire = require('proxyquire');

const csp = proxyquire(path.join(process.cwd(), 'server', 'lib', 'csp'), {
Expand Down Expand Up @@ -34,15 +34,15 @@ suite.tests['blockingRules'] = function() {
const CDN_SERVER = 'https://static.accounts.firefox.com';
config.set('static_resource_url', CDN_SERVER);

const blockingRules = BlockingRules(config);
const Sources = blockingRules.Sources;
const blockingRulesWithConfig = blockingRules(config);
const Sources = blockingRulesWithConfig.Sources;

// Ensure none of the Sources map to `undefined`G
assert.notProperty(Sources, 'undefined');

assert.isFalse(blockingRules.reportOnly);
assert.isFalse(blockingRulesWithConfig.reportOnly);

const directives = blockingRules.directives;
const directives = blockingRulesWithConfig.directives;

const connectSrc = directives.connectSrc;
assert.lengthOf(connectSrc, 7);
Expand Down
236 changes: 138 additions & 98 deletions packages/fxa-payments-server/server/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,182 +2,222 @@
* 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';
"use strict";

const fs = require('fs');
const path = require('path');
const convict = require('convict');
const fs = require("fs");
const path = require("path");
const convict = require("convict");

const conf = convict({
clientAddressDepth: {
default: 3,
doc: 'location of the client ip address in the remote address chain',
env: 'CLIENT_ADDRESS_DEPTH',
doc: "location of the client ip address in the remote address chain",
env: "CLIENT_ADDRESS_DEPTH",
format: Number
},
csp: {
enabled: {
default: false,
doc: 'Send "Content-Security-Policy" header',
env: "CSP_ENABLED"
},
/*eslint-disable sorting/sort-object-props*/
reportUri: {
default: "/_/csp-violation",
doc: 'Location of "report-uri" for full, blocking CSP rules',
env: "CSP_REPORT_URI"
},
reportOnly: {
default: false,
doc:
'DEPRECATED - Only send the "Content-Security-Policy-Report-Only" header',
env: "CSP_REPORT_ONLY"
},
reportOnlyEnabled: {
default: false,
doc: 'Send "Content-Security-Policy-Report-Only" header',
env: "CSP_REPORT_ONLY_ENABLED"
},
reportOnlyUri: {
default: "/_/csp-violation-report-only",
doc: 'Location of "report-uri" for report-only CSP rules',
env: "CSP_REPORT_ONLY_URI"
}
/*eslint-enable sorting/sort-object-props*/
},
env: {
default: 'production',
doc: 'The current node.js environment',
env: 'NODE_ENV',
format: [ 'development', 'production' ],
default: "production",
doc: "The current node.js environment",
env: "NODE_ENV",
format: ["development", "production"]
},
hstsMaxAge: {
default: 31536000, // a year
doc: 'Max age of the STS directive in seconds',
doc: "Max age of the STS directive in seconds",
// Note: This format is a number because the value needs to be in seconds
format: Number
},
listen: {
host: {
default: '127.0.0.1',
doc: 'The ip address the server should bind',
env: 'IP_ADDRESS',
format: 'ipaddress',
default: "127.0.0.1",
doc: "The ip address the server should bind",
env: "IP_ADDRESS",
format: "ipaddress"
},
port: {
default: 3031,
doc: 'The port the server should bind',
env: 'PORT',
format: 'port',
doc: "The port the server should bind",
env: "PORT",
format: "port"
},
publicUrl: {
default: 'http://127.0.0.1:3031',
env: 'PUBLIC_URL',
format: 'url',
default: "http://127.0.0.1:3031",
env: "PUBLIC_URL",
format: "url"
},
useHttps: {
default: false,
doc: 'set to true to serve directly over https',
env: 'USE_TLS',
},
doc: "set to true to serve directly over https",
env: "USE_TLS"
}
},
logging: {
app: { default: 'fxa-payments-server' },
app: { default: "fxa-payments-server" },
fmt: {
default: 'heka',
env: 'LOGGING_FORMAT',
format: [
'heka',
'pretty'
],
default: "heka",
env: "LOGGING_FORMAT",
format: ["heka", "pretty"]
},
level: {
default: 'info',
env: 'LOG_LEVEL'
default: "info",
env: "LOG_LEVEL"
},
routes: {
enabled: {
default: true,
doc: 'Enable route logging. Set to false to trimming CI logs.',
env: 'ENABLE_ROUTE_LOGGING'
doc: "Enable route logging. Set to false to trimming CI logs.",
env: "ENABLE_ROUTE_LOGGING"
},
format: {
default: 'default_fxa',
format: [
'default_fxa',
'dev_fxa',
'default',
'dev',
'short',
'tiny'
]
},
},
default: "default_fxa",
format: ["default_fxa", "dev_fxa", "default", "dev", "short", "tiny"]
}
}
},
productRedirectURLs: {
default: {
'123doneProProduct': 'http://127.0.0.1:8080/',
'prod_Ex9Z1q5yVydhyk': 'https://123done-latest.dev.lcip.org/',
'prod_FUUNYnlDso7FeB': 'https://123done-stage.dev.lcip.org',
"123doneProProduct": "http://127.0.0.1:8080/",
prod_Ex9Z1q5yVydhyk: "https://123done-latest.dev.lcip.org/",
prod_FUUNYnlDso7FeB: "https://123done-stage.dev.lcip.org"
},
doc: 'Mapping between product IDs and post-subscription redirect URLs',
env: 'PRODUCT_REDIRECT_URLS',
format: Object,
doc: "Mapping between product IDs and post-subscription redirect URLs",
env: "PRODUCT_REDIRECT_URLS",
format: Object
},
proxyStaticResourcesFrom: {
default: '',
doc: 'Instead of loading static resources from disk, get them by proxy from this URL (typically a special reloading dev server)',
env: 'PROXY_STATIC_RESOURCES_FROM',
format: String,
default: "",
doc:
"Instead of loading static resources from disk, get them by proxy from this URL (typically a special reloading dev server)",
env: "PROXY_STATIC_RESOURCES_FROM",
format: String
},
sentryDsn: {
default: '',
doc: 'Sentry DSN',
env: 'SENTRY_DSN',
format: 'String',
default: "",
doc: "Sentry DSN",
env: "SENTRY_DSN",
format: "String"
},
servers: {
auth: {
url: {
default: 'http://127.0.0.1:9000',
doc: 'The url of the fxa-auth-server instance',
env: 'AUTH_SERVER_URL',
format: 'url',
default: "http://127.0.0.1:9000",
doc: "The url of the fxa-auth-server instance",
env: "AUTH_SERVER_URL",
format: "url"
}
},
content: {
url: {
default: 'http://127.0.0.1:3030',
doc: 'The url of the corresponding fxa-content-server instance',
env: 'CONTENT_SERVER_URL',
format: 'url',
default: "http://127.0.0.1:3030",
doc: "The url of the corresponding fxa-content-server instance",
env: "CONTENT_SERVER_URL",
format: "url"
}
},
oauth: {
url: {
default: 'http://127.0.0.1:9010',
doc: 'The url of the corresponding fxa-oauth-server instance',
env: 'OAUTH_SERVER_URL',
format: 'url',
default: "http://127.0.0.1:9010",
doc: "The url of the corresponding fxa-oauth-server instance",
env: "OAUTH_SERVER_URL",
format: "url"
}
},
profile: {
url: {
default: 'http://127.0.0.1:1111',
doc: 'The url of the corresponding fxa-profile-server instance',
env: 'PROFILE_SERVER_URL',
format: 'url',
default: "http://127.0.0.1:1111",
doc: "The url of the corresponding fxa-profile-server instance",
env: "PROFILE_SERVER_URL",
format: "url"
}
},
}
},
staticResources: {
directory: {
default: 'build',
doc: 'Directory where static resources are located',
env: 'STATIC_DIRECTORY',
format: String,
default: "build",
doc: "Directory where static resources are located",
env: "STATIC_DIRECTORY",
format: String
},
maxAge: {
default: '10 minutes',
doc: 'Cache max age for static assets, in ms',
env: 'STATIC_MAX_AGE',
format: 'duration'
default: "10 minutes",
doc: "Cache max age for static assets, in ms",
env: "STATIC_MAX_AGE",
format: "duration"
},
url: {
default: 'http://127.0.0.1:3031',
doc: 'The origin of the static resources',
env: 'STATIC_RESOURCE_URL',
format: 'url'
default: "http://127.0.0.1:3031",
doc: "The origin of the static resources",
env: "STATIC_RESOURCE_URL",
format: "url"
}
},
stripe: {
apiKey: {
default: 'pk_test_FL2cOisOukoCQUZsrochvTlk00ff4IakfE',
doc: 'API key for Stripe',
env: 'STRIPE_API_KEY',
format: String,
default: "pk_test_FL2cOisOukoCQUZsrochvTlk00ff4IakfE",
doc: "API key for Stripe",
env: "STRIPE_API_KEY",
format: String
}
},
}
});

// Always send CSP headers in development mode
if (conf.get("env") === "development") {
conf.set("csp.enabled", true);
}

// TO DO: remove these - gross
// if (! conf.has('fxaccount_url')) {
// conf.set('fxaccount_url', conf.get('servers.auth.url'));
// }
// if (! conf.has('static_resource_url')) {
// conf.set('static_resource_url', conf.get('staticResources.url'));
// }
// if (! conf.has('oauth_url')) {
// conf.set('static_resource_url', conf.get('servers.oauth.url'));
// }
// if (! conf.has('profile_url')) {
// conf.set('static_resource_url', conf.get('servers.oauth.url'));
// }

// handle configuration files. you can specify a CSV list of configuration
// files to process, which will be overlayed in order, in the CONFIG_FILES
// environment variable.

let envConfig = path.join(__dirname, `${conf.get('env') }.json`);
envConfig = `${envConfig },${ process.env.CONFIG_FILES || ''}`;
const files = envConfig.split(',').filter(fs.existsSync);
let envConfig = path.join(__dirname, `${conf.get("env")}.json`);
envConfig = `${envConfig},${process.env.CONFIG_FILES || ""}`;
const files = envConfig.split(",").filter(fs.existsSync);
conf.loadFile(files);
conf.validate({ allowed: 'strict' });
conf.validate({ allowed: "strict" });

module.exports = conf;
Empty file.
Loading

0 comments on commit 300dea0

Please sign in to comment.