Insert keychange advisories

On click, these open a verification panel for the relevant contact,
within this conversation.

// FREEBIE
This commit is contained in:
lilia 2016-09-17 23:55:05 -07:00
parent 1f0a93bf70
commit 7fe708d195
10 changed files with 93 additions and 13 deletions

View File

@ -458,5 +458,15 @@
"safetyNumbersSettingDescription": {
"message": "Require approval of new safety numbers when they change.",
"description": "Description for safety numbers setting"
},
"keychanged": {
"message": "$name$'s safety numbers have changed",
"description": "",
"placeholders": {
"name": {
"content": "$1",
"example": "John"
}
}
}
}

View File

@ -155,6 +155,9 @@
{{ messageNotSent }}
<span href='#' class='retry'>{{ resend }}</span>
</script>
<script type='text/x-tmpl-mustache' id='keychange'>
<span class='content' dir='auto'>{{ content }}</span>
</script>
<script type='text/x-tmpl-mustache' id='message'>
{{> avatar }}
<div class='bubble {{ avatar.color }}'>

View File

@ -41,6 +41,25 @@
this.on('change:avatar', this.updateAvatarUrl);
this.on('destroy', this.revokeAvatarUrl);
this.on('read', this.onReadMessage);
this.fetchContacts().then(function() {
this.contactCollection.each(function(contact) {
textsecure.storage.protocol.on('keychange:' + contact.id, function() {
this.addKeyChange(contact.id);
}.bind(this));
}.bind(this));
}.bind(this));
},
addKeyChange: function(id) {
var now = Date.now();
var message = this.messageCollection.add({
conversationId : this.id,
type : 'keychange',
sent_at : now,
received_at : now,
key_changed : id
});
message.save();
},
onReadMessage: function(message) {

View File

@ -132,6 +132,15 @@
}
return c;
},
getModelForKeyChange: function() {
var id = this.get('key_changed');
var c = ConversationController.get(id);
if (!c) {
c = ConversationController.create({ id: id, type: 'private' });
c.fetch();
}
return c;
},
isOutgoing: function() {
return this.get('type') === 'outgoing';
},

View File

@ -261,20 +261,15 @@
var identityKey = new IdentityKey({id: number});
identityKey.fetch().always(function() {
var oldpublicKey = identityKey.get('publicKey');
var matches = equalArrayBuffers(oldpublicKey, publicKey);
var changed = !!oldpublicKey && !matches;
if (changed) {
console.log('Key changed for', identifier);
this.trigger('keychange', identifier);
}
var trusted = !oldpublicKey || matches;
if (trusted) {
if (!oldpublicKey || equalArrayBuffers(oldpublicKey, publicKey)) {
resolve(true);
} else if (!storage.get('safety-numbers-approval', true)) {
this.removeIdentityKey(identifier).then(function() {
this.saveIdentity(identifier, publicKey).then(function() {
console.log('Key changed for', identifier);
this.trigger('keychange:' + identifier);
resolve(true);
});
}.bind(this));
}.bind(this));
} else {
resolve(false);

View File

@ -149,7 +149,8 @@
'loadMore .message-list': 'fetchMessages',
'close .menu': 'closeMenu',
'select .message-list .entry': 'messageDetail',
'force-resize': 'forceUpdateMessageFieldSize'
'force-resize': 'forceUpdateMessageFieldSize',
'verify-identity': 'verifyIdentity'
},
enableDisappearingMessages: function() {
if (!this.model.get('expireTimer')) {
@ -252,10 +253,13 @@
this.model.markRead();
},
verifyIdentity: function() {
if (this.model.isPrivate()) {
verifyIdentity: function(ev, model) {
if (!model && this.model.isPrivate()) {
model = this.model;
}
if (model) {
var view = new Whisper.KeyVerificationPanelView({
model: { their_number: this.model.id }
model: { their_number: model.id }
});
this.listenBack(view);
}

View File

@ -46,6 +46,8 @@
var view;
if (model.isExpirationTimerUpdate()) {
view = new Whisper.ExpirationTimerUpdateView({model: model}).render();
} else if (model.get('type') === 'keychange') {
view = new Whisper.KeyChangeView({model: model}).render();
} else {
view = new this.itemView({model: model}).render();
this.listenTo(view, 'beforeChangeHeight', this.measureScrollPosition);

View File

@ -67,6 +67,27 @@
}
});
Whisper.KeyChangeView = Whisper.View.extend({
tagName: 'li',
className: 'keychange',
templateName: 'keychange',
initialize: function() {
this.conversation = this.model.getModelForKeyChange();
this.listenTo(this.conversation, 'change', this.render);
},
events: {
'click .content': 'verifyIdentity'
},
render_attributes: function() {
return {
content: i18n('keychanged', this.conversation.getTitle())
};
},
verifyIdentity: function() {
this.$el.trigger('verify-identity', this.conversation);
}
});
Whisper.MessageView = Whisper.View.extend({
tagName: 'li',
templateName: 'message',

View File

@ -601,3 +601,12 @@ li.entry .error-icon-container {
}
}
}
.message-list li.keychange {
text-align: center;
.content {
display: inline-block;
padding: 5px 10px;
background: #fff5c4;
border-radius: $border-radius;
}
}

View File

@ -1380,6 +1380,14 @@ li.entry .error-icon-container {
background-color: #d9d9d9;
border-color: silver; }
.message-list li.keychange {
text-align: center; }
.message-list li.keychange .content {
display: inline-block;
padding: 5px 10px;
background: #fff5c4;
border-radius: 5px; }
.ios #header {
height: 64px;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);