Skip to content

Commit

Permalink
Support for group-member verifications via second-level panel
Browse files Browse the repository at this point in the history
Also:
- All the necessary wire-up to update things in real time. If you have
a safety number page up via a group member view as well as via a 1:1
conversation with that contact, they'll both be updated as the
underlying model changes. Similarly, the overall group will update
in real-time as members change.
- A bit of special-casing for yourself in a group conversation - you're
shown as 'me' and are not clickable, where normally that would take you
to the Safety Number screen for that contact. You are also not included
in the trust calculations for a given group.

FREEBIE
  • Loading branch information
scottnonnenberg committed Aug 4, 2017
1 parent ae3587f commit bedf100
Show file tree
Hide file tree
Showing 12 changed files with 281 additions and 46 deletions.
35 changes: 32 additions & 3 deletions _locales/en/messages.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"me": {
"message": "Me",
"description": "The label for yourself when shown in a group member list"
},
"youLeftTheGroup": {
"message": "You left the group",
"description": "Displayed when a user can't send a message because they have left the group"
Expand Down Expand Up @@ -172,15 +176,40 @@
"message": "Send a message",
"description": "Placeholder text in the message entry field"
},
"members": {
"message": "Members"
"groupMembers": {
"message": "Group members"
},
"showMembers": {
"message": "Show members"
},
"resetSession": {
"message": "Reset session",
"description": "This is a menu item for resetting the session, using the imperative case, as in a command."
},
"showSafetyNumber": {
"message": "Show safety number"
"message": "Show safety number"
},
"markAsNotVerified": {
"message": "Mark as not verified"
},
"verifyHelp": {
"message": "If you wish to verify the security of your end-to-end encryption with $name$, compare the numbers above with the numbers on their device.",
"placeholders": {
"name": {
"content": "$1",
"example": "John"
}
}
},
"isVerified": {
"message": "$name$ is verified",
"description": "If the user has manually marked a contact's safety number as verified, this string is shown on the 'Show Safety Number' screen",
"placeholders": {
"name": {
"content": "$1",
"example": "John"
}
}
},
"theirIdentityUnknown": {
"message": "You haven't exchanged any messages with this contact yet. Your safety number with them will be available after the first message."
Expand Down
36 changes: 23 additions & 13 deletions background.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ <h3>{{ welcomeToSignal }}</h3>
<script type='text/x-tmpl-mustache' id='hint'>
<p> {{ content }}</p>
</script>
<script type='text/x-tmpl-mustache' id='conversation-title'>
{{ #name }}
<span class='conversation-name' dir='auto'>{{ name }}</span>
{{ /name }}
{{ #number }}
<span class='conversation-number'>{{ number }}</span>
{{ /number }}
{{ #verified }}
<span class='verified'>✓ Verified</span>
{{ /verified }}
</script>
<script type='text/x-tmpl-mustache' id='conversation'>
<div class='conversation-header {{ avatar.color }}'>
<div class='header-buttons left'>
Expand All @@ -78,16 +89,16 @@ <h3>{{ welcomeToSignal }}</h3>
<div class='conversation-menu menu'>
<button class='hamburger' alt='conversation menu'></button>
<ul class='menu-list'>
<li class='disappearing-messages'>{{ disappearing-messages }}</li>
{{#group}}
<li class='view-members'>{{ view-members }}</li>
<li class='show-members'>{{ show-members }}</li>
<!-- <li class='update-group'>Update group</li> -->
<!-- <li class='leave-group'>Leave group</li> -->
{{/group}}
{{^group}}
<li class='end-session'>{{ end-session }}</li>
<li class='show-identity'>{{ show-identity }}</li>
<li class='end-session'>{{ end-session }}</li>
{{/group}}
<li class='disappearing-messages'>{{ disappearing-messages }}</li>
<li class='destroy'>{{ destroy }}</li>
</ul>
</div>
Expand All @@ -101,14 +112,7 @@ <h3>{{ welcomeToSignal }}</h3>
</div>
</div>
</div>
<span class='conversation-title'>
{{ #name }}
<span class='conversation-name' dir='auto'>{{ name }}</span>
{{ /name }}
{{ #number }}
<span class='conversation-number'>{{ number }}</span>
{{ /number }}
</span>
<span class='conversation-title'></span>
{{> avatar }}
</div>
<div class='main panel'>
Expand Down Expand Up @@ -239,11 +243,11 @@ <h3>{{ welcomeToSignal }}</h3>
</script>
<script type='text/x-tmpl-mustache' id='contact_name_and_number'>
<h3 class='name' dir='auto'> {{ title }} </h3>
<div class='number'>{{ number }}</div>
<div class='number'>{{ #verified }} Verified &middot;{{ /verified }} {{ number }}</div>
</script>
<script type='text/x-tmpl-mustache' id='contact'>
{{> avatar }}
<div class='contact-details'> {{> contact_name_and_number }} </div>
<div class='contact-details {{ class }}'> {{> contact_name_and_number }} </div>
</script>
<script type='text/x-tmpl-mustache' id='new-contact'>
{{> avatar }}
Expand Down Expand Up @@ -321,7 +325,13 @@ <h3 class='name' dir='auto'> {{ title }} </h3>
{{ #chunks }} <span>{{ . }}</span> {{ /chunks }}
</div>
{{ /has_their_key }}
{{ verifyHelp }}
<p> {{> link_to_support }} </p>
<div class='verify'>
<button class='verify'>
{{ verifyButton }}
</button>
</div>
</div>
</script>
<!-- index -->
Expand Down
82 changes: 82 additions & 0 deletions js/models/conversations.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
},

initialize: function() {
this.ourNumber = textsecure.storage.user.getNumber();

this.contactCollection = new Backbone.Collection();
this.messageCollection = new Whisper.MessageCollection([], {
conversation: this
Expand All @@ -48,6 +50,84 @@
this.on('destroy', this.revokeAvatarUrl);
},

updateVerified: function() {
// TODO: replace this with the real call
function checkTrustStore() {
return Promise.resolve('default');
}

if (this.isPrivate()) {
return Promise.all([
checkTrustStore(this.id),
this.fetch()
]).then(function(results) {
var trust = results[0];
return this.save({verified: trust});
});
} else {
return this.fetchContacts().then(function() {
return Promise.all(this.contactCollection.map(function(contact) {
if (contact.id !== this.myNumber) {
return contact.updateVerified();
}
}.bind(this)));
}.bind(this));
}
},

isVerified: function() {
if (this.isPrivate()) {
return this.get('verified') === 'verified';
} else {
return this.contactCollection.every(function(contact) {
if (contact.id === this.myNumber) {
return true;
} else {
return contact.isVerified();
}
}.bind(this));
}
},
isConflict: function() {
if (this.isPrivate()) {
var verified = this.get('verified');
return verified !== 'verified' && verified !== 'default';
} else {
return Boolean(this.getConflicts().length);
}
},
getConflicts: function() {
if (this.isPrivate()) {
return this.isConflict() ? [this] : [];
} else {
return this.contactCollection.filter(function(contact) {
if (contact.id === this.myNumber) {
return false;
} else {
return contact.isConflict();
}
}.bind(this));
}
},
onMemberVerifiedChange: function() {
// If the verified state of a member changes, our aggregate state changes.
// We trigger both events to replicate the behavior of Backbone.Model.set()
this.trigger('change:verified');
this.trigger('change');
},
toggleVerified: function() {
if (!this.isPrivate()) {
throw new Error('You cannot verify a group conversation. ' +
'You must verify individual contacts.');
}

if (this.isVerified()) {
this.save({verified: 'default'});
} else {
this.save({verified: 'verified'});
}
},

addKeyChange: function(id) {
console.log('adding key change advisory for', this.id, this.get('timestamp'));
var timestamp = Date.now();
Expand Down Expand Up @@ -373,12 +453,14 @@
} else {
var promises = [];
var members = this.get('members') || [];

this.contactCollection.reset(
members.map(function(number) {
var c = ConversationController.create({
id : number,
type : 'private'
});
this.listenTo(c, 'change:verified', this.onMemberVerifiedChange);
promises.push(new Promise(function(resolve) {
c.fetch().always(resolve);
}));
Expand Down
31 changes: 30 additions & 1 deletion js/views/contact_list_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,41 @@
tagName: 'div',
className: 'contact',
templateName: 'contact',
events: {
'click': 'showIdentity'
},
initialize: function(options) {
this.ourNumber = textsecure.storage.user.getNumber();
this.listenBack = options.listenBack;

this.listenTo(this.model, 'change', this.render);
},
render_attributes: function() {
if (this.model.id === this.ourNumber) {
return {
class: 'not-clickable',
title: i18n('me'),
number: this.model.getNumber(),
avatar: this.model.getAvatar()
};
}

return {
class: '',
title: this.model.getTitle(),
number: this.model.getNumber(),
avatar: this.model.getAvatar()
avatar: this.model.getAvatar(),
verified: this.model.isVerified()
};
},
showIdentity: function() {
if (this.model.id === this.ourNumber) {
return;
}
var view = new Whisper.KeyVerificationPanelView({
model: this.model
});
this.listenBack(view);
}
})
});
Expand Down

0 comments on commit bedf100

Please sign in to comment.