diff --git a/lib/commands/pin-rpc.js b/lib/commands/pin-rpc.js index 1c9052a14..f5dcf7163 100644 --- a/lib/commands/pin-rpc.js +++ b/lib/commands/pin-rpc.js @@ -9,7 +9,7 @@ const Pinning = module.exports; const Util = require("../common-util"); const nThen = require("nthen"); -//const escapeKeyCharacters = Util.escapeKeyCharacters; +const escapeKeyCharacters = Util.escapeKeyCharacters; const unescapeKeyCharacters = Util.unescapeKeyCharacters; var sumChannelSizes = function (sizes) { // FIXME this synchronous code could be done by a worker @@ -174,6 +174,23 @@ Pinning.pinChannel = function (Env, safeKey, channels, cb) { return void cb(); } + let pin = function () { + Env.pinStore.message(safeKey, JSON.stringify(['PIN', toStore, +new Date()]), + function (e) { + if (e) { return void cb(e); } + if (!session || !session.channels) { return void cb(); } + toStore.forEach(function (channel) { + session.channels[channel] = true; + }); + cb(); + }); + }; + + // Support tickets are always pinned, no need to check the limit + if (safeKey === escapeKeyCharacters(Env.supportPinKey)) { + return void pin(); + } + getMultipleFileSize(Env, toStore, function (e, sizes) { if (typeof(sizes) === 'undefined') { return void cb(e); } var pinSize = sumChannelSizes(sizes); // FIXME don't do this in the main thread... @@ -185,15 +202,7 @@ Pinning.pinChannel = function (Env, safeKey, channels, cb) { } if (pinSize > free) { return void cb('E_OVER_LIMIT'); } - Env.pinStore.message(safeKey, JSON.stringify(['PIN', toStore, +new Date()]), - function (e) { - if (e) { return void cb(e); } - if (!session || !session.channels) { return; } - toStore.forEach(function (channel) { - session.channels[channel] = true; - }); - cb(); - }); + pin(); }); }); }); @@ -238,7 +247,26 @@ Pinning.resetUserPins = function (Env, safeKey, channelList, _cb) { return void cb(); } - var pins = {}; + let reset = function () { + var pins = {}; + Env.pinStore.message(safeKey, JSON.stringify(['RESET', channelList, +new Date()]), + function (e) { + if (e) { return void cb(e); } + channelList.forEach(function (channel) { + pins[channel] = true; + }); + + // update in-memory cache IFF the reset was allowed. + if (session) { session.channels = pins; } + cb(); + }); + }; + + // Support tickets are always pinned, no need to check the limit + if (safeKey === escapeKeyCharacters(Env.supportPinKey)) { + return void reset(); + } + getMultipleFileSize(Env, channelList, function (e, sizes) { if (typeof(sizes) === 'undefined') { return void cb(e); } var pinSize = sumChannelSizes(sizes); @@ -259,24 +287,7 @@ Pinning.resetUserPins = function (Env, safeKey, channelList, _cb) { They will not be able to pin additional pads until they upgrade or delete enough files to go back under their limit. */ if (pinSize > limit[0] && session.hasPinned) { return void(cb('E_OVER_LIMIT')); } - Env.pinStore.message(safeKey, JSON.stringify(['RESET', channelList, +new Date()]), - function (e) { - if (e) { return void cb(e); } - channelList.forEach(function (channel) { - pins[channel] = true; - }); - - var oldChannels; - if (session.channels && typeof(session.channels) === 'object') { - oldChannels = Object.keys(session.channels); - } else { - oldChannels = []; - } - - // update in-memory cache IFF the reset was allowed. - session.channels = pins; - cb(); - }); + reset(); }); }); }; diff --git a/lib/decrees.js b/lib/decrees.js index 98eb97f55..b51053130 100644 --- a/lib/decrees.js +++ b/lib/decrees.js @@ -210,10 +210,20 @@ commands.SET_ADMIN_EMAIL = makeGenericSetter('adminEmail', args_isString); commands.SET_SUPPORT_MAILBOX = makeGenericSetter('supportMailbox', function (args) { return args_isString(args) && Core.isValidPublicKey(args[0]); }); -// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_SUPPORT_MAILBOX2', ["Tdz6+fE9N9XXBY93rW5qeNa/k27yd40c0vq7EJyt7jA="]]], console.log) -commands.SET_SUPPORT_MAILBOX2 = makeGenericSetter('newSupportMailbox', function (args) { - return args_isString(args) && (Core.isValidPublicKey(args[0]) || !args[0]); -}); +// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_SUPPORT_KEYS', ["Tdz6+fE9N9XXBY93rW5qeNa/k27yd40c0vq7EJyt7jA=", "Tdz6+fE9N9XXBY93rW5qeNa/k27yd40c0vq7EJyt7jA="]]], console.log) +commands.SET_SUPPORT_KEYS = function (Env, args) { + const curvePublic = args[0]; // Support mailbox key + const edPublic = args[1]; // Support pin log + let validated = typeof(curvePublic) === "string" && + (Core.isValidPublicKey(curvePublic) || !curvePublic) && + typeof(edPublic) === "string" && + (Core.isValidPublicKey(edPublic) || !edPublic); + if (!validated) { throw new Error('INVALID_ARGS'); } + if (Env.supportMailboxKey === curvePublic && Env.supportPinKey === edPublic) { return false; } + Env.supportMailboxKey = curvePublic; + Env.supportPinKey = edPublic; + return true; +}; // CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_PURPOSE', ["development"]]], console.log) commands.SET_INSTANCE_PURPOSE = makeGenericSetter('instancePurpose', args_isString); diff --git a/lib/env.js b/lib/env.js index 5f648d0c9..49a53963d 100644 --- a/lib/env.js +++ b/lib/env.js @@ -147,7 +147,7 @@ module.exports.create = function (config) { adminEmail: config.adminEmail, supportMailbox: config.supportMailboxPublicKey, - newSupportMailbox: undefined, + supportMailboxKey: undefined, metadata_cache: {}, channel_cache: {}, diff --git a/lib/http-worker.js b/lib/http-worker.js index 0c9dffd4c..9be982193 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -571,7 +571,7 @@ var serveConfig = makeRouteCache(function () { adminKeys: Env.admins, inactiveTime: Env.inactiveTime, supportMailbox: Env.supportMailbox, - newSupportMailbox: Env.newSupportMailbox, + supportMailboxKey: Env.supportMailboxKey, defaultStorageLimit: Env.defaultStorageLimit, maxUploadSize: Env.maxUploadSize, premiumUploadSize: Env.premiumUploadSize, diff --git a/lib/stats.js b/lib/stats.js index 5d1fdc6a9..9b8781df5 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -45,7 +45,7 @@ Stats.instanceData = function (Env) { // we expect that you enable your support mailbox data.supportMailbox = Boolean(Env.supportMailbox); - data.newSupportMailbox = Boolean(Env.newSupportMailbox); + data.supportMailboxKey = Boolean(Env.supportMailboxKey); // do you allow registration? data.restrictRegistration = Boolean(Env.restrictRegistration); diff --git a/www/admin/inner.js b/www/admin/inner.js index dc88f425c..b17d0405e 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -2926,7 +2926,7 @@ Example Messages.admin_supportNewConfirm = "Are you sure? This will remove access to all current moderators."; create['support-new'] = function () { var $div = makeBlock('support-new'); // Msg.admin_supportNewHint, .admin_supportNewTitle - var newSupportKey = ApiConfig.newSupportMailbox; + var newSupportKey = ApiConfig.supportMailboxKey; (function () { var state = h('div'); var $state = $(state).appendTo($div); @@ -2989,6 +2989,8 @@ Example var keyPair = Nacl.box.keyPair(); var pub = Nacl.util.encodeBase64(keyPair.publicKey); var priv = Nacl.util.encodeBase64(keyPair.secretKey); + var ed = Nacl.sign.keyPair.fromSeed(keypair.secretKey); + var edPub = Nacl.util.encodeBase64(ed.publicKey); // Store the private key first. It won't be used until the decree is accepted. sFrameChan.query("Q_ADMIN_MAILBOX", { version: 2, @@ -3003,7 +3005,7 @@ Example // Then send the decree sFrameChan.query('Q_ADMIN_RPC', { cmd: 'ADMIN_DECREE', - data: ['SET_SUPPORT_MAILBOX2', [pub]] + data: ['SET_SUPPORT_MAILBOX2', [pub, edPub]] }, function (e, response) { $button.removeAttr('disabled'); if (e || response.error) { diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 4a6198f20..d62a33d8e 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1623,7 +1623,7 @@ define([ if (!priv || !pub) { return void cb({error: 'EINVAL'}); } var channel = Hash.getChannelIdFromKey(pub); var mailboxes = store.proxy.mailboxes = store.proxy.mailboxes || {}; - var key = isNewSupport ? 'support2' : 'supportadmin'; + var key = isNewSupport ? 'supportteam' : 'supportadmin'; var box = mailboxes[key] = { channel: channel, viewed: [], diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js index 120cd33ce..c3eb249dc 100644 --- a/www/common/outer/mailbox.js +++ b/www/common/outer/mailbox.js @@ -20,7 +20,7 @@ define([ 'notifications', 'supportadmin', 'support', - 'support2', + 'supportteam', 'broadcast' ]; var BLOCKING_TYPES = [ diff --git a/www/common/outer/support.js b/www/common/outer/support.js index f0b3f4d91..31d41c8b9 100644 --- a/www/common/outer/support.js +++ b/www/common/outer/support.js @@ -24,12 +24,12 @@ define([ require(['/api/config?' + (+new Date())], function (NewConfig) { ctx.adminKeys = NewConfig.adminKeys; // Update admin keys // XXX MODERATOR - var supportKey = NewConfig.newSupportMailbox; + var supportKey = NewConfig.supportMailboxKey; if (!supportKey) { return void cb('E_NOT_INIT'); } // If admin, check key if (isAdmin && Util.find(ctx.store.proxy, [ - 'mailboxes', 'support2', 'keys', 'curvePublic']) !== supportKey) { + 'mailboxes', 'supportteam', 'keys', 'curvePublic']) !== supportKey) { return void cb('EFORBIDDEN'); } @@ -37,7 +37,7 @@ define([ return ctx.adminRdyEvt.reg(() => { cb(null, { myCurve: data.adminCurvePrivate || Util.find(ctx.store.proxy, [ - 'mailboxes', 'support2', 'keys', 'curvePrivate']), + 'mailboxes', 'supportteam', 'keys', 'curvePrivate']), theirPublic: data.curvePublic, notifKey: data.curvePublic }); @@ -461,7 +461,7 @@ define([ let cb = Util.mkAsync(_cb); let Nacl = Crypto.Nacl; let proxy = ctx.store.proxy; - let curvePrivate = Util.find(proxy, ['mailboxes', 'support2', 'keys', 'curvePrivate']); + let curvePrivate = Util.find(proxy, ['mailboxes', 'supportteam', 'keys', 'curvePrivate']); if (!curvePrivate) { return void cb('EFORBIDDEN'); } let edPrivate, edPublic try { @@ -526,8 +526,8 @@ define([ var initializeSupportAdmin = function (ctx, waitFor) { let unlock = waitFor(); let proxy = ctx.store.proxy; - let supportKey = Util.find(proxy, ['mailboxes', 'support2', 'keys', 'curvePublic']); - let privateKey = Util.find(proxy, ['mailboxes', 'support2', 'keys', 'curvePrivate']); + let supportKey = Util.find(proxy, ['mailboxes', 'supportteam', 'keys', 'curvePublic']); + let privateKey = Util.find(proxy, ['mailboxes', 'supportteam', 'keys', 'curvePrivate']); ctx.adminRdyEvt = Util.mkEvent(true); nThen((waitFor) => { getKeys(ctx, false, {}, waitFor((err, obj) => { @@ -580,7 +580,7 @@ define([ clients: {} }; - if (Util.find(store, ['proxy', 'mailboxes', 'support2'])) { + if (Util.find(store, ['proxy', 'mailboxes', 'supportteam'])) { initializeSupportAdmin(ctx, waitFor); } diff --git a/www/common/sframe-common-mailbox.js b/www/common/sframe-common-mailbox.js index ceb49c321..92da483c3 100644 --- a/www/common/sframe-common-mailbox.js +++ b/www/common/sframe-common-mailbox.js @@ -163,7 +163,7 @@ define([ // Call the onMessage handlers var isNotification = function (type) { - return type === "notifications" || /^team-/.test(type) || type === "broadcast" || type === "reminders" || type === "support2"; + return type === "notifications" || /^team-/.test(type) || type === "broadcast" || type === "reminders" || type === "supportteam"; }; var pushMessage = function (data, handler) { var todo = function (f) { diff --git a/www/common/toolbar.js b/www/common/toolbar.js index 270cde69d..e9e800f9f 100644 --- a/www/common/toolbar.js +++ b/www/common/toolbar.js @@ -1173,7 +1173,7 @@ MessengerUI, Messages, Pages) { $button.addClass('fa-bell'); }; - Common.mailbox.subscribe(['notifications', 'team', 'broadcast', 'reminders', 'support2'], { + Common.mailbox.subscribe(['notifications', 'team', 'broadcast', 'reminders', 'supportteam'], { onMessage: function (data, el) { if (toolbar.$top.hasClass('toolbar-hidden')) { $('.cp-collapsed-notif').css('display', '');