diff --git a/Gruntfile.js b/Gruntfile.js index 620ea71f6..0e040de4f 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -102,7 +102,6 @@ module.exports = grunt => { libloki: { src: [ 'libloki/api.js', - 'libloki/friends.js', 'libloki/crypto.js', 'libloki/service_nodes.js', 'libloki/storage.js', diff --git a/app/sql.js b/app/sql.js index 0c2589efa..fcac55d92 100644 --- a/app/sql.js +++ b/app/sql.js @@ -110,8 +110,6 @@ module.exports = { updateConversation, removeConversation, getAllConversations, - getPubKeysWithFriendStatus, - getConversationsWithFriendStatus, getAllRssFeedConversations, getAllPublicConversations, getPublicConversationsByServer, @@ -471,10 +469,10 @@ async function updateToSchemaVersion6(currentVersion, instance) { console.log('updateToSchemaVersion6: starting...'); await instance.run('BEGIN TRANSACTION;'); - await instance.run( - `ALTER TABLE conversations - ADD COLUMN friendRequestStatus INTEGER;` - ); + // await instance.run( + // `ALTER TABLE conversations + // ADD COLUMN friendRequestStatus INTEGER;` + // ); await instance.run( `CREATE TABLE lastHashes( @@ -837,7 +835,7 @@ async function updateToLokiSchemaVersion1(currentVersion, instance) { const initConversation = async data => { // eslint-disable-next-line camelcase - const { id, active_at, type, name, friendRequestStatus } = data; + const { id, active_at, type, name } = data; await instance.run( `INSERT INTO conversations ( id, @@ -845,8 +843,7 @@ async function updateToLokiSchemaVersion1(currentVersion, instance) { active_at, type, members, - name, - friendRequestStatus + name ) values ( $id, $json, @@ -854,7 +851,6 @@ async function updateToLokiSchemaVersion1(currentVersion, instance) { $type, $members, $name, - $friendRequestStatus );`, { $id: id, @@ -863,7 +859,6 @@ async function updateToLokiSchemaVersion1(currentVersion, instance) { $type: type, $members: null, $name: name, - $friendRequestStatus: friendRequestStatus, } ); }; @@ -877,7 +872,6 @@ async function updateToLokiSchemaVersion1(currentVersion, instance) { const baseData = { active_at: Date.now(), - friendRequestStatus: 4, // Friends sealedSender: 0, sessionResetStatus: 0, swarmNodes: [], @@ -1860,7 +1854,6 @@ async function saveConversation(data) { type, members, name, - friendRequestStatus, profileName, } = data; @@ -1873,7 +1866,6 @@ async function saveConversation(data) { type, members, name, - friendRequestStatus, profileName ) values ( $id, @@ -1883,7 +1875,6 @@ async function saveConversation(data) { $type, $members, $name, - $friendRequestStatus, $profileName );`, { @@ -1894,7 +1885,6 @@ async function saveConversation(data) { $type: type, $members: members ? members.join(' ') : null, $name: name, - $friendRequestStatus: friendRequestStatus, $profileName: profileName, } ); @@ -1924,7 +1914,6 @@ async function updateConversation(data) { type, members, name, - friendRequestStatus, profileName, } = data; @@ -1936,7 +1925,6 @@ async function updateConversation(data) { type = $type, members = $members, name = $name, - friendRequestStatus = $friendRequestStatus, profileName = $profileName WHERE id = $id;`, { @@ -1947,7 +1935,6 @@ async function updateConversation(data) { $type: type, $members: members ? members.join(' ') : null, $name: name, - $friendRequestStatus: friendRequestStatus, $profileName: profileName, } ); @@ -2028,31 +2015,6 @@ async function getAllConversations() { return map(rows, row => jsonToObject(row.json)); } -async function getPubKeysWithFriendStatus(status) { - const rows = await db.all( - `SELECT id FROM ${CONVERSATIONS_TABLE} WHERE - friendRequestStatus = $status - AND type = 'private' - ORDER BY id ASC;`, - { - $status: status, - } - ); - return map(rows, row => row.id); -} - -async function getConversationsWithFriendStatus(status) { - const rows = await db.all( - `SELECT * FROM ${CONVERSATIONS_TABLE} WHERE - friendRequestStatus = $status - AND type = 'private' - ORDER BY id ASC;`, - { - $status: status, - } - ); - return map(rows, row => jsonToObject(row.json)); -} async function getAllConversationIds() { const rows = await db.all( @@ -2521,7 +2483,7 @@ async function getMessageBySender({ source, sourceDevice, sent_at }) { async function getAllUnsentMessages() { const rows = await db.all(` SELECT json FROM messages WHERE - type IN ('outgoing', 'friend-request') AND + type IN ('outgoing', 'session-request') AND NOT sent ORDER BY sent_at DESC; `); diff --git a/js/conversation_controller.js b/js/conversation_controller.js index 171703716..c018f9abc 100644 --- a/js/conversation_controller.js +++ b/js/conversation_controller.js @@ -257,8 +257,6 @@ promises.concat([ conversation.updateProfileName(), conversation.updateProfileAvatar(), - conversation.resetPendingSend(), - conversation.setFriendRequestExpiryTimeout(), ]); }); await Promise.all(promises); diff --git a/js/models/conversation.d.ts b/js/models/conversation.d.ts index 0af2164e3..02c78688a 100644 --- a/js/models/conversation.d.ts +++ b/js/models/conversation.d.ts @@ -12,10 +12,8 @@ interface ConversationAttributes { export interface ConversationModel extends Backbone.Model { - setFriendRequestStatus: (status: any) => Promise; idForLogging: () => string; saveChangesToDB: () => Promise; - notifyFriendRequest: (source: string, type: string) => Promise; notify: (message: MessageModel) => void; isSessionResetReceived: () => boolean; updateExpirationTimer: ( @@ -30,10 +28,6 @@ export interface ConversationModel getRecipients: () => Array; onReadMessage: (message: MessageModel) => void; updateTextInputState: () => void; - isFriend: () => boolean; - hasSentFriendRequest: () => boolean; - onFriendRequestAccepted: () => Promise; - onFriendRequestReceived: () => Promise; lastMessage: string; } diff --git a/js/models/conversations.js b/js/models/conversations.js index 3419e15b3..683ae0d2b 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -4,7 +4,7 @@ log, i18n, Backbone, - libloki, + libsession, ConversationController, MessageController, storage, @@ -50,9 +50,6 @@ deleteAttachmentData, } = window.Signal.Migrations; - // Possible conversation friend states - const FriendRequestStatusEnum = window.friends.friendRequestStatusEnum; - // Possible session reset states const SessionResetEnum = Object.freeze({ // No ongoing reset @@ -83,8 +80,6 @@ return { unreadCount: 0, verified: textsecure.storage.protocol.VerifiedStatus.DEFAULT, - friendRequestStatus: FriendRequestStatusEnum.none, - unlockTimestamp: null, // Timestamp used for expiring friend requests. sessionResetStatus: SessionResetEnum.none, swarmNodes: [], groupAdmins: [], @@ -181,10 +176,6 @@ this.typingRefreshTimer = null; this.typingPauseTimer = null; - if (this.id === this.ourNumber) { - this.set({ friendRequestStatus: FriendRequestStatusEnum.friends }); - } - this.messageSendQueue = new JobQueue(); this.selectedMessages = new Set(); @@ -249,48 +240,6 @@ this.trigger('change'); this.messageCollection.forEach(m => m.trigger('change')); }, - async acceptFriendRequest() { - // Friend request message conmfirmations (Accept / Decline) are always - // sent to the primary device conversation - const messages = await window.Signal.Data.getMessagesByConversation( - this.getPrimaryDevicePubKey(), - { - limit: 5, - MessageCollection: Whisper.MessageCollection, - type: 'friend-request', - } - ); - - let lastMessage = null; - messages.forEach(m => { - m.acceptFriendRequest(); - lastMessage = m; - }); - - if (lastMessage) { - await this.markRead(); - window.Whisper.events.trigger( - 'showConversation', - this.id, - lastMessage.id - ); - } - }, - async declineFriendRequest() { - const messages = await window.Signal.Data.getMessagesByConversation( - this.id, - { - limit: 1, - MessageCollection: Whisper.MessageCollection, - type: 'friend-request', - } - ); - - const lastMessageModel = messages.at(0); - if (lastMessageModel) { - lastMessageModel.declineFriendRequest(); - } - }, setMessageSelectionBackdrop() { const messageSelected = this.selectedMessages.size > 0; @@ -363,9 +312,12 @@ }, async bumpTyping() { - // We don't send typing messages if the setting is disabled or we aren't friends - const hasFriendDevice = await this.isFriendWithAnyDevice(); - if (!storage.get('typing-indicators-setting') || !hasFriendDevice) { + // We don't send typing messages if the setting is disabled or we do not have a session + // or we blocked that user + const devicePubkey = new libsession.Types.PubKey(this.id); + const hasSession = await libsession.Protocols.SessionProtocol.hasSession(devicePubkey); + + if (!storage.get('typing-indicators-setting') || !hasSession || this.isBlocked()) { return; } @@ -549,36 +501,6 @@ : `${message.source}.${message.sourceDevice}`; this.clearContactTypingTimer(identifier); }, - - // This goes through all our message history and finds a friend request - async getFriendRequests(direction = null, status = ['pending']) { - // Theoretically all our messages could be friend requests, - // thus we have to unfortunately go through each one :( - const messages = await window.Signal.Data.getMessagesByConversation( - this.id, - { - type: 'friend-request', - MessageCollection: Whisper.MessageCollection, - } - ); - - if (typeof status === 'string') { - // eslint-disable-next-line no-param-reassign - status = [status]; - } - // Get the pending friend requests that match the direction - // If no direction is supplied then return all pending friend requests - return messages.models.filter(m => { - if (!status.includes(m.get('friendStatus'))) { - return false; - } - return direction === null || m.get('direction') === direction; - }); - }, - async getPendingFriendRequests(direction = null) { - return this.getFriendRequests(direction, ['pending']); - }, - addSingleMessage(message, setToExpire = true) { const model = this.messageCollection.add(message, { merge: true }); if (setToExpire) { @@ -614,9 +536,6 @@ title: this.getTitle(), unreadCount: this.get('unreadCount') || 0, mentionedUs: this.get('mentionedUs') || false, - isPendingFriendRequest: this.isPendingFriendRequest(), - hasReceivedFriendRequest: this.hasReceivedFriendRequest(), - hasSentFriendRequest: this.hasSentFriendRequest(), isBlocked: this.isBlocked(), isSecondary: !!this.get('secondaryStatus'), primaryDevice: this.getPrimaryDevicePubKey(), @@ -630,7 +549,6 @@ }, isOnline: this.isOnline(), hasNickname: !!this.getNickname(), - isFriend: !!this.isFriendWithAnyCache, selectedMessages: this.selectedMessages, @@ -643,12 +561,8 @@ onDeleteContact: () => this.deleteContact(), onDeleteMessages: () => this.deleteMessages(), onCloseOverlay: () => this.resetMessageSelection(), - acceptFriendRequest: () => this.acceptFriendRequest(), - declineFriendRequest: () => this.declineFriendRequest(), }; - this.updateAsyncPropsCache(); - return result; }, @@ -792,85 +706,6 @@ return contact.isVerified(); }); }, - isFriendRequestStatusNone() { - return this.get('friendRequestStatus') === FriendRequestStatusEnum.none; - }, - isFriendRequestStatusNoneOrExpired() { - const status = this.get('friendRequestStatus'); - return ( - status === FriendRequestStatusEnum.none || - status === FriendRequestStatusEnum.requestExpired - ); - }, - isPendingFriendRequest() { - const status = this.get('friendRequestStatus'); - return ( - status === FriendRequestStatusEnum.requestSent || - status === FriendRequestStatusEnum.requestReceived || - status === FriendRequestStatusEnum.pendingSend - ); - }, - hasSentFriendRequest() { - const status = this.get('friendRequestStatus'); - return ( - status === FriendRequestStatusEnum.pendingSend || - status === FriendRequestStatusEnum.requestSent - ); - }, - hasReceivedFriendRequest() { - return ( - this.get('friendRequestStatus') === - FriendRequestStatusEnum.requestReceived - ); - }, - isFriend() { - return ( - this.get('friendRequestStatus') === FriendRequestStatusEnum.friends - ); - }, - async getAnyDeviceFriendRequestStatus() { - const secondaryDevices = await window.libloki.storage.getSecondaryDevicesFor( - this.id - ); - const allDeviceStatus = secondaryDevices - // Get all the secondary device friend status' - .map(pubKey => { - const conversation = ConversationController.get(pubKey); - if (!conversation) { - return FriendRequestStatusEnum.none; - } - return conversation.getFriendRequestStatus(); - }) - // Also include this conversation's friend status - .concat(this.get('friendRequestStatus')) - .reduce((acc, cur) => { - if ( - acc === FriendRequestStatusEnum.friends || - cur === FriendRequestStatusEnum.friends - ) { - return FriendRequestStatusEnum.friends; - } - if (acc !== FriendRequestStatusEnum.none) { - return acc; - } - return cur; - }, FriendRequestStatusEnum.none); - return allDeviceStatus; - }, - async updateAsyncPropsCache() { - const isFriendWithAnyDevice = await this.isFriendWithAnyDevice(); - if (this.isFriendWithAnyCache !== isFriendWithAnyDevice) { - this.isFriendWithAnyCache = isFriendWithAnyDevice; - this.trigger('change'); - } - }, - async isFriendWithAnyDevice() { - const allDeviceStatus = await this.getAnyDeviceFriendRequestStatus(); - return allDeviceStatus === FriendRequestStatusEnum.friends; - }, - getFriendRequestStatus() { - return this.get('friendRequestStatus'); - }, async getPrimaryConversation() { if (!this.isSecondaryDevice()) { // This is already the primary conversation @@ -900,8 +735,6 @@ primaryConversation.updateTextInputState(); return; } - const allDeviceStatus = await this.getAnyDeviceFriendRequestStatus(); - if (this.get('isKickedFromGroup')) { this.trigger('disable:input', true); return; @@ -911,25 +744,10 @@ this.trigger('change:placeholder', 'left-group'); return; } - switch (allDeviceStatus) { - case FriendRequestStatusEnum.none: - case FriendRequestStatusEnum.requestExpired: - this.trigger('disable:input', false); - this.trigger('change:placeholder', 'friend-request'); - return; - case FriendRequestStatusEnum.pendingSend: - case FriendRequestStatusEnum.requestReceived: - case FriendRequestStatusEnum.requestSent: - this.trigger('disable:input', true); - this.trigger('change:placeholder', 'disabled'); - return; - case FriendRequestStatusEnum.friends: - this.trigger('disable:input', false); - this.trigger('change:placeholder', 'chat'); - return; - default: - throw new Error('Invalid friend request state'); - } + // otherwise, enable the input and set default placeholder + this.trigger('disable:input', false); + this.trigger('change:placeholder', 'chat'); + }, isSecondaryDevice() { return !!this.get('secondaryStatus'); @@ -948,253 +766,12 @@ }); } }, - async setFriendRequestStatus(newStatus, options = {}) { - const { blockSync } = options; - // Ensure that the new status is a valid FriendStatusEnum value - if (!(newStatus in Object.values(FriendRequestStatusEnum))) { - return; - } - if ( - this.ourNumber === this.id && - newStatus !== FriendRequestStatusEnum.friends - ) { - return; - } - if (this.get('friendRequestStatus') !== newStatus) { - this.set({ friendRequestStatus: newStatus }); - if (newStatus === FriendRequestStatusEnum.friends) { - if (!blockSync) { - // Sync contact - this.wrapSend(textsecure.messaging.sendContactSyncMessage([this])); - } - // Only enable sending profileKey after becoming friends - this.set({ profileSharing: true }); - } - await window.Signal.Data.updateConversation(this.id, this.attributes, { - Conversation: Whisper.Conversation, - }); - await this.updateTextInputState(); - } - }, async updateGroupAdmins(groupAdmins) { this.set({ groupAdmins }); await window.Signal.Data.updateConversation(this.id, this.attributes, { Conversation: Whisper.Conversation, }); }, - async updateAllFriendRequestsMessages(options) { - const { response, status, direction = null } = options; - // Ignore if no response supplied - if (!response) { - return; - } - - // Accept FRs from all the user's devices - const allDevices = await libloki.storage.getAllDevicePubKeysForPrimaryPubKey( - this.getPrimaryDevicePubKey() - ); - - if (!allDevices.length) { - return; - } - - const allConversationsWithUser = allDevices.map(d => - ConversationController.get(d) - ); - - // Search through each conversation (device) for friend request messages - const pendingRequestPromises = allConversationsWithUser.map( - async conversation => { - const request = ( - await conversation.getFriendRequests(direction, status) - )[0]; - return { conversation, request }; - } - ); - - let pendingRequests = await Promise.all(pendingRequestPromises); - - // Filter out all undefined requests - pendingRequests = pendingRequests.filter(p => Boolean(p.request)); - - // We set all friend request messages from all devices - // from a user here to accepted where possible - await Promise.all( - pendingRequests.map(async friendRequest => { - const { conversation, request } = friendRequest; - - if (request.hasErrors()) { - return; - } - - request.set({ friendStatus: response }); - await window.Signal.Data.saveMessage(request.attributes, { - Message: Whisper.Message, - }); - conversation.trigger('updateMessage', request); - }) - ); - }, - async updateAllPendingFriendRequestsMessages(options) { - return this.updateAllFriendRequestsMessages({ - ...options, - status: 'pending', - }); - }, - async resetPendingSend() { - if ( - this.get('friendRequestStatus') === FriendRequestStatusEnum.pendingSend - ) { - await this.setFriendRequestStatus(FriendRequestStatusEnum.none); - } - }, - // We have declined an incoming friend request - async onDeclineFriendRequest() { - this.setFriendRequestStatus(FriendRequestStatusEnum.none); - await this.updateAllPendingFriendRequestsMessages({ - response: 'declined', - direction: 'incoming', - }); - await window.libloki.storage.removeContactPreKeyBundle(this.id); - await this.destroyMessages(); - window.pushToast({ - title: i18n('friendRequestDeclined'), - type: 'success', - id: 'declineFriendRequest', - }); - }, - // We have accepted an incoming friend request - async onAcceptFriendRequest(options = {}) { - if (this.get('type') !== Message.PRIVATE) { - return; - } - if (this.unlockTimer) { - clearTimeout(this.unlockTimer); - } - if (this.hasReceivedFriendRequest()) { - this.setFriendRequestStatus(FriendRequestStatusEnum.friends, options); - - await this.updateAllFriendRequestsMessages({ - response: 'accepted', - direction: 'incoming', - status: ['pending', 'expired'], - }); - window.libloki.api.sendBackgroundMessage( - this.id, - window.textsecure.OutgoingMessage.DebugMessageType - .INCOMING_FR_ACCEPTED - ); - } else if (this.isFriendRequestStatusNoneOrExpired()) { - // send AFR if we haven't sent a message before - const autoFrMessage = textsecure.OutgoingMessage.buildAutoFriendRequestMessage( - this.id - ); - await autoFrMessage.sendToNumber(this.id, false); - } - }, - // Our outgoing friend request has been accepted - async onFriendRequestAccepted() { - if (this.isFriend()) { - return false; - } - if (this.unlockTimer) { - clearTimeout(this.unlockTimer); - } - if (this.hasSentFriendRequest()) { - this.setFriendRequestStatus(FriendRequestStatusEnum.friends); - await this.updateAllFriendRequestsMessages({ - response: 'accepted', - status: ['pending', 'expired'], - }); - window.libloki.api.sendBackgroundMessage( - this.id, - window.textsecure.OutgoingMessage.DebugMessageType - .OUTGOING_FR_ACCEPTED - ); - return true; - } - return false; - }, - async onFriendRequestTimeout() { - // Unset the timer - if (this.unlockTimer) { - clearTimeout(this.unlockTimer); - } - this.unlockTimer = null; - if (this.isFriend()) { - return; - } - - // Set the unlock timestamp to null - if (this.get('unlockTimestamp')) { - this.set({ unlockTimestamp: null }); - await window.Signal.Data.updateConversation(this.id, this.attributes, { - Conversation: Whisper.Conversation, - }); - } - - // Change any pending outgoing friend requests to expired - await this.updateAllPendingFriendRequestsMessages({ - response: 'expired', - direction: 'outgoing', - }); - await this.setFriendRequestStatus(FriendRequestStatusEnum.requestExpired); - }, - async onFriendRequestReceived() { - if (this.isFriendRequestStatusNone()) { - this.setFriendRequestStatus(FriendRequestStatusEnum.requestReceived); - } else if (this.hasSentFriendRequest()) { - await Promise.all([ - this.setFriendRequestStatus(FriendRequestStatusEnum.friends), - // Accept all outgoing FR - this.updateAllPendingFriendRequestsMessages({ - direction: 'outgoing', - response: 'accepted', - }), - ]); - } - // Delete stale incoming friend requests - const incoming = await this.getPendingFriendRequests('incoming'); - await Promise.all( - incoming.map(request => this._removeMessage(request.id)) - ); - this.trigger('change'); - }, - async onFriendRequestSent() { - // Check if we need to set the friend request expiry - const unlockTimestamp = this.get('unlockTimestamp'); - if (!this.isFriend() && !unlockTimestamp) { - // Expire the messages after 72 hours - const hourLockDuration = 72; - const ms = 60 * 60 * 1000 * hourLockDuration; - - this.set({ unlockTimestamp: Date.now() + ms }); - await window.Signal.Data.updateConversation(this.id, this.attributes, { - Conversation: Whisper.Conversation, - }); - this.setFriendRequestExpiryTimeout(); - } - await this.setFriendRequestStatus(FriendRequestStatusEnum.requestSent); - }, - friendRequestTimerIsExpired() { - const unlockTimestamp = this.get('unlockTimestamp'); - if (unlockTimestamp && unlockTimestamp > Date.now()) { - return false; - } - return true; - }, - setFriendRequestExpiryTimeout() { - if (this.isFriend()) { - return; - } - const unlockTimestamp = this.get('unlockTimestamp'); - if (unlockTimestamp && !this.unlockTimer) { - const delta = Math.max(unlockTimestamp - Date.now(), 0); - this.unlockTimer = setTimeout(() => { - this.onFriendRequestTimeout(); - }, delta); - } - }, isUnverified() { if (this.isPrivate()) { const verified = this.get('verified'); @@ -1614,73 +1191,18 @@ ); const conversationType = this.get('type'); - - let messageWithSchema = null; - - // If we are a friend with any of the devices, send the message normally - const canSendNormalMessage = await this.isFriendWithAnyDevice(); - const isGroup = conversationType === Message.GROUP; - if (canSendNormalMessage || isGroup) { - messageWithSchema = await upgradeMessageSchema({ - type: 'outgoing', - body, - conversationId: destination, - quote, - preview, - attachments, - sent_at: now, - received_at: now, - expireTimer, - recipients, - }); - } else { - // Check if we have sent a friend request - const outgoingRequests = await this.getPendingFriendRequests( - 'outgoing' - ); - if (outgoingRequests.length > 0) { - // Check if the requests have errored, if so then remove them - // and send the new request if possible - let friendRequestSent = false; - const promises = []; - outgoingRequests.forEach(outgoing => { - if (outgoing.hasErrors()) { - promises.push(this._removeMessage(outgoing.id)); - } else { - // No errors = we have sent over the friend request - friendRequestSent = true; - } - }); - await Promise.all(promises); - - // If the requests didn't error then don't add a new friend request - // because one of them was sent successfully - if (friendRequestSent) { - return null; - } - } - await this.setFriendRequestStatus( - FriendRequestStatusEnum.pendingSend - ); - - // Always share our profileKey in the friend request - // This will get added automatically after the FR - // is accepted, via the profileSharing flag - profileKey = storage.get('profileKey'); - - // Send the friend request! - messageWithSchema = await upgradeMessageSchema({ - type: 'friend-request', - body, - conversationId: destination, - sent_at: now, - received_at: now, - expireTimer, - recipients, - direction: 'outgoing', - friendStatus: 'pending', - }); - } + const messageWithSchema = await upgradeMessageSchema({ + type: 'outgoing', + body, + conversationId: destination, + quote, + preview, + attachments, + sent_at: now, + received_at: now, + expireTimer, + recipients, + }); if (this.isPrivate()) { messageWithSchema.destination = destination; @@ -1880,12 +1402,7 @@ async handleMessageSendResult({ failoverNumbers, unidentifiedDeliveries, - messageType, - success, }) { - if (success && messageType === 'friend-request') { - await this.onFriendRequestSent(); - } await Promise.all( (failoverNumbers || []).map(async number => { const conversation = ConversationController.get(number); @@ -2491,8 +2008,9 @@ // conversation is viewed, another error message shows up for the contact read = read.filter(item => !item.hasErrors); - // Do not send read receipt if not friends yet - if (!this.isFriendWithAnyDevice()) { + const devicePubkey = new libsession.Types.PubKey(this.id); + const hasSession = await libsession.Protocols.SessionProtocol.hasSession(devicePubkey); + if (hasSession) { return; } @@ -2592,7 +2110,7 @@ this.get('server') !== newServer || this.get('channelId') !== newChannelId ) { - // mark active so it's not in the friends list but the conversation list + // mark active so it's not in the contacts list but in the conversation list this.set({ server: newServer, channelId: newChannelId, @@ -2985,11 +2503,6 @@ }); } - // Reset our friend status if we're not friends - if (!this.isFriend()) { - this.set({ friendRequestStatus: FriendRequestStatusEnum.none }); - } - await window.Signal.Data.updateConversation(this.id, this.attributes, { Conversation: Whisper.Conversation, }); @@ -3113,12 +2626,6 @@ }, notify(message) { - if (message.isFriendRequest()) { - if (this.hasSentFriendRequest()) { - return this.notifyFriendRequest(message.get('source'), 'accepted'); - } - return this.notifyFriendRequest(message.get('source'), 'requested'); - } if (!message.isIncoming()) { return Promise.resolve(); } @@ -3151,55 +2658,6 @@ }) ); }, - // Notification for friend request received - async notifyFriendRequest(source, type) { - // Data validation - if (!source) { - throw new Error('Invalid source'); - } - if (!['accepted', 'requested'].includes(type)) { - throw new Error('Type must be accepted or requested.'); - } - - // Call the notification on the right conversation - let conversation = this; - if (conversation.id !== source) { - try { - conversation = await ConversationController.getOrCreateAndWait( - source, - 'private' - ); - window.log.info(`Notify called on a different conversation. - Expected: ${this.id}. Actual: ${conversation.id}`); - } catch (e) { - throw new Error('Failed to fetch conversation.'); - } - } - - const isTypeAccepted = type === 'accepted'; - const title = isTypeAccepted - ? 'friendRequestAcceptedNotificationTitle' - : 'friendRequestNotificationTitle'; - const message = isTypeAccepted - ? 'friendRequestAcceptedNotificationMessage' - : 'friendRequestNotificationMessage'; - - const iconUrl = await conversation.getNotificationIcon(); - // window.log.info('Add notification for friend request updated', { - // conversationId: conversation.idForLogging(), - // }); - Whisper.Notifications.add({ - conversationId: conversation.id, - iconUrl, - isExpiringMessage: false, - message: i18n(message, conversation.getTitle()), - messageSentAt: Date.now(), - title: i18n(title), - isFriendRequest: true, - friendRequestType: type, - }); - }, - notifyTyping(options = {}) { const { isTyping, sender, senderDevice } = options; diff --git a/js/models/messages.js b/js/models/messages.js index 1fa45741d..2fd259693 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -277,8 +277,8 @@ isKeyChange() { return this.get('type') === 'keychange'; }, - isFriendRequest() { - return this.get('type') === 'friend-request'; + isSessionRequest() { + return this.get('type') === 'session-request'; }, isGroupInvitation() { return !!this.get('groupInvitation'); diff --git a/js/modules/data.js b/js/modules/data.js index cfbc3d006..59db4cce4 100644 --- a/js/modules/data.js +++ b/js/modules/data.js @@ -128,8 +128,6 @@ module.exports = { _removeConversations, getAllConversations, - getPubKeysWithFriendStatus, - getConversationsWithFriendStatus, getAllConversationIds, getAllPrivateConversations, getAllRssFeedConversations, @@ -826,22 +824,6 @@ async function _removeConversations(ids) { await channels.removeConversation(ids); } -async function getConversationsWithFriendStatus( - status, - { ConversationCollection } -) { - const conversations = await channels.getConversationsWithFriendStatus(status); - - const collection = new ConversationCollection(); - collection.add(conversations); - return collection; -} - -async function getPubKeysWithFriendStatus(status) { - const conversations = await getConversationsWithFriendStatus(status); - return conversations.map(row => row.id); -} - async function getAllConversations({ ConversationCollection }) { const conversations = await channels.getAllConversations(); diff --git a/js/notifications.js b/js/notifications.js index 2daf2c4b8..823aa7d4c 100644 --- a/js/notifications.js +++ b/js/notifications.js @@ -92,9 +92,9 @@ let message; let iconUrl; - // The number of notifications excluding friend request + // The number of notifications excluding session request const messagesNotificationCount = this.models.filter( - n => !n.get('isFriendRequest') + n => !n.get('isSessionRequest') ).length; // NOTE: i18n has more complex rules for pluralization than just @@ -112,9 +112,7 @@ case SettingNames.COUNT: title = 'Session'; - if (last.isFriendRequest) { - message = `Friend request ${last.friendRequestType}`; - } else if (messagesNotificationCount > 0) { + if (messagesNotificationCount > 0) { message = newMessageCountLabel; } else { return; @@ -125,7 +123,7 @@ title = newMessageCountLabel; // eslint-disable-next-line prefer-destructuring iconUrl = last.iconUrl; - if (last.isFriendRequest || messagesNotificationCount === 1) { + if (messagesNotificationCount === 1) { message = `${i18n('notificationFrom')} ${lastMessageTitle}`; } else { message = `${i18n( @@ -135,7 +133,7 @@ break; } case SettingNames.MESSAGE: - if (last.isFriendRequest || messagesNotificationCount === 1) { + if (messagesNotificationCount === 1) { // eslint-disable-next-line prefer-destructuring title = last.title; // eslint-disable-next-line prefer-destructuring diff --git a/js/views/conversation_view.js b/js/views/conversation_view.js index ec70413cd..7f5875d3d 100644 --- a/js/views/conversation_view.js +++ b/js/views/conversation_view.js @@ -57,11 +57,6 @@ initialize(options) { this.listenTo(this.model, 'destroy', this.stopListening); this.listenTo(this.model, 'change:verified', this.onVerifiedChange); - this.listenTo( - this.model, - 'change:friendRequestStatus', - this.onFriendStatusChange - ); this.listenTo(this.model, 'newmessage', this.addMessage); this.listenTo(this.model, 'opened', this.onOpened); this.listenTo(this.model, 'prune', this.onPrune); @@ -129,7 +124,6 @@ ); this.render(); - this.onFriendStatusChange(); this.model.updateTextInputState(); @@ -532,9 +526,6 @@ } let placeholder; switch (type) { - case 'friend-request': - placeholder = i18n('sendMessageFriendRequest'); - break; case 'disabled': placeholder = i18n('sendMessageDisabled'); break; @@ -735,14 +726,6 @@ } }, - onFriendStatusChange() { - if (this.model.isPrivate() && !this.model.isFriend()) { - this.$('#choose-file').hide(); - } else { - this.$('#choose-file').show(); - } - }, - async toggleMicrophone() { const allowMicrophone = await window.getMediaPermissions(); if ( diff --git a/js/views/create_group_dialog_view.js b/js/views/create_group_dialog_view.js index a74074e6d..5d702a758 100644 --- a/js/views/create_group_dialog_view.js +++ b/js/views/create_group_dialog_view.js @@ -17,7 +17,7 @@ const convos = window.getConversations().models; let allMembers = convos.filter( - d => !!d && d.isFriend() && d.isPrivate() && !d.isMe() + d => !!d && d.isPrivate() && !d.isMe() ); allMembers = _.uniq(allMembers, true, d => d.id); diff --git a/js/views/invite_friends_dialog_view.js b/js/views/invite_friends_dialog_view.js index c4bec8b9f..cbbd4ae9b 100644 --- a/js/views/invite_friends_dialog_view.js +++ b/js/views/invite_friends_dialog_view.js @@ -14,12 +14,12 @@ const convos = window.getConversations().models; - this.friends = convos.filter( - d => !!d && d.isFriend() && d.isPrivate() && !d.isMe() + this.contacts = convos.filter( + d => !!d && d.isPrivate() && !d.isMe() ); if (!convo.isPublic()) { const members = convo.get('members') || []; - this.friends = this.friends.filter(d => !members.includes(d.id)); + this.contacts = this.contacts.filter(d => !members.includes(d.id)); } this.chatName = convo.get('name'); @@ -36,7 +36,7 @@ className: 'invite-friends-dialog', Component: window.Signal.Components.InviteFriendsDialog, props: { - friendList: this.friends, + friendList: this.contacts, onSubmit: this.submit, onClose: this.close, chatName: this.chatName, diff --git a/js/views/moderators_add_dialog_view.js b/js/views/moderators_add_dialog_view.js index df304ca0a..095f441db 100644 --- a/js/views/moderators_add_dialog_view.js +++ b/js/views/moderators_add_dialog_view.js @@ -22,16 +22,15 @@ const convos = window.getConversations().models; // private friends (not you) that aren't already moderators - const friends = convos.filter( + const contacts = convos.filter( d => !!d && - d.isFriend() && d.isPrivate() && !d.isMe() && !modPubKeys.includes(d.id) ); - this.friends = friends; + this.contacts = contacts; this.$el.focus(); this.render(); @@ -41,7 +40,7 @@ className: 'add-moderators-dialog', Component: window.Signal.Components.AddModeratorsDialog, props: { - friendList: this.friends, + friendList: this.contacts, chatName: this.chatName, onSubmit: this.onSubmit, onClose: this.close, diff --git a/libloki/api.js b/libloki/api.js index 179d0d426..5996cb717 100644 --- a/libloki/api.js +++ b/libloki/api.js @@ -100,13 +100,6 @@ await backgroundMessage.sendToNumber(pubKey, false); } - async function sendAutoFriendRequestMessage(pubKey) { - const autoFrMessage = textsecure.OutgoingMessage.buildAutoFriendRequestMessage( - pubKey - ); - await autoFrMessage.sendToNumber(pubKey, false); - } - function createPairingAuthorisationProtoMessage({ primaryDevicePubKey, secondaryDevicePubKey, @@ -322,7 +315,6 @@ window.libloki.api = { sendSessionEstablishedMessage, sendBackgroundMessage, - sendAutoFriendRequestMessage, sendSessionRequestsToMembers, sendPairingAuthorisation, createPairingAuthorisationProtoMessage, diff --git a/libloki/friends.js b/libloki/friends.js deleted file mode 100644 index 3912732b5..000000000 --- a/libloki/friends.js +++ /dev/null @@ -1,24 +0,0 @@ -/* global window */ - -// eslint-disable-next-line func-names -(function() { - // Possible conversation friend states - const friendRequestStatusEnum = Object.freeze({ - // New conversation, no messages sent or received - none: 0, - // This state is used to lock the input early while sending - pendingSend: 1, - // Friend request sent, awaiting response - requestSent: 2, - // Friend request received, awaiting user input - requestReceived: 3, - // We did it! - friends: 4, - // Friend Request sent but timed out - requestExpired: 5, - }); - - window.friends = { - friendRequestStatusEnum, - }; -})(); diff --git a/libloki/test/messages.js b/libloki/test/messages.js index 2e798911a..ff2ed3c4a 100644 --- a/libloki/test/messages.js +++ b/libloki/test/messages.js @@ -43,36 +43,4 @@ describe('Loki Messages', () => { ); }); }); - - describe('#autoFriendRequestMessage', () => { - it('structure is valid', () => { - const pubkey = - '05050505050505050505050505050505050505050505050505050505050505050'; - const autoFrMessage = window.textsecure.OutgoingMessage.buildAutoFriendRequestMessage( - pubkey - ); - - const validAutoFrObject = { - server: null, - numbers: [pubkey], - }; - - const validAutoFrMessage = { - syncMessage: null, - callMessage: null, - nullMessage: null, - receiptMessage: null, - typingMessage: null, - preKeyBundleMessage: null, - lokiAddressMessage: null, - pairingAuthorisation: null, - }; - - assert.isNumber(autoFrMessage.timestamp); - assert.isFunction(autoFrMessage.callback); - assert.deepInclude(autoFrMessage.message, validAutoFrMessage); - assert.isObject(autoFrMessage.message.dataMessage); - assert.deepInclude(autoFrMessage, validAutoFrObject); - }); - }); }); diff --git a/libtextsecure/account_manager.js b/libtextsecure/account_manager.js index e88c1581a..7124659bf 100644 --- a/libtextsecure/account_manager.js +++ b/libtextsecure/account_manager.js @@ -611,13 +611,6 @@ throw e; } - // Always be friends with secondary devices - await secondaryConversation.setFriendRequestStatus( - window.friends.friendRequestStatusEnum.friends, - { - blockSync: true, - } - ); // Send sync messages // bad hack to send sync messages when secondary device is ready to process them setTimeout(async () => { diff --git a/libtextsecure/outgoing_message.js b/libtextsecure/outgoing_message.js index a09f75645..1e3fb8bf4 100644 --- a/libtextsecure/outgoing_message.js +++ b/libtextsecure/outgoing_message.js @@ -2,7 +2,6 @@ textsecure, libsignal, window, - ConversationController, libloki, StringView, lokiMessageAPI, @@ -15,8 +14,8 @@ const NUM_SEND_CONNECTIONS = 3; const getTTLForType = type => { switch (type) { - case 'friend-request': - return 4 * 24 * 60 * 60 * 1000; // 4 days for friend request message + case 'session-request': + return 4 * 24 * 60 * 60 * 1000; // 4 days for session request message case 'device-unpairing': return 4 * 24 * 60 * 60 * 1000; // 4 days for device unpairing case 'onlineBroadcast': @@ -358,51 +357,11 @@ OutgoingMessage.prototype = { const updatedDevices = await getStaleDeviceIdsForNumber(devicePubKey); const keysFound = await this.getKeysForNumber(devicePubKey, updatedDevices); - // let isMultiDeviceRequest = false; - let thisDeviceMessageType = this.messageType; - if ( - thisDeviceMessageType !== 'pairing-request' && - thisDeviceMessageType !== 'friend-request' && - thisDeviceMessageType !== 'onlineBroadcast' - ) { - try { - const conversation = ConversationController.get(devicePubKey); - if (conversation && !this.isGroup) { - const isOurDevice = await conversation.isOurDevice(); - const isFriends = - conversation.isFriend() || conversation.hasReceivedFriendRequest(); - // We should only send a friend request to our device if we don't have keys - const shouldSendAutomatedFR = isOurDevice ? !keysFound : !isFriends; - if (shouldSendAutomatedFR) { - // We want to send an automated friend request if: - // - We aren't already friends - // - We haven't received a friend request from this device - // - We haven't sent a friend request recently - if (conversation.friendRequestTimerIsExpired()) { - // isMultiDeviceRequest = true; - thisDeviceMessageType = 'friend-request'; - } else { - // Throttle automated friend requests - this.successfulNumbers.push(devicePubKey); - return null; - } - } - // If we're not friends with our own device then we should become friends - if (isOurDevice && keysFound && !isFriends) { - conversation.setFriendRequestStatus( - window.friends.friendRequestStatusEnum.friends - ); - } - } - } catch (e) { - // do nothing - } - } // Check if we need to attach the preKeys const enableFallBackEncryption = - !keysFound || thisDeviceMessageType === 'friend-request'; + !keysFound || this.messageType === 'session-request'; const flags = this.message.dataMessage ? this.message.dataMessage.get_flags() : null; @@ -451,7 +410,7 @@ OutgoingMessage.prototype = { // FIXME options not used at all; if (ourPubkey === number) { // options.messageKeysLimit = false; // } - const ttl = getTTLForType(thisDeviceMessageType); + const ttl = getTTLForType(this.messageType); const ourKey = textsecure.storage.user.getNumber(); return { @@ -634,14 +593,6 @@ OutgoingMessage.prototype = { this.timestamp, ttl ); - - if (!this.isGroup && !isSessionRequest) { - const conversation = ConversationController.get(destination); - if (conversation) { - // Redundant for primary device but marks secondary devices as pending - await conversation.onFriendRequestSent(); - } - } this.successfulNumbers.push(destination); } catch (e) { e.number = destination; @@ -691,14 +642,7 @@ OutgoingMessage.prototype = { }, sendToNumber(number, multiDevice = true) { - let conversation; - try { - conversation = ConversationController.get(number); - } catch (e) { - // do nothing - } return this.reloadDevicesAndSend(number, multiDevice).catch(error => { - conversation.resetPendingSend(); if (error.message === 'Identity key changed') { // eslint-disable-next-line no-param-reassign error = new textsecure.OutgoingIdentityKeyError( @@ -719,32 +663,6 @@ OutgoingMessage.prototype = { }, }; -OutgoingMessage.buildAutoFriendRequestMessage = function buildAutoFriendRequestMessage( - pubKey -) { - const body = 'Please accept to enable messages to be synced across devices'; - const dataMessage = new textsecure.protobuf.DataMessage({ body }); - - const content = new textsecure.protobuf.Content({ - dataMessage, - }); - - const options = { - messageType: 'friend-request', - debugMessageType: DebugMessageType.AUTO_FR_REQUEST, - }; - // Send a empty message with information about how to contact us directly - return new OutgoingMessage( - null, // server - Date.now(), // timestamp, - [pubKey], // numbers - content, // message - true, // silent - () => null, // callback - options - ); -}; - OutgoingMessage.buildSessionRequestMessage = function buildSessionRequestMessage( pubKey ) { @@ -760,7 +678,7 @@ OutgoingMessage.buildSessionRequestMessage = function buildSessionRequestMessage }); const options = { - messageType: 'friend-request', + messageType: 'session-request', debugMessageType: DebugMessageType.SESSION_REQUEST, }; // Send a empty message with information about how to contact us directly diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index faae1af35..8e193a31d 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -440,7 +440,7 @@ MessageSender.prototype = { keysFound || options.isPublic || options.isMediumGroup || - options.messageType === 'friend-request' + options.messageType === 'session-request' ) { const outgoing = new OutgoingMessage( this.server, @@ -672,7 +672,7 @@ MessageSender.prototype = { c => c.isPrivate() && !c.isOurLocalDevice() && - c.isFriend() && + !c.isBlocked() && !c.get('secondaryStatus') ) || []; @@ -681,7 +681,7 @@ MessageSender.prototype = { c => c.isPrivate() && !c.isOurLocalDevice() && - c.isFriend() && + !c.isBlocked() && c.get('secondaryStatus') ); @@ -757,7 +757,7 @@ MessageSender.prototype = { c => c.isClosedGroup() && !c.get('left') && - c.isFriend() && + !c.isBlocked() && !c.isMediumGroup() ); if (sessionGroups.length === 0) { @@ -1177,12 +1177,6 @@ MessageSender.prototype = { throw error; }; - // Loki - Temp hack for new protocol - // A session reset should be a `SESSION_REQUEST` - const msgOptions = { - messageType: 'friend-request', - ...options, - }; // The actual deletion of the session now happens later // as we need to ensure the other contact has successfully @@ -1192,7 +1186,7 @@ MessageSender.prototype = { proto, timestamp, silent, - msgOptions + options ).catch(logError('resetSession/sendToContact error:')); }, diff --git a/test/backup_test.js b/test/backup_test.js index 7d7ef8eea..616dde667 100644 --- a/test/backup_test.js +++ b/test/backup_test.js @@ -565,7 +565,6 @@ describe('Backup', () => { const ommited = [ 'profileAvatar', 'swarmNodes', - 'friendRequestStatus', 'groupAdmins', 'isKickedFromGroup', 'unlockTimestamp', diff --git a/ts/components/ConversationListItem.tsx b/ts/components/ConversationListItem.tsx index b03d67ad4..3dcd827e2 100644 --- a/ts/components/ConversationListItem.tsx +++ b/ts/components/ConversationListItem.tsx @@ -39,13 +39,9 @@ export type PropsData = { isRss: boolean; }; - isPendingFriendRequest?: boolean; - hasReceivedFriendRequest?: boolean; - hasSentFriendRequest?: boolean; isBlocked?: boolean; isOnline?: boolean; hasNickname?: boolean; - isFriend?: boolean; isSecondary?: boolean; isGroupInvitation?: boolean; }; @@ -61,8 +57,6 @@ type PropsHousekeeping = { onClearNickname?: () => void; onCopyPublicKey?: () => void; onUnblockContact?: () => void; - acceptFriendRequest?: () => void; - declineFriendRequest?: () => void; }; type Props = PropsData & PropsHousekeeping; @@ -79,15 +73,11 @@ export class ConversationListItem extends React.PureComponent { phoneNumber, profileName, isOnline, - isPendingFriendRequest, - hasSentFriendRequest, } = this.props; - let borderColor; - if (!(isPendingFriendRequest && !hasSentFriendRequest)) { - borderColor = isOnline ? Colors.ONLINE : Colors.OFFLINE; - } - const iconSize = isPendingFriendRequest && !hasSentFriendRequest ? 28 : 36; + const borderColor = isOnline ? Colors.ONLINE : Colors.OFFLINE; + + const iconSize = 36; return (
@@ -132,8 +122,6 @@ export class ConversationListItem extends React.PureComponent { i18n, isMe, lastUpdated, - isFriend, - hasReceivedFriendRequest, } = this.props; return ( @@ -148,8 +136,8 @@ export class ConversationListItem extends React.PureComponent { > {isMe ? i18n('noteToSelf') : this.renderUser()}
- {hasReceivedFriendRequest || this.renderUnread()} - {isFriend && ( + {this.renderUnread()} + {(
{ : null )} > - {!hasReceivedFriendRequest && ( + {( { isTyping, unreadCount, i18n, - isPendingFriendRequest, } = this.props; if (!lastMessage && !isTyping) { @@ -245,10 +232,6 @@ export class ConversationListItem extends React.PureComponent { text = text.replace(/<[^>]*>?/gm, ''); } - if (isPendingFriendRequest) { - text = text.replace('Friend Request: ', ''); - } - if (isEmpty(text)) { return null; } @@ -287,24 +270,6 @@ export class ConversationListItem extends React.PureComponent { ); } - public renderFriendRequestButtons() { - const { acceptFriendRequest, declineFriendRequest } = this.props; - - return ( -
- - -
- ); - } - public render() { const { phoneNumber, @@ -312,7 +277,6 @@ export class ConversationListItem extends React.PureComponent { onClick, id, isSelected, - hasReceivedFriendRequest, isBlocked, style, mentionedUs, @@ -340,9 +304,6 @@ export class ConversationListItem extends React.PureComponent { ? 'module-conversation-list-item--mentioned-us' : null, isSelected ? 'module-conversation-list-item--is-selected' : null, - hasReceivedFriendRequest - ? 'module-conversation-list-item--has-friend-request' - : null, isBlocked ? 'module-conversation-list-item--is-blocked' : null )} > @@ -351,7 +312,6 @@ export class ConversationListItem extends React.PureComponent { {this.renderHeader()} {this.renderMessage()}
- {hasReceivedFriendRequest && this.renderFriendRequestButtons()} {this.renderContextMenu(triggerId)} diff --git a/ts/components/LeftPane.tsx b/ts/components/LeftPane.tsx index 88fe9b5da..d567c23ab 100644 --- a/ts/components/LeftPane.tsx +++ b/ts/components/LeftPane.tsx @@ -29,11 +29,9 @@ interface State { interface Props { conversations: Array; - friends: Array; - sentFriendsRequest: Array; - receivedFriendsRequest: Array; + contacts: Array; + unreadMessageCount: number; - receivedFriendRequestCount: number; searchResults?: SearchResultsProps; searchTerm: string; isSecondaryDevice: boolean; @@ -88,7 +86,6 @@ export class LeftPane extends React.Component { selectedSection={this.state.selectedSection} onSectionSelected={this.handleSectionSelected} conversations={this.props.conversations} - receivedFriendRequestCount={this.props.receivedFriendRequestCount} unreadMessageCount={this.props.unreadMessageCount} />
{this.renderSection()}
@@ -140,9 +137,6 @@ export class LeftPane extends React.Component { private renderContactSection() { const { openConversationInternal, - friends, - sentFriendsRequest, - receivedFriendsRequest, conversations, searchResults, searchTerm, @@ -150,23 +144,20 @@ export class LeftPane extends React.Component { updateSearchTerm, search, clearSearch, - receivedFriendRequestCount, + contacts, } = this.props; return ( ); } diff --git a/ts/components/SearchResults.tsx b/ts/components/SearchResults.tsx index cd6f1c04b..1e12e1b98 100644 --- a/ts/components/SearchResults.tsx +++ b/ts/components/SearchResults.tsx @@ -39,19 +39,16 @@ export class SearchResults extends React.Component { openConversation, searchTerm, showStartNewConversation, - friends, } = this.props; const haveConversations = conversations && conversations.length; const haveContacts = contacts && contacts.length; - const haveFriends = friends && friends.length; const haveMessages = messages && messages.length; const noResults = !showStartNewConversation && !haveConversations && !haveContacts && - !haveMessages && - !haveFriends; + !haveMessages; return (
@@ -75,8 +72,8 @@ export class SearchResults extends React.Component { ))}
) : null} - {haveFriends - ? this.renderContacts(i18n('friendsHeader'), friends, true) + {haveContacts + ? this.renderContacts(i18n('friendsHeader'), contacts, true) : null} {haveMessages ? ( @@ -102,7 +99,7 @@ export class SearchResults extends React.Component { private renderContacts( header: string, items: Array, - friends?: boolean + contacts?: boolean ) { const { i18n, openConversation } = this.props; @@ -112,7 +109,6 @@ export class SearchResults extends React.Component { {items.map(contact => ( { public render() { const { contacts, searchTerm } = this.props; - const friends = contacts.filter(contact => contact.isFriend); - const noResults = !friends || friends.length <= 0; + const noResults = !contacts || contacts.length <= 0; return (
@@ -29,7 +28,7 @@ export class UserSearchResults extends React.Component { {window.i18n('noSearchResults', [searchTerm])}
) : ( - this.renderContacts(friends) + this.renderContacts(contacts) )} ); @@ -38,12 +37,12 @@ export class UserSearchResults extends React.Component { private renderContacts(items: Array) { return (
- {items.map((friend, index) => this.renderFriend(friend, index))} + {items.map((contact, index) => this.renderContact(contact, index))}
); } - private renderFriend(contact: ConversationListItemPropsType, index: Number) { + private renderContact(contact: ConversationListItemPropsType, index: Number) { const { profileName, phoneNumber } = contact; const { selectedContact } = this.props; diff --git a/ts/components/conversation/FriendRequest.tsx b/ts/components/conversation/FriendRequest.tsx deleted file mode 100644 index 4033ec7fb..000000000 --- a/ts/components/conversation/FriendRequest.tsx +++ /dev/null @@ -1,210 +0,0 @@ -import React from 'react'; -import classNames from 'classnames'; - -import { LocalizerType } from '../../types/Util'; -import { MessageBody } from './MessageBody'; -import { Timestamp } from './Timestamp'; - -interface Props { - text: string; - direction: 'incoming' | 'outgoing'; - status: string; - friendStatus: 'pending' | 'accepted' | 'declined' | 'expired'; - i18n: LocalizerType; - isBlocked: boolean; - timestamp: number; - onAccept: () => void; - onDecline: () => void; - onDeleteConversation: () => void; - onRetrySend: () => void; - onBlockUser: () => void; - onUnblockUser: () => void; -} - -export class FriendRequest extends React.Component { - public getStringId() { - const { friendStatus } = this.props; - - switch (friendStatus) { - case 'pending': - return 'friendRequestPending'; - case 'accepted': - return 'friendRequestAccepted'; - case 'declined': - return 'friendRequestDeclined'; - case 'expired': - return 'friendRequestExpired'; - default: - throw new Error(`Invalid friend request status: ${friendStatus}`); - } - } - - public renderContents() { - const { direction, i18n, text } = this.props; - const id = this.getStringId(); - - return ( -
-
- {i18n(id)} -
-
- -
-
- ); - } - - public renderButtons() { - const { - i18n, - friendStatus, - direction, - status, - onAccept, - onDecline, - onDeleteConversation, - onRetrySend, - isBlocked, - onBlockUser, - onUnblockUser, - } = this.props; - - if (direction === 'incoming') { - if (friendStatus === 'pending') { - return ( -
- - -
- ); - } else if (friendStatus === 'declined') { - const blockTitle = isBlocked ? i18n('unblockUser') : i18n('blockUser'); - const blockHandler = isBlocked ? onUnblockUser : onBlockUser; - - return ( -
- - -
- ); - } - } else { - // Render the retry button if we errored - if (status === 'error' && friendStatus === 'pending') { - return ( -
- -
- ); - } - } - - return null; - } - - public renderError(isCorrectSide: boolean) { - const { status, direction } = this.props; - - if (!isCorrectSide || status !== 'error') { - return null; - } - - return ( -
-
-
- ); - } - - // Renders 'sending', 'read' icons - public renderStatusIndicator() { - const { direction, status, i18n, text, timestamp } = this.props; - if (status === 'error') { - return null; - } - - const withImageNoCaption = Boolean(!text); - - return ( -
- - -
-
- ); - } - - public render() { - const { direction } = this.props; - - return ( -
-
- {this.renderError(direction === 'incoming')} -
-
- {this.renderContents()} - {this.renderStatusIndicator()} - {this.renderButtons()} -
-
- {this.renderError(direction === 'outgoing')} -
-
- ); - } -} diff --git a/ts/components/session/ActionsPanel.tsx b/ts/components/session/ActionsPanel.tsx index 215560583..d2d28fe62 100644 --- a/ts/components/session/ActionsPanel.tsx +++ b/ts/components/session/ActionsPanel.tsx @@ -21,7 +21,6 @@ interface Props { selectedSection: SectionType; conversations: Array | undefined; unreadMessageCount: number; - receivedFriendRequestCount: number; } export class ActionsPanel extends React.Component { @@ -130,7 +129,6 @@ export class ActionsPanel extends React.Component { const { selectedSection, unreadMessageCount, - receivedFriendRequestCount, } = this.props; const isProfilePageSelected = selectedSection === SectionType.Profile; @@ -157,7 +155,6 @@ export class ActionsPanel extends React.Component { type={SectionType.Contact} isSelected={isContactPageSelected} onSelect={this.handleSectionSelect} - notificationCount={receivedFriendRequestCount} /> ; - friends: Array; - receivedFriendsRequest: Array; - receivedFriendRequestCount: number; - sentFriendsRequest: Array; + contacts: Array; searchResults?: SearchResultsProps; @@ -45,7 +42,6 @@ interface State { showAddContactView: boolean; selectedTab: number; addContactRecipientID: string; - showFriendRequestsPopup: boolean; pubKeyPasted: string; } @@ -59,7 +55,6 @@ export class LeftPaneContactSection extends React.Component { selectedTab: 0, addContactRecipientID: '', pubKeyPasted: '', - showFriendRequestsPopup: false, }; this.debouncedSearch = debounce(this.search.bind(this), 20); @@ -69,9 +64,6 @@ export class LeftPaneContactSection extends React.Component { this.handleRecipientSessionIDChanged = this.handleRecipientSessionIDChanged.bind( this ); - this.handleToggleFriendRequestPopup = this.handleToggleFriendRequestPopup.bind( - this - ); } public componentWillUnmount() { @@ -84,17 +76,15 @@ export class LeftPaneContactSection extends React.Component { } public renderHeader(): JSX.Element | undefined { - const { receivedFriendRequestCount } = this.props; - // The feature "organize your friends as custom list" is not included in the first release - const labels = [window.i18n('contactsHeader') /*, window.i18n('lists')*/]; + const labels = [window.i18n('contactsHeader')]; return LeftPane.RENDER_HEADER( labels, this.handleTabSelected, undefined, undefined, - this.handleToggleFriendRequestPopup, - receivedFriendRequestCount + undefined, + undefined ); } @@ -117,37 +107,14 @@ export class LeftPaneContactSection extends React.Component { ); } - public renderRowFriendRequest = ({ - index, - key, - style, - }: RowRendererParamsType): JSX.Element | undefined => { - const receivedFriendsRequest = this.props.receivedFriendsRequest; - - const item = receivedFriendsRequest[index]; - const onClick = this.props.openConversationInternal; - - return ( - - ); - }; public renderRow = ({ index, key, style, }: RowRendererParamsType): JSX.Element | undefined => { - const { sentFriendsRequest } = this.props; - const contacts = this.props.friends.filter(f => f.type === 'direct'); - const friends = contacts.filter(c => c.isFriend); - const combined = [...sentFriendsRequest, ...friends]; - const item = combined[index]; + const contacts = this.getDirectContactsOnly(); + const item = contacts[index]; return ( { })); } - private handleToggleFriendRequestPopup() { - this.setState((prevState: { showFriendRequestsPopup: boolean }) => ({ - showFriendRequestsPopup: !prevState.showFriendRequestsPopup, - })); - } private handleOnAddContact() { const sessionID = this.state.addContactRecipientID.trim(); @@ -248,16 +210,9 @@ export class LeftPaneContactSection extends React.Component { } private renderContacts() { - const { showFriendRequestsPopup } = this.state; - const hasReceivedFriendRequest = - this.props.receivedFriendsRequest.length > 0; - return (
{this.renderList()} - {showFriendRequestsPopup && - hasReceivedFriendRequest && - this.renderFriendRequestPopup()} {this.renderBottomButtons()}
); @@ -298,40 +253,13 @@ export class LeftPaneContactSection extends React.Component { ); } - private renderFriendRequestPopup() { - const frTitle = window.i18n('youHaveFriendRequestFrom'); - const length = this.props.receivedFriendsRequest.length; - - return ( -
-
{frTitle}
-
- - {({ height, width }) => ( - - )} - -
-
- ); + private getDirectContactsOnly() { + return this.props.contacts.filter(f => f.type === 'direct'); } private renderList() { - const { sentFriendsRequest } = this.props; - - const contacts = this.props.friends.filter(f => f.type === 'direct'); - const friends = contacts.filter(c => c.isFriend); - const length = Number(sentFriendsRequest.length) + Number(friends.length); - - const combined = [...sentFriendsRequest, ...friends]; + const contacts = this.getDirectContactsOnly(); + const length = Number(contacts.length); const list = (
@@ -341,7 +269,6 @@ export class LeftPaneContactSection extends React.Component { className="module-left-pane__virtual-list" height={height} rowCount={length} - combined={combined} rowHeight={64} rowRenderer={this.renderRow} width={width} diff --git a/ts/components/session/LeftPaneMessageSection.tsx b/ts/components/session/LeftPaneMessageSection.tsx index d390b9a5c..b05b7c6d7 100644 --- a/ts/components/session/LeftPaneMessageSection.tsx +++ b/ts/components/session/LeftPaneMessageSection.tsx @@ -119,7 +119,7 @@ export class LeftPaneMessageSection extends React.Component { if (conversationList !== undefined) { conversationList = conversationList.filter( conversation => - !conversation.isPendingFriendRequest && !conversation.isSecondary + !conversation.isSecondary ); } @@ -154,16 +154,13 @@ export class LeftPaneMessageSection extends React.Component { public renderList(): JSX.Element | Array { const { openConversationInternal, searchResults } = this.props; - const friends = - (searchResults && - searchResults.contacts.filter(contact => contact.isFriend)) || - []; + const contacts = searchResults?.contacts || []; if (searchResults) { return ( diff --git a/ts/components/session/SessionClosableOverlay.tsx b/ts/components/session/SessionClosableOverlay.tsx index 8c26927d7..74f702e5a 100644 --- a/ts/components/session/SessionClosableOverlay.tsx +++ b/ts/components/session/SessionClosableOverlay.tsx @@ -72,8 +72,7 @@ export class SessionClosableOverlay extends React.Component { return ( !conversation.isMe() && conversation.isPrivate() && - !conversation.isSecondaryDevice() && - conversation.isFriend() + !conversation.isSecondaryDevice() ); }); diff --git a/ts/global.d.ts b/ts/global.d.ts index 500047422..c055d9e7c 100644 --- a/ts/global.d.ts +++ b/ts/global.d.ts @@ -38,7 +38,6 @@ interface Window { Session: any; log: any; i18n: any; - friends: any; generateID: any; storage: any; pushToast: any; diff --git a/ts/session/protocols/SessionProtocol.ts b/ts/session/protocols/SessionProtocol.ts index da0f95129..e2b8f4b61 100644 --- a/ts/session/protocols/SessionProtocol.ts +++ b/ts/session/protocols/SessionProtocol.ts @@ -18,7 +18,7 @@ export class SessionProtocol { * This map should not be used directly, but instead through * `updateSendSessionTimestamp()`, or `hasSendSessionRequest()` */ - private static sentSessionsTimestamp: StringToNumberMap; + private static sentSessionsTimestamp: StringToNumberMap = {}; /** * This map olds the processed session timestamps, i.e. when we received a session request and handled it. @@ -26,7 +26,7 @@ export class SessionProtocol { * This map should not be used directly, but instead through * `updateProcessedSessionTimestamp()`, `getProcessedSessionRequest()` or `hasProcessedSessionRequest()` */ - private static processedSessionsTimestamp: StringToNumberMap; + private static processedSessionsTimestamp: StringToNumberMap = {}; /** * This map olds the timestamp on which a sent session reset is triggered for a specific device. @@ -179,6 +179,8 @@ export class SessionProtocol { if (!SessionProtocol.dbLoaded) { const sentItem = await getItemById('sentSessionsTimestamp'); if (sentItem) { + // FIXME we must update the existing map with those items + // or empty the existing map, not create a new one SessionProtocol.sentSessionsTimestamp = sentItem.value; } else { SessionProtocol.sentSessionsTimestamp = {}; diff --git a/ts/session/sending/MessageQueue.ts b/ts/session/sending/MessageQueue.ts index 43746d09f..6142c780f 100644 --- a/ts/session/sending/MessageQueue.ts +++ b/ts/session/sending/MessageQueue.ts @@ -133,7 +133,7 @@ export class MessageQueue implements MessageQueueInterface { const messages = this.pendingMessageCache.getForDevice(device); const isMediumGroup = GroupUtils.isMediumGroup(device); - const hasSession = SessionProtocol.hasSession(device); + const hasSession = await SessionProtocol.hasSession(device); if (!isMediumGroup && !hasSession) { await SessionProtocol.sendSessionRequestIfNeeded(device); diff --git a/ts/session/utils/SyncMessageUtils.ts b/ts/session/utils/SyncMessageUtils.ts index 92c1116c0..f2b01ca2f 100644 --- a/ts/session/utils/SyncMessageUtils.ts +++ b/ts/session/utils/SyncMessageUtils.ts @@ -41,7 +41,7 @@ export async function getSyncContacts(): Promise | undefined> { c => c.isPrivate() && !c.isOurLocalDevice() && - c.isFriend() && + !c.isBlocked() && !c.attributes.secondaryStatus ) || []; @@ -49,7 +49,7 @@ export async function getSyncContacts(): Promise | undefined> { c => c.isPrivate() && !c.isOurLocalDevice() && - c.isFriend() && + !c.isBlocked() && c.attributes.secondaryStatus ); diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index 2305cae6d..80c2ddc47 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -52,12 +52,8 @@ export type ConversationType = { mentionedUs: boolean; isSelected: boolean; isTyping: boolean; - isFriend?: boolean; isSecondary?: boolean; primaryDevice: string; - isPendingFriendRequest?: boolean; - hasReceivedFriendRequest?: boolean; - hasSentFriendRequest?: boolean; }; export type ConversationLookupType = { [key: string]: ConversationType; diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index 0ea4e6ce7..d0f8ba3c2 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -97,9 +97,7 @@ export const _getLeftPaneLists = ( ): { conversations: Array; archivedConversations: Array; - friends: Array; - receivedFriendsRequest: Array; - sentFriendsRequest: Array; + contacts: Array; unreadCount: number; } => { const values = Object.values(lookup); @@ -107,9 +105,7 @@ export const _getLeftPaneLists = ( const conversations: Array = []; const archivedConversations: Array = []; - const allFriends: Array = []; - const allReceivedFriendsRequest: Array = []; - const allSentFriendsRequest: Array = []; + const allContacts: Array = []; const max = sorted.length; let unreadCount = 0; @@ -124,34 +120,16 @@ export const _getLeftPaneLists = ( }; } - if (conversation.isFriend && conversation.activeAt !== undefined) { - allFriends.push(conversation); + if (conversation.activeAt !== undefined) { + allContacts.push(conversation); } - if (conversation.hasReceivedFriendRequest) { - // Friend requests should always appear as coming from primary - const primaryConversation = - conversations.find(c => c.id === conversation.primaryDevice) || - conversation; - primaryConversation.hasReceivedFriendRequest = - conversation.hasReceivedFriendRequest; - primaryConversation.isPendingFriendRequest = - conversation.isPendingFriendRequest; - allReceivedFriendsRequest.push(primaryConversation); - } else if ( + if ( unreadCount < 9 && - conversation.isFriend && conversation.unreadCount > 0 ) { unreadCount += conversation.unreadCount; } - if (conversation.hasSentFriendRequest) { - if (!conversation.isFriend) { - if (!conversation.isSecondary) { - allSentFriendsRequest.push(conversation); - } - } - } if (!conversation.activeAt) { continue; @@ -191,20 +169,12 @@ export const _getLeftPaneLists = ( return filteredGroup as T; }; - const friends: Array = filterToPrimary(allFriends); - const receivedFriendsRequest: Array = filterToPrimary( - allReceivedFriendsRequest - ); - const sentFriendsRequest: Array = filterToPrimary( - allSentFriendsRequest - ); + const contacts: Array = filterToPrimary(allContacts); return { conversations, archivedConversations, - friends, - receivedFriendsRequest, - sentFriendsRequest, + contacts, unreadCount, }; }; diff --git a/ts/state/selectors/search.ts b/ts/state/selectors/search.ts index 2725af29f..2b2436e53 100644 --- a/ts/state/selectors/search.ts +++ b/ts/state/selectors/search.ts @@ -82,21 +82,6 @@ export const getSearchResults = createSelector( return value; }) ), - friends: compact( - state.conversations.map(id => { - const value = lookup[id]; - const friend = value && value.isFriend ? { ...value } : null; - - if (friend && id === selectedConversation) { - return { - ...friend, - isSelected: true, - }; - } - - return friend; - }) - ), hideMessagesHeader: false, messages: state.messages.map(message => { if (message.id === selectedMessage) { diff --git a/ts/state/smart/LeftPane.tsx b/ts/state/smart/LeftPane.tsx index ed326c6f5..97a0d73f7 100644 --- a/ts/state/smart/LeftPane.tsx +++ b/ts/state/smart/LeftPane.tsx @@ -32,7 +32,6 @@ const mapStateToProps = (state: StateType) => { showArchived: getShowArchived(state), i18n: getIntl(state), unreadMessageCount: leftPaneList.unreadCount, - receivedFriendRequestCount: leftPaneList.receivedFriendsRequest.length, }; };