guard against possible typeErrors from unvalidated config input

pull/1/head
ansuz 4 years ago
parent c392d52fe2
commit b5d3a10dc2

@ -176,13 +176,12 @@ var restoreArchivedDocument = function (Env, Server, cb) {
}; };
// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['RESTRICT_REGISTRATION', [true]]], console.log) // CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['RESTRICT_REGISTRATION', [true]]], console.log)
var adminDecree = function (Env, Server, cb, data, safeKey) { var adminDecree = function (Env, Server, cb, data, unsafeKey) {
var value = data[1]; var value = data[1];
if (!Array.isArray(value)) { return void cb('INVALID_DECREE'); } if (!Array.isArray(value)) { return void cb('INVALID_DECREE'); }
var command = value[0]; var command = value[0];
var args = value[1]; var args = value[1];
var unsafeKey = Util.unescapeKeyCharacters(safeKey);
/* /*
@ -253,15 +252,16 @@ Admin.command = function (Env, safeKey, data, _cb, Server) {
var cb = Util.once(Util.mkAsync(_cb)); var cb = Util.once(Util.mkAsync(_cb));
var admins = Env.admins; var admins = Env.admins;
//var unsafeKey = Util.unescapeKeyCharacters(safeKey);
if (admins.indexOf(safeKey) === -1) { var unsafeKey = Util.unescapeKeyCharacters(safeKey);
if (admins.indexOf(unsafeKey) === -1) {
return void cb("FORBIDDEN"); return void cb("FORBIDDEN");
} }
var command = commands[data[0]]; var command = commands[data[0]];
if (typeof(command) === 'function') { if (typeof(command) === 'function') {
return void command(Env, Server, cb, data, safeKey); return void command(Env, Server, cb, data, unsafeKey);
} }
return void cb('UNHANDLED_ADMIN_COMMAND'); return void cb('UNHANDLED_ADMIN_COMMAND');

@ -85,6 +85,8 @@ module.exports.create = function (config, cb) {
(function () { (function () {
var custom = config.customLimits; var custom = config.customLimits;
if (!custom) { return; }
var stored = Env.customLimits; var stored = Env.customLimits;
Object.keys(custom).forEach(function (k) { Object.keys(custom).forEach(function (k) {
@ -147,11 +149,15 @@ module.exports.create = function (config, cb) {
Core.DEFAULT_LIMIT; Core.DEFAULT_LIMIT;
try { try {
// XXX this should be the same as is exposed in server.js
// /api/config.adminKeys
Env.admins = (config.adminKeys || []).map(function (k) { Env.admins = (config.adminKeys || []).map(function (k) {
k = k.replace(/\/+$/, ''); try {
var s = k.split('/'); return Keys.canonicalize(k);
return s[s.length-1]; } catch (err) {
}); return;
}
}).filter(Boolean);
} catch (e) { } catch (e) {
console.error("Can't parse admin keys. Please update or fix your config.js file!"); console.error("Can't parse admin keys. Please update or fix your config.js file!");
} }

@ -90,8 +90,6 @@ config.flushCache = function () {
config.log.info("UPDATING_FRESH_KEY", FRESH_KEY); config.log.info("UPDATING_FRESH_KEY", FRESH_KEY);
}; };
const clone = (x) => (JSON.parse(JSON.stringify(x)));
var setHeaders = (function () { var setHeaders = (function () {
// load the default http headers unless the admin has provided their own via the config file // load the default http headers unless the admin has provided their own via the config file
var headers; var headers;
@ -99,7 +97,7 @@ var setHeaders = (function () {
var custom = config.httpHeaders; var custom = config.httpHeaders;
// if the admin provided valid http headers then use them // if the admin provided valid http headers then use them
if (custom && typeof(custom) === 'object' && !Array.isArray(custom)) { if (custom && typeof(custom) === 'object' && !Array.isArray(custom)) {
headers = clone(custom); headers = Util.clone(custom);
} else { } else {
// otherwise use the default // otherwise use the default
headers = Default.httpHeaders(); headers = Default.httpHeaders();
@ -120,7 +118,7 @@ var setHeaders = (function () {
headers['Content-Security-Policy'] = Default.contentSecurity(config.httpUnsafeOrigin); headers['Content-Security-Policy'] = Default.contentSecurity(config.httpUnsafeOrigin);
} }
const padHeaders = clone(headers); const padHeaders = Util.clone(headers);
if (typeof(config.padContentSecurity) === 'string') { if (typeof(config.padContentSecurity) === 'string') {
padHeaders['Content-Security-Policy'] = config.padContentSecurity; padHeaders['Content-Security-Policy'] = config.padContentSecurity;
} else { } else {
@ -202,6 +200,7 @@ app.use(/^\/[^\/]*$/, Express.static('customize.dist'));
var admins = []; var admins = [];
try { try {
admins = (config.adminKeys || []).map(function (k) { admins = (config.adminKeys || []).map(function (k) {
// XXX is there any reason not to use Keys.canonicalize ?
// return each admin's "unsafeKey" // return each admin's "unsafeKey"
// this might throw and invalidate all the other admin's keys // this might throw and invalidate all the other admin's keys
// but we want to get the admin's attention anyway. // but we want to get the admin's attention anyway.
@ -228,12 +227,12 @@ var serveConfig = (function () {
allowSubscriptions: (config.allowSubscriptions === true), allowSubscriptions: (config.allowSubscriptions === true),
websocketPath: config.externalWebsocketURL, websocketPath: config.externalWebsocketURL,
httpUnsafeOrigin: config.httpUnsafeOrigin, httpUnsafeOrigin: config.httpUnsafeOrigin,
adminEmail: config.adminEmail, adminEmail: config.adminEmail, // XXX mutable
adminKeys: admins, adminKeys: admins,
inactiveTime: config.inactiveTime, inactiveTime: config.inactiveTime, // XXX mutable
supportMailbox: config.supportMailboxPublicKey, supportMailbox: config.supportMailboxPublicKey,
maxUploadSize: config.maxUploadSize, maxUploadSize: config.maxUploadSize, // XXX mutable
premiumUploadSize: config.premiumUploadSize, premiumUploadSize: config.premiumUploadSize, // XXX mutable
}, null, '\t'), }, null, '\t'),
'obj.httpSafeOrigin = ' + (function () { 'obj.httpSafeOrigin = ' + (function () {
if (config.httpSafeOrigin) { return '"' + config.httpSafeOrigin + '"'; } if (config.httpSafeOrigin) { return '"' + config.httpSafeOrigin + '"'; }
@ -259,6 +258,8 @@ var serveConfig = (function () {
} }
// generate a lookup key for the cache // generate a lookup key for the cache
var cacheKey = host + ':' + cacheString(); var cacheKey = host + ':' + cacheString();
// XXX we must be able to clear the cache when updating any mutable key
// if there's nothing cached for that key... // if there's nothing cached for that key...
if (!configCache[cacheKey]) { if (!configCache[cacheKey]) {
// generate the response and cache it in memory // generate the response and cache it in memory

Loading…
Cancel
Save