#!/usr/bin/env node /* 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/. */ const fs = require('fs'), path = require('path'), url = require('url'), http = require('http'); urlparse = require('urlparse'), express = require('express'), wsapi = require('../lib/wsapi.js'), httputils = require('../lib/httputils.js'); secrets = require('../lib/secrets.js'), db = require('../lib/db.js'); config = require('../lib/configuration.js'), heartbeat = require('../lib/heartbeat.js'), metrics = require('../lib/metrics.js'), logger = require('../lib/logging.js').logger, shutdown = require('../lib/shutdown'); var app = undefined; app = express.createServer(); logger.info("dbwriter starting up"); // Setup health check / heartbeat middleware. // This is in front of logging on purpose. see issue #537 heartbeat.setup(app, function(cb) { // ping the database to verify we're really healthy. db.ping(function(e) { if (e) logger.error("database ping error: " + e); cb(!e); }); }); // logging! all requests other than __heartbeat__ are logged app.use(express.logger({ format: config.get('express_log_format'), stream: { write: function(x) { logger.info(typeof x === 'string' ? x.trim() : x); } } })); var statsd_config = config.get('statsd'); if (statsd_config && statsd_config.enabled) { logger_statsd = require("connect-logger-statsd"); app.use(logger_statsd({ host: statsd_config.hostname || "localhost", port: statsd_config.port || 8125, prefix: statsd_config.prefix || "browserid.dbwriter." })); } // Add Strict-Transport-Security headers if we're serving over SSL if (config.get('scheme') == 'https') { app.use(function(req, resp, next) { // expires in 30 days, include subdomains like www resp.setHeader("Strict-Transport-Security", "max-age=2592000; includeSubdomains"); next(); }); } // prevent framing of everything. content underneath that needs to be // framed must explicitly remove the x-frame-options app.use(function(req, resp, next) { resp.setHeader('x-frame-options', 'DENY'); next(); }); // verify all JSON responses are objects - prevents regression on issue #217 app.use(function(req, resp, next) { var realRespJSON = resp.json; resp.json = function(obj) { if (!obj || typeof obj !== 'object') { logger.error("INTERNAL ERROR! *all* json responses must be objects"); throw "internal error"; } realRespJSON.call(resp, obj); }; return next(); }); // handle /wsapi requests wsapi.setup({ only_write_apis: true }, app); function doShutdown(readyForShutdownCB) { require('../lib/bcrypt.js').shutdown(); db.close(readyForShutdownCB) } // open the databse db.open(config.get('database'), function (error) { if (error) { logger.error("can't open database: " + error); // let async logging flush, then exit 1 return process.nextTick(function() { process.exit(1); }); } // shut down express gracefully on SIGINT shutdown.handleTerminationSignals(app, doShutdown); var bindTo = config.get('bind_to'); app.listen(bindTo.port, bindTo.host, function() { logger.info("running on http://" + app.address().address + ":" + app.address().port); }); });