guard against possible typeErrors from unvalidated config input

This commit is contained in:
ansuz 2020-10-09 13:28:13 +05:30
parent c392d52fe2
commit b5d3a10dc2
3 changed files with 24 additions and 17 deletions

View File

@ -176,13 +176,12 @@ var restoreArchivedDocument = function (Env, Server, cb) {
};
// 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];
if (!Array.isArray(value)) { return void cb('INVALID_DECREE'); }
var command = value[0];
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 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");
}
var command = commands[data[0]];
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');

View File

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

View File

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