Merge branch 'staging' into communities-comments
commit
75dcc3121b
20
lib/api.js
20
lib/api.js
|
@ -9,6 +9,16 @@ module.exports.create = function (config) {
|
|||
|
||||
var log = config.log;
|
||||
|
||||
var noop = function () {};
|
||||
|
||||
var special_errors = {};
|
||||
['EPIPE', 'ECONNRESET'].forEach(function (k) { special_errors[k] = noop; });
|
||||
special_errors.NF_ENOENT = function (error, label, info) {
|
||||
log.error(label, {
|
||||
info: info,
|
||||
});
|
||||
};
|
||||
|
||||
// spawn ws server and attach netflux event handlers
|
||||
NetfluxSrv.create(new WebSocketServer({ server: config.httpServer}))
|
||||
.on('channelClose', historyKeeper.channelClose)
|
||||
|
@ -17,11 +27,17 @@ module.exports.create = function (config) {
|
|||
.on('sessionClose', historyKeeper.sessionClose)
|
||||
.on('error', function (error, label, info) {
|
||||
if (!error) { return; }
|
||||
if (['EPIPE', 'ECONNRESET'].indexOf(error && error.code) !== -1) { return; }
|
||||
if (error && error.code) {
|
||||
/* EPIPE,ECONNERESET, NF_ENOENT */
|
||||
if (typeof(special_errors[error.code]) === 'function') {
|
||||
return void special_errors[error.code](error, label, info);
|
||||
}
|
||||
}
|
||||
|
||||
/* labels:
|
||||
SEND_MESSAGE_FAIL, SEND_MESSAGE_FAIL_2, FAIL_TO_DISCONNECT,
|
||||
FAIL_TO_TERMINATE, HANDLE_CHANNEL_LEAVE, NETFLUX_BAD_MESSAGE,
|
||||
NETFLUX_WEBSOCKET_ERROR, NF_ENOENT
|
||||
NETFLUX_WEBSOCKET_ERROR
|
||||
*/
|
||||
log.error(label, {
|
||||
code: error.code,
|
||||
|
|
|
@ -75,8 +75,21 @@ Upload.upload = function (Env, safeKey, chunk, cb) {
|
|||
Env.blobStore.upload(safeKey, chunk, cb);
|
||||
};
|
||||
|
||||
var reportStatus = function (Env, label, safeKey, err, id) {
|
||||
var data = {
|
||||
safeKey: safeKey,
|
||||
err: err && err.message || err,
|
||||
id: id,
|
||||
};
|
||||
var method = err? 'error': 'info';
|
||||
Env.Log[method](label, data);
|
||||
};
|
||||
|
||||
Upload.complete = function (Env, safeKey, arg, cb) {
|
||||
Env.blobStore.complete(safeKey, arg, cb);
|
||||
Env.blobStore.complete(safeKey, arg, function (err, id) {
|
||||
reportStatus(Env, 'UPLOAD_COMPLETE', safeKey, err, id);
|
||||
cb(err, id);
|
||||
});
|
||||
};
|
||||
|
||||
Upload.cancel = function (Env, safeKey, arg, cb) {
|
||||
|
@ -84,6 +97,9 @@ Upload.cancel = function (Env, safeKey, arg, cb) {
|
|||
};
|
||||
|
||||
Upload.complete_owned = function (Env, safeKey, arg, cb) {
|
||||
Env.blobStore.completeOwned(safeKey, arg, cb);
|
||||
Env.blobStore.completeOwned(safeKey, arg, function (err, id) {
|
||||
reportStatus(Env, 'UPLOAD_COMPLETE_OWNED', safeKey, err, id);
|
||||
cb(err, id);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -622,7 +622,8 @@ const handleGetHistory = function (Env, Server, seq, userId, parsed) {
|
|||
}, (err) => {
|
||||
if (err && err.code !== 'ENOENT') {
|
||||
if (err.message !== 'EINVAL') { Log.error("HK_GET_HISTORY", {
|
||||
err: err && err.message,
|
||||
channel: channelName,
|
||||
err: err && err.message || err,
|
||||
stack: err && err.stack,
|
||||
}); }
|
||||
const parsedMsg = {error:err.message, channel: channelName, txid: txid};
|
||||
|
|
32
lib/log.js
32
lib/log.js
|
@ -23,29 +23,13 @@ var write = function (ctx, content) {
|
|||
// various degrees of logging
|
||||
const logLevels = Logger.levels = ['silly', 'verbose', 'debug', 'feedback', 'info', 'warn', 'error'];
|
||||
|
||||
var handlers = {
|
||||
silly: function (ctx, time, tag, info) {
|
||||
console.log('[SILLY]', time, tag, info);
|
||||
},
|
||||
debug: function (ctx, time, tag, info) {
|
||||
console.log('[DEBUG]', time, tag, info);
|
||||
},
|
||||
verbose: function (ctx, time, tag, info) {
|
||||
console.log('[VERBOSE]', time, tag, info);
|
||||
},
|
||||
feedback: function (ctx, time, tag, info) {
|
||||
console.log('[FEEDBACK]', time, tag, info);
|
||||
},
|
||||
info: function (ctx, time, tag, info) {
|
||||
console.info('[INFO]', time, tag, info);
|
||||
},
|
||||
warn: function (ctx, time, tag, info) {
|
||||
console.warn('[WARN]', time, tag, info);
|
||||
},
|
||||
error: function (ctx, time, tag, info) {
|
||||
console.error('[ERROR]', time, tag, info);
|
||||
}
|
||||
};
|
||||
var handlers = {};
|
||||
['silly', 'debug', 'verbose', 'feedback', 'info'].forEach(function (level) {
|
||||
handlers[level] = function (ctx, content) { console.log(content); };
|
||||
});
|
||||
['warn', 'error'].forEach(function (level) {
|
||||
handlers[level] = function (ctx, content) { console.error(content); };
|
||||
});
|
||||
|
||||
var noop = function () {};
|
||||
|
||||
|
@ -65,7 +49,7 @@ var createLogType = function (ctx, type) {
|
|||
return;
|
||||
}
|
||||
if (ctx.logToStdout && typeof(handlers[type]) === 'function') {
|
||||
handlers[type](ctx, time, tag, info);
|
||||
handlers[type](ctx, content);
|
||||
}
|
||||
write(ctx, content);
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@ const Workers = module.exports;
|
|||
const PID = process.pid;
|
||||
|
||||
const DB_PATH = 'lib/workers/db-worker';
|
||||
const MAX_JOBS = 16;
|
||||
const MAX_JOBS = 8;
|
||||
|
||||
Workers.initialize = function (Env, config, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
|
@ -97,7 +97,7 @@ Workers.initialize = function (Env, config, _cb) {
|
|||
// track which worker is doing which jobs
|
||||
state.tasks[txid] = msg;
|
||||
|
||||
response.expect(txid, cb, 60000);
|
||||
response.expect(txid, cb, 180000);
|
||||
state.worker.send(msg);
|
||||
};
|
||||
|
||||
|
|
|
@ -32,9 +32,18 @@
|
|||
.cp-support-list-message {
|
||||
&:last-child:not(.cp-support-fromadmin) {
|
||||
color: @colortheme_cp-red;
|
||||
background-color: lighten(@colortheme_cp-red, 25%);
|
||||
background-color: lighten(@colortheme_form-warning, 25%);
|
||||
.cp-support-showdata {
|
||||
background-color: lighten(@colortheme_cp-red, 30%);
|
||||
background-color: lighten(@colortheme_form-warning, 30%);
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
&.cp-support-frompremium {
|
||||
background-color: lighten(@colortheme_cp-red, 25%);
|
||||
.cp-support-showdata {
|
||||
background-color: lighten(@colortheme_cp-red, 30%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,8 +110,11 @@ define([
|
|||
c2.height = D.dim;
|
||||
|
||||
var ctx = c2.getContext('2d');
|
||||
ctx.drawImage(canvas, D.x, D.y, D.w, D.h);
|
||||
|
||||
try {
|
||||
ctx.drawImage(canvas, D.x, D.y, D.w, D.h);
|
||||
} catch (e) {
|
||||
return void cb('ERROR');
|
||||
}
|
||||
cb(void 0, c2.toDataURL());
|
||||
};
|
||||
|
||||
|
@ -157,6 +160,8 @@ define([
|
|||
viewport: page.getViewport(scale)
|
||||
}).promise.then(function () {
|
||||
return canvas;
|
||||
}).catch(function () {
|
||||
cb('ERROR');
|
||||
});
|
||||
};
|
||||
PDFJS.getDocument(url).promise
|
||||
|
@ -190,7 +195,8 @@ define([
|
|||
});
|
||||
reader.readAsText(blob);
|
||||
};
|
||||
Thumb.fromBlob = function (blob, cb) {
|
||||
Thumb.fromBlob = function (blob, _cb) {
|
||||
var cb = Util.once(_cb);
|
||||
if (blob.type.indexOf('video/') !== -1) {
|
||||
return void Thumb.fromVideoBlob(blob, cb);
|
||||
}
|
||||
|
@ -200,7 +206,10 @@ define([
|
|||
if (Util.isPlainTextFile(blob.type, blob.name)) {
|
||||
return void Thumb.fromPlainTextBlob(blob, cb);
|
||||
}
|
||||
Thumb.fromImageBlob(blob, cb);
|
||||
if (blob.type.indexOf('image/') !== -1) {
|
||||
return void Thumb.fromImageBlob(blob, cb);
|
||||
}
|
||||
return void cb('NO_THUMBNAIL');
|
||||
};
|
||||
|
||||
window.html2canvas = undefined;
|
||||
|
|
|
@ -395,7 +395,7 @@ define([
|
|||
var forceCreationScreen = cfg.useCreationScreen &&
|
||||
sessionStorage[Utils.Constants.displayPadCreationScreen];
|
||||
delete sessionStorage[Utils.Constants.displayPadCreationScreen];
|
||||
var isSafe = ['debug', 'profile', 'drive'].indexOf(currentPad.app) !== -1;
|
||||
var isSafe = ['debug', 'profile', 'drive', 'teams'].indexOf(currentPad.app) !== -1;
|
||||
var updateMeta = function () {
|
||||
//console.log('EV_METADATA_UPDATE');
|
||||
var metaObj;
|
||||
|
@ -620,6 +620,172 @@ define([
|
|||
}, href);
|
||||
});
|
||||
|
||||
// Add or remove our mailbox from the list if we're an owner
|
||||
sframeChan.on('Q_UPDATE_MAILBOX', function (data, cb) {
|
||||
var metadata = data.metadata;
|
||||
var add = data.add;
|
||||
var _secret = secret;
|
||||
if (metadata && (metadata.href || metadata.roHref)) {
|
||||
var _parsed = Utils.Hash.parsePadUrl(metadata.href || metadata.roHref);
|
||||
_secret = Utils.Hash.getSecrets(_parsed.type, _parsed.hash, metadata.password);
|
||||
}
|
||||
if (_secret.channel.length !== 32) {
|
||||
return void cb({error: 'EINVAL'});
|
||||
}
|
||||
var crypto = Crypto.createEncryptor(_secret.keys);
|
||||
nThen(function (waitFor) {
|
||||
// If we already have metadata, use it, otherwise, try to get it
|
||||
if (metadata) { return; }
|
||||
|
||||
Cryptpad.getPadMetadata({
|
||||
channel: secret.channel
|
||||
}, waitFor(function (obj) {
|
||||
obj = obj || {};
|
||||
if (obj.error) {
|
||||
waitFor.abort();
|
||||
return void cb(obj);
|
||||
}
|
||||
metadata = obj;
|
||||
}));
|
||||
}).nThen(function () {
|
||||
// Get and maybe migrate the existing mailbox object
|
||||
var owners = metadata.owners;
|
||||
if (!Array.isArray(owners) || owners.indexOf(edPublic) === -1) {
|
||||
return void cb({ error: 'INSUFFICIENT_PERMISSIONS' });
|
||||
}
|
||||
|
||||
// Remove a mailbox
|
||||
if (!add) {
|
||||
// Old format: this is the mailbox of the first owner
|
||||
if (typeof (metadata.mailbox) === "string" && metadata.mailbox) {
|
||||
// Not our mailbox? abort
|
||||
if (owners[0] !== edPublic) {
|
||||
return void cb({ error: 'INSUFFICIENT_PERMISSIONS' });
|
||||
}
|
||||
// Remove it
|
||||
return void Cryptpad.setPadMetadata({
|
||||
channel: _secret.channel,
|
||||
command: 'RM_MAILBOX',
|
||||
value: []
|
||||
}, cb);
|
||||
} else if (metadata.mailbox) { // New format
|
||||
return void Cryptpad.setPadMetadata({
|
||||
channel: _secret.channel,
|
||||
command: 'RM_MAILBOX',
|
||||
value: [edPublic]
|
||||
}, cb);
|
||||
}
|
||||
return void cb({
|
||||
error: 'NO_MAILBOX'
|
||||
});
|
||||
}
|
||||
// Add a mailbox
|
||||
var toAdd = {};
|
||||
toAdd[edPublic] = crypto.encrypt(JSON.stringify({
|
||||
notifications: notifications,
|
||||
curvePublic: curvePublic
|
||||
}));
|
||||
Cryptpad.setPadMetadata({
|
||||
channel: _secret.channel,
|
||||
command: 'ADD_MAILBOX',
|
||||
value: toAdd
|
||||
}, cb);
|
||||
});
|
||||
});
|
||||
|
||||
// REQUEST_ACCESS is used both to check IF we can contact an owner (send === false)
|
||||
// AND also to send the request if we want (send === true)
|
||||
sframeChan.on('Q_REQUEST_ACCESS', function (data, cb) {
|
||||
if (readOnly && hashes.editHash) {
|
||||
return void cb({error: 'ALREADYKNOWN'});
|
||||
}
|
||||
var send = data.send;
|
||||
var metadata = data.metadata;
|
||||
var owner, owners;
|
||||
var _secret = secret;
|
||||
if (metadata && metadata.roHref) {
|
||||
var _parsed = Utils.Hash.parsePadUrl(metadata.roHref);
|
||||
_secret = Utils.Hash.getSecrets(_parsed.type, _parsed.hash, metadata.password);
|
||||
}
|
||||
if (_secret.channel.length !== 32) {
|
||||
return void cb({error: 'EINVAL'});
|
||||
}
|
||||
var crypto = Crypto.createEncryptor(_secret.keys);
|
||||
nThen(function (waitFor) {
|
||||
// Try to get the owner's mailbox from the pad metadata first.
|
||||
// If it's is an older owned pad, check if the owner is a friend
|
||||
// or an acquaintance (from async-store directly in requestAccess)
|
||||
var todo = function (obj) {
|
||||
owners = obj.owners;
|
||||
|
||||
var mailbox;
|
||||
// Get the first available mailbox (the field can be an string or an object)
|
||||
// TODO maybe we should send the request to all the owners?
|
||||
if (typeof (obj.mailbox) === "string") {
|
||||
mailbox = obj.mailbox;
|
||||
} else if (obj.mailbox && obj.owners && obj.owners.length) {
|
||||
mailbox = obj.mailbox[obj.owners[0]];
|
||||
}
|
||||
if (mailbox) {
|
||||
try {
|
||||
var dataStr = crypto.decrypt(mailbox, true, true);
|
||||
var data = JSON.parse(dataStr);
|
||||
if (!data.notifications || !data.curvePublic) { return; }
|
||||
owner = data;
|
||||
} catch (e) { console.error(e); }
|
||||
}
|
||||
};
|
||||
|
||||
// If we already have metadata, use it, otherwise, try to get it
|
||||
if (metadata) { return void todo(metadata); }
|
||||
|
||||
Cryptpad.getPadMetadata({
|
||||
channel: _secret.channel
|
||||
}, waitFor(function (obj) {
|
||||
obj = obj || {};
|
||||
if (obj.error) { return; }
|
||||
todo(obj);
|
||||
}));
|
||||
}).nThen(function () {
|
||||
// If we are just checking (send === false) and there is a mailbox field, cb state true
|
||||
// If there is no mailbox, we'll have to check if an owner is a friend in the worker
|
||||
if (!send) { return void cb({state: Boolean(owner)}); }
|
||||
|
||||
Cryptpad.padRpc.requestAccess({
|
||||
send: send,
|
||||
channel: _secret.channel,
|
||||
owner: owner,
|
||||
owners: owners
|
||||
}, cb);
|
||||
});
|
||||
});
|
||||
|
||||
sframeChan.on('Q_BLOB_PASSWORD_CHANGE', function (data, cb) {
|
||||
data.href = data.href || currentPad.href;
|
||||
var onPending = function (cb) {
|
||||
sframeChan.query('Q_BLOB_PASSWORD_CHANGE_PENDING', null, function (err, obj) {
|
||||
if (obj && obj.cancel) { cb(); }
|
||||
});
|
||||
};
|
||||
var updateProgress = function (p) {
|
||||
sframeChan.event('EV_BLOB_PASSWORD_CHANGE_PROGRESS', p);
|
||||
};
|
||||
Cryptpad.changeBlobPassword(data, {
|
||||
onPending: onPending,
|
||||
updateProgress: updateProgress
|
||||
}, cb);
|
||||
});
|
||||
|
||||
sframeChan.on('Q_OO_PASSWORD_CHANGE', function (data, cb) {
|
||||
data.href = data.href;
|
||||
Cryptpad.changeOOPassword(data, cb);
|
||||
});
|
||||
|
||||
sframeChan.on('Q_PAD_PASSWORD_CHANGE', function (data, cb) {
|
||||
data.href = data.href;
|
||||
Cryptpad.changePadPassword(Cryptget, Crypto, data, cb);
|
||||
});
|
||||
|
||||
};
|
||||
addCommonRpc(sframeChan, isSafe);
|
||||
|
||||
|
@ -1126,32 +1292,6 @@ define([
|
|||
});
|
||||
});
|
||||
|
||||
sframeChan.on('Q_BLOB_PASSWORD_CHANGE', function (data, cb) {
|
||||
data.href = data.href || currentPad.href;
|
||||
var onPending = function (cb) {
|
||||
sframeChan.query('Q_BLOB_PASSWORD_CHANGE_PENDING', null, function (err, obj) {
|
||||
if (obj && obj.cancel) { cb(); }
|
||||
});
|
||||
};
|
||||
var updateProgress = function (p) {
|
||||
sframeChan.event('EV_BLOB_PASSWORD_CHANGE_PROGRESS', p);
|
||||
};
|
||||
Cryptpad.changeBlobPassword(data, {
|
||||
onPending: onPending,
|
||||
updateProgress: updateProgress
|
||||
}, cb);
|
||||
});
|
||||
|
||||
sframeChan.on('Q_OO_PASSWORD_CHANGE', function (data, cb) {
|
||||
data.href = data.href;
|
||||
Cryptpad.changeOOPassword(data, cb);
|
||||
});
|
||||
|
||||
sframeChan.on('Q_PAD_PASSWORD_CHANGE', function (data, cb) {
|
||||
data.href = data.href;
|
||||
Cryptpad.changePadPassword(Cryptget, Crypto, data, cb);
|
||||
});
|
||||
|
||||
sframeChan.on('Q_CHANGE_USER_PASSWORD', function (data, cb) {
|
||||
Cryptpad.changeUserPassword(Cryptget, edPublic, data, cb);
|
||||
});
|
||||
|
@ -1248,145 +1388,6 @@ define([
|
|||
sframeChan.on('EV_GIVE_ACCESS', function (data, cb) {
|
||||
Cryptpad.padRpc.giveAccess(data, cb);
|
||||
});
|
||||
// REQUEST_ACCESS is used both to check IF we can contact an owner (send === false)
|
||||
// AND also to send the request if we want (send === true)
|
||||
sframeChan.on('Q_REQUEST_ACCESS', function (data, cb) {
|
||||
if (readOnly && hashes.editHash) {
|
||||
return void cb({error: 'ALREADYKNOWN'});
|
||||
}
|
||||
var send = data.send;
|
||||
var metadata = data.metadata;
|
||||
var owner, owners;
|
||||
var _secret = secret;
|
||||
if (metadata && metadata.roHref) {
|
||||
var _parsed = Utils.Hash.parsePadUrl(metadata.roHref);
|
||||
_secret = Utils.Hash.getSecrets(_parsed.type, _parsed.hash, metadata.password);
|
||||
}
|
||||
if (_secret.channel.length !== 32) {
|
||||
return void cb({error: 'EINVAL'});
|
||||
}
|
||||
var crypto = Crypto.createEncryptor(_secret.keys);
|
||||
nThen(function (waitFor) {
|
||||
// Try to get the owner's mailbox from the pad metadata first.
|
||||
// If it's is an older owned pad, check if the owner is a friend
|
||||
// or an acquaintance (from async-store directly in requestAccess)
|
||||
var todo = function (obj) {
|
||||
owners = obj.owners;
|
||||
|
||||
var mailbox;
|
||||
// Get the first available mailbox (the field can be an string or an object)
|
||||
// TODO maybe we should send the request to all the owners?
|
||||
if (typeof (obj.mailbox) === "string") {
|
||||
mailbox = obj.mailbox;
|
||||
} else if (obj.mailbox && obj.owners && obj.owners.length) {
|
||||
mailbox = obj.mailbox[obj.owners[0]];
|
||||
}
|
||||
if (mailbox) {
|
||||
try {
|
||||
var dataStr = crypto.decrypt(mailbox, true, true);
|
||||
var data = JSON.parse(dataStr);
|
||||
if (!data.notifications || !data.curvePublic) { return; }
|
||||
owner = data;
|
||||
} catch (e) { console.error(e); }
|
||||
}
|
||||
};
|
||||
|
||||
// If we already have metadata, use it, otherwise, try to get it
|
||||
if (metadata) { return void todo(metadata); }
|
||||
|
||||
Cryptpad.getPadMetadata({
|
||||
channel: _secret.channel
|
||||
}, waitFor(function (obj) {
|
||||
obj = obj || {};
|
||||
if (obj.error) { return; }
|
||||
todo(obj);
|
||||
}));
|
||||
}).nThen(function () {
|
||||
// If we are just checking (send === false) and there is a mailbox field, cb state true
|
||||
// If there is no mailbox, we'll have to check if an owner is a friend in the worker
|
||||
if (!send) { return void cb({state: Boolean(owner)}); }
|
||||
|
||||
Cryptpad.padRpc.requestAccess({
|
||||
send: send,
|
||||
channel: _secret.channel,
|
||||
owner: owner,
|
||||
owners: owners
|
||||
}, cb);
|
||||
});
|
||||
});
|
||||
|
||||
// Add or remove our mailbox from the list if we're an owner
|
||||
sframeChan.on('Q_UPDATE_MAILBOX', function (data, cb) {
|
||||
var metadata = data.metadata;
|
||||
var add = data.add;
|
||||
var _secret = secret;
|
||||
if (metadata && (metadata.href || metadata.roHref)) {
|
||||
var _parsed = Utils.Hash.parsePadUrl(metadata.href || metadata.roHref);
|
||||
_secret = Utils.Hash.getSecrets(_parsed.type, _parsed.hash, metadata.password);
|
||||
}
|
||||
if (_secret.channel.length !== 32) {
|
||||
return void cb({error: 'EINVAL'});
|
||||
}
|
||||
var crypto = Crypto.createEncryptor(_secret.keys);
|
||||
nThen(function (waitFor) {
|
||||
// If we already have metadata, use it, otherwise, try to get it
|
||||
if (metadata) { return; }
|
||||
|
||||
Cryptpad.getPadMetadata({
|
||||
channel: secret.channel
|
||||
}, waitFor(function (obj) {
|
||||
obj = obj || {};
|
||||
if (obj.error) {
|
||||
waitFor.abort();
|
||||
return void cb(obj);
|
||||
}
|
||||
metadata = obj;
|
||||
}));
|
||||
}).nThen(function () {
|
||||
// Get and maybe migrate the existing mailbox object
|
||||
var owners = metadata.owners;
|
||||
if (!Array.isArray(owners) || owners.indexOf(edPublic) === -1) {
|
||||
return void cb({ error: 'INSUFFICIENT_PERMISSIONS' });
|
||||
}
|
||||
|
||||
// Remove a mailbox
|
||||
if (!add) {
|
||||
// Old format: this is the mailbox of the first owner
|
||||
if (typeof (metadata.mailbox) === "string" && metadata.mailbox) {
|
||||
// Not our mailbox? abort
|
||||
if (owners[0] !== edPublic) {
|
||||
return void cb({ error: 'INSUFFICIENT_PERMISSIONS' });
|
||||
}
|
||||
// Remove it
|
||||
return void Cryptpad.setPadMetadata({
|
||||
channel: _secret.channel,
|
||||
command: 'RM_MAILBOX',
|
||||
value: []
|
||||
}, cb);
|
||||
} else if (metadata.mailbox) { // New format
|
||||
return void Cryptpad.setPadMetadata({
|
||||
channel: _secret.channel,
|
||||
command: 'RM_MAILBOX',
|
||||
value: [edPublic]
|
||||
}, cb);
|
||||
}
|
||||
return void cb({
|
||||
error: 'NO_MAILBOX'
|
||||
});
|
||||
}
|
||||
// Add a mailbox
|
||||
var toAdd = {};
|
||||
toAdd[edPublic] = crypto.encrypt(JSON.stringify({
|
||||
notifications: notifications,
|
||||
curvePublic: curvePublic
|
||||
}));
|
||||
Cryptpad.setPadMetadata({
|
||||
channel: _secret.channel,
|
||||
command: 'ADD_MAILBOX',
|
||||
value: toAdd
|
||||
}, cb);
|
||||
});
|
||||
});
|
||||
|
||||
sframeChan.on('EV_BURN_PAD', function (channel) {
|
||||
if (!burnAfterReading) { return; }
|
||||
|
|
|
@ -188,6 +188,7 @@ define([
|
|||
var senderKey = content.sender && content.sender.edPublic;
|
||||
var fromMe = senderKey === privateData.edPublic;
|
||||
var fromAdmin = ctx.adminKeys.indexOf(senderKey) !== -1;
|
||||
var fromPremium = Boolean(content.sender.plan);
|
||||
|
||||
var userData = h('div.cp-support-showdata', [
|
||||
Messages.support_showData,
|
||||
|
@ -199,8 +200,10 @@ define([
|
|||
ev.stopPropagation();
|
||||
});
|
||||
|
||||
var adminClass = (fromAdmin? '.cp-support-fromadmin': '');
|
||||
var premiumClass = (fromPremium && !fromAdmin? '.cp-support-frompremium': '');
|
||||
var name = Util.fixHTML(content.sender.name) || Messages.anonymous;
|
||||
return h('div.cp-support-list-message' + (fromAdmin? '.cp-support-fromadmin': ''), {
|
||||
return h('div.cp-support-list-message' + adminClass + premiumClass, {
|
||||
'data-hash': hash
|
||||
}, [
|
||||
h('div.cp-support-message-from' + (fromMe ? '.cp-support-fromme' : ''), [
|
||||
|
|
Loading…
Reference in New Issue