sync/src/web/webserver.js

246 lines
7.3 KiB
JavaScript
Raw Normal View History

2014-01-22 21:12:43 -06:00
var path = require("path");
2014-02-24 18:32:54 -06:00
var fs = require("fs");
2014-01-22 21:12:43 -06:00
var net = require("net");
var express = require("express");
var webroot = path.join(__dirname, "..", "www");
var sendJade = require("./jade").sendJade;
var Server = require("../server");
var $util = require("../utilities");
var Logger = require("../logger");
var Config = require("../config");
2014-01-28 00:05:14 -06:00
var db = require("../database");
2014-08-19 00:07:24 -05:00
var bodyParser = require("body-parser");
var cookieParser = require("cookie-parser");
var serveStatic = require("serve-static");
var morgan = require("morgan");
2015-02-15 21:56:00 -06:00
var session = require("../session");
2015-02-22 18:15:22 -06:00
var csrf = require("./csrf");
var XSS = require("../xss");
2015-10-26 22:56:53 -07:00
import * as HTTPStatus from './httpstatus';
import { CSRFError } from '../errors';
2014-09-11 19:00:27 -05:00
const LOG_FORMAT = ':real-address - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"';
morgan.token('real-address', function (req) { return req._ip; });
/**
* Extracts an IP address from a request. Uses X-Forwarded-For if the IP is localhost
*/
function ipForRequest(req) {
var ip = req.ip;
2014-01-22 21:12:43 -06:00
if (ip === "127.0.0.1" || ip === "::1") {
var xforward = req.header("x-forwarded-for");
if (typeof xforward !== "string") {
xforward = [];
} else {
xforward = xforward.split(",");
}
for (var i = 0; i < xforward.length; i++) {
if (net.isIP(xforward[i])) {
return xforward[i];
}
}
return ip;
}
return ip;
}
2014-01-22 21:12:43 -06:00
/**
* Redirects a request to HTTPS if the server supports it
*/
function redirectHttps(req, res) {
2015-03-29 11:34:27 -05:00
if (!req.secure && Config.get("https.enabled") && Config.get("https.redirect")) {
var ssldomain = Config.get("https.full-address");
2015-02-15 21:56:00 -06:00
if (ssldomain.indexOf(req.hostname) < 0) {
return false;
}
2014-01-22 21:12:43 -06:00
res.redirect(ssldomain + req.path);
return true;
}
return false;
}
/**
* Redirects a request to HTTP if the server supports it
*/
function redirectHttp(req, res) {
if (req.secure) {
var domain = Config.get("http.full-address");
2014-01-22 21:12:43 -06:00
res.redirect(domain + req.path);
return true;
}
return false;
}
2014-01-22 21:12:43 -06:00
/**
2015-10-19 22:32:00 -07:00
* Legacy socket.io configuration endpoint. This is being migrated to
* /socketconfig/<channel name>.json (see ./routes/socketconfig.js)
2014-01-22 21:12:43 -06:00
*/
function handleSocketConfig(req, res) {
2015-09-30 18:36:50 -07:00
if (/\.json$/.test(req.path)) {
res.json(Config.get("sioconfigjson"));
return;
}
2014-01-22 21:12:43 -06:00
res.type("application/javascript");
2014-05-20 19:30:14 -07:00
var sioconfig = Config.get("sioconfig");
var iourl;
var ip = ipForRequest(req);
2014-06-12 20:29:12 -07:00
var ipv6 = false;
2014-05-20 19:30:14 -07:00
if (net.isIPv6(ip)) {
iourl = Config.get("io.ipv6-default");
2014-06-12 20:29:12 -07:00
ipv6 = true;
2014-05-20 19:30:14 -07:00
}
if (!iourl) {
iourl = Config.get("io.ipv4-default");
}
2015-02-15 21:56:00 -06:00
2014-05-20 19:30:14 -07:00
sioconfig += "var IO_URL='" + iourl + "';";
2014-06-12 20:29:12 -07:00
sioconfig += "var IO_V6=" + ipv6 + ";";
2014-05-20 19:30:14 -07:00
res.send(sioconfig);
2014-02-13 00:12:17 -06:00
}
function handleUserAgreement(req, res) {
sendJade(res, "tos", {
domain: Config.get("http.domain")
});
}
2014-01-22 21:12:43 -06:00
2014-02-13 18:15:22 -06:00
function handleContactPage(req, res) {
// Make a copy to prevent messing with the original
var contacts = Config.get("contacts").map(function (c) {
return {
name: c.name,
email: c.email,
title: c.title
};
});
// Rudimentary hiding of email addresses to prevent spambots
contacts.forEach(function (c) {
c.emkey = $util.randomSalt(16)
var email = new Array(c.email.length);
for (var i = 0; i < c.email.length; i++) {
email[i] = String.fromCharCode(
c.email.charCodeAt(i) ^ c.emkey.charCodeAt(i % c.emkey.length)
);
}
c.email = escape(email.join(""));
c.emkey = escape(c.emkey);
});
sendJade(res, "contact", {
contacts: contacts
});
}
module.exports = {
/**
* Initializes webserver callbacks
*/
2015-10-26 22:56:53 -07:00
init: function (app, ioConfig, clusterClient, channelIndex) {
app.use(function (req, res, next) {
2014-09-11 19:00:27 -05:00
req._ip = ipForRequest(req);
next();
});
app.use(bodyParser.urlencoded({
extended: false,
limit: '1kb' // No POST data should ever exceed this size under normal usage
}));
2015-02-15 21:56:00 -06:00
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")));
2015-02-24 10:48:51 -06:00
app.use(csrf.init(Config.get("http.root-domain-dotted")));
2014-09-11 19:00:27 -05:00
app.use(morgan(LOG_FORMAT, {
2014-11-16 21:06:10 -06:00
stream: require("fs").createWriteStream(path.join(__dirname, "..", "..",
"http.log"), {
flags: "a",
encoding: "utf-8"
})
}));
2015-02-15 21:56:00 -06:00
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();
});
});
2014-11-16 21:06:10 -06:00
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")) {
2014-02-24 18:32:54 -06:00
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");
}
2015-10-26 22:56:53 -07:00
require("./routes/channel")(app, ioConfig);
require("./routes/index")(app, channelIndex);
2015-09-30 18:36:50 -07:00
app.get("/sioconfig(.json)?", handleSocketConfig);
2015-10-26 22:56:53 -07:00
require("./routes/socketconfig")(app, clusterClient);
2014-02-13 00:12:17 -06:00
app.get("/useragreement", handleUserAgreement);
2014-02-13 18:15:22 -06:00
app.get("/contact", handleContactPage);
2014-01-28 20:04:25 -06:00
require("./auth").init(app);
require("./account").init(app);
require("./acp").init(app);
require("../google2vtt").attach(app);
app.use(serveStatic(path.join(__dirname, "..", "..", "www"), {
2014-11-16 21:06:10 -06:00
maxAge: Config.get("http.max-age") || Config.get("http.cache-ttl")
}));
app.use(function (err, req, res, next) {
if (err) {
2015-10-26 22:56:53 -07:00
if (err instanceof CSRFError) {
res.status(HTTPStatus.FORBIDDEN);
return sendJade(res, 'csrferror', { path: req.path });
}
let { message, status } = err;
if (!status) {
status = HTTPStatus.INTERNAL_SERVER_ERROR;
}
if (!message) {
message = 'An unknown error occurred.';
}
2015-10-26 22:56:53 -07:00
if (Math.floor(status / 100) === 5) {
Logger.errlog.log(err.stack);
}
return res.status(status).send(message);
} else {
next();
}
});
},
2014-01-22 21:12:43 -06:00
ipForRequest: ipForRequest,
redirectHttps: redirectHttps,
2015-02-15 21:56:00 -06:00
redirectHttp: redirectHttp
};