Merge branch 'inviteUI' of github.com:xwiki-labs/cryptpad into inviteUI
This commit is contained in:
@@ -12,6 +12,13 @@ define([
|
||||
var handlers = {};
|
||||
var removeHandlers = {};
|
||||
|
||||
var isMuted = function (ctx, data) {
|
||||
var muted = ctx.store.proxy.mutedUsers || {};
|
||||
var curvePublic = Util.find(data, ['msg', 'author']);
|
||||
if (!curvePublic) { return false; }
|
||||
return Boolean(muted[curvePublic]);
|
||||
};
|
||||
|
||||
// Store the friend request displayed to avoid duplicates
|
||||
var friendRequest = {};
|
||||
handlers['FRIEND_REQUEST'] = function (ctx, box, data, cb) {
|
||||
@@ -21,6 +28,8 @@ define([
|
||||
return void cb(true);
|
||||
}
|
||||
|
||||
if (isMuted(ctx, data)) { return void cb(true); }
|
||||
|
||||
// Don't show duplicate friend request: if we already have a friend request
|
||||
// in memory from the same user, dismiss the new one
|
||||
if (friendRequest[data.msg.author]) { return void cb(true); }
|
||||
@@ -30,10 +39,22 @@ define([
|
||||
// If the user is already in our friend list, automatically accept the request
|
||||
if (Messaging.getFriend(ctx.store.proxy, data.msg.author) ||
|
||||
ctx.store.proxy.friends_pending[data.msg.author]) {
|
||||
delete ctx.store.proxy.friends_pending[data.msg.author];
|
||||
Messaging.acceptFriendRequest(ctx.store, data.msg.content, function (obj) {
|
||||
if (obj && obj.error) {
|
||||
return void cb();
|
||||
}
|
||||
Messaging.addToFriendList({
|
||||
proxy: ctx.store.proxy,
|
||||
realtime: ctx.store.realtime,
|
||||
pinPads: ctx.pinPads
|
||||
}, data.msg.content, function (err) {
|
||||
if (err) { console.error(err); }
|
||||
if (ctx.store.messenger) {
|
||||
ctx.store.messenger.onFriendAdded(data.msg.content);
|
||||
}
|
||||
});
|
||||
ctx.updateMetadata();
|
||||
cb(true);
|
||||
});
|
||||
return;
|
||||
@@ -170,6 +191,8 @@ define([
|
||||
var content = msg.content;
|
||||
// content.name, content.title, content.href, content.password
|
||||
|
||||
if (isMuted(ctx, data)) { return void cb(true); }
|
||||
|
||||
var channel = Hash.hrefToHexChannelId(content.href, content.password);
|
||||
var parsed = Hash.parsePadUrl(content.href);
|
||||
var mode = parsed.hashData && parsed.hashData.mode || 'n/a';
|
||||
@@ -212,6 +235,9 @@ define([
|
||||
supportMessage = true;
|
||||
cb();
|
||||
};
|
||||
removeHandlers['SUPPORT_MESSAGE'] = function () {
|
||||
supportMessage = false;
|
||||
};
|
||||
|
||||
// Incoming edit rights request: add data before sending it to inner
|
||||
handlers['REQUEST_PAD_ACCESS'] = function (ctx, box, data, cb) {
|
||||
@@ -220,6 +246,8 @@ define([
|
||||
|
||||
if (msg.author !== content.user.curvePublic) { return void cb(true); }
|
||||
|
||||
if (isMuted(ctx, data)) { return void cb(true); }
|
||||
|
||||
var channel = content.channel;
|
||||
var res = ctx.store.manager.findChannel(channel);
|
||||
|
||||
@@ -270,6 +298,9 @@ define([
|
||||
var content = msg.content;
|
||||
|
||||
if (msg.author !== content.user.curvePublic) { return void cb(true); }
|
||||
|
||||
if (isMuted(ctx, data)) { return void cb(true); }
|
||||
|
||||
if (!content.teamChannel && !(content.href && content.title && content.channel)) {
|
||||
console.log('Remove invalid notification');
|
||||
return void cb(true);
|
||||
@@ -327,6 +358,9 @@ define([
|
||||
var content = msg.content;
|
||||
|
||||
if (msg.author !== content.user.curvePublic) { return void cb(true); }
|
||||
|
||||
if (isMuted(ctx, data)) { return void cb(true); }
|
||||
|
||||
if (!content.team) {
|
||||
console.log('Remove invalid notification');
|
||||
return void cb(true);
|
||||
|
||||
@@ -428,20 +428,21 @@ define([
|
||||
}
|
||||
|
||||
var channel = ctx.channels[data.channel];
|
||||
if (!channel) {
|
||||
return void cb({error: "NO_SUCH_CHANNEL"});
|
||||
}
|
||||
|
||||
// Unfriend with mailbox
|
||||
if (ctx.store.mailbox && data.curvePublic && data.notifications) {
|
||||
Messaging.removeFriend(ctx.store, curvePublic, function (obj) {
|
||||
if (obj && obj.error) { return void cb({error:obj.error}); }
|
||||
ctx.updateMetadata();
|
||||
cb(obj);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Unfriend with channel
|
||||
if (!channel) {
|
||||
return void cb({error: "NO_SUCH_CHANNEL"});
|
||||
}
|
||||
try {
|
||||
var msg = [Types.unfriend, proxy.curvePublic, +new Date()];
|
||||
var msgStr = JSON.stringify(msg);
|
||||
@@ -458,6 +459,40 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
var getAllClients = function (ctx) {
|
||||
var all = [];
|
||||
Array.prototype.push.apply(all, ctx.friendsClients);
|
||||
Object.keys(ctx.channels).forEach(function (id) {
|
||||
Array.prototype.push.apply(all, ctx.channels[id].clients);
|
||||
});
|
||||
return Util.deduplicateString(all);
|
||||
};
|
||||
|
||||
var muteUser = function (ctx, data, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
var proxy = ctx.store.proxy;
|
||||
var muted = proxy.mutedUsers = proxy.mutedUsers || {};
|
||||
if (muted[data.curvePublic]) { return void cb(); }
|
||||
muted[data.curvePublic] = data;
|
||||
ctx.emit('UPDATE_MUTED', null, getAllClients(ctx));
|
||||
cb();
|
||||
};
|
||||
var unmuteUser = function (ctx, curvePublic, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
var proxy = ctx.store.proxy;
|
||||
var muted = proxy.mutedUsers = proxy.mutedUsers || {};
|
||||
delete muted[curvePublic];
|
||||
ctx.emit('UPDATE_MUTED', null, getAllClients(ctx));
|
||||
cb(Object.keys(muted).length);
|
||||
};
|
||||
var getMutedUsers = function (ctx, cb) {
|
||||
var proxy = ctx.store.proxy;
|
||||
if (cb) {
|
||||
return void cb(proxy.mutedUsers || {});
|
||||
}
|
||||
return proxy.mutedUsers || {};
|
||||
};
|
||||
|
||||
var openChannel = function (ctx, data) {
|
||||
var proxy = ctx.store.proxy;
|
||||
var network = ctx.store.network;
|
||||
@@ -664,7 +699,14 @@ define([
|
||||
nThen(function (waitFor) {
|
||||
// Load or get all friends channels
|
||||
Object.keys(friends).forEach(function (key) {
|
||||
if (key === 'me') { return; }
|
||||
if (key === 'me') {
|
||||
// At some point a bug inserted a friend's channel into our "me" data.
|
||||
// This led to displaying our name instead of our friend's name in the
|
||||
// contacts app. The following line is here to prevent this issue to happen
|
||||
// again.
|
||||
delete friends.me.channel;
|
||||
return;
|
||||
}
|
||||
var friend = clone(friends[key]);
|
||||
if (typeof(friend) !== 'object') { return; }
|
||||
if (!friend.channel) { return; }
|
||||
@@ -887,15 +929,6 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
var getAllClients = function (ctx) {
|
||||
var all = [];
|
||||
Array.prototype.push.apply(all, ctx.friendsClients);
|
||||
Object.keys(ctx.channels).forEach(function (id) {
|
||||
Array.prototype.push.apply(all, ctx.channels[id].clients);
|
||||
});
|
||||
return Util.deduplicateString(all);
|
||||
};
|
||||
|
||||
Msg.init = function (cfg, waitFor, emit) {
|
||||
var messenger = {};
|
||||
var store = cfg.store;
|
||||
@@ -911,6 +944,9 @@ define([
|
||||
range_requests: {}
|
||||
};
|
||||
|
||||
store.proxy.on('change', ['mutedUsers'], function () {
|
||||
ctx.emit('UPDATE_MUTED', null, getAllClients(ctx));
|
||||
});
|
||||
|
||||
ctx.store.network.on('message', function(msg, sender) {
|
||||
onDirectMessage(ctx, msg, sender);
|
||||
@@ -942,6 +978,12 @@ define([
|
||||
var channel = friend.channel;
|
||||
if (!channel) { return; }
|
||||
|
||||
// Already friend? don't load the channel a second time
|
||||
var chanId = friend.channel;
|
||||
var chan = ctx.channels[chanId];
|
||||
if (chan) { return; }
|
||||
|
||||
// Load the channel and add the friend to the contacts app
|
||||
loadFriend(ctx, null, friend, function () {
|
||||
emit('FRIEND', {
|
||||
curvePublic: friend.curvePublic,
|
||||
@@ -990,6 +1032,9 @@ define([
|
||||
if (cmd === 'GET_ROOMS') {
|
||||
return void getRooms(ctx, data, cb);
|
||||
}
|
||||
if (cmd === 'GET_MUTED_USERS') {
|
||||
return void getMutedUsers(ctx, cb);
|
||||
}
|
||||
if (cmd === 'GET_USERLIST') {
|
||||
return void getUserList(ctx, data, cb);
|
||||
}
|
||||
@@ -1002,6 +1047,12 @@ define([
|
||||
if (cmd === 'REMOVE_FRIEND') {
|
||||
return void removeFriend(ctx, data, cb);
|
||||
}
|
||||
if (cmd === 'MUTE_USER') {
|
||||
return void muteUser(ctx, data, cb);
|
||||
}
|
||||
if (cmd === 'UNMUTE_USER') {
|
||||
return void unmuteUser(ctx, data, cb);
|
||||
}
|
||||
if (cmd === 'GET_STATUS') {
|
||||
return void getStatus(ctx, data, cb);
|
||||
}
|
||||
|
||||
@@ -451,7 +451,6 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) {
|
||||
|
||||
// copy the new profile from the old one
|
||||
members[curve] = Util.clone(members[author]);
|
||||
members[curve].curvePublic = curve;
|
||||
// and erase the old one
|
||||
delete members[author];
|
||||
return true;
|
||||
@@ -776,7 +775,6 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) {
|
||||
Object.keys(data).forEach(function (curve) {
|
||||
if (!isValidId(curve) || isMap(ref.state.members[curve])) { return delete data[curve]; }
|
||||
});
|
||||
console.error('SENDING INVITE');
|
||||
|
||||
send(['INVITE', data], cb);
|
||||
};
|
||||
|
||||
@@ -446,7 +446,6 @@ define([
|
||||
// If we've been kicked, don't try to update our data, we'll close everything
|
||||
// in the next nThen part
|
||||
var state = roster.getState();
|
||||
console.error(state);
|
||||
var me = Util.find(ctx, ['store', 'proxy', 'curvePublic']);
|
||||
if (!state.members[me]) { return; }
|
||||
|
||||
@@ -1280,6 +1279,8 @@ define([
|
||||
var seeds = data.seeds; // {scrypt, preview}
|
||||
var bytes64 = data.bytes64;
|
||||
|
||||
if (!teamId || !team) { return void cb({error: 'EINVAL'}); }
|
||||
|
||||
var roster = team.roster;
|
||||
|
||||
var teamName;
|
||||
@@ -1312,12 +1313,16 @@ define([
|
||||
var putOpts = {
|
||||
initialState: '{}',
|
||||
network: ctx.store.network,
|
||||
metadata: {
|
||||
owners: [ctx.store.proxy.edPublic, ephemeralKeys.edPublic]
|
||||
}
|
||||
};
|
||||
|
||||
(function () {
|
||||
// a random signing keypair to prevent further writes to the channel
|
||||
// we don't need to remember it cause we're only writing once
|
||||
var sign = Invite.generateSignPair(); // { validateKey, signKey}
|
||||
putOpts.metadata.validateKey = sign.validateKey;
|
||||
|
||||
// visible with only the invite link
|
||||
var previewContent = {
|
||||
@@ -1325,7 +1330,6 @@ define([
|
||||
message: message,
|
||||
author: Messaging.createData(ctx.store.proxy, false),
|
||||
displayName: name,
|
||||
curvePublic: ephemeralKeys.curvePublic,
|
||||
};
|
||||
|
||||
var cryptput_config = {
|
||||
@@ -1352,6 +1356,7 @@ define([
|
||||
// a different random signing key so that the server can't correlate these documents
|
||||
// as components of an invite
|
||||
var sign = Invite.generateSignPair(); // { validateKey, signKey}
|
||||
putOpts.metadata.validateKey = sign.validateKey;
|
||||
|
||||
// available only with the link and the content
|
||||
var inviteContent = {
|
||||
@@ -1486,13 +1491,16 @@ define([
|
||||
// Accept the roster invitation: relplace our ephemeral keys with our user keys
|
||||
var rosterData = Util.find(inviteContent, ['teamData', 'keys', 'roster']);
|
||||
var myKeys = inviteContent.ephemeral;
|
||||
if (!rosterData || !myKeys) {
|
||||
waitFor.abort();
|
||||
return void cb({error: 'INVALID_INVITE_CONTENT'});
|
||||
}
|
||||
var rosterKeys = Crypto.Team.deriveMemberKeys(rosterData.edit, myKeys);
|
||||
Roster.create({
|
||||
network: ctx.store.network,
|
||||
channel: rosterData.channel,
|
||||
keys: rosterKeys,
|
||||
anon_rpc: ctx.store.anon_rpc,
|
||||
lastKnownHash: rosterData.lastKnownHash, // XXX Can we trust this user?
|
||||
}, waitFor(function (err, roster) {
|
||||
if (err) {
|
||||
waitFor.abort();
|
||||
|
||||
Reference in New Issue
Block a user