mirror of https://github.com/xwiki-labs/cryptpad
guard against possible typeErrors from unvalidated config input
This commit is contained in:
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!");
|
||||||
}
|
}
|
||||||
|
|
17
server.js
17
server.js
|
@ -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…
Reference in New Issue