diff --git a/lib/commands/admin-rpc.js b/lib/commands/admin-rpc.js index 427d9c03c..0e1a9a8e5 100644 --- a/lib/commands/admin-rpc.js +++ b/lib/commands/admin-rpc.js @@ -4,6 +4,7 @@ const nThen = require("nthen"); const getFolderSize = require("get-folder-size"); const Util = require("../common-util"); const Ulimit = require("ulimit"); +const Decrees = require("../decrees"); var Fs = require("fs"); @@ -175,6 +176,8 @@ var restoreArchivedDocument = function (Env, Server, cb) { }; // CryptPad_AsyncStore.rpc.send('ADMIN', ['SET_DEFAULT_STORAGE_LIMIT', 1024 * 1024 * 1024 /* 1GB */], console.log) +// XXX make this a decree +// XXX expose this via the admin panel (with UI) var setDefaultStorageLimit = function (Env, Server, cb, data) { var value = Array.isArray(data) && data[1]; if (typeof(value) !== 'number' || value <= 0) { return void cb('EINVAL'); } @@ -190,6 +193,56 @@ var setDefaultStorageLimit = function (Env, Server, cb, data) { cb(void 0, change); }; +// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['RESTRICT_REGISTRATION', [true]]], console.log) +var adminDecree = function (Env, Server, cb, data, safeKey) { + 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); + +/* + +The admin should have sent a command to be run: + +the server adds two pieces of information to the supplied decree: + +* the unsafeKey of the admin who uploaded it +* the current time + +1. test the command to see if it's valid and will result in a change +2. if so, apply it and write it to the log for persistence +3. respond to the admin with an error or nothing + +*/ + + var decree = [command, args, unsafeKey, +new Date()]; + var changed; + try { + changed = Decrees.handleCommand(Env, decree) || false; + } catch (err) { + return void cb(err); + } + + if (!changed) { return void cb(); } + Decrees.write(Env, decree, cb); +}; + +// CryptPad_AsyncStore.rpc.send('ADMIN', ['INSTANCE_STATUS], console.log) +var instanceStatus = function (Env, Server, cb) { + cb(void 0, { + restrictRegistration: Boolean(Env.restrictRegistration), + launchTime: Env.launchTime, + currentTime: +new Date(), + + accountRetentionTime: Env.accountRetentionTime, + archiveRetentionTime: Env.archiveRetentionTime, + + defaultStorageLimit: Env.defaultStorageLimit, + }); +}; + var commands = { ACTIVE_SESSIONS: getActiveSessions, ACTIVE_PADS: getActiveChannelCount, @@ -204,6 +257,9 @@ var commands = { ARCHIVE_DOCUMENT: archiveDocument, RESTORE_ARCHIVED_DOCUMENT: restoreArchivedDocument, + + ADMIN_DECREE: adminDecree, + INSTANCE_STATUS: instanceStatus, }; Admin.command = function (Env, safeKey, data, _cb, Server) { @@ -218,10 +274,9 @@ Admin.command = function (Env, safeKey, data, _cb, Server) { var command = commands[data[0]]; if (typeof(command) === 'function') { - return void command(Env, Server, cb, data); + return void command(Env, Server, cb, data, safeKey); } return void cb('UNHANDLED_ADMIN_COMMAND'); }; - diff --git a/lib/decrees.js b/lib/decrees.js new file mode 100644 index 000000000..4c769179e --- /dev/null +++ b/lib/decrees.js @@ -0,0 +1,132 @@ +var Decrees = module.exports; + +/* Admin decrees which modify global server state + +IMPLEMENTED: + +RESTRICT_REGISTRATION + +NOT IMPLEMENTED: + +ADD_QUOTA +RM_QUOTA +UPDATE_QUOTA +ADD_INVITE +REVOKE_INVITE +REDEEM_INVITE + + +*/ + +var commands = {}; +/* commands have a simple API: + +* they receive the global Env and the arguments to be applied +* if the arguments are invalid the operation will not be applied + * the command throws +* if the arguments are valid but do not result in a change, the operation is redundant. + * return false +* if the arguments are valid and will result in a change, the operation should be applied + * apply it + * return true to indicate that it was applied + +*/ + +// Toggles a simple boolean +commands.RESTRICT_REGISTRATION = function (Env, args) { + if (!Array.isArray(args) || typeof(args[0]) !== 'boolean') { + throw new Error('INVALID_ARGS'); + } + var bool = args[0]; + if (bool === Env.restrictRegistration) { return false; } + Env.restrictRegistration = bool; + return true; +}; + +// [, , ,