mirror of
https://github.com/cryptpad/cryptpad.git
synced 2026-09-12 19:49:59 +05:00
New support: key rotation part 2
This commit is contained in:
parent
20dd15b99d
commit
a62dc7cfae
@ -942,6 +942,24 @@ var removeModerator = (Env, Server, cb, data) => {
|
||||
const id = Array.isArray(data) && data[1];
|
||||
Moderators.delete(Env, id, cb);
|
||||
};
|
||||
var archiveSupport = (Env, Server, cb, data) => {
|
||||
let supportPinKey = Env.supportPinKey;
|
||||
console.log(supportPinKey);
|
||||
getPinList(Env, Server, (err, list) => {
|
||||
console.log(list);
|
||||
if (err) { return void cb(err); }
|
||||
let n = nThen;
|
||||
list.forEach(id => {
|
||||
n = n(waitFor => {
|
||||
console.log(id);
|
||||
archiveDocument(Env, Server, waitFor(), [null, {id, reason:'DISABLE_SUPPORT'}]);
|
||||
}).nThen;
|
||||
});
|
||||
n(() => {
|
||||
cb();
|
||||
});
|
||||
}, [null, supportPinKey]);
|
||||
};
|
||||
|
||||
var commands = {
|
||||
ACTIVE_SESSIONS: getActiveSessions,
|
||||
@ -1011,6 +1029,7 @@ var commands = {
|
||||
DELETE_KNOWN_USER: deleteKnownUser,
|
||||
UPDATE_KNOWN_USER: updateKnownUser,
|
||||
|
||||
ARCHIVE_SUPPORT: archiveSupport,
|
||||
GET_MODERATORS: getModerators,
|
||||
ADD_MODERATOR: addModerator,
|
||||
REMOVE_MODERATOR: removeModerator,
|
||||
|
||||
@ -357,7 +357,7 @@ Channel.writePrivateMessage = function (Env, args, _cb, Server, netfluxId) {
|
||||
|
||||
// historyKeeper already knows how to handle metadata and message validation, so we just pass it off here
|
||||
// if the message isn't valid it won't be stored.
|
||||
Env.historyKeeper.channelMessage(Server, channelStruct, fullMessage, function (err) {
|
||||
Env.historyKeeper.channelMessage(Server, channelStruct, fullMessage, function (err, time) {
|
||||
if (err) {
|
||||
// Message not stored...
|
||||
return void cb(err);
|
||||
@ -368,7 +368,7 @@ Channel.writePrivateMessage = function (Env, args, _cb, Server, netfluxId) {
|
||||
Server.send(userId, fullMessage);
|
||||
});
|
||||
|
||||
cb();
|
||||
cb(void 0, time);
|
||||
});
|
||||
|
||||
|
||||
|
||||
@ -319,6 +319,7 @@ const storeMessage = function (Env, channel, msg, isCp, optionalMessageHash, cb)
|
||||
|
||||
Env.queueStorage(id, function (next) {
|
||||
const msgBin = Buffer.from(msg + '\n', 'utf8');
|
||||
const time = Array.isArray(msg) && msg[msg.length - 1];
|
||||
// Store the message first, and update the index only once it's stored.
|
||||
// store.messageBin can be async so updating the index first may
|
||||
// result in a wrong cpIndex
|
||||
@ -388,7 +389,7 @@ const storeMessage = function (Env, channel, msg, isCp, optionalMessageHash, cb)
|
||||
}
|
||||
|
||||
// Message stored, call back
|
||||
cb();
|
||||
cb(void 0, time);
|
||||
|
||||
var msgLength = msgBin.length;
|
||||
index.size += msgLength;
|
||||
|
||||
@ -2973,16 +2973,12 @@ Example
|
||||
// the support UI for the clients
|
||||
spinner.spin();
|
||||
$delButton.attr('disabled', 'disabled');
|
||||
sFrameChan.query('Q_ADMIN_RPC', {
|
||||
cmd: 'ADMIN_DECREE',
|
||||
data: ['SET_SUPPORT_MAILBOX2', ['', '']]
|
||||
}, function (e, response) {
|
||||
APP.supportModule.execCommand('DISABLE_SUPPORT', {}, (obj) => {
|
||||
$delButton.removeAttr('disabled');
|
||||
if (e || response.error) {
|
||||
if (obj && obj.error) {
|
||||
UI.warn(Messages.error);
|
||||
console.error(e, response);
|
||||
spinner.hide();
|
||||
return;
|
||||
console.error(obj.error);
|
||||
return void spinner.hide();
|
||||
}
|
||||
spinner.done();
|
||||
UI.log(Messages.saved);
|
||||
|
||||
@ -860,7 +860,7 @@ define([
|
||||
handlers['NOTIF_TICKET'] = function (ctx, box, data, cb) {
|
||||
var msg = data.msg;
|
||||
var content = msg.content;
|
||||
content.time = data.time;
|
||||
if (!content.time) { content.time = data.time; }
|
||||
|
||||
var support = Util.find(ctx, ['store', 'modules', 'support']);
|
||||
|
||||
|
||||
@ -147,12 +147,14 @@ define([
|
||||
ctx.supportData[channel] = {
|
||||
time: +new Date(),
|
||||
title: title,
|
||||
curvePublic: supportKey // XXX Should we store this value or delete the ticket on key rotation?
|
||||
curvePublic: supportKey // Old tickets still use previous keys
|
||||
};
|
||||
ctx.Store.onSync(null, waitFor());
|
||||
}).nThen(() => {
|
||||
var supportChannel = Hash.getChannelIdFromKey(supportKey);
|
||||
// XXX create tickt as an admin
|
||||
// XXX isAdmin
|
||||
// First message to deal with the new ticket (store it in the list)
|
||||
mailbox.sendTo('NEW_TICKET', {
|
||||
title: title,
|
||||
channel: channel,
|
||||
@ -165,7 +167,9 @@ define([
|
||||
if (obj && obj.error) { delete ctx.supportData[channel]; }
|
||||
cb(obj);
|
||||
});
|
||||
// XXX create tickt as an admin
|
||||
// XXX isAdmin
|
||||
// Second message is only a notification to warn the user/admins
|
||||
mailbox.sendTo('NOTIF_TICKET', {
|
||||
title: title,
|
||||
channel: channel,
|
||||
@ -182,6 +186,7 @@ define([
|
||||
if (!mailbox) { return void cb('E_NOT_READY'); }
|
||||
if (!anonRpc) { return void cb("anonymous rpc session not ready"); }
|
||||
var theirPublic, myCurve, notifKey;
|
||||
var time;
|
||||
nThen((waitFor) => {
|
||||
// Get correct keys
|
||||
getKeys(ctx, isAdmin, data, waitFor((err, obj) => {
|
||||
@ -202,12 +207,13 @@ define([
|
||||
anonRpc.send("WRITE_PRIVATE_MESSAGE", [
|
||||
data.channel,
|
||||
ciphertext
|
||||
], waitFor((err) => {
|
||||
], waitFor((err, res) => {
|
||||
if (err) {
|
||||
waitFor.abort();
|
||||
return void cb(err);
|
||||
}
|
||||
cb();
|
||||
time = res && res[0];
|
||||
cb(void 0, time);
|
||||
}));
|
||||
}).nThen(() => {
|
||||
// On success, notify
|
||||
@ -218,6 +224,7 @@ define([
|
||||
title: data.ticket.title,
|
||||
isClose: data.ticket.close,
|
||||
channel: data.channel,
|
||||
time: time,
|
||||
user: Util.find(data.ticket, ['sender', 'curvePublic']) ? undefined : {
|
||||
supportTeam: true
|
||||
}
|
||||
@ -245,13 +252,20 @@ define([
|
||||
var t = Util.clone(ctx.supportData[ticket]);
|
||||
getContent(ctx, {
|
||||
channel: ticket,
|
||||
curvePublic: t.curvePublic
|
||||
}, false, waitFor((err, messages) => {
|
||||
if (err) { t.error = err; }
|
||||
else { t.messages = messages; }
|
||||
|
||||
if (messages[messages.length -1].close) {
|
||||
ctx.supportData[ticket].closed = true;
|
||||
t.closed = true;
|
||||
if (err) {
|
||||
if (err.type === 'EDELETED') {
|
||||
delete ctx.supportData[ticket];
|
||||
return;
|
||||
}
|
||||
t.error = err;
|
||||
} else {
|
||||
t.messages = messages;
|
||||
if (messages.length && messages[messages.length -1].close) {
|
||||
ctx.supportData[ticket].closed = true;
|
||||
t.closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
t.id = ticket;
|
||||
@ -309,28 +323,37 @@ define([
|
||||
};
|
||||
|
||||
var loadTicketAdmin = function (ctx, data, cId, cb) {
|
||||
getContent(ctx, data, true, function (err, res) {
|
||||
if (err) { return void cb({error: err}); }
|
||||
ctx.adminRdyEvt.reg(() => {
|
||||
let supportKey = data.supportKey;
|
||||
ctx.adminRdyEvt.reg(() => {
|
||||
let doc = ctx.adminDoc.proxy;
|
||||
// If this ticket was created with an older support key, use the old one
|
||||
if (doc.oldKeys && doc.oldKeys[supportKey]) {
|
||||
data.adminCurvePrivate = doc.oldKeys[supportKey].curvePrivate;
|
||||
}
|
||||
|
||||
getContent(ctx, data, true, function (err, res) {
|
||||
if (err) { return void cb({error: err}); }
|
||||
var doc = ctx.adminDoc.proxy;
|
||||
if (Array.isArray(res) && res.length) {
|
||||
res.sort((t1, t2) => { return t1.time - t2.time; });
|
||||
let last = res[res.length - 1];
|
||||
let premium = res.some((msg) => {
|
||||
let curve = Util.find(msg, ['sender', 'curvePublic']);
|
||||
if (data.curvePublic !== curve) { return; }
|
||||
return Util.find(msg, ['sender', 'quota', 'plan']);
|
||||
});
|
||||
var senderKey = last.sender && last.sender.edPublic;
|
||||
if (!Array.isArray(res) || !res.length) { return void cb(res); }
|
||||
|
||||
var entry = doc.tickets.active[data.channel];
|
||||
if (entry) {
|
||||
entry.time = last.time;
|
||||
entry.premium = premium;
|
||||
// Sort messages by server time
|
||||
res.sort((t1, t2) => { return t1.time - t2.time; });
|
||||
let last = res[res.length - 1];
|
||||
let premium = res.some((msg) => {
|
||||
let curve = Util.find(msg, ['sender', 'curvePublic']);
|
||||
if (data.curvePublic !== curve) { return; }
|
||||
return Util.find(msg, ['sender', 'quota', 'plan']);
|
||||
});
|
||||
var senderKey = last.sender && last.sender.edPublic;
|
||||
|
||||
if (senderKey) {
|
||||
entry.lastAdmin = ctx.moderatorKeys.indexOf(senderKey) !== -1
|
||||
}
|
||||
// Update ChainPad with latest ticket data
|
||||
var entry = doc.tickets.active[data.channel];
|
||||
if (entry) {
|
||||
entry.time = last.time;
|
||||
entry.premium = premium;
|
||||
|
||||
if (senderKey) {
|
||||
entry.lastAdmin = ctx.moderatorKeys.indexOf(senderKey) !== -1
|
||||
}
|
||||
}
|
||||
cb(res);
|
||||
@ -340,24 +363,36 @@ define([
|
||||
|
||||
var replyTicketAdmin = function (ctx, data, cId, cb) {
|
||||
if (!ctx.adminRdyEvt) { return void cb({ error: 'EFORBIDDEN' }); }
|
||||
replyTicket(ctx, data, true, (err) => {
|
||||
if (err) { return void cb({error: err}); }
|
||||
ctx.adminRdyEvt.reg(() => {
|
||||
let supportKey = data.supportKey;
|
||||
ctx.adminRdyEvt.reg(() => {
|
||||
let doc = ctx.adminDoc.proxy;
|
||||
// If this ticket was created with an older support key, use the old one
|
||||
if (doc.oldKeys && doc.oldKeys[supportKey]) {
|
||||
data.adminCurvePrivate = doc.oldKeys[supportKey].curvePrivate;
|
||||
}
|
||||
replyTicket(ctx, data, true, (err, time) => {
|
||||
if (err) { return void cb({error: err}); }
|
||||
var doc = ctx.adminDoc.proxy;
|
||||
var entry = doc.tickets.active[data.channel] || doc.tickets.pending[data.channel];
|
||||
entry.time = +new Date();
|
||||
entry.time = time;
|
||||
entry.lastAdmin = true;
|
||||
cb({sent: true});
|
||||
});
|
||||
cb({sent: true});
|
||||
});
|
||||
};
|
||||
|
||||
var closeTicketAdmin = function (ctx, data, cId, cb) {
|
||||
if (!ctx.adminRdyEvt) { return void cb({ error: 'EFORBIDDEN' }); }
|
||||
// Reply with `data.ticket.close = true`
|
||||
replyTicket(ctx, data, true, (err) => {
|
||||
if (err) { return void cb({error: err}); }
|
||||
ctx.adminRdyEvt.reg(() => {
|
||||
let supportKey = data.supportKey;
|
||||
ctx.adminRdyEvt.reg(() => {
|
||||
let doc = ctx.adminDoc.proxy;
|
||||
// If this ticket was created with an older support key, use the old one
|
||||
if (doc.oldKeys && doc.oldKeys[supportKey]) {
|
||||
data.adminCurvePrivate = doc.oldKeys[supportKey].curvePrivate;
|
||||
}
|
||||
replyTicket(ctx, data, true, (err) => {
|
||||
if (err) { return void cb({error: err}); }
|
||||
var doc = ctx.adminDoc.proxy;
|
||||
var entry = doc.tickets.active[data.channel] || doc.tickets.pending[data.channel];
|
||||
entry.time = +new Date();
|
||||
@ -381,7 +416,7 @@ define([
|
||||
|
||||
var addAdminTicket = function (ctx, data, cb) {
|
||||
// Wait for the chainpad to be ready before adding the data
|
||||
if (!ctx.adminRdyEvt) { return void cb(false); } // XXX not an admin, delete mailbox?
|
||||
if (!ctx.adminRdyEvt) { return void cb(true); } // XXX not an admin, delete mailbox?
|
||||
|
||||
ctx.adminRdyEvt.reg(() => {
|
||||
let supportKey;
|
||||
@ -390,7 +425,7 @@ define([
|
||||
getKeys(ctx, false, data, waitFor((err, obj) => {
|
||||
if (err) {
|
||||
waitFor.abort();
|
||||
return void cb({error: err});
|
||||
return void cb(true);
|
||||
}
|
||||
supportKey = obj.theirPublic;
|
||||
}));
|
||||
@ -401,7 +436,7 @@ define([
|
||||
var doc = ctx.adminDoc.proxy;
|
||||
if (doc.tickets.active[data.channel] || doc.tickets.closed[data.channel]
|
||||
|| doc.tickets.pending[data.channel]) {
|
||||
return void cb(false); }
|
||||
return void cb(true); }
|
||||
doc.tickets.active[data.channel] = {
|
||||
title: data.title,
|
||||
premium: data.premium,
|
||||
@ -411,7 +446,9 @@ define([
|
||||
authorKey: data.user && data.user.curvePublic
|
||||
};
|
||||
Realtime.whenRealtimeSyncs(ctx.adminDoc.realtime, function () {
|
||||
cb(false);
|
||||
// Call back only when synced. That way we can handle the mailbox message
|
||||
// later in case of network issues.
|
||||
cb(true);
|
||||
});
|
||||
notifyClient(ctx, true, 'NEW_TICKET', data.channel);
|
||||
if (ctx.supportRpc) { ctx.supportRpc.pin([data.channel], () => {}); }
|
||||
@ -431,12 +468,14 @@ define([
|
||||
if (!doc.tickets.active[data.channel] && !doc.tickets.pending[data.channel]) {
|
||||
return; }
|
||||
let t = doc.tickets.active[data.channel] || doc.tickets.pending[data.channel];
|
||||
if (data.time > (t.time + 2000)) { t.time = data.time; }
|
||||
if (data.isClose) {
|
||||
doc.tickets.closed[data.channel] = t;
|
||||
delete doc.tickets.active[data.channel];
|
||||
delete doc.tickets.pending[data.channel];
|
||||
}
|
||||
if (data.time < t.time) { return; }
|
||||
|
||||
t.time = data.time;
|
||||
t.lastAdmin = false;
|
||||
notifyClient(ctx, true, 'UPDATE_TICKET', data.channel);
|
||||
});
|
||||
@ -614,6 +653,7 @@ define([
|
||||
editKeyStr: seed
|
||||
}
|
||||
});
|
||||
console.error(hash);
|
||||
loadAdminDoc(ctx, hash, waitFor());
|
||||
}).nThen(() => {
|
||||
console.log('Support admin loaded')
|
||||
@ -660,6 +700,7 @@ define([
|
||||
nThen((waitFor) => {
|
||||
// Check if support was already enabled
|
||||
getKeys(ctx, false, {}, waitFor((err, obj) => {
|
||||
if (err === 'E_NOT_INIT') { return; } // We're going to set up a support key
|
||||
if (err) {
|
||||
cb({error: err});
|
||||
return void waitFor.abort();
|
||||
@ -796,6 +837,76 @@ define([
|
||||
cb({success: true});
|
||||
});
|
||||
};
|
||||
let disableSupport = function (ctx, data, cId, _cb) {
|
||||
let cb = Util.once(Util.mkAsync(_cb));
|
||||
let proxy = ctx.store.proxy;
|
||||
let edPublic = proxy.edPublic;
|
||||
|
||||
let supportKey;
|
||||
let moderators;
|
||||
nThen((waitFor) => {
|
||||
// Check if support is enabled
|
||||
getKeys(ctx, false, {}, waitFor((err, obj) => {
|
||||
if (err) {
|
||||
cb({error: err});
|
||||
return void waitFor.abort();
|
||||
}
|
||||
supportKey = obj.theirPublic;
|
||||
}));
|
||||
}).nThen((waitFor) => {
|
||||
// Only admins can disable support
|
||||
if (!ctx.adminKeys.includes(edPublic)) {
|
||||
waitFor.abort();
|
||||
return void cb({error: 'EFORBIDDEN'});
|
||||
}
|
||||
}).nThen((waitFor) => {
|
||||
// Archive ChainPad and all the tickets (from pin log)
|
||||
ctx.Store.adminRpc(null, {
|
||||
cmd: 'ARCHIVE_SUPPORT',
|
||||
data: {}
|
||||
}, waitFor((obj) => {
|
||||
if (obj && obj.error) {
|
||||
waitFor.abort();
|
||||
return void cb(obj);
|
||||
}
|
||||
}));
|
||||
}).nThen((waitFor) => {
|
||||
ctx.Store.adminRpc(null, {
|
||||
cmd: 'ADMIN_DECREE',
|
||||
data: ['SET_SUPPORT_KEYS', ['', '']]
|
||||
}, waitFor(function (obj) {
|
||||
if (obj && obj.error) {
|
||||
waitFor.abort();
|
||||
return void cb(obj);
|
||||
}
|
||||
}));
|
||||
}).nThen((waitFor) => {
|
||||
getModerators(ctx, null, null, waitFor((obj) => {
|
||||
if (!obj || obj.error) {
|
||||
waitFor.abort();
|
||||
return void cb();
|
||||
}
|
||||
moderators = obj[0] || {};
|
||||
}));
|
||||
}).nThen((waitFor) => {
|
||||
let n = nThen;
|
||||
Object.keys(moderators).forEach((ed) => {
|
||||
n = n((waitFor) => {
|
||||
ctx.Store.adminRpc(null, {
|
||||
cmd: 'REMOVE_MODERATOR',
|
||||
data: ed
|
||||
}, waitFor(obj => {
|
||||
if (obj && obj.error) {
|
||||
console.error('Error removing moderator data', ed, obj.error);
|
||||
}
|
||||
}));
|
||||
}).nThen;
|
||||
});
|
||||
n(() => {
|
||||
cb();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var getAdminKey = function (ctx, data, cId, cb) {
|
||||
let proxy = ctx.store.proxy;
|
||||
@ -803,10 +914,12 @@ define([
|
||||
let privateKey = Util.find(proxy, ['mailboxes', 'supportteam', 'keys', 'curvePrivate']);
|
||||
getKeys(ctx, false, {}, (err, obj) => {
|
||||
if (err) { return void cb({error: err}); }
|
||||
if (obj.theirPublic !== supportKey) { return void cb({ error: 'EFORBIDDEN' }); }
|
||||
if (supportKey && obj.theirPublic !== supportKey) {
|
||||
privateKey = undefined;
|
||||
}
|
||||
cb({
|
||||
curvePrivate: privateKey,
|
||||
curvePublic: supportKey
|
||||
curvePublic: obj.theirPublic
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -860,15 +973,14 @@ define([
|
||||
|
||||
if (Util.find(store, ['proxy', 'mailboxes', 'supportteam'])) {
|
||||
initializeSupportAdmin(ctx, false, waitFor);
|
||||
window.CryptPad_SupportCtx = ctx;
|
||||
}
|
||||
|
||||
support.ctx = ctx;
|
||||
support.removeClient = function (clientId) {
|
||||
delete ctx.clients[clientId];
|
||||
};
|
||||
support.leavePad = function (padChan) {
|
||||
// XXX TODO
|
||||
};
|
||||
support.leavePad = function (padChan) {};
|
||||
support.addAdminTicket = function (content, cb) {
|
||||
addAdminTicket(ctx, content, cb);
|
||||
};
|
||||
@ -887,30 +999,10 @@ define([
|
||||
support.execCommand = function (clientId, obj, cb) {
|
||||
var cmd = obj.cmd;
|
||||
var data = obj.data;
|
||||
// User commands
|
||||
if (cmd === 'MAKE_TICKET') {
|
||||
return void makeTicket(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'LIST_TICKETS_ADMIN') {
|
||||
return void listTicketsAdmin(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'LOAD_TICKET_ADMIN') {
|
||||
return void loadTicketAdmin(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'REPLY_TICKET_ADMIN') {
|
||||
return void replyTicketAdmin(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'CLOSE_TICKET_ADMIN') {
|
||||
return void closeTicketAdmin(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'GET_PRIVATE_KEY') {
|
||||
return void getAdminKey(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'ROTATE_KEYS') {
|
||||
return void rotateKeys(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'ADD_MODERATOR') {
|
||||
return void addModerator(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'GET_MY_TICKETS') {
|
||||
return void getMyTickets(ctx, data, clientId, cb);
|
||||
}
|
||||
@ -923,6 +1015,32 @@ define([
|
||||
if (cmd === 'DELETE_TICKET') {
|
||||
return void deleteMyTicket(ctx, data, clientId, cb);
|
||||
}
|
||||
// Moderator commands
|
||||
if (cmd === 'LIST_TICKETS_ADMIN') {
|
||||
return void listTicketsAdmin(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'LOAD_TICKET_ADMIN') {
|
||||
return void loadTicketAdmin(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'REPLY_TICKET_ADMIN') {
|
||||
return void replyTicketAdmin(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'CLOSE_TICKET_ADMIN') {
|
||||
return void closeTicketAdmin(ctx, data, clientId, cb);
|
||||
}
|
||||
// Admin commands
|
||||
if (cmd === 'GET_PRIVATE_KEY') {
|
||||
return void getAdminKey(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'DISABLE_SUPPORT') {
|
||||
return void disableSupport(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'ROTATE_KEYS') {
|
||||
return void rotateKeys(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'ADD_MODERATOR') {
|
||||
return void addModerator(ctx, data, clientId, cb);
|
||||
}
|
||||
cb({error: 'NOT_SUPPORTED'});
|
||||
};
|
||||
|
||||
|
||||
@ -102,7 +102,7 @@ define([
|
||||
h('div.cp-notification-content', {
|
||||
tabindex: tabIndexValue
|
||||
}, [
|
||||
h('p', formatData(data))
|
||||
h('p', data.content.msg.type + ' - ' +formatData(data))
|
||||
])
|
||||
]);
|
||||
|
||||
|
||||
@ -110,9 +110,11 @@ define([
|
||||
};
|
||||
|
||||
const onShow = function (ticket, channel, data, done) {
|
||||
let supportKey = data.supportKey;
|
||||
APP.module.execCommand('LOAD_TICKET_ADMIN', {
|
||||
channel: channel,
|
||||
curvePublic: data.authorKey
|
||||
curvePublic: data.authorKey,
|
||||
supportKey: data.supportKey
|
||||
}, function (obj) {
|
||||
if (!Array.isArray(obj)) {
|
||||
console.error(obj && obj.error);
|
||||
@ -148,6 +150,7 @@ define([
|
||||
channel: channel,
|
||||
curvePublic: data.authorKey,
|
||||
notifChannel: data.notifications,
|
||||
supportKey: data.supportKey,
|
||||
ticket: formData
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) {
|
||||
@ -164,6 +167,7 @@ define([
|
||||
channel: channel,
|
||||
curvePublic: data.authorKey,
|
||||
notifChannel: data.notifications,
|
||||
supportKey: data.supportKey,
|
||||
ticket: APP.support.getDebuggingData({
|
||||
close: true
|
||||
})
|
||||
@ -311,6 +315,10 @@ define([
|
||||
var privateData = metadataMgr.getPrivateData();
|
||||
common.setTabTitle(Messages.supportPage);
|
||||
|
||||
if (!ApiConfig.supportMailboxKey) {
|
||||
return void UI.errorLoadingScreen(Messages.support_disabledTitle);
|
||||
}
|
||||
|
||||
APP.privateKey = privateData.supportPrivateKey;
|
||||
APP.origin = privateData.origin;
|
||||
APP.readOnly = privateData.readOnly;
|
||||
|
||||
@ -321,6 +321,7 @@ define([
|
||||
return void UI.warn(Messages.error);
|
||||
}
|
||||
id = Util.uid();
|
||||
events.UPDATE_TICKET.fire();
|
||||
$('.cp-sidebarlayout-category[data-category="tickets"]').click();
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user