diff --git a/conversation.html b/conversation.html
index 5bb1d68e..f47eac8e 100644
--- a/conversation.html
+++ b/conversation.html
@@ -22,6 +22,7 @@
{{/group}}
{{^group}}
End Session
+ Verify Identity
{{/group}}
Delete messages
@@ -116,6 +117,22 @@
+
@@ -138,6 +155,7 @@
+
diff --git a/js/views/conversation_view.js b/js/views/conversation_view.js
index 95c4fd61..70ff6981 100644
--- a/js/views/conversation_view.js
+++ b/js/views/conversation_view.js
@@ -52,11 +52,32 @@
'click .end-session': 'endSession',
'click .leave-group': 'leaveGroup',
'click .new-group-update': 'newGroupUpdate',
+ 'click .verify-identity': 'verifyIdentity',
'click .hamburger': 'toggleMenu',
'click' : 'closeMenu',
'select .entry': 'messageDetail'
},
+ verifyIdentity: function() {
+ if (this.model.isPrivate()) {
+ var number = this.model.id;
+ var view = new Whisper.KeyVerificationView({
+ model: {
+ their_key: textsecure.storage.devices.getIdentityKeyForNumber(number),
+ your_key: textsecure.storage.devices.getIdentityKeyForNumber(
+ textsecure.utils.unencodeNumber(textsecure.storage.getUnencrypted("number_id"))[0]
+ )
+ }
+ });
+ this.$el.hide();
+ view.render().$el.insertAfter(this.el);
+ this.listenTo(view, 'back', function() {
+ view.remove();
+ this.$el.show();
+ });
+ }
+ },
+
messageDetail: function(e, data) {
var view = new Whisper.MessageDetailView({ model: data.message, conversation: this.model });
view.$el.insertAfter(this.$el);
diff --git a/js/views/key_verification_view.js b/js/views/key_verification_view.js
new file mode 100644
index 00000000..c500eae6
--- /dev/null
+++ b/js/views/key_verification_view.js
@@ -0,0 +1,48 @@
+/* vim: ts=4:sw=4:expandtab
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+(function () {
+ 'use strict';
+
+ window.Whisper = window.Whisper || {};
+
+ Whisper.KeyVerificationView = Backbone.View.extend({
+ className: 'key-verification',
+ initialize: function(options) {
+ this.template = $('#key-verification').html();
+ Mustache.parse(this.template);
+ },
+ events: {
+ 'click .back': 'goBack'
+ },
+ goBack: function() {
+ this.trigger('back');
+ },
+ splitKey: function(key) {
+ // key is a binary string
+ return _.map(key, function(chr, i) {
+ return ('0' + key.charCodeAt(i).toString(16)).slice(-2);
+
+ });
+ },
+ render: function() {
+ this.$el.html(Mustache.render(this.template, {
+ your_key: this.splitKey(this.model.your_key),
+ their_key: this.splitKey(this.model.their_key)
+ }));
+ return this;
+ }
+ });
+})();
diff --git a/js/views/message_detail_view.js b/js/views/message_detail_view.js
index f51cacc0..d52fee1f 100644
--- a/js/views/message_detail_view.js
+++ b/js/views/message_detail_view.js
@@ -27,11 +27,28 @@
this.conversation = options.conversation;
},
events: {
- 'click .back': 'goBack'
+ 'click .back': 'goBack',
+ 'verify': 'verify'
},
goBack: function() {
this.trigger('back');
},
+ verify: function(number) {
+ var view = new Whisper.KeyVerificationView({
+ model: {
+ their_key: textsecure.storage.devices.getIdentityKeyForNumber(number),
+ your_key: textsecure.storage.devices.getIdentityKeyForNumber(
+ textsecure.utils.unencodeNumber(textsecure.storage.getUnencrypted("number_id"))[0]
+ )
+ }
+ });
+ this.$el.hide();
+ view.render().$el.insertAfter(this.el);
+ this.listenTo(view, 'back', function() {
+ view.remove();
+ this.$el.show();
+ });
+ },
render: function() {
this.$el.html(Mustache.render(this.template, {
sent_at: moment(this.model.get('sent_at')).toString(),
diff --git a/stylesheets/_conversation.scss b/stylesheets/_conversation.scss
index afbf61e0..defa91be 100644
--- a/stylesheets/_conversation.scss
+++ b/stylesheets/_conversation.scss
@@ -2,10 +2,24 @@
padding: $header-height 0;
}
-.conversation, .discussion-container, .message-list, .message-detail {
+.conversation, .discussion-container, .message-list, .message-detail, .key-verification {
height: 100%;
}
+.key-verification {
+ padding: $header-height 0 0;
+ .container {
+ height: 100%;
+ overflow: auto;
+ }
+ p {
+ padding: 1em;
+ }
+ .key {
+ font-family: monospace;
+ padding: 0 1em;
+ }
+}
.message-detail {
padding: $header-height 0 0;
background: $grey_l;
diff --git a/stylesheets/manifest.css b/stylesheets/manifest.css
index 62d44187..30cad05e 100644
--- a/stylesheets/manifest.css
+++ b/stylesheets/manifest.css
@@ -280,9 +280,20 @@ input.new-message {
.conversation {
padding: 36px 0; }
-.conversation, .discussion-container, .message-list, .message-detail {
+.conversation, .discussion-container, .message-list, .message-detail, .key-verification {
height: 100%; }
+.key-verification {
+ padding: 36px 0 0; }
+ .key-verification .container {
+ height: 100%;
+ overflow: auto; }
+ .key-verification p {
+ padding: 1em; }
+ .key-verification .key {
+ font-family: monospace;
+ padding: 0 1em; }
+
.message-detail {
padding: 36px 0 0;
background: #f3f3f3; }