sync/lib/config.js

374 lines
11 KiB
JavaScript
Raw Normal View History

2013-07-28 15:49:29 +00:00
var fs = require("fs");
2014-01-22 23:11:26 +00:00
var path = require("path");
2013-07-28 15:49:29 +00:00
var Logger = require("./logger");
var nodemailer = require("nodemailer");
2014-05-21 02:30:14 +00:00
var net = require("net");
2014-01-22 23:11:26 +00:00
var YAML = require("yamljs");
2013-05-30 18:07:29 +00:00
2013-07-28 15:49:29 +00:00
var defaults = {
2014-01-22 23:11:26 +00:00
mysql: {
server: "localhost",
2015-02-14 22:20:26 +00:00
port: 3306,
2014-01-22 23:11:26 +00:00
database: "cytube3",
user: "cytube3",
2015-02-14 22:20:26 +00:00
password: "",
2013-07-28 15:49:29 +00:00
},
listen: [
{
2015-02-14 18:17:06 +00:00
ip: "0.0.0.0",
port: 8080,
http: true,
},
{
2015-02-14 18:17:06 +00:00
ip: "0.0.0.0",
port: 1337,
io: true
}
],
2014-01-22 23:11:26 +00:00
http: {
domain: "http://localhost",
"default-port": 8080,
2014-02-26 16:50:59 +00:00
"root-domain": "localhost",
"alt-domains": ["127.0.0.1"],
2014-02-24 05:27:07 +00:00
minify: false,
2014-11-17 03:06:10 +00:00
"max-age": "7d",
gzip: true,
2015-02-16 03:56:00 +00:00
"gzip-threshold": 1024,
"cookie-secret": "change-me"
2014-01-22 23:11:26 +00:00
},
https: {
enabled: false,
2014-01-26 06:01:36 +00:00
domain: "https://localhost",
"default-port": 8443,
2014-01-22 23:11:26 +00:00
keyfile: "localhost.key",
passphrase: "",
2014-03-06 04:26:10 +00:00
certfile: "localhost.cert",
cafile: "",
2015-03-06 21:59:34 +00:00
ciphers: "HIGH:!DSS:!aNULL@STRENGTH"
2014-01-22 23:11:26 +00:00
},
io: {
2014-02-26 16:57:49 +00:00
domain: "http://localhost",
"default-port": 1337,
2014-01-22 23:11:26 +00:00
"ip-connection-limit": 10
},
mail: {
enabled: false,
/* the key "config" is omitted because the format depends on the
service the owner is configuring for nodemailer */
2015-02-19 21:10:04 +00:00
"from-address": "some.user@gmail.com",
"from-name": "CyTube Services"
2014-01-22 23:11:26 +00:00
},
"youtube-v2-key": "",
"channel-save-interval": 5,
"max-channels-per-user": 5,
2014-02-10 01:52:24 +00:00
"max-accounts-per-ip": 5,
2014-01-22 23:11:26 +00:00
"guest-login-delay": 60,
stats: {
interval: 3600000,
"max-age": 86400000
},
aliases: {
"purge-interval": 3600000,
"max-age": 2592000000
},
2014-04-07 19:41:21 +00:00
"vimeo-workaround": false,
"vimeo-oauth": {
enabled: false,
"consumer-key": "",
secret: ""
},
"html-template": {
2014-02-06 00:05:52 +00:00
title: "CyTube Beta", description: "Free, open source synchtube"
},
"reserved-names": {
usernames: ["^(.*?[-_])?admin(istrator)?([-_].*)?$", "^(.*?[-_])?owner([-_].*)?$"],
channels: ["^(.*?[-_])?admin(istrator)?([-_].*)?$", "^(.*?[-_])?owner([-_].*)?$"],
pagetitles: []
2014-02-14 00:15:22 +00:00
},
"contacts": [
{
name: "calzoneman",
title: "Developer",
email: "cyzon@cytu.be"
}
],
2014-05-21 02:30:14 +00:00
"aggressive-gc": false,
playlist: {
"max-items": 4000,
"update-interval": 5
},
"channel-blacklist": [],
ffmpeg: {
enabled: false
2014-09-13 05:01:54 +00:00
},
"link-domain-blacklist": [],
setuid: {
enabled: false,
"group": "users",
"user": "nobody",
"timeout": 15
},
2014-01-22 23:11:26 +00:00
};
2013-07-06 17:00:02 +00:00
2014-01-22 23:11:26 +00:00
/**
* Merges a config object with the defaults, warning about missing keys
*/
function merge(obj, def, path) {
for (var key in def) {
if (key in obj) {
if (typeof obj[key] === "object") {
merge(obj[key], def[key], path + "." + key);
2013-07-28 15:49:29 +00:00
}
2014-01-22 23:11:26 +00:00
} else {
Logger.syslog.log("[WARNING] Missing config key " + (path + "." + key) +
"; using default: " + JSON.stringify(def[key]));
obj[key] = def[key];
2013-07-28 15:49:29 +00:00
}
2014-01-22 23:11:26 +00:00
}
}
var cfg = defaults;
2013-07-28 15:49:29 +00:00
2014-01-22 23:11:26 +00:00
/**
* Initializes the configuration from the given YAML file
*/
exports.load = function (file) {
try {
cfg = YAML.load(path.join(__dirname, "..", file));
} catch (e) {
if (e.code === "ENOENT") {
Logger.syslog.log(file + " does not exist, assuming default configuration");
cfg = defaults;
return;
} else {
Logger.errlog.log("Error loading config file " + file + ": ");
2014-03-09 16:42:45 +00:00
Logger.errlog.log(e);
2014-01-22 23:11:26 +00:00
if (e.stack) {
Logger.errlog.log(e.stack);
}
cfg = defaults;
2013-07-28 15:49:29 +00:00
return;
}
2014-01-22 23:11:26 +00:00
}
2013-07-28 15:49:29 +00:00
2014-01-22 23:11:26 +00:00
if (cfg == null) {
Logger.syslog.log(file + " is an Invalid configuration file, " +
"assuming default configuration");
cfg = defaults;
return;
}
2013-07-28 15:49:29 +00:00
2014-01-22 23:11:26 +00:00
var mailconfig = {};
if (cfg.mail && cfg.mail.config) {
mailconfig = cfg.mail.config;
delete cfg.mail.config;
}
merge(cfg, defaults, "config");
cfg.mail.config = mailconfig;
preprocessConfig(cfg);
Logger.syslog.log("Loaded configuration from " + file);
};
function preprocessConfig(cfg) {
/* Detect 3.0.0-style config and warng the user about it */
if ("host" in cfg.http || "port" in cfg.http || "port" in cfg.https) {
Logger.syslog.log("[WARN] The method of specifying which IP/port to bind has "+
"changed. The config loader will try to handle this "+
"automatically, but you should read config.template.yaml "+
"and change your config.yaml to the new format.");
cfg.listen = [
{
2015-02-14 18:17:06 +00:00
ip: cfg.http.host || "0.0.0.0",
port: cfg.http.port,
http: true
},
{
2015-02-14 18:17:06 +00:00
ip: cfg.http.host || "0.0.0.0",
port: cfg.io.port,
io: true
}
];
if (cfg.https.enabled) {
cfg.listen.push(
{
2015-02-14 18:17:06 +00:00
ip: cfg.http.host || "0.0.0.0",
port: cfg.https.port,
https: true,
io: true
}
);
}
cfg.http["default-port"] = cfg.http.port;
cfg.https["default-port"] = cfg.https.port;
cfg.io["default-port"] = cfg.io.port;
}
// Root domain should start with a . for cookies
var root = cfg.http["root-domain"];
root = root.replace(/^\.*/, "");
cfg.http["root-domain"] = root;
2015-02-21 20:48:24 +00:00
if (root.indexOf(".") !== -1 && !net.isIP(root)) {
2014-03-01 23:37:59 +00:00
root = "." + root;
}
cfg.http["root-domain-dotted"] = root;
// Setup nodemailer
2014-01-22 23:11:26 +00:00
cfg.mail.nodemailer = nodemailer.createTransport(
cfg.mail.config
);
// Debug
2014-01-22 23:11:26 +00:00
if (process.env.DEBUG === "1" || process.env.DEBUG === "true") {
cfg.debug = true;
} else {
cfg.debug = false;
}
// Strip trailing slashes from domains
2014-01-26 06:01:36 +00:00
cfg.http.domain = cfg.http.domain.replace(/\/*$/, "");
cfg.https.domain = cfg.https.domain.replace(/\/*$/, "");
// HTTP/HTTPS domains with port numbers
2014-02-28 06:09:20 +00:00
if (!cfg.http["full-address"]) {
var httpfa = cfg.http.domain;
2014-04-14 00:27:32 +00:00
if (cfg.http["default-port"] !== 80) {
httpfa += ":" + cfg.http["default-port"];
2014-02-28 06:09:20 +00:00
}
cfg.http["full-address"] = httpfa;
}
2014-02-28 06:09:20 +00:00
if (!cfg.https["full-address"]) {
var httpsfa = cfg.https.domain;
2014-04-14 00:27:32 +00:00
if (cfg.https["default-port"] !== 443) {
httpsfa += ":" + cfg.https["default-port"];
2014-02-28 06:09:20 +00:00
}
cfg.https["full-address"] = httpsfa;
}
2014-03-09 16:42:45 +00:00
2014-05-21 02:30:14 +00:00
// Socket.IO URLs
cfg.io["ipv4-nossl"] = "";
cfg.io["ipv4-ssl"] = "";
cfg.io["ipv6-nossl"] = "";
cfg.io["ipv6-ssl"] = "";
for (var i = 0; i < cfg.listen.length; i++) {
var srv = cfg.listen[i];
2015-02-14 18:17:06 +00:00
if (!srv.ip) {
srv.ip = "0.0.0.0";
}
2014-05-21 02:30:14 +00:00
if (!srv.io) {
continue;
}
if (srv.ip === "") {
if (srv.port === cfg.io["default-port"]) {
cfg.io["ipv4-nossl"] = cfg.io["domain"] + ":" + cfg.io["default-port"];
} else if (srv.port === cfg.https["default-port"]) {
cfg.io["ipv4-ssl"] = cfg.https["domain"] + ":" + cfg.https["default-port"];
}
continue;
}
if (net.isIPv4(srv.ip) || srv.ip === "::") {
if (srv.https && !cfg.io["ipv4-ssl"]) {
if (srv.url) {
cfg.io["ipv4-ssl"] = srv.url;
} else {
2014-06-13 03:29:12 +00:00
cfg.io["ipv4-ssl"] = cfg.https["domain"] + ":" + srv.port;
2014-05-21 02:30:14 +00:00
}
} else if (!cfg.io["ipv4-nossl"]) {
if (srv.url) {
cfg.io["ipv4-nossl"] = srv.url;
} else {
2014-06-13 03:29:12 +00:00
cfg.io["ipv4-nossl"] = cfg.io["domain"] + ":" + srv.port;
2014-05-21 02:30:14 +00:00
}
}
}
if (net.isIPv6(srv.ip) || srv.ip === "::") {
if (srv.https && !cfg.io["ipv6-ssl"]) {
if (!srv.url) {
Logger.errlog.log("Config Error: no URL defined for IPv6 " +
"Socket.IO listener! Ignoring this listener " +
"because the Socket.IO client cannot connect to " +
"a raw IPv6 address.");
Logger.errlog.log("(Listener was: " + JSON.stringify(srv) + ")");
} else {
cfg.io["ipv6-ssl"] = srv.url;
}
} else if (!cfg.io["ipv6-nossl"]) {
if (!srv.url) {
Logger.errlog.log("Config Error: no URL defined for IPv6 " +
"Socket.IO listener! Ignoring this listener " +
"because the Socket.IO client cannot connect to " +
"a raw IPv6 address.");
Logger.errlog.log("(Listener was: " + JSON.stringify(srv) + ")");
} else {
cfg.io["ipv6-nossl"] = srv.url;
}
}
}
}
cfg.io["ipv4-default"] = cfg.io["ipv4-ssl"] || cfg.io["ipv4-nossl"];
cfg.io["ipv6-default"] = cfg.io["ipv6-ssl"] || cfg.io["ipv6-nossl"];
// sioconfig
var sioconfig = "var IO_URLS={'ipv4-nossl':'" + cfg.io["ipv4-nossl"] + "'," +
"'ipv4-ssl':'" + cfg.io["ipv4-ssl"] + "'," +
"'ipv6-nossl':'" + cfg.io["ipv6-nossl"] + "'," +
"'ipv6-ssl':'" + cfg.io["ipv6-ssl"] + "'};";
cfg.sioconfig = sioconfig;
// Generate RegExps for reserved names
2014-02-06 00:05:52 +00:00
var reserved = cfg["reserved-names"];
for (var key in reserved) {
if (reserved[key] && reserved[key].length > 0) {
reserved[key] = new RegExp(reserved[key].join("|"), "i");
} else {
reserved[key] = false;
}
}
/* Convert channel blacklist to a hashtable */
var tbl = {};
cfg["channel-blacklist"].forEach(function (c) {
tbl[c.toLowerCase()] = true;
});
cfg["channel-blacklist"] = tbl;
2014-09-13 05:01:54 +00:00
if (cfg["link-domain-blacklist"].length > 0) {
cfg["link-domain-blacklist-regex"] = new RegExp(
cfg["link-domain-blacklist"].join("|").replace(/\./g, "\\."), "gi");
} else {
// Match nothing
cfg["link-domain-blacklist-regex"] = new RegExp("$^", "gi");
}
return cfg;
}
2014-01-22 23:11:26 +00:00
/**
* Retrieves a configuration value with the given key
*
* Accepts a dot-separated key for nested values, e.g. "http.port"
* Throws an error if a nonexistant key is requested
*/
exports.get = function (key) {
var obj = cfg;
var keylist = key.split(".");
var current = keylist.shift();
var path = current;
while (keylist.length > 0) {
if (!(current in obj)) {
throw new Error("Nonexistant config key '" + path + "." + current + "'");
}
obj = obj[current];
current = keylist.shift();
path += "." + current;
}
return obj[current];
};