diff --git a/app/sql.js b/app/sql.js index 23da7f554..5b882a325 100644 --- a/app/sql.js +++ b/app/sql.js @@ -49,7 +49,7 @@ module.exports = { getContactPreKeys, getAllContactPreKeys, bulkAddContactPreKeys, - removeContactPreKeyById, + removeContactPreKeyByIdentityKey, removeAllContactPreKeys, createOrUpdateContactSignedPreKey, @@ -57,7 +57,7 @@ module.exports = { getContactSignedPreKeyByIdentityKey, getContactSignedPreKeys, bulkAddContactSignedPreKeys, - removeContactSignedPreKeyById, + removeContactSignedPreKeyByIdentityKey, removeAllContactSignedPreKeys, createOrUpdateItem, @@ -712,8 +712,10 @@ async function getContactPreKeys(keyId, identityKeyString) { async function bulkAddContactPreKeys(array) { return bulkAdd(CONTACT_PRE_KEYS_TABLE, array); } -async function removeContactPreKeyById(id) { - return removeById(CONTACT_PRE_KEYS_TABLE, id); +async function removeContactPreKeyByIdentityKey(key) { + await db.run(`DELETE FROM ${CONTACT_PRE_KEYS_TABLE} WHERE identityKeyString = $identityKeyString;`, { + $identityKeyString: key, + }); } async function removeAllContactPreKeys() { return removeAllFromTable(CONTACT_PRE_KEYS_TABLE); @@ -765,8 +767,10 @@ async function getContactSignedPreKeys(keyId, identityKeyString) { async function bulkAddContactSignedPreKeys(array) { return bulkAdd(CONTACT_SIGNED_PRE_KEYS_TABLE, array); } -async function removeContactSignedPreKeyById(id) { - return removeById(CONTACT_SIGNED_PRE_KEYS_TABLE, id); +async function removeContactSignedPreKeyByIdentityKey(key) { + await db.run(`DELETE FROM ${CONTACT_SIGNED_PRE_KEYS_TABLE} WHERE identityKeyString = $identityKeyString;`, { + $identityKeyString: key, + }); } async function removeAllContactSignedPreKeys() { return removeAllFromTable(CONTACT_SIGNED_PRE_KEYS_TABLE); diff --git a/js/background.js b/js/background.js index 2137da46a..c772ba62a 100644 --- a/js/background.js +++ b/js/background.js @@ -1268,7 +1268,6 @@ unidentifiedDeliveryReceived: data.unidentifiedDeliveryReceived, type: 'incoming', unread: 1, - preKeyBundle: data.preKeyBundle || null, }; if (data.type === 'friend-request') { diff --git a/js/modules/data.js b/js/modules/data.js index a31ed1c74..f61ccfdd5 100644 --- a/js/modules/data.js +++ b/js/modules/data.js @@ -80,7 +80,7 @@ module.exports = { getContactPreKeys, getAllContactPreKeys, bulkAddContactPreKeys, - removeContactPreKeyById, + removeContactPreKeyByIdentityKey, removeAllContactPreKeys, createOrUpdateContactSignedPreKey, @@ -88,7 +88,7 @@ module.exports = { getContactSignedPreKeyByIdentityKey, getContactSignedPreKeys, bulkAddContactSignedPreKeys, - removeContactSignedPreKeyById, + removeContactSignedPreKeyByIdentityKey, removeAllContactSignedPreKeys, createOrUpdateItem, @@ -528,8 +528,8 @@ async function bulkAddContactPreKeys(array) { const updated = map(array, data => keysFromArrayBuffer(PRE_KEY_KEYS, data)); await channels.bulkAddContactPreKeys(updated); } -async function removeContactPreKeyById(id) { - await channels.removePreContactKeyById(id); +async function removeContactPreKeyByIdentityKey(id) { + await channels.removeContactPreKeyByIdentityKey(id); } async function removeAllContactPreKeys() { await channels.removeAllContactPreKeys(); @@ -556,8 +556,8 @@ async function bulkAddContactSignedPreKeys(array) { const updated = map(array, data => keysFromArrayBuffer(PRE_KEY_KEYS, data)); await channels.bulkAddContactSignedPreKeys(updated); } -async function removeContactSignedPreKeyById(id) { - await channels.removePreContactSignedKeyById(id); +async function removeContactSignedPreKeyByIdentityKey(id) { + await channels.removeContactSignedPreKeyByIdentityKey(id); } async function removeAllContactSignedPreKeys() { await channels.removeAllContactSignedPreKeys(); @@ -727,7 +727,6 @@ async function searchConversations(query, { ConversationCollection }) { } // Message -const MESSAGE_PRE_KEYS = ['identityKey', 'preKey', 'signature', 'signedKey'].map(k => `preKeyBundle.${k}`); async function getMessageCount() { return channels.getMessageCount(); } @@ -745,8 +744,7 @@ async function saveSeenMessageHash(data) { } async function saveMessage(data, { forceSave, Message } = {}) { - const updated = keysFromArrayBuffer(MESSAGE_PRE_KEYS, data); - const id = await channels.saveMessage(_cleanData(updated), { forceSave }); + const id = await channels.saveMessage(_cleanData(data), { forceSave }); Message.refreshExpirationTimer(); return id; } @@ -789,8 +787,7 @@ async function saveLegacyMessage(data) { } async function saveMessages(arrayOfMessages, { forceSave } = {}) { - const updated = arrayOfMessages.map(m => keysFromArrayBuffer(MESSAGE_PRE_KEYS, m)); - await channels.saveMessages(_cleanData(updated), { forceSave }); + await channels.saveMessages(_cleanData(arrayOfMessages), { forceSave }); } async function removeMessage(id, { Message }) { @@ -815,22 +812,18 @@ async function getMessageById(id, { Message }) { return null; } - const encoded = keysToArrayBuffer(MESSAGE_PRE_KEYS, message); - - return new Message(encoded); + return new Message(message); } // For testing only async function getAllMessages({ MessageCollection }) { const messages = await channels.getAllMessages(); - const encoded = messages.map(m => keysToArrayBuffer(MESSAGE_PRE_KEYS, m)); - return new MessageCollection(encoded); + return new MessageCollection(messages); } async function getAllUnsentMessages({ MessageCollection }) { const messages = await channels.getAllUnsentMessages(); - const encoded = messages.map(m => keysToArrayBuffer(MESSAGE_PRE_KEYS, m)); - return new MessageCollection(encoded); + return new MessageCollection(messages); } async function getAllMessageIds() { @@ -852,9 +845,7 @@ async function getMessageBySender( return null; } - const encoded = keysToArrayBuffer(MESSAGE_PRE_KEYS, messages[0]); - - return new Message(encoded); + return new Message(messages[0]); } async function getUnreadByConversation(conversationId, { MessageCollection }) { @@ -872,9 +863,7 @@ async function getMessagesByConversation( type, }); - const encoded = messages.map(m => keysToArrayBuffer(MESSAGE_PRE_KEYS, m)); - - return new MessageCollection(encoded); + return new MessageCollection(messages); } async function getSeenMessagesByHashList( @@ -916,26 +905,22 @@ async function removeAllMessagesInConversation( async function getMessagesBySentAt(sentAt, { MessageCollection }) { const messages = await channels.getMessagesBySentAt(sentAt); - const encoded = messages.map(m => keysToArrayBuffer(MESSAGE_PRE_KEYS, m)); - return new MessageCollection(encoded); + return new MessageCollection(messages); } async function getExpiredMessages({ MessageCollection }) { const messages = await channels.getExpiredMessages(); - const encoded = messages.map(m => keysToArrayBuffer(MESSAGE_PRE_KEYS, m)); - return new MessageCollection(encoded); + return new MessageCollection(messages); } async function getOutgoingWithoutExpiresAt({ MessageCollection }) { const messages = await channels.getOutgoingWithoutExpiresAt(); - const encoded = messages.map(m => keysToArrayBuffer(MESSAGE_PRE_KEYS, m)); - return new MessageCollection(encoded); + return new MessageCollection(messages); } async function getNextExpiringMessage({ MessageCollection }) { const messages = await channels.getNextExpiringMessage(); - const encoded = messages.map(m => keysToArrayBuffer(MESSAGE_PRE_KEYS, m)); - return new MessageCollection(encoded); + return new MessageCollection(messages); } // Unprocessed diff --git a/js/signal_protocol_store.js b/js/signal_protocol_store.js index 80185d238..6e7bc52c3 100644 --- a/js/signal_protocol_store.js +++ b/js/signal_protocol_store.js @@ -162,7 +162,7 @@ }, async getLocalRegistrationId() { return 1; - + // const item = await window.Signal.Data.getItemById('registrationId'); // if (item) { // return item.value; @@ -197,6 +197,8 @@ recipient: key.recipient, }; } + + return undefined; }, async loadContactPreKey(pubKey) { const preKey = await window.Signal.Data.getContactPreKeyByIdentityKey(pubKey); @@ -266,6 +268,13 @@ await window.Signal.Data.removeAllPreKeys(); }, + async removeContactPreKey(pubKey) { + await window.Signal.Data.removeContactPreKeyByIdentityKey(pubKey); + }, + async clearContactPreKeysStore() { + await window.Signal.Data.removeAllContactPreKeys(); + }, + /* Returns a signed keypair object or undefined */ async loadSignedPreKey(keyId) { const key = await window.Signal.Data.getSignedPreKeyById(keyId); @@ -366,6 +375,13 @@ await window.Signal.Data.removeAllSignedPreKeys(); }, + async removeContactSignedPreKey(pubKey) { + await window.Signal.Data.removeContactSignedPreKeyByIdentityKey(pubKey); + }, + async clearContactSignedPreKeysStore() { + await window.Signal.Data.removeAllContactSignedPreKeys(); + }, + async loadSession(encodedNumber) { if (encodedNumber === null || encodedNumber === undefined) { throw new Error('Tried to get session for undefined/null number'); diff --git a/libloki/libloki-protocol.js b/libloki/libloki-protocol.js index 204a36c9c..0a78f0ca0 100644 --- a/libloki/libloki-protocol.js +++ b/libloki/libloki-protocol.js @@ -98,51 +98,37 @@ signedKey, signature, }) { - const signedKeyPromise = new Promise(async resolve => { - const existingSignedKeys = await textsecure.storage.protocol.loadContactSignedPreKeys( - { identityKeyString: pubKey, keyId: signedKeyId } - ); - if ( - !existingSignedKeys || - (existingSignedKeys instanceof Array && existingSignedKeys.length === 0) - ) { - const signedPreKey = { - keyId: signedKeyId, - publicKey: signedKey, - signature, - }; - await textsecure.storage.protocol.storeContactSignedPreKey( - pubKey, - signedPreKey - ); - } - resolve(); - }); + const signedPreKey = { + keyId: signedKeyId, + publicKey: signedKey, + signature, + }; - const preKeyPromise = new Promise(async resolve => { - const existingPreKeys = await textsecure.storage.protocol.loadContactPreKeys({ - identityKeyString: pubKey, - keyId: preKeyId, - }); - if ( - !existingPreKeys || - (existingPreKeys instanceof Array && existingPreKeys.length === 0) - ) { - const preKeyObject = { - publicKey: preKey, - keyId: preKeyId, - }; - await textsecure.storage.protocol.storeContactPreKey( - pubKey, - preKeyObject - ); - } - resolve(); - }); + const signedKeyPromise = textsecure.storage.protocol.storeContactSignedPreKey( + pubKey, + signedPreKey + ); + + const preKeyObject = { + publicKey: preKey, + keyId: preKeyId, + }; + + const preKeyPromise = textsecure.storage.protocol.storeContactPreKey( + pubKey, + preKeyObject + ); await Promise.all([signedKeyPromise, preKeyPromise]); } + async function removePreKeyBundleForNumber(pubKey) { + await Promise.all([ + textsecure.storage.protocol.removeContactPreKey(pubKey), + textsecure.storage.protocol.removeContactSignedPreKey(pubKey), + ]); + } + async function sendFriendRequestAccepted(pubKey) { // empty content message const content = new textsecure.protobuf.Content(); @@ -175,5 +161,6 @@ window.libloki.getPreKeyBundleForNumber = getPreKeyBundleForNumber; window.libloki.FallBackDecryptionError = FallBackDecryptionError; window.libloki.savePreKeyBundleForNumber = savePreKeyBundleForNumber; + window.libloki.removePreKeyBundleForNumber = removePreKeyBundleForNumber; window.libloki.sendFriendRequestAccepted = sendFriendRequestAccepted; })(); diff --git a/libtextsecure/account_manager.js b/libtextsecure/account_manager.js index 52ea87b62..8c91f44af 100644 --- a/libtextsecure/account_manager.js +++ b/libtextsecure/account_manager.js @@ -328,7 +328,7 @@ textsecure.storage.remove('userAgent'), textsecure.storage.remove('read-receipts-setting'), ]); - + // update our own identity key, which may have changed // if we're relinking after a reinstall on the master device await textsecure.storage.protocol.saveIdentityWithAttributes(pubKeyString, { @@ -362,7 +362,9 @@ window.log.info('clearing all sessions, prekeys, and signed prekeys'); return Promise.all([ store.clearPreKeyStore(), + store.clearContactPreKeysStore(), store.clearSignedPreKeysStore(), + store.clearContactSignedPreKeysStore(), store.clearSessionStore(), ]); }, diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 28b3ad11c..be8cfdb06 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -721,15 +721,11 @@ MessageReceiver.prototype.extend({ // eslint-disable-next-line no-param-reassign envelope.preKeyBundleMessage = decodedBundle; - // Save the preKey bundle if this is not a friend request. - // We don't automatically save on a friend request because - // we only want to save the preKeys when we click the accept button. - if (envelope.type !== textsecure.protobuf.Envelope.Type.FRIEND_REQUEST) { - await this.handlePreKeyBundleMessage( - envelope.source, - envelope.preKeyBundleMessage - ); - } + // Save the preKeyBundle + await this.handlePreKeyBundleMessage( + envelope.source, + envelope.preKeyBundleMessage + ); } const me = { @@ -970,7 +966,6 @@ MessageReceiver.prototype.extend({ receivedAt: envelope.receivedAt, unidentifiedDeliveryReceived: envelope.unidentifiedDeliveryReceived, message, - preKeyBundle: envelope.preKeyBundleMessage || null, }; return this.dispatchAndWait(ev); }) @@ -1010,24 +1005,23 @@ MessageReceiver.prototype.extend({ await conversation.updateTextInputState(); } - // If we accepted an incoming friend request then save the preKeyBundle - if (message.direction === 'incoming' && message.friendStatus === 'accepted') { - // Register the preKeys used for communication - if (message.preKeyBundle) { - await this.handlePreKeyBundleMessage( - pubKey, - message.preKeyBundle - ); - } + // Check if we changed the state of the incoming friend request + if (message.direction === 'incoming') { + // If we accepted an incoming friend request then update our state + if (message.friendStatus === 'accepted') { + // Accept the friend request + if (conversation) { + await conversation.onFriendRequestAccepted(); + } - // Accept the friend request - if (conversation) { - await conversation.onFriendRequestAccepted(); + // Send a reply back + libloki.sendFriendRequestAccepted(pubKey); + } else if (message.friendStatus === 'declined') { + // Delete the preKeys + await libloki.removePreKeyBundleForNumber(pubKey); } - - // Send a reply back - libloki.sendFriendRequestAccepted(pubKey); } + window.log.info(`Friend request for ${pubKey} was ${message.friendStatus}`, message); }, async innerHandleContentMessage(envelope, plaintext) {