More refactoring

This commit is contained in:
calzoneman 2015-11-01 17:42:20 -08:00
parent c2726898e5
commit 6505aa2f5e
4 changed files with 177 additions and 129 deletions

View File

@ -1,9 +1,9 @@
import clone from 'clone'; import clone from 'clone';
const DEFAULT_TRUSTED_PROXIES = [ const DEFAULT_TRUSTED_PROXIES = Object.freeze([
'127.0.0.1', '127.0.0.1',
'::1' '::1'
]; ]);
export default class WebConfiguration { export default class WebConfiguration {
constructor(config) { constructor(config) {
@ -15,7 +15,31 @@ export default class WebConfiguration {
} }
getTrustedProxies() { getTrustedProxies() {
return DEFAULT_TRUSTED_PROXIES.slice(); return DEFAULT_TRUSTED_PROXIES;
}
getCookieSecret() {
return this.config.authCookie.cookieSecret;
}
getCookieDomain() {
return this.config.authCookie.cookieDomain;
}
getEnableGzip() {
return this.config.gzip.enabled;
}
getGzipThreshold() {
return this.config.gzip.threshold;
}
getEnableMinification() {
return this.config.enableMinification;
}
getCacheTTL() {
return this.config.cacheTTL;
} }
} }
@ -32,5 +56,19 @@ WebConfiguration.fromOldConfig = function (oldConfig) {
}); });
}); });
config.gzip = {
enabled: oldConfig.get('http.gzip'),
threshold: oldConfig.get('http.gzip-threshold')
};
config.authCookie = {
cookieSecret: oldConfig.get('http.cookie-secret'),
cookieDomain: oldConfig.get('http.root-domain-dotted')
};
config.enableMinification = oldConfig.get('http.minify');
config.cacheTTL = oldConfig.get('http.max-age');
return new WebConfiguration(config); return new WebConfiguration(config);
}; };

View File

@ -46,6 +46,7 @@ import LocalChannelIndex from './web/localchannelindex';
import IOConfiguration from './configuration/ioconfig'; import IOConfiguration from './configuration/ioconfig';
import WebConfiguration from './configuration/webconfig'; import WebConfiguration from './configuration/webconfig';
import NullClusterClient from './io/cluster/nullclusterclient'; import NullClusterClient from './io/cluster/nullclusterclient';
import session from './session';
var Server = function () { var Server = function () {
var self = this; var self = this;
@ -73,7 +74,8 @@ var Server = function () {
webConfig, webConfig,
ioConfig, ioConfig,
clusterClient, clusterClient,
channelIndex); channelIndex,
session);
// http/https/sio server init ----------------------------------------- // http/https/sio server init -----------------------------------------
var key = "", cert = "", ca = undefined; var key = "", cert = "", ca = undefined;
@ -255,4 +257,3 @@ Server.prototype.shutdown = function () {
process.exit(1); process.exit(1);
}); });
}; };

View File

@ -0,0 +1,19 @@
const STATIC_RESOURCE = /\..+$/;
export default function initialize(app, session) {
app.use((req, res, next) => {
if (STATIC_RESOURCE.test(req.path)) {
return next();
} else if (!req.signedCookies || !req.signedCookies.auth) {
return nuext();
} else {
session.verifySession(req.signedCookies.auth, (err, account) => {
if (!err) {
req.user = res.user = account;
}
next();
});
}
});
}

View File

@ -1,33 +1,37 @@
var path = require("path"); import fs from 'fs';
var fs = require("fs"); import path from 'path';
var net = require("net"); import net from 'net';
var express = require("express"); import express from 'express';
var webroot = path.join(__dirname, "..", "www"); import { sendJade } from './jade';
var sendJade = require("./jade").sendJade; import Logger from '../logger';
var Server = require("../server"); import Config from '../config';
var $util = require("../utilities"); import bodyParser from 'body-parser';
var Logger = require("../logger"); import cookieParser from 'cookie-parser';
var Config = require("../config"); import serveStatic from 'serve-static';
var db = require("../database"); import morgan from 'morgan';
var bodyParser = require("body-parser"); import csrf from './csrf';
var cookieParser = require("cookie-parser");
var serveStatic = require("serve-static");
var morgan = require("morgan");
var session = require("../session");
var csrf = require("./csrf");
var XSS = require("../xss");
import * as HTTPStatus from './httpstatus'; import * as HTTPStatus from './httpstatus';
import { CSRFError, HTTPError } from '../errors'; import { CSRFError, HTTPError } from '../errors';
const LOG_FORMAT = ':real-address - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'; function initializeLog(app) {
morgan.token('real-address', function (req) { return req.realIP; }); const logFormat = ':real-address - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"';
const logPath = path.join(__dirname, '..', '..', 'http.log');
const outputStream = fs.createWriteStream(logPath, {
flags: 'a', // append to existing file
encoding: 'utf8'
});
morgan.token('real-address', req => req.realIP);
app.use(morgan(logFormat, {
stream: outputStream
}));
}
/** /**
* Redirects a request to HTTPS if the server supports it * Redirects a request to HTTPS if the server supports it
*/ */
function redirectHttps(req, res) { function redirectHttps(req, res) {
if (!req.secure && Config.get("https.enabled") && Config.get("https.redirect")) { if (!req.secure && Config.get('https.enabled') && Config.get('https.redirect')) {
var ssldomain = Config.get("https.full-address"); var ssldomain = Config.get('https.full-address');
if (ssldomain.indexOf(req.hostname) < 0) { if (ssldomain.indexOf(req.hostname) < 0) {
return false; return false;
} }
@ -43,7 +47,7 @@ function redirectHttps(req, res) {
*/ */
function redirectHttp(req, res) { function redirectHttp(req, res) {
if (req.secure) { if (req.secure) {
var domain = Config.get("http.full-address"); var domain = Config.get('http.full-address');
res.redirect(domain + req.path); res.redirect(domain + req.path);
return true; return true;
} }
@ -54,115 +58,47 @@ function redirectHttp(req, res) {
* Legacy socket.io configuration endpoint. This is being migrated to * Legacy socket.io configuration endpoint. This is being migrated to
* /socketconfig/<channel name>.json (see ./routes/socketconfig.js) * /socketconfig/<channel name>.json (see ./routes/socketconfig.js)
*/ */
function handleSocketConfig(req, res) { function handleLegacySocketConfig(req, res) {
if (/\.json$/.test(req.path)) { if (/\.json$/.test(req.path)) {
res.json(Config.get("sioconfigjson")); res.json(Config.get('sioconfigjson'));
return; return;
} }
res.type("application/javascript"); res.type('application/javascript');
var sioconfig = Config.get("sioconfig"); var sioconfig = Config.get('sioconfig');
var iourl; var iourl;
var ip = req.realIP; var ip = req.realIP;
var ipv6 = false; var ipv6 = false;
if (net.isIPv6(ip)) { if (net.isIPv6(ip)) {
iourl = Config.get("io.ipv6-default"); iourl = Config.get('io.ipv6-default');
ipv6 = true; ipv6 = true;
} }
if (!iourl) { if (!iourl) {
iourl = Config.get("io.ipv4-default"); iourl = Config.get('io.ipv4-default');
} }
sioconfig += "var IO_URL='" + iourl + "';"; sioconfig += 'var IO_URL=\'' + iourl + '\';';
sioconfig += "var IO_V6=" + ipv6 + ";"; sioconfig += 'var IO_V6=' + ipv6 + ';';
res.send(sioconfig); res.send(sioconfig);
} }
function handleUserAgreement(req, res) { function handleUserAgreement(req, res) {
sendJade(res, "tos", { sendJade(res, 'tos', {
domain: Config.get("http.domain") domain: Config.get('http.domain')
}); });
} }
module.exports = { function initializeErrorHandlers(app) {
/**
* Initializes webserver callbacks
*/
init: function (app, webConfig, ioConfig, clusterClient, channelIndex) {
require("./middleware/x-forwarded-for")(app, webConfig);
app.use(bodyParser.urlencoded({
extended: false,
limit: '1kb' // No POST data should ever exceed this size under normal usage
}));
if (Config.get("http.cookie-secret") === "change-me") {
Logger.errlog.log("YOU SHOULD CHANGE THE VALUE OF cookie-secret IN config.yaml");
}
app.use(cookieParser(Config.get("http.cookie-secret")));
app.use(csrf.init(Config.get("http.root-domain-dotted")));
app.use(morgan(LOG_FORMAT, {
stream: require("fs").createWriteStream(path.join(__dirname, "..", "..",
"http.log"), {
flags: "a",
encoding: "utf-8"
})
}));
app.use(function (req, res, next) {
if (req.path.match(/^\/(css|js|img|boop).*$/)) {
return next();
}
if (!req.signedCookies || !req.signedCookies.auth) {
return next();
}
session.verifySession(req.signedCookies.auth, function (err, account) {
if (!err) {
req.user = res.user = account;
}
next();
});
});
if (Config.get("http.gzip")) {
app.use(require("compression")({ threshold: Config.get("http.gzip-threshold") }));
Logger.syslog.log("Enabled gzip compression");
}
if (Config.get("http.minify")) {
var cache = path.join(__dirname, "..", "..", "www", "cache")
if (!fs.existsSync(cache)) {
fs.mkdirSync(cache);
}
app.use(require("express-minify")({
cache: cache
}));
Logger.syslog.log("Enabled express-minify for CSS and JS");
}
require("./routes/channel")(app, ioConfig);
require("./routes/index")(app, channelIndex);
app.get("/sioconfig(.json)?", handleSocketConfig);
require("./routes/socketconfig")(app, clusterClient);
app.get("/useragreement", handleUserAgreement);
require("./routes/contact")(app, webConfig);
require("./auth").init(app);
require("./account").init(app);
require("./acp").init(app);
require("../google2vtt").attach(app);
app.use(serveStatic(path.join(__dirname, "..", "..", "www"), {
maxAge: Config.get("http.max-age") || Config.get("http.cache-ttl")
}));
app.use((req, res, next) => { app.use((req, res, next) => {
return next(new HTTPError(`No route for ${req.path}`, { return next(new HTTPError(`No route for ${req.path}`, {
status: HTTPStatus.NOT_FOUND status: HTTPStatus.NOT_FOUND
})); }));
}); });
app.use(function (err, req, res, next) {
app.use((err, req, res, next) => {
if (err) { if (err) {
if (err instanceof CSRFError) { if (err instanceof CSRFError) {
res.status(HTTPStatus.FORBIDDEN); res.status(HTTPStatus.FORBIDDEN);
@ -198,6 +134,60 @@ module.exports = {
next(); next();
} }
}); });
}
module.exports = {
/**
* Initializes webserver callbacks
*/
init: function (app, webConfig, ioConfig, clusterClient, channelIndex, session) {
require('./middleware/x-forwarded-for')(app, webConfig);
app.use(bodyParser.urlencoded({
extended: false,
limit: '1kb' // No POST data should ever exceed this size under normal usage
}));
if (webConfig.getCookieSecret() === 'change-me') {
Logger.errlog.log('WARNING: The configured cookie secret was left as the ' +
'default of "change-me".');
}
app.use(cookieParser(webConfig.getCookieSecret()));
app.use(csrf.init(webConfig.getCookieDomain()));
initializeLog(app);
require('./middleware/authorize')(app, session);
if (webConfig.getEnableGzip()) {
app.use(require('compression')({
threshold: webConfig.getGzipThreshold()
}));
Logger.syslog.log('Enabled gzip compression');
}
if (webConfig.getEnableMinification()) {
const cacheDir = path.join(__dirname, '..', '..', 'www', 'cache');
if (!fs.existsSync(cache)) {
fs.mkdirSync(cache);
}
app.use(require('express-minify')({
cache: cacheDir
}));
Logger.syslog.log('Enabled express-minify for CSS and JS');
}
require('./routes/channel')(app, ioConfig);
require('./routes/index')(app, channelIndex);
app.get('/sioconfig(.json)?', handleLegacySocketConfig);
require('./routes/socketconfig')(app, clusterClient);
app.get('/useragreement', handleUserAgreement);
require('./routes/contact')(app, webConfig);
require('./auth').init(app);
require('./account').init(app);
require('./acp').init(app);
require('../google2vtt').attach(app);
app.use(serveStatic(path.join(__dirname, '..', '..', 'www'), {
maxAge: webConfig.getCacheTTL()
}));
initializeErrorHandlers(app);
}, },
redirectHttps: redirectHttps, redirectHttps: redirectHttps,