diff --git a/www/common/common-messaging.js b/www/common/common-messaging.js index feb3d79d3..15d0408f7 100644 --- a/www/common/common-messaging.js +++ b/www/common/common-messaging.js @@ -53,10 +53,18 @@ define([ return list; }; + Msg.declineFriendRequest = function (store, data, cb) { + store.mailbox.sendTo('DECLINE_FRIEND_REQUEST', {}, { + channel: data.notifications, + curvePublic: data.curvePublic + }, function (obj) { + cb(obj); + }); + }; Msg.acceptFriendRequest = function (store, data, cb) { var friend = getFriend(store.proxy, data.curvePublic) || {}; var myData = createData(store.proxy, friend.channel || data.channel); - store.mailbox.sendTo('ACCEPT_FRIEND_REQUEST', myData, { + store.mailbox.sendTo('ACCEPT_FRIEND_REQUEST', { user: myData }, { channel: data.notifications, curvePublic: data.curvePublic }, function (obj) { @@ -110,7 +118,7 @@ define([ var proxy = store.proxy; var friend = proxy.friends[curvePublic]; if (!friend) { return void cb({error: 'ENOENT'}); } - if (!friend.notifications || !friend.channel) { return void cb({error: 'EINVAL'}); } + if (!friend.notifications) { return void cb({error: 'EINVAL'}); } store.mailbox.sendTo('UNFRIEND', { curvePublic: proxy.curvePublic diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 8bfa02e3a..c60ef652d 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -212,15 +212,7 @@ define([ common.mailbox.sendTo("RM_OWNER", { channel: channel, title: data.title, - pending: pending, - user: { - displayName: user.name, - avatar: user.avatar, - profile: user.profile, - notifications: user.notifications, - curvePublic: user.curvePublic, - edPublic: priv.edPublic - } + pending: pending }, { channel: friend.notifications, curvePublic: friend.curvePublic @@ -363,15 +355,7 @@ define([ channel: channel, href: data.href, password: data.password, - title: data.title, - user: { - displayName: user.name, - avatar: user.avatar, - profile: user.profile, - notifications: user.notifications, - curvePublic: user.curvePublic, - edPublic: priv.edPublic - } + title: data.title }, { channel: friend.notifications, curvePublic: friend.curvePublic @@ -4335,7 +4319,8 @@ define([ UIElements.displayFriendRequestModal = function (common, data) { var msg = data.content.msg; - var text = Messages._getKey('contacts_request', [Util.fixHTML(msg.content.displayName)]); + var userData = msg.content.user; + var text = Messages._getKey('contacts_request', [Util.fixHTML(userData.displayName)]); var todo = function (yes) { common.getSframeChannel().query("Q_ANSWER_FRIEND_REQUEST", { @@ -4362,7 +4347,6 @@ define([ UIElements.displayAddOwnerModal = function (common, data) { var priv = common.getMetadataMgr().getPrivateData(); - var user = common.getMetadataMgr().getUserData(); var sframeChan = common.getSframeChannel(); var msg = data.content.msg; @@ -4397,15 +4381,7 @@ define([ href: msg.content.href, password: msg.content.password, title: msg.content.title, - answer: yes, - user: { - displayName: user.name, - avatar: user.avatar, - profile: user.profile, - notifications: user.notifications, - curvePublic: user.curvePublic, - edPublic: priv.edPublic - } + answer: yes }, { channel: msg.content.user.notifications, curvePublic: msg.content.user.curvePublic @@ -4486,7 +4462,6 @@ define([ }; UIElements.displayAddTeamOwnerModal = function (common, data) { var priv = common.getMetadataMgr().getPrivateData(); - var user = common.getMetadataMgr().getUserData(); var sframeChan = common.getSframeChannel(); var msg = data.content.msg; @@ -4503,15 +4478,7 @@ define([ common.mailbox.sendTo("ADD_OWNER_ANSWER", { teamChannel: msg.content.teamChannel, title: msg.content.title, - answer: yes, - user: { - displayName: user.name, - avatar: user.avatar, - profile: user.profile, - notifications: user.notifications, - curvePublic: user.curvePublic, - edPublic: priv.edPublic - } + answer: yes }, { channel: msg.content.user.notifications, curvePublic: msg.content.user.curvePublic @@ -4627,8 +4594,6 @@ define([ }; UIElements.displayInviteTeamModal = function (common, data) { - var priv = common.getMetadataMgr().getPrivateData(); - var user = common.getMetadataMgr().getUserData(); var msg = data.content.msg; var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous; @@ -4649,15 +4614,7 @@ define([ common.mailbox.sendTo("INVITE_TO_TEAM_ANSWER", { answer: yes, teamChannel: msg.content.team.channel, - teamName: teamName, - user: { - displayName: user.name, - avatar: user.avatar, - profile: user.profile, - notifications: user.notifications, - curvePublic: user.curvePublic, - edPublic: priv.edPublic - } + teamName: teamName }, { channel: msg.content.user.notifications, curvePublic: msg.content.user.curvePublic diff --git a/www/common/notifications.js b/www/common/notifications.js index 192d2b4c6..8546f2787 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -29,7 +29,9 @@ define([ handlers['FRIEND_REQUEST'] = function (common, data) { var content = data.content; var msg = content.msg; - var name = Util.fixHTML(msg.content.displayName) || Messages.anonymous; + var userData = msg.content.user || msg.content; + var name = Util.fixHTML(userData.displayName) || Messages.anonymous; + msg.content = { user: userData }; // Display the notification content.getFormatText = function () { @@ -37,7 +39,7 @@ define([ }; // Check authenticity - if (msg.author !== msg.content.curvePublic) { return; } + if (msg.author !== userData.curvePublic) { return; } // if not archived, add handlers if (!content.archived) { @@ -51,7 +53,11 @@ define([ handlers['FRIEND_REQUEST_ACCEPTED'] = function (common, data) { var content = data.content; var msg = content.msg; - var name = Util.fixHTML(msg.content.name) || Messages.anonymous; + var userData = typeof(msg.content.user) === "object" ? msg.content.user : { + displayName: msg.content.name, + curvePublic: msg.content.user + }; + var name = Util.fixHTML(userData.displayName) || Messages.anonymous; content.getFormatText = function () { return Messages._getKey('friendRequest_accepted', [name]); }; @@ -63,7 +69,11 @@ define([ handlers['FRIEND_REQUEST_DECLINED'] = function (common, data) { var content = data.content; var msg = content.msg; - var name = Util.fixHTML(msg.content.name) || Messages.anonymous; + var userData = typeof(msg.content.user) === "object" ? msg.content.user : { + displayName: msg.content.name, + curvePublic: msg.content.user + }; + var name = Util.fixHTML(userData.displayName) || Messages.anonymous; content.getFormatText = function () { return Messages._getKey('friendRequest_declined', [name]); }; diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 51c04066f..c544754ba 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -1267,15 +1267,15 @@ define([ // If we accept the request, add the friend to the list if (value) { - Messaging.acceptFriendRequest(store, msg.content, function (obj) { + Messaging.acceptFriendRequest(store, msg.content.user, function (obj) { if (obj && obj.error) { return void cb(obj); } Messaging.addToFriendList({ proxy: store.proxy, realtime: store.realtime, pinPads: function (data, cb) { Store.pinPads(null, data, cb); }, - }, msg.content, function (err) { + }, msg.content.user, function (err) { if (store.messenger) { - store.messenger.onFriendAdded(msg.content); + store.messenger.onFriendAdded(msg.content.user); } broadcast([], "UPDATE_METADATA"); if (err) { return void cb({error: err}); } @@ -1285,12 +1285,7 @@ define([ return; } // Otherwise, just remove the notification - store.mailbox.sendTo('DECLINE_FRIEND_REQUEST', { - displayName: store.proxy['cryptpad.username'] - }, { - channel: msg.content.notifications, - curvePublic: msg.content.curvePublic - }, function (obj) { + Messaging.declineFriendRequest(store, msg.content.user, function (obj) { broadcast([], "UPDATE_METADATA"); cb(obj); }); @@ -1312,8 +1307,9 @@ define([ store.proxy.friends_pending[data.curvePublic] = +new Date(); broadcast([], "UPDATE_METADATA"); - var myData = Messaging.createData(store.proxy); - store.mailbox.sendTo('FRIEND_REQUEST', myData, { + store.mailbox.sendTo('FRIEND_REQUEST', { + user: Messaging.createData(store.proxy) + }, { channel: data.notifications, curvePublic: data.curvePublic }, function (obj) { @@ -1649,11 +1645,8 @@ define([ // If send is true, send the request to the owner. if (owner) { if (data.send) { - var myData = Messaging.createData(store.proxy); - delete myData.channel; store.mailbox.sendTo('REQUEST_PAD_ACCESS', { - channel: data.channel, - user: myData + channel: data.channel }, { channel: owner.notifications, curvePublic: owner.curvePublic @@ -1687,13 +1680,10 @@ define([ } })) { return void cb({error: 'ENOTFOUND'}); } - var myData = Messaging.createData(store.proxy); - delete myData.channel; store.mailbox.sendTo("GIVE_PAD_ACCESS", { channel: channel, href: href, - title: title, - user: myData + title: title }, { channel: data.user.notifications, curvePublic: data.user.curvePublic @@ -1727,13 +1717,11 @@ define([ } // Tell all the owners that the pad was deleted from the server var curvePublic = store.proxy.curvePublic; - var myData = Messaging.createData(store.proxy, false); m.forEach(function (obj) { var mb = JSON.parse(obj); if (mb.curvePublic === curvePublic) { return; } store.mailbox.sendTo('OWNED_PAD_REMOVED', { - channel: channel, - user: myData + channel: channel }, { channel: mb.notifications, curvePublic: mb.curvePublic diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js index 253157361..d66ff516e 100644 --- a/www/common/outer/mailbox-handlers.js +++ b/www/common/outer/mailbox-handlers.js @@ -4,6 +4,7 @@ define([ '/common/common-util.js', ], function (Messaging, Hash, Util) { + // Random timeout between 10 and 30 times your sync time (lag + chainpad sync) var getRandomTimeout = function (ctx) { var lag = ctx.store.realtime.getLag().lag || 0; return (Math.max(0, lag) + 300) * 20 * (0.5 + Math.random()); @@ -22,9 +23,11 @@ define([ // Store the friend request displayed to avoid duplicates var friendRequest = {}; handlers['FRIEND_REQUEST'] = function (ctx, box, data, cb) { + // Old format: data was stored directly in "content" + var userData = data.msg.content.user || data.msg.content; // Check if the request is valid (send by the correct user) - if (data.msg.author !== data.msg.content.curvePublic) { + if (data.msg.author !== userData.curvePublic) { return void cb(true); } @@ -40,7 +43,8 @@ define([ 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) { + + Messaging.acceptFriendRequest(ctx.store, userData, function (obj) { if (obj && obj.error) { return void cb(); } @@ -48,10 +52,10 @@ define([ proxy: ctx.store.proxy, realtime: ctx.store.realtime, pinPads: ctx.pinPads - }, data.msg.content, function (err) { - if (err) { console.error(err); } + }, userData, function (err) { + if (err) { return void console.error(err); } if (ctx.store.messenger) { - ctx.store.messenger.onFriendAdded(data.msg.content); + ctx.store.messenger.onFriendAdded(userData); } }); ctx.updateMetadata(); @@ -63,96 +67,110 @@ define([ cb(); }; removeHandlers['FRIEND_REQUEST'] = function (ctx, box, data) { - if (friendRequest[data.content.curvePublic]) { - delete friendRequest[data.content.curvePublic]; + var userData = data.content.user || data.content; + if (friendRequest[userData.curvePublic]) { + delete friendRequest[userData.curvePublic]; } }; + // The DECLINE and ACCEPT messages act on the contacts data + // They are processed with a random timeout to avoid having + // multiple workers trying to add or remove the contacts at + // the same time. Once processed, they are dismissed. + // We must dismiss them and send another message to our own + // mailbox for the UI part otherwise it would automatically + // accept or decline future requests from the same user + // until the message is manually dismissed. + var friendRequestDeclined = {}; handlers['DECLINE_FRIEND_REQUEST'] = function (ctx, box, data, cb) { - setTimeout(function () { - // Our friend request was declined. - if (!ctx.store.proxy.friends_pending[data.msg.author]) { return; } + // Old format: data was stored directly in "content" + var userData = data.msg.content.user || data.msg.content; + if (!userData.curvePublic) { userData.curvePublic = data.msg.author; } + // Our friend request was declined. + setTimeout(function () { + // Only dismissed once in the timeout to make sure we won't lose + // the data if we close the worker before adding the friend + cb(true); + + // Make sure we really sent it + if (!ctx.store.proxy.friends_pending[data.msg.author]) { return; } // Remove the pending message and display the "declined" state in the UI delete ctx.store.proxy.friends_pending[data.msg.author]; + ctx.updateMetadata(); if (friendRequestDeclined[data.msg.author]) { return; } + friendRequestDeclined[data.msg.author] = true; box.sendMessage({ type: 'FRIEND_REQUEST_DECLINED', - content: { - user: data.msg.author, - name: data.msg.content.displayName - } - }, function () { - if (friendRequestDeclined[data.msg.author]) { - // TODO remove our message because another one was sent first? - } - friendRequestDeclined[data.msg.author] = true; - }); + content: { user: userData } + }, function () {}); }, getRandomTimeout(ctx)); - cb(true); }; + // UI for declined friend request handlers['FRIEND_REQUEST_DECLINED'] = function (ctx, box, data, cb) { ctx.updateMetadata(); - if (friendRequestDeclined[data.msg.content.user]) { return void cb(true); } - friendRequestDeclined[data.msg.content.user] = true; + var curve = data.msg.content.user.curvePublic || data.msg.content.user; + if (friendRequestDeclined[curve]) { return void cb(true); } + friendRequestDeclined[curve] = true; cb(); }; removeHandlers['FRIEND_REQUEST_DECLINED'] = function (ctx, box, data) { - if (friendRequestDeclined[data.content.user]) { - delete friendRequestDeclined[data.content.user]; - } + var curve = data.content.user.curvePublic || data.content.user; + if (friendRequestDeclined[curve]) { delete friendRequestDeclined[curve]; } }; var friendRequestAccepted = {}; handlers['ACCEPT_FRIEND_REQUEST'] = function (ctx, box, data, cb) { + // Old format: data was stored directly in "content" + var userData = data.msg.content.user || data.msg.content; + // Our friend request was accepted. setTimeout(function () { + // Only dismissed once in the timeout to make sure we won't lose + // the data if we close the worker before adding the friend + cb(true); + // Make sure we really sent it if (!ctx.store.proxy.friends_pending[data.msg.author]) { return; } + // Remove the pending state. It will also us to send a new request in case of error + delete ctx.store.proxy.friends_pending[data.msg.author]; + // And add the friend Messaging.addToFriendList({ proxy: ctx.store.proxy, realtime: ctx.store.realtime, pinPads: ctx.pinPads - }, data.msg.content, function (err) { - if (err) { console.error(err); } - delete ctx.store.proxy.friends_pending[data.msg.author]; - if (ctx.store.messenger) { - ctx.store.messenger.onFriendAdded(data.msg.content); - } + }, userData, function (err) { + if (err) { return void console.error(err); } + // Load the chat if contacts app loaded + if (ctx.store.messenger) { ctx.store.messenger.onFriendAdded(userData); } + // Update the userlist ctx.updateMetadata(); // If you have a profile page open, update it if (ctx.store.modules['profile']) { ctx.store.modules['profile'].update(); } - if (friendRequestAccepted[data.msg.author]) { return; } // Display the "accepted" state in the UI + if (friendRequestAccepted[data.msg.author]) { return; } + friendRequestAccepted[data.msg.author] = true; box.sendMessage({ type: 'FRIEND_REQUEST_ACCEPTED', - content: { - user: data.msg.author, - name: data.msg.content.displayName - } - }, function () { - if (friendRequestAccepted[data.msg.author]) { - // TODO remove our message because another one was sent first? - } - friendRequestAccepted[data.msg.author] = true; - }); + content: { user: userData } + }, function () {}); }); }, getRandomTimeout(ctx)); - cb(true); }; + // UI for accepted friend request handlers['FRIEND_REQUEST_ACCEPTED'] = function (ctx, box, data, cb) { ctx.updateMetadata(); - if (friendRequestAccepted[data.msg.content.user]) { return void cb(true); } - friendRequestAccepted[data.msg.content.user] = true; + var curve = data.msg.content.user.curvePublic || data.msg.content.user; + if (friendRequestAccepted[curve]) { return void cb(true); } + friendRequestAccepted[curve] = true; cb(); }; removeHandlers['FRIEND_REQUEST_ACCEPTED'] = function (ctx, box, data) { - if (friendRequestAccepted[data.content.user]) { - delete friendRequestAccepted[data.content.user]; - } + var curve = data.content.user.curvePublic || data.content.user; + if (friendRequestAccepted[curve]) { delete friendRequestAccepted[curve]; } }; handlers['UNFRIEND'] = function (ctx, box, data, cb) { diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js index b84e98dd7..ce9bbe850 100644 --- a/www/common/outer/mailbox.js +++ b/www/common/outer/mailbox.js @@ -2,11 +2,12 @@ define([ '/common/common-util.js', '/common/common-hash.js', '/common/common-realtime.js', + '/common/common-messaging.js', '/common/notify.js', '/common/outer/mailbox-handlers.js', '/bower_components/chainpad-netflux/chainpad-netflux.js', '/bower_components/chainpad-crypto/crypto.js', -], function (Util, Hash, Realtime, Notify, Handlers, CpNetflux, Crypto) { +], function (Util, Hash, Realtime, Messaging, Notify, Handlers, CpNetflux, Crypto) { var Mailbox = {}; var TYPES = [ @@ -96,6 +97,12 @@ proxy.mailboxes = { var crypto = Crypto.Mailbox.createEncryptor(keys); + // Always send your data + if (typeof(msg) === "object" && !msg.user) { + var myData = Messaging.createData(ctx.store.proxy, false); + msg.user = myData; + } + var text = JSON.stringify({ type: type, content: msg @@ -187,6 +194,11 @@ proxy.mailboxes = { history: [], // All the hashes loaded from the server in corretc order content: {}, // Content of the messages that should be displayed sendMessage: function (msg) { // To send a message to our box + // Always send your data + if (typeof(msg) === "object" && !msg.user) { + var myData = Messaging.createData(ctx.store.proxy, false); + msg.user = myData; + } try { msg = JSON.stringify(msg); } catch (e) { diff --git a/www/common/outer/team.js b/www/common/outer/team.js index ce79a800f..24952f5c9 100644 --- a/www/common/outer/team.js +++ b/www/common/outer/team.js @@ -909,13 +909,11 @@ define([ })); }).nThen(function (waitFor) { // Send mailbox to offer ownership - var myData = Messaging.createData(ctx.store.proxy, false); ctx.store.mailbox.sendTo("ADD_OWNER", { teamChannel: teamData.channel, chatChannel: Util.find(teamData, ['keys', 'chat', 'channel']), rosterChannel: Util.find(teamData, ['keys', 'roster', 'channel']), - title: teamData.metadata.name, - user: myData + title: teamData.metadata.name }, { channel: user.notifications, curvePublic: user.curvePublic @@ -969,12 +967,10 @@ define([ })); }).nThen(function (waitFor) { // Send mailbox to offer ownership - var myData = Messaging.createData(ctx.store.proxy, false); ctx.store.mailbox.sendTo("RM_OWNER", { teamChannel: teamData.channel, title: teamData.metadata.name, - pending: isPendingOwner, - user: myData + pending: isPendingOwner }, { channel: user.notifications, curvePublic: user.curvePublic @@ -1104,11 +1100,9 @@ define([ if (!team) { return void cb ({error: 'ENOENT'}); } // Send mailbox to offer ownership - var myData = Messaging.createData(ctx.store.proxy, false); ctx.store.mailbox.sendTo("TEAM_EDIT_RIGHTS", { state: state, - teamData: getInviteData(ctx, teamId, state), - user: myData + teamData: getInviteData(ctx, teamId, state) }, { channel: user.notifications, curvePublic: user.curvePublic @@ -1175,7 +1169,6 @@ define([ team.roster.add(obj, function (err) { if (err && err !== 'NO_CHANGE') { return void cb({error: err}); } ctx.store.mailbox.sendTo('INVITE_TO_TEAM', { - user: Messaging.createData(ctx.store.proxy, false), team: getInviteData(ctx, teamId) }, { channel: user.notifications, @@ -1202,7 +1195,6 @@ define([ if (!userData || !userData.notifications) { return cb(); } ctx.store.mailbox.sendTo('KICKED_FROM_TEAM', { pending: data.pending, - user: Messaging.createData(ctx.store.proxy, false), teamChannel: getInviteData(ctx, teamId).channel, teamName: getInviteData(ctx, teamId).metadata.name }, { diff --git a/www/common/sframe-common-mailbox.js b/www/common/sframe-common-mailbox.js index c10a45ff3..a5602fc3f 100644 --- a/www/common/sframe-common-mailbox.js +++ b/www/common/sframe-common-mailbox.js @@ -55,9 +55,7 @@ define([ var createElement = mailbox.createElement = function (data) { var notif; var avatar; - var type = Util.find(data, ['content', 'msg', 'type']); - var userData = ['FRIEND_REQUEST'].indexOf(type) !== -1 ? Util.find(data, ['content', 'msg', 'content']) - : Util.find(data, ['content', 'msg', 'content', 'user']); + var userData = Util.find(data, ['content', 'msg', 'content', 'user']); if (userData && typeof(userData) === "object" && userData.profile) { avatar = h('span.cp-avatar'); Common.displayAvatar($(avatar), userData.avatar, userData.displayName || userData.name); @@ -65,9 +63,6 @@ define([ e.stopPropagation(); Common.openURL(Hash.hashToHref(userData.profile, 'profile')); }); - } else { - console.warn(data); - } notif = h('div.cp-notification', { 'data-hash': data.content.hash diff --git a/www/pad/inner.js b/www/pad/inner.js index 52ae7325a..3f6e717ce 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -736,9 +736,9 @@ define([ }); framework._.sfCommon.isPadStored(function (err, val) { - //if (!val) { return; } + if (!val) { return; } var b64images = $inner.find('img[src^="data:image"]:not(.cke_reset)'); - if (true || b64images.length && framework._.sfCommon.isLoggedIn()) { + if (b64images.length && framework._.sfCommon.isLoggedIn()) { var no = h('button.cp-corner-cancel', Messages.cancel); var yes = h('button.cp-corner-primary', Messages.ok); var actions = h('div', [no, yes]);