From 991c56fec3454557647e22ab9366d1a1f7075579 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 21 May 2019 18:43:11 +0200 Subject: [PATCH] Friend requests with mailboxes --- .../src/less2/include/notifications.less | 11 +- www/common/common-messaging.js | 165 +--------- www/common/common-ui-elements.js | 20 ++ www/common/cryptpad-common.js | 26 +- www/common/outer/async-store.js | 101 ++++-- www/common/outer/mailbox.js | 287 ++++++++++-------- www/common/outer/store-rpc.js | 4 +- www/common/sframe-common-outer.js | 16 +- www/common/sframe-common.js | 31 +- www/common/toolbar3.js | 33 +- 10 files changed, 326 insertions(+), 368 deletions(-) diff --git a/customize.dist/src/less2/include/notifications.less b/customize.dist/src/less2/include/notifications.less index d65da5e49..b0d6b22ed 100644 --- a/customize.dist/src/less2/include/notifications.less +++ b/customize.dist/src/less2/include/notifications.less @@ -15,12 +15,21 @@ .cp-notification-content { flex: 1; min-width: 0; + p { + word-break: break-all; + } + &.cp-clickable { + cursor: pointer; + &:hover { + background-color: rgba(0,0,0,0.1); + } + } } .cp-notification-dismiss { color: black; width: 25px; height: 100%; - display: flex; + display: none; align-items: center; justify-content: center; span { diff --git a/www/common/common-messaging.js b/www/common/common-messaging.js index b0d13ec81..a53f0c3b2 100644 --- a/www/common/common-messaging.js +++ b/www/common/common-messaging.js @@ -7,14 +7,7 @@ define([ '/common/common-realtime.js', ], function (Crypto, Hash, Util, Constants, Messages, Realtime) { - var Msg = { - inputs: [], - }; - - // TODO - // - mute a channel (hide notifications or don't open it?) - var pending = {}; - var pendingRequests = []; + var Msg = {}; var createData = Msg.createData = function (proxy, hash) { return { @@ -23,11 +16,13 @@ define([ profile: proxy.profile && proxy.profile.view, edPublic: proxy.edPublic, curvePublic: proxy.curvePublic, + notifications: Util.find(proxy, ['mailboxes', 'notifications', 'channel']), avatar: proxy.profile && proxy.profile.avatar }; }; - var getFriend = function (proxy, pubkey) { + var getFriend = Msg.getFriend = function (proxy, pubkey) { + if (!pubkey) { return; } if (pubkey === proxy.curvePublic) { var data = createData(proxy); delete data.channel; @@ -56,21 +51,18 @@ define([ return list; }; - // TODO make this internal to the messenger - var channels = Msg.channels = {}; - - Msg.getLatestMessages = function () { - Object.keys(channels).forEach(function (id) { - if (id === 'me') { return; } - var friend = channels[id]; - friend.getMessagesSinceDisconnect(); - friend.refresh(); + 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, { + channel: data.notifications, + curvePublic: data.curvePublic + }, function (obj) { + cb(obj); + if (obj && obj.error) { return void cb(obj); } }); }; - - // Invitation - // FIXME there are too many functions with this name - var addToFriendList = Msg.addToFriendList = function (cfg, data, cb) { + Msg.addToFriendList = function (cfg, data, cb) { var proxy = cfg.proxy; var friends = getFriendList(proxy); var pubKey = data.curvePublic; // todo validata data @@ -85,135 +77,6 @@ define([ if (res.error) { console.error(res.error); } }); }); - cfg.updateMetadata(); - }; - - /* Used to accept friend requests within apps other than /contacts/ */ - Msg.addDirectMessageHandler = function (cfg, href) { - var network = cfg.network; - var proxy = cfg.proxy; - if (!network) { return void console.error('Network not ready'); } - network.on('message', function (message, sender) { - var msg; - if (sender === network.historyKeeper) { return; } - try { - var parsed = Hash.parsePadUrl(href); - var secret = Hash.getSecrets(parsed.type, parsed.hash); - if (!parsed.hashData) { return; } - var chan = secret.channel; - // Decrypt - var key = secret.keys ? secret.keys.cryptKey : Hash.decodeBase64(secret.key); - var decryptMsg; - try { - decryptMsg = Crypto.decrypt(message, key); - } catch (e) { - // If we can't decrypt, it means it is not a friend request message - } - if (!decryptMsg) { return; } - // Parse - msg = JSON.parse(decryptMsg); - if (msg[1] !== chan) { return; } - var msgData = msg[2]; - var msgStr; - if (msg[0] === "FRIEND_REQ") { - msg = ["FRIEND_REQ_NOK", chan]; - var todo = function (yes) { - if (yes) { - pending[sender] = msgData; - msg = ["FRIEND_REQ_OK", chan, createData(proxy, msgData.channel)]; - } - msgStr = Crypto.encrypt(JSON.stringify(msg), key); - network.sendto(sender, msgStr); - }; - var existing = getFriend(proxy, msgData.curvePublic); - if (existing) { - todo(true); - return; - } - var confirmMsg = Messages._getKey('contacts_request', [ - Util.fixHTML(msgData.displayName) - ]); - cfg.friendRequest(confirmMsg, todo); - return; - } - if (msg[0] === "FRIEND_REQ_OK") { - var idx = pendingRequests.indexOf(sender); - if (idx !== -1) { pendingRequests.splice(idx, 1); } - - // FIXME clarify this function's name - addToFriendList(cfg, msgData, function (err) { - if (err) { - return void cfg.friendComplete({ - logText: Messages.contacts_addError, - netfluxId: sender - }); - } - cfg.friendComplete({ - logText: Messages.contacts_added, - netfluxId: sender, - friend: msgData - }); - var msg = ["FRIEND_REQ_ACK", chan]; - var msgStr = Crypto.encrypt(JSON.stringify(msg), key); - network.sendto(sender, msgStr); - }); - return; - } - if (msg[0] === "FRIEND_REQ_NOK") { - var i = pendingRequests.indexOf(sender); - if (i !== -1) { pendingRequests.splice(i, 1); } - cfg.friendComplete({ - logText: Messages.contacts_rejected, - netfluxId: sender, - }); - cfg.updateMetadata(); - return; - } - if (msg[0] === "FRIEND_REQ_ACK") { - var data = pending[sender]; - if (!data) { return; } - addToFriendList(cfg, data, function (err) { - if (err) { - return void cfg.friendComplete({ - logText: Messages.contacts_addError, - netfluxId: sender - }); - } - cfg.friendComplete({ - logText: Messages.contacts_added, - netfluxId: sender, - friend: data - }); - }); - return; - } - // TODO: timeout ACK: warn the user - } catch (e) { - console.error("Cannot parse direct message", msg || message, "from", sender, e); - } - }); - }; - - Msg.inviteFromUserlist = function (cfg, data, cb) { - var network = cfg.network; - var netfluxId = data.netfluxId; - var parsed = Hash.parsePadUrl(data.href); - var secret = Hash.getSecrets(parsed.type, parsed.hash); - if (!parsed.hashData) { return; } - // Message - var chan = secret.channel; - var myData = createData(cfg.proxy); - var msg = ["FRIEND_REQ", chan, myData]; - // Encryption - var key = secret.keys ? secret.keys.cryptKey : Hash.decodeBase64(secret.key); - var msgStr = Crypto.encrypt(JSON.stringify(msg), key); - // Send encrypted message - if (pendingRequests.indexOf(netfluxId) === -1) { - pendingRequests.push(netfluxId); - cfg.updateMetadata(); // redraws the userlist in pad - } - network.sendto(netfluxId, msgStr); - cb(); }; return Msg; diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 4949b76c0..3ba27f86f 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2607,5 +2607,25 @@ define([ return m; }; + UIElements.displayFriendRequestModal = function (common, data) { + var msg = data.content.msg; + var text = Messages._getKey('contacts_request', [msg.content.displayName]); + UI.confirm(text, function (yes) { + common.getSframeChannel().query("Q_ANSWER_FRIEND_REQUEST", { + data: data, + value: yes + }, function (err, obj) { + var error = err || (obj && obj.error); + if (error) { + return void UI.warn(error); + } + UI.log(Messages.contacts_added); + }); + }, { + ok: 'Accept', // XXX + cancel: 'Ignore the request' // XXX + }, true); + }; + return UIElements; }); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 027b61929..dde1e9d5e 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -604,16 +604,6 @@ define([ }); }; - // Messaging (manage friends from the userlist) - common.inviteFromUserlist = function (netfluxId, cb) { - postMessage("INVITE_FROM_USERLIST", { - netfluxId: netfluxId, - href: window.location.href - }, function (obj) { - if (obj && obj.error) { return void cb(obj.error); } - cb(); - }); - }; // Admin common.adminRpc = function (data, cb) { @@ -625,14 +615,13 @@ define([ common.onNetworkReconnect = Util.mkEvent(); common.onNewVersionReconnect = Util.mkEvent(); - // Messaging + // Messaging (friend requests) var messaging = common.messaging = {}; - messaging.onFriendRequest = Util.mkEvent(); - messaging.onFriendComplete = Util.mkEvent(); - messaging.addHandlers = function (href) { - postMessage("ADD_DIRECT_MESSAGE_HANDLERS", { - href: href - }); + messaging.answerFriendRequest = function (data, cb) { + postMessage("ANSWER_FRIEND_REQUEST", data, cb); + }; + messaging.sendFriendRequest = function (data, cb) { + postMessage("SEND_FRIEND_REQUEST", data, cb); }; // Onlyoffice @@ -1081,9 +1070,6 @@ define([ var localToken = tryParsing(localStorage.getItem(Constants.tokenKey)); if (localToken !== data.token) { requestLogin(); } }, - // Messaging - Q_FRIEND_REQUEST: common.messaging.onFriendRequest.fire, - EV_FRIEND_COMPLETE: common.messaging.onFriendComplete.fire, // Network NETWORK_DISCONNECT: common.onNetworkDisconnect.fire, NETWORK_RECONNECT: function (data) { diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 5b25b0379..ac02e3ce3 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -461,7 +461,8 @@ define([ friends: store.proxy.friends || {}, settings: store.proxy.settings, thumbnails: disableThumbnails === false, - isDriveOwned: Boolean(Util.find(store, ['driveMetadata', 'owners'])) + isDriveOwned: Boolean(Util.find(store, ['driveMetadata', 'owners'])), + pendingFriends: store.proxy.friends_pending || {} } }; cb(JSON.parse(JSON.stringify(metadata))); @@ -902,36 +903,63 @@ define([ // Messaging (manage friends from the userlist) - var getMessagingCfg = function (clientId) { - return { - proxy: store.proxy, - realtime: store.realtime, - network: store.network, - updateMetadata: function () { - postMessage(clientId, "UPDATE_METADATA"); - }, - pinPads: function (data, cb) { Store.pinPads(null, data, cb); }, - friendComplete: function (data) { - if (data.friend && store.messenger && store.messenger.onFriendAdded) { - store.messenger.onFriendAdded(data.friend); - } - postMessage(clientId, "EV_FRIEND_COMPLETE", data); - }, - friendRequest: function (data, cb) { - postMessage(clientId, "Q_FRIEND_REQUEST", data, cb); - }, - }; - }; - Store.inviteFromUserlist = function (clientId, data, cb) { - var messagingCfg = getMessagingCfg(clientId); - Messaging.inviteFromUserlist(messagingCfg, data, cb); - }; - Store.addDirectMessageHandlers = function (clientId, data) { - var messagingCfg = getMessagingCfg(clientId); - Messaging.addDirectMessageHandler(messagingCfg, data.href); - }; + Store.answerFriendRequest = function (clientId, obj, cb) { + console.log(obj); + var value = obj.value; + var data = obj.data; + if (data.type !== 'notifications') { return void cb ({error: 'EINVAL'}); } + var hash = data.content.hash; + var msg = data.content.msg; - // Messenger + var dismiss = function (cb) { + cb = cb || function () {}; + store.mailbox.dismiss({ + hash: hash, + type: 'notifications' + }, cb); + }; + + if (value) { + Messaging.acceptFriendRequest(store, msg.content, 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) { + broadcast([], "UPDATE_METADATA"); + if (err) { return void cb({error: err}); } + dismiss(cb); + }); + }); + return; + } + dismiss(); + }; + Store.sendFriendRequest = function (clientId, data, cb) { + var friend = Messaging.getFriend(store.proxy, data.curvePublic); + if (friend) { return void cb({error: 'ALREADY_FRIEND'}); } + if (!data.notifications || !data.curvePublic) { return void cb({error: 'INVALID_USER'}); } + + store.proxy.friends_pending = store.proxy.friends_pending || {}; + + var twoDaysAgo = +new Date(); // (+new Date() - (2 * 24 * 3600 * 1000)); // XXX + if (store.proxy.friends_pending[data.curvePublic] && + store.proxy.friends_pending[data.curvePublic] > twoDaysAgo) { + return void cb({error: 'TIMEOUT'}); + } + + store.proxy.friends_pending[data.curvePublic] = +new Date(); + broadcast([], "UPDATE_METADATA"); + + var myData = Messaging.createData(store.proxy); + store.mailbox.sendTo('FRIEND_REQUEST', myData, { + channel: data.notifications, + curvePublic: data.curvePublic + }, function (obj) { + cb(obj); + }); + }; // Get hashes for the share button Store.getStrongerHash = function (clientId, data, cb) { @@ -946,6 +974,7 @@ define([ cb(); }; + // Messenger Store.messenger = { execCommand: function (clientId, data, cb) { if (!store.messenger) { return void cb({error: 'Messenger is disabled'}); } @@ -1444,7 +1473,13 @@ define([ if (!store.loggedIn || !store.proxy.edPublic) { return; } - store.mailbox = Mailbox.init(store, waitFor, function (ev, data, clients) { + store.mailbox = Mailbox.init({ + store: store, + updateMetadata: function () { + broadcast([], "UPDATE_METADATA"); + }, + pinPads: function (data, cb) { Store.pinPads(null, data, cb); }, + }, waitFor, function (ev, data, clients) { clients.forEach(function (cId) { postMessage(cId, 'MAILBOX_EVENT', { ev: ev, @@ -1606,6 +1641,10 @@ define([ // Trigger userlist update when the friendlist has changed broadcast([], "UPDATE_METADATA"); }); + proxy.on('change', ['friends_pending'], function () { + // Trigger userlist update when the friendlist has changed + broadcast([], "UPDATE_METADATA"); + }); proxy.on('change', ['settings'], function () { broadcast([], "UPDATE_METADATA"); }); diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js index da7b8bf90..0b4ce7367 100644 --- a/www/common/outer/mailbox.js +++ b/www/common/outer/mailbox.js @@ -2,9 +2,10 @@ define([ '/common/common-util.js', '/common/common-hash.js', '/common/common-realtime.js', + '/common/outer/mailbox-handlers.js', '/bower_components/chainpad-netflux/chainpad-netflux.js', '/bower_components/chainpad-crypto/crypto.js', -], function (Util, Hash, Realtime, CpNetflux, Crypto) { +], function (Util, Hash, Realtime, Handlers, CpNetflux, Crypto) { var Mailbox = {}; var TYPES = [ @@ -14,13 +15,16 @@ define([ var BLOCKING_TYPES = [ ]; - var initializeMailboxes = function (mailboxes) { + var initializeMailboxes = function (ctx, mailboxes) { if (!mailboxes['notifications']) { mailboxes.notifications = { channel: Hash.createChannelId(), lastKnownHash: '', viewed: [] }; + ctx.pinPads([mailboxes.notifications.channel], function (res) { + if (res.error) { console.error(res); } + }); } }; @@ -55,133 +59,6 @@ proxy.mailboxes = { }; }; - var openChannel = function (ctx, type, m, onReady) { - var box = ctx.boxes[type] = { - queue: [], // Store the messages to send when the channel is ready - 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 - try { - msg = JSON.stringify(msg); - } catch (e) { - console.error(e); - } - box.queue.push(msg); - } - }; - Crypto = Crypto; - if (!Crypto.Mailbox) { - return void console.error("chainpad-crypto is outdated and doesn't support mailboxes."); - } - var keys = getMyKeys(ctx); - if (!keys) { return void console.error("missing asymmetric encryption keys"); } - var crypto = Crypto.Mailbox.createEncryptor(keys); - // XXX remove 'test' - if (type === 'test') { - crypto = { - encrypt: function (x) { return x; }, - decrypt: function (x) { return x; } - }; - } - var cfg = { - network: ctx.store.network, - channel: m.channel, - noChainPad: true, - crypto: crypto, - owners: [ctx.store.proxy.edPublic], - lastKnownHash: m.lastKnownHash - }; - cfg.onConnect = function (wc, sendMessage) { - // Send a message to our box? - // NOTE: we use our own curvePublic so that we can decrypt our own message :) - box.sendMessage = function (msg) { - try { - msg = JSON.stringify(msg); - } catch (e) { - console.error(e); - } - sendMessage(msg, function (err, hash) { - if (m.viewed.indexOf(hash) === -1) { - m.viewed.push(hash); - } - }, keys.curvePublic); - }; - box.queue.forEach(function (msg) { - box.sendMessage(msg); - }); - box.queue = []; - }; - cfg.onMessage = function (msg, user, vKey, isCp, hash, author) { - if (hash === m.lastKnownHash) { return; } - try { - msg = JSON.parse(msg); - } catch (e) { - console.error(e); - } - if (author) { msg.author = author; } - box.history.push(hash); - if (isMessageNew(hash, m)) { - // Message should be displayed - var message = { - msg: msg, - hash: hash - }; - box.content[hash] = msg; - showMessage(ctx, type, message); - } else { - // Message has already been viewed by the user - if (Object.keys(box.content).length === 0) { - // If nothing is displayed yet, we can bump our lastKnownHash and remove this hash - // from our "viewed" array - m.lastKnownHash = hash; - box.history = []; - var idxViewed = m.viewed.indexOf(hash); - if (idxViewed !== -1) { m.viewed.splice(idxViewed, 1); } - } - } - }; - cfg.onReady = function () { - // Clean the "viewed" array: make sure all the "viewed" hashes are - // in history - var toClean = []; - m.viewed.forEach(function (h, i) { - if (box.history.indexOf(h) === -1) { - toClean.push(i); - } - }); - for (var i = toClean.length-1; i>=0; i--) { - m.viewed.splice(toClean[i], 1); - } - // Listen for changes in the "viewed" and lastKnownHash values - var view = function (h) { - delete box.content[h]; - ctx.emit('VIEWED', { - type: type, - hash: h - }, ctx.clients); - }; - ctx.store.proxy.on('change', ['mailboxes', type], function (o, n, p) { - if (p[2] === 'lastKnownHash') { - // Hide everything up to this hash - var sliceIdx; - box.history.some(function (h, i) { - sliceIdx = i + 1; - view(h); - if (h === n) { return true; } - }); - box.history = box.history.slice(sliceIdx); - } - if (p[2] === 'viewed') { - // Hide this message - view(n); - } - }); - // Continue - onReady(); - }; - CpNetflux.start(cfg); - }; - // Send a message to someone else var sendTo = function (ctx, type, msg, user, cb) { if (!Crypto.Mailbox) { @@ -202,6 +79,7 @@ proxy.mailboxes = { network.join(user.channel).then(function (wc) { wc.bcast(ciphertext).then(function () { cb(); + wc.leave(); }); }, function (err) { cb({error: err}); @@ -282,6 +160,146 @@ proxy.mailboxes = { }); }; + + var openChannel = function (ctx, type, m, onReady) { + var box = ctx.boxes[type] = { + queue: [], // Store the messages to send when the channel is ready + 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 + try { + msg = JSON.stringify(msg); + } catch (e) { + console.error(e); + } + box.queue.push(msg); + } + }; + Crypto = Crypto; + if (!Crypto.Mailbox) { + return void console.error("chainpad-crypto is outdated and doesn't support mailboxes."); + } + var keys = getMyKeys(ctx); + if (!keys) { return void console.error("missing asymmetric encryption keys"); } + var crypto = Crypto.Mailbox.createEncryptor(keys); + // XXX remove 'test' + if (type === 'test') { + crypto = { + encrypt: function (x) { return x; }, + decrypt: function (x) { return x; } + }; + } + var cfg = { + network: ctx.store.network, + channel: m.channel, + noChainPad: true, + crypto: crypto, + owners: [ctx.store.proxy.edPublic], + lastKnownHash: m.lastKnownHash + }; + cfg.onConnect = function (wc, sendMessage) { + // Send a message to our box? + // NOTE: we use our own curvePublic so that we can decrypt our own message :) + box.sendMessage = function (msg) { + try { + msg = JSON.stringify(msg); + } catch (e) { + console.error(e); + } + sendMessage(msg, function (err, hash) { + if (m.viewed.indexOf(hash) === -1) { + m.viewed.push(hash); + } + }, keys.curvePublic); + }; + box.queue.forEach(function (msg) { + box.sendMessage(msg); + }); + box.queue = []; + }; + cfg.onMessage = function (msg, user, vKey, isCp, hash, author) { + if (hash === m.lastKnownHash) { return; } + try { + msg = JSON.parse(msg); + } catch (e) { + console.error(e); + } + if (author) { msg.author = author; } + box.history.push(hash); + if (isMessageNew(hash, m)) { + // Message should be displayed + var message = { + msg: msg, + hash: hash + }; + Handlers(ctx, box, message, function (toDismiss) { + if (toDismiss) { + dismiss(ctx, { + type: type, + hash: hash + }, '', function () { + console.log('Notification handled automatically'); + }); + return; + } + box.content[hash] = msg; + showMessage(ctx, type, message); + }); + } else { + // Message has already been viewed by the user + if (Object.keys(box.content).length === 0) { + // If nothing is displayed yet, we can bump our lastKnownHash and remove this hash + // from our "viewed" array + m.lastKnownHash = hash; + box.history = []; + var idxViewed = m.viewed.indexOf(hash); + if (idxViewed !== -1) { m.viewed.splice(idxViewed, 1); } + } + } + }; + cfg.onReady = function () { + // Clean the "viewed" array: make sure all the "viewed" hashes are + // in history + var toClean = []; + m.viewed.forEach(function (h, i) { + if (box.history.indexOf(h) === -1) { + toClean.push(i); + } + }); + for (var i = toClean.length-1; i>=0; i--) { + m.viewed.splice(toClean[i], 1); + } + // Listen for changes in the "viewed" and lastKnownHash values + var view = function (h) { + delete box.content[h]; + ctx.emit('VIEWED', { + type: type, + hash: h + }, ctx.clients); + }; + ctx.store.proxy.on('change', ['mailboxes', type], function (o, n, p) { + if (p[2] === 'lastKnownHash') { + // Hide everything up to this hash + var sliceIdx; + box.history.some(function (h, i) { + sliceIdx = i + 1; + view(h); + if (h === n) { return true; } + }); + box.history = box.history.slice(sliceIdx); + } + if (p[2] === 'viewed') { + // Hide this message + view(n); + } + }); + // Continue + onReady(); + }; + CpNetflux.start(cfg); + }; + + var subscribe = function (ctx, data, cId, cb) { // Get existing notifications Object.keys(ctx.boxes).forEach(function (type) { @@ -306,10 +324,13 @@ proxy.mailboxes = { ctx.clients.splice(idx, 1); }; - Mailbox.init = function (store, waitFor, emit) { + Mailbox.init = function (cfg, waitFor, emit) { var mailbox = {}; + var store = cfg.store; var ctx = { store: store, + pinPads: cfg.pinPads, + updateMetadata: cfg.updateMetadata, emit: emit, clients: [], boxes: {} @@ -317,7 +338,7 @@ proxy.mailboxes = { var mailboxes = store.proxy.mailboxes = store.proxy.mailboxes || {}; - initializeMailboxes(mailboxes); + initializeMailboxes(ctx, mailboxes); Object.keys(mailboxes).forEach(function (key) { if (TYPES.indexOf(key) === -1) { return; } @@ -346,6 +367,10 @@ proxy.mailboxes = { }); }; + mailbox.dismiss = function (data, cb) { + dismiss(ctx, data, '', cb); + }; + mailbox.sendTo = function (type, msg, user, cb) { sendTo(ctx, type, msg, user, cb); }; diff --git a/www/common/outer/store-rpc.js b/www/common/outer/store-rpc.js index aed0d5ab4..40c446c48 100644 --- a/www/common/outer/store-rpc.js +++ b/www/common/outer/store-rpc.js @@ -58,8 +58,8 @@ define([ ADD_SHARED_FOLDER: Store.addSharedFolder, LOAD_SHARED_FOLDER: Store.loadSharedFolderAnon, // Messaging - INVITE_FROM_USERLIST: Store.inviteFromUserlist, - ADD_DIRECT_MESSAGE_HANDLERS: Store.addDirectMessageHandlers, + ANSWER_FRIEND_REQUEST: Store.answerFriendRequest, + SEND_FRIEND_REQUEST: Store.sendFriendRequest, // Chat CHAT_COMMAND: Store.messenger.execCommand, // OnlyOffice diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 5c164a3eb..9a5ba5730 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -502,16 +502,11 @@ define([ }); // Messaging - sframeChan.on('Q_SEND_FRIEND_REQUEST', function (netfluxId, cb) { - Cryptpad.inviteFromUserlist(netfluxId, cb); + sframeChan.on('Q_SEND_FRIEND_REQUEST', function (data, cb) { + Cryptpad.messaging.sendFriendRequest(data, cb); }); - Cryptpad.messaging.onFriendRequest.reg(function (confirmText, cb) { - sframeChan.query('Q_INCOMING_FRIEND_REQUEST', confirmText, function (err, data) { - cb(data); - }); - }); - Cryptpad.messaging.onFriendComplete.reg(function (data) { - sframeChan.event('EV_FRIEND_REQUEST', data); + sframeChan.on('Q_ANSWER_FRIEND_REQUEST', function (data, cb) { + Cryptpad.messaging.answerFriendRequest(data, cb); }); // History @@ -954,9 +949,6 @@ define([ readOnly: readOnly, crypto: Crypto.createEncryptor(secret.keys), onConnect: function () { - var href = parsed.getUrl(); - // Add friends requests handlers when we have the final href - Cryptpad.messaging.addHandlers(href); if (window.location.hash && window.location.hash !== '#') { /*window.location = parsed.getUrl({ present: parsed.hashData.present, diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 76dcaa029..7081136c0 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -380,14 +380,24 @@ define([ funcs.mergeAnonDrive = function (cb) { ctx.sframeChan.query('Q_MERGE_ANON_DRIVE', null, cb); }; - // Friends - var pendingFriends = []; + + // Create friend request funcs.getPendingFriends = function () { - return pendingFriends.slice(); + return ctx.metadataMgr.getPrivateData().pendingFriends; }; - funcs.sendFriendRequest = function (netfluxId) { - ctx.sframeChan.query('Q_SEND_FRIEND_REQUEST', netfluxId, $.noop); - pendingFriends.push(netfluxId); + funcs.sendFriendRequest = function (data, cb) { + ctx.sframeChan.query('Q_SEND_FRIEND_REQUEST', data, cb); + }; + // Friend requests received + var friendRequests = {}; + funcs.addFriendRequest = function (data) { + var curve = Util.find(data, ['content', 'msg', 'author']); + console.log(data); + console.log(curve); + friendRequests[curve] = data; + }; + funcs.getFriendRequests = function () { + return JSON.parse(JSON.stringify(friendRequests)); }; // Feedback @@ -524,15 +534,6 @@ define([ UI.addTooltips(); - ctx.sframeChan.on('Q_INCOMING_FRIEND_REQUEST', function (confirmMsg, cb) { - UI.confirm(confirmMsg, cb, null, true); - }); - ctx.sframeChan.on('EV_FRIEND_REQUEST', function (data) { - var i = pendingFriends.indexOf(data.netfluxId); - if (i !== -1) { pendingFriends.splice(i, 1); } - UI.log(data.logText); - }); - ctx.sframeChan.on("EV_PAD_PASSWORD", function () { UIElements.displayPasswordPrompt(funcs); }); diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index 8eb3b6c2d..d782622e5 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -8,10 +8,11 @@ define([ '/common/common-util.js', '/common/common-feedback.js', '/common/hyperscript.js', + '/common/notifications.js', '/common/messenger-ui.js', '/customize/messages.js', ], function ($, Config, ApiConfig, UIElements, UI, Hash, Util, Feedback, h, -MessengerUI, Messages) { +Notifications, MessengerUI, Messages) { var Common; var Bar = { @@ -232,7 +233,11 @@ MessengerUI, Messages) { // Display the userlist // Editors - var pendingFriends = Common.getPendingFriends(); + var pendingFriends = Common.getPendingFriends(); // Friend requests sent + var friendRequests = Common.getFriendRequests(); // Friend requests received + console.log(friendRequests); + var friendTo = +new Date() - (2 * 24 * 3600 * 1000); + friendTo = +new Date(); // XXX editUsersNames.forEach(function (data) { var name = data.name || Messages.anonymous; var $span = $('', {'class': 'cp-avatar'}); @@ -300,9 +305,21 @@ MessengerUI, Messages) { } } else if (Common.isLoggedIn() && data.curvePublic && !friends[data.curvePublic] && !priv.readOnly) { - if (pendingFriends.indexOf(data.netfluxId) !== -1) { + console.log(pendingFriends); + if (pendingFriends[data.curvePublic] && pendingFriends[data.curvePublic] > friendTo) { $('', {'class': 'cp-toolbar-userlist-friend'}).text(Messages.userlist_pending) .appendTo($rightCol); + } else if (friendRequests[data.curvePublic]) { + $('