From ee0b0f5ffb26a96914d766a2b28682dbaad9eeb0 Mon Sep 17 00:00:00 2001 From: Scott Nonnenberg Date: Thu, 8 Jun 2017 18:08:41 -0700 Subject: [PATCH] Remove all concept of 'key conflict' from the app --- _locales/en/messages.json | 6 --- background.html | 34 ++------------- js/models/conversations.js | 33 -------------- js/models/messages.js | 60 -------------------------- js/views/contact_list_view.js | 1 + js/views/error_view.js | 44 ------------------- js/views/group_member_list_view.js | 5 +++ js/views/key_conflict_dialogue_view.js | 53 ----------------------- js/views/key_verification_view.js | 12 +++--- js/views/message_detail_view.js | 17 +------- js/views/new_group_update_view.js | 1 + stylesheets/_conversation.scss | 49 +-------------------- stylesheets/manifest.css | 37 +--------------- test/index.html | 54 ++++------------------- test/models/messages_test.js | 22 +--------- 15 files changed, 28 insertions(+), 400 deletions(-) delete mode 100644 js/views/key_conflict_dialogue_view.js diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 25c1fd9d81..c10fa49789 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -69,12 +69,6 @@ "identityChanged": { "message": "Your safety number with this contact has changed. This could either mean that someone is trying to intercept your communication, or this contact simply reinstalled Signal. You may wish to verify the new safety number below." }, - "outgoingKeyConflict": { - "message": "Your safety number with this contact has changed. Click to process and display." - }, - "incomingKeyConflict": { - "message": "Received message with a new safety number. Click to process and display." - }, "incomingError": { "message": "Error handling incoming message." }, diff --git a/background.html b/background.html index 0fc15339c7..eb127d8ce5 100644 --- a/background.html +++ b/background.html @@ -280,12 +280,6 @@ - - - - diff --git a/js/models/conversations.js b/js/models/conversations.js index 2f947bf438..a6b9a54179 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -512,39 +512,6 @@ }.bind(this)); }, - resolveConflicts: function(conflict) { - var number = conflict.number; - var identityKey = conflict.identityKey; - if (this.isPrivate()) { - number = this.id; - } else if (!_.include(this.get('members'), number)) { - throw 'Tried to resolve conflicts for a unknown group member'; - } - - if (!this.messageCollection.hasKeyConflicts()) { - throw 'No conflicts to resolve'; - } - - return textsecure.storage.protocol.saveIdentity(number, identityKey, true).then(function() { - var promise = Promise.resolve(); - var conflicts = this.messageCollection.filter(function(message) { - return message.hasKeyConflict(number); - }); - // group incoming & outgoing - conflicts = _.groupBy(conflicts, function(m) { return m.get('type'); }); - // sort each group by date and concatenate outgoing after incoming - conflicts = _.flatten([ - _.sortBy(conflicts.incoming, function(m) { return m.get('received_at'); }), - _.sortBy(conflicts.outgoing, function(m) { return m.get('received_at'); }), - ]).forEach(function(message) { - var resolveConflict = function() { - return message.resolveConflict(number); - }; - promise = promise.then(resolveConflict, resolveConflict); - }); - return promise; - }.bind(this)); - }, notify: function(message) { if (!message.isIncoming()) { return; diff --git a/js/models/messages.js b/js/models/messages.js index 23840ff37e..7a9b2cf38c 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -88,9 +88,6 @@ if (this.isEndSession()) { return i18n('sessionEnded'); } - if (this.isIncoming() && this.hasKeyConflicts()) { - return i18n('incomingKeyConflict'); - } if (this.isIncoming() && this.hasErrors()) { return i18n('incomingError'); } @@ -191,26 +188,6 @@ hasErrors: function() { return _.size(this.get('errors')) > 0; }, - hasKeyConflicts: function() { - return _.any(this.get('errors'), function(e) { - return (e.name === 'IncomingIdentityKeyError' || - e.name === 'OutgoingIdentityKeyError'); - }); - }, - hasKeyConflict: function(number) { - return _.any(this.get('errors'), function(e) { - return (e.name === 'IncomingIdentityKeyError' || - e.name === 'OutgoingIdentityKeyError') && - e.number === number; - }); - }, - getKeyConflict: function(number) { - return _.find(this.get('errors'), function(e) { - return (e.name === 'IncomingIdentityKeyError' || - e.name === 'OutgoingIdentityKeyError') && - e.number === number; - }); - }, send: function(promise) { this.trigger('pending'); @@ -281,15 +258,6 @@ return this.save({errors : errors}); }, - removeConflictFor: function(number) { - var errors = _.reject(this.get('errors'), function(e) { - return e.number === number && - (e.name === 'IncomingIdentityKeyError' || - e.name === 'OutgoingIdentityKeyError'); - }); - this.set({errors: errors}); - }, - hasNetworkError: function(number) { var error = _.find(this.get('errors'), function(e) { return (e.name === 'MessageError' || @@ -325,30 +293,6 @@ } }, - resolveConflict: function(number) { - var error = this.getKeyConflict(number); - if (error) { - this.removeConflictFor(number); - var promise = new textsecure.ReplayableError(error).replay(); - if (this.isIncoming()) { - promise = promise.then(function(dataMessage) { - this.removeConflictFor(number); - this.handleDataMessage(dataMessage); - }.bind(this)); - } else { - promise = this.send(promise).then(function() { - this.removeConflictFor(number); - this.save(); - }.bind(this)); - } - promise.catch(function(e) { - this.removeConflictFor(number); - this.saveErrors(e); - }.bind(this)); - - return promise; - } - }, handleDataMessage: function(dataMessage) { // This function can be called from the background script on an // incoming message or from the frontend after the user accepts an @@ -640,10 +584,6 @@ conditions: { expires_at: { $lte: Date.now() } }, addIndividually: true }); - }, - - hasKeyConflicts: function() { - return this.any(function(m) { return m.hasKeyConflicts(); }); } }); })(); diff --git a/js/views/contact_list_view.js b/js/views/contact_list_view.js index f263b28c05..4e76d9037c 100644 --- a/js/views/contact_list_view.js +++ b/js/views/contact_list_view.js @@ -5,6 +5,7 @@ 'use strict'; window.Whisper = window.Whisper || {}; + // Contact list view is used in the list group members senario, as well as the NewGroupUpdate view Whisper.ContactListView = Whisper.ListView.extend({ tagName: 'div', itemView: Whisper.View.extend({ diff --git a/js/views/error_view.js b/js/views/error_view.js index f4b1725b46..3c9558f921 100644 --- a/js/views/error_view.js +++ b/js/views/error_view.js @@ -13,48 +13,4 @@ return this.model; } }); - - var KeyConflictView = ErrorView.extend({ - className: 'key-conflict', - templateName: 'key-conflict', - initialize: function(options) { - this.message = options.message; - }, - events: { - 'click': 'select' - }, - render_attributes: function() { - var errorMessage; - if (this.message.isIncoming()) { - errorMessage = 'incomingKeyConflict'; - } else { - errorMessage = 'outgoingKeyConflict'; - } - return { message: i18n(errorMessage) }; - }, - select: function() { - this.$el.trigger('select', {message: this.message}); - }, - }); - - Whisper.MessageErrorView = Backbone.View.extend({ - className: 'error', - initialize: function(options) { - if (this.model.name === 'IncomingIdentityKeyError' || - this.model.name === 'OutgoingIdentityKeyError') { - this.view = new KeyConflictView({ - model : this.model, - message : options.message - }); - } else { - this.view = new ErrorView({ model: this.model }); - } - this.$el.append(this.view.el); - this.view.render(); - }, - render: function() { - this.view.render(); - return this; - } - }); })(); diff --git a/js/views/group_member_list_view.js b/js/views/group_member_list_view.js index 7a341ece5a..02432b17d8 100644 --- a/js/views/group_member_list_view.js +++ b/js/views/group_member_list_view.js @@ -5,6 +5,11 @@ 'use strict'; window.Whisper = window.Whisper || {}; + // This needs to make each member link to their verification view - except for yourself + // Do we update the display of each user to add Verified to their name if verified? + // What about the case where we're brought here because there are multiple users in the no-longer-verified state? + // We probably want to display some sort of helper text in that case at the least + // Or do we show only the problematic users in that case? Whisper.GroupMemberList = Whisper.View.extend({ className: 'group-member-list panel', templateName: 'group-member-list', diff --git a/js/views/key_conflict_dialogue_view.js b/js/views/key_conflict_dialogue_view.js deleted file mode 100644 index 224784a118..0000000000 --- a/js/views/key_conflict_dialogue_view.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * vim: ts=4:sw=4:expandtab - */ -(function () { - 'use strict'; - - window.Whisper = window.Whisper || {}; - - Whisper.KeyConflictDialogueView = Whisper.View.extend({ - templateName: 'key-conflict-dialogue', - className: 'key-conflict-dialogue clearfix', - initialize: function(options) { - this.contact = options.contact; - this.conversation = options.conversation; - this.render(); - var view = new Whisper.KeyVerificationView({ - model : this.contact, - newKey : this.model.identityKey - }); - view.$el.appendTo(this.$('.keys')); - }, - events: { - 'click .showKeys': 'showKeys', - 'click .hideKeys': 'hideKeys', - 'click .resolve' : 'resolve' - }, - hideKeys: function() { - this.$('.keys, .hideKeys').hide(); - this.$('.showKeys').show(); - }, - showKeys: function() { - this.$('.keys, .hideKeys').show(); - this.$('.showKeys').hide(); - }, - resolve: function() { - this.remove(); - this.conversation.resolveConflicts(this.model); - }, - render_attributes: function() { - return { - name : this.contact.getTitle(), - avatar : this.contact.getAvatar(), - conflict : this.model, - newIdentity : i18n('newIdentity'), - message : i18n('identityChanged'), - resolve : i18n('acceptNewKey'), - showKeys : i18n('showMore'), - hideKeys : i18n('showLess'), - learnMore : i18n('learnMore') - }; - } - }); -})(); diff --git a/js/views/key_verification_view.js b/js/views/key_verification_view.js index 71cfcfd7d5..ef39dde207 100644 --- a/js/views/key_verification_view.js +++ b/js/views/key_verification_view.js @@ -5,9 +5,11 @@ 'use strict'; window.Whisper = window.Whisper || {}; + // TODO; find all uses of that removed panel + // Add the Verify functionality to this view Whisper.KeyVerificationView = Whisper.View.extend({ - className: 'key-verification', - templateName: 'key_verification', + className: 'key-verification panel', + templateName: 'key-verification', initialize: function(options) { this.our_number = textsecure.storage.user.getNumber(); if (options.newKey) { @@ -21,6 +23,8 @@ //.then(this.makeQRCode.bind(this)); }, makeQRCode: function() { + // Per Lilia: We can't turn this on until it geneates a Latin1 string, as is + // required by the mobile clients. new QRCode(this.$('.qr')[0]).makeCode( dcodeIO.ByteBuffer.wrap(this.our_key).toString('base64') ); @@ -72,8 +76,4 @@ }; } }); - Whisper.KeyVerificationPanelView = Whisper.KeyVerificationView.extend({ - className: 'key-verification panel', - templateName: 'key_verification_panel', - }); })(); diff --git a/js/views/message_detail_view.js b/js/views/message_detail_view.js index 6bbada3f19..d4413bd44b 100644 --- a/js/views/message_detail_view.js +++ b/js/views/message_detail_view.js @@ -9,7 +9,6 @@ className: 'contact-detail', templateName: 'contact-detail', initialize: function(options) { - this.conflict = options.conflict; this.errors = _.reject(options.errors, function(e) { return (e.name === 'IncomingIdentityKeyError' || e.name === 'OutgoingIdentityKeyError' || @@ -51,19 +50,6 @@ errors: this.errors[contact.id] }).render(); this.$('.contacts').append(view.el); - - var conflict = this.model.getKeyConflict(contact.id); - if (conflict) { - this.renderConflict(contact, conflict); - } - }, - renderConflict: function(contact, conflict) { - var view = new Whisper.KeyConflictDialogueView({ - model: conflict, - contact: contact, - conversation: this.conversation - }); - this.$('.conflicts').append(view.el); }, render: function() { this.errors = _.groupBy(this.model.get('errors'), 'number'); @@ -81,8 +67,7 @@ title : i18n('messageDetail'), sent : i18n('sent'), received : i18n('received'), - errorLabel : i18n('error'), - hasConflict : this.model.hasKeyConflicts() + errorLabel : i18n('error') })); this.view.$el.prependTo(this.$('.message-container')); diff --git a/js/views/new_group_update_view.js b/js/views/new_group_update_view.js index dbd88c4a7b..701752959a 100644 --- a/js/views/new_group_update_view.js +++ b/js/views/new_group_update_view.js @@ -5,6 +5,7 @@ 'use strict'; window.Whisper = window.Whisper || {}; + // When is this used? Whisper.NewGroupUpdateView = Whisper.View.extend({ tagName: "div", className: 'new-group-update', diff --git a/stylesheets/_conversation.scss b/stylesheets/_conversation.scss index f2b24b3d7e..27be2fbf76 100644 --- a/stylesheets/_conversation.scss +++ b/stylesheets/_conversation.scss @@ -106,40 +106,6 @@ .message-detail { background-color: #eee; - .key-conflict-dialogue { - border-radius: $border-radius; - margin: 20px 0; - - .header { - border-radius: $border-radius $border-radius 0 0; - background: #F3F3A7; - margin: 0; - padding: 10px 20px - } - .content { - padding: 20px; - border: 2px solid #F3F3A7; - } - - button.resolve { - outline: none; - border: none; - border-radius: $border-radius; - color: white; - font-weight: bold; - line-height: 36px; - padding: 0 20px; - float: right; - background: $blue; - margin-left: 20px; - } - - .hideKeys, .showKeys { - float: right; - line-height: 36px; - } - } - .message-container { padding: 20px 0; @@ -192,10 +158,6 @@ padding: 5px; } - button.conflict { - float: right; - background: #d00; - } button.cancel { float: right; color: $grey_d; @@ -533,19 +495,10 @@ li.entry .error-icon-container { cursor: pointer; font-style: italic; } - - .key-conflict { - padding: 15px 10px; - - button { - margin-top: 5px; - } - } } .message-list, -.message-container, -.key-conflict-dialogue { +.message-container { .avatar { height: 36px; width: 36px; diff --git a/stylesheets/manifest.css b/stylesheets/manifest.css index be6af755b2..6b178efadc 100644 --- a/stylesheets/manifest.css +++ b/stylesheets/manifest.css @@ -1055,31 +1055,6 @@ input.search { .message-detail { background-color: #eee; } - .message-detail .key-conflict-dialogue { - border-radius: 5px; - margin: 20px 0; } - .message-detail .key-conflict-dialogue .header { - border-radius: 5px 5px 0 0; - background: #F3F3A7; - margin: 0; - padding: 10px 20px; } - .message-detail .key-conflict-dialogue .content { - padding: 20px; - border: 2px solid #F3F3A7; } - .message-detail .key-conflict-dialogue button.resolve { - outline: none; - border: none; - border-radius: 5px; - color: white; - font-weight: bold; - line-height: 36px; - padding: 0 20px; - float: right; - background: #2090ea; - margin-left: 20px; } - .message-detail .key-conflict-dialogue .hideKeys, .message-detail .key-conflict-dialogue .showKeys { - float: right; - line-height: 36px; } .message-detail .message-container { padding: 20px 0; } .message-detail .message-container .sender { @@ -1111,9 +1086,6 @@ input.search { .message-detail h3 { font-size: 1em; padding: 5px; } - .message-detail button.conflict { - float: right; - background: #d00; } .message-detail button.cancel { float: right; color: #454545; @@ -1408,16 +1380,9 @@ li.entry .error-icon-container { .message-list .bubble .content.error-message { cursor: pointer; font-style: italic; } - .message-container .key-conflict, - .message-list .key-conflict { - padding: 15px 10px; } - .message-container .key-conflict button, - .message-list .key-conflict button { - margin-top: 5px; } .message-list .avatar, -.message-container .avatar, -.key-conflict-dialogue .avatar { +.message-container .avatar { height: 36px; width: 36px; line-height: 36px; } diff --git a/test/index.html b/test/index.html index 1e4e173a6d..fc283b11f9 100644 --- a/test/index.html +++ b/test/index.html @@ -264,12 +264,6 @@ - - - - - diff --git a/test/models/messages_test.js b/test/models/messages_test.js index a2f4bc494b..b45e037a14 100644 --- a/test/models/messages_test.js +++ b/test/models/messages_test.js @@ -136,27 +136,11 @@ assert.ok(message.isGroupUpdate()); }); - it('checks if there are any key conflicts', function() { - var messages = new Whisper.MessageCollection(); - var message = messages.add(attributes); - assert.notOk(message.hasKeyConflicts()); - - message = messages.add({errors: [{name: 'OutgoingIdentityKeyError'}]}); - assert.ok(message.hasKeyConflicts()); - }); - - it('returns a description of key conflicts', function() { - var messages = new Whisper.MessageCollection(); - var message = messages.add({errors: [{name: 'IncomingIdentityKeyError'}]}); - - assert.deepEqual(message.getKeyConflict(), {name: 'IncomingIdentityKeyError'}); - }); - it('returns an accurate description', function() { var messages = new Whisper.MessageCollection(); var message = messages.add(attributes); - assert.equal(message.getDescription(), 'hi', 'If no group updates, key conflicts, or end session flags, return message body.'); + assert.equal(message.getDescription(), 'hi', 'If no group updates or end session flags, return message body.'); message = messages.add({group_update: {left: 'Alice'}}); assert.equal(message.getDescription(), 'Alice left the group.', 'Notes one person leaving the group.'); @@ -175,10 +159,6 @@ message = messages.add({flags: true}); assert.equal(message.getDescription(), i18n('sessionEnded')); - - message = messages.add({type: 'incoming', errors: [{name: 'OutgoingIdentityKeyError'}]}); - assert.equal(message.getDescription(), i18n('incomingKeyConflict')); - }); it('checks if it is end of the session', function() {