Update safety number change warning dialog

This commit is contained in:
Josh Perez 2020-06-25 20:08:58 -04:00 committed by Scott Nonnenberg
parent e87a0103cc
commit 5b83485c89
38 changed files with 1221 additions and 425 deletions

View file

@ -451,9 +451,12 @@
const result = {
id: this.id,
uuid: this.get('uuid'),
e164: this.get('e164'),
isArchived: this.get('isArchived'),
isBlocked: this.isBlocked(),
isVerified: this.isVerified(),
activeAt: this.get('active_at'),
avatarPath: this.getAvatarPath(),
color,

View file

@ -40,6 +40,9 @@ const {
MessageDetail,
} = require('../../ts/components/conversation/MessageDetail');
const { Quote } = require('../../ts/components/conversation/Quote');
const {
SafetyNumberChangeDialog,
} = require('../../ts/components/SafetyNumberChangeDialog');
const {
StagedLinkPreview,
} = require('../../ts/components/conversation/StagedLinkPreview');
@ -51,6 +54,9 @@ const {
} = require('../../ts/state/roots/createCompositionArea');
const { createCallManager } = require('../../ts/state/roots/createCallManager');
const { createLeftPane } = require('../../ts/state/roots/createLeftPane');
const {
createSafetyNumberViewer,
} = require('../../ts/state/roots/createSafetyNumberViewer');
const {
createStickerManager,
} = require('../../ts/state/roots/createStickerManager');
@ -274,6 +280,7 @@ exports.setup = (options = {}) => {
MediaGallery,
MessageDetail,
Quote,
SafetyNumberChangeDialog,
StagedLinkPreview,
Types: {
Message: MediaGalleryMessage,
@ -284,6 +291,7 @@ exports.setup = (options = {}) => {
createCallManager,
createCompositionArea,
createLeftPane,
createSafetyNumberViewer,
createShortcutGuideModal,
createStickerManager,
createStickerPreviewModal,

View file

@ -2502,33 +2502,17 @@
showSendAnywayDialog(contacts) {
return new Promise(resolve => {
let message;
const isUnverified = this.model.isUnverified();
if (contacts.length > 1) {
if (isUnverified) {
message = i18n('changedSinceVerifiedMultiple');
} else {
message = i18n('changedRecentlyMultiple');
}
} else {
const contactName = contacts.at(0).getTitle();
if (isUnverified) {
message = i18n('changedSinceVerified', [contactName, contactName]);
} else {
message = i18n('changedRecently', [contactName, contactName]);
}
}
const dialog = new Whisper.ConfirmationDialogView({
message,
okText: i18n('sendAnyway'),
resolve: () => resolve(true),
reject: () => resolve(false),
const dialog = new Whisper.SafetyNumberChangeDialogView({
contacts,
reject: () => {
resolve(false);
},
resolve: () => {
resolve(true);
},
});
this.$el.prepend(dialog.el);
dialog.focusCancel();
});
},

View file

@ -1,4 +1,4 @@
/* global Whisper, textsecure, QRCode, dcodeIO, libsignal, i18n, _ */
/* global Whisper, Signal */
/* eslint-disable more/no-then */
@ -9,152 +9,18 @@
window.Whisper = window.Whisper || {};
Whisper.KeyVerificationPanelView = Whisper.View.extend({
className: 'key-verification panel',
className: 'panel',
templateName: 'key-verification',
events: {
'click button.verify': 'toggleVerified',
},
initialize(options) {
this.ourNumber = textsecure.storage.user.getNumber();
this.ourUuid = textsecure.storage.user.getUuid();
if (options.newKey) {
this.theirKey = options.newKey;
}
this.loadTheirKey();
this.loadOurKey();
this.render();
if (options.onLoad) {
options.onLoad(this);
}
this.loadKeys().then(() => {
this.listenTo(this.model, 'change', this.render);
});
},
async loadKeys() {
await this.generateSecurityNumber();
this.render();
},
makeQRCode() {
// Per Lilia: We can't turn this on until it generates a Latin1 string, as is
// required by the mobile clients.
new QRCode(this.$('.qr')[0]).makeCode(
dcodeIO.ByteBuffer.wrap(this.ourKey).toString('base64')
);
},
loadTheirKey() {
const item = textsecure.storage.protocol.getIdentityRecord(
this.model.get('id')
);
this.theirKey = item ? item.publicKey : null;
},
loadOurKey() {
const item = textsecure.storage.protocol.getIdentityRecord(
this.ourUuid || this.ourNumber
);
this.ourKey = item ? item.publicKey : null;
},
generateSecurityNumber() {
return new libsignal.FingerprintGenerator(5200)
.createFor(
// TODO: we cannot use UUIDs for safety numbers yet
// this.ourUuid || this.ourNumber,
this.ourNumber,
this.ourKey,
// TODO: we cannot use UUIDs for safety numbers yet
// this.model.get('uuid') || this.model.get('e164'),
this.model.get('e164'),
this.theirKey
)
.then(securityNumber => {
this.securityNumber = securityNumber;
});
},
onSafetyNumberChanged() {
this.model.getProfiles().then(this.loadKeys.bind(this));
const dialog = new Whisper.ConfirmationDialogView({
message: i18n('changedRightAfterVerify', [
this.model.getTitle(),
this.model.getTitle(),
]),
hideCancel: true,
const view = new Whisper.ReactWrapperView({
JSX: Signal.State.Roots.createSafetyNumberViewer(window.reduxStore, {
contactID: options.model.get('id'),
}),
});
dialog.$el.insertBefore(this.el);
dialog.focusCancel();
},
toggleVerified() {
this.$('button.verify').attr('disabled', true);
this.model
.toggleVerified()
.catch(result => {
if (result instanceof Error) {
if (result.name === 'OutgoingIdentityKeyError') {
this.onSafetyNumberChanged();
} else {
window.log.error(
'failed to toggle verified:',
result && result.stack ? result.stack : result
);
}
} else {
const keyError = _.some(
result.errors,
error => error.name === 'OutgoingIdentityKeyError'
);
if (keyError) {
this.onSafetyNumberChanged();
} else {
_.forEach(result.errors, error => {
window.log.error(
'failed to toggle verified:',
error && error.stack ? error.stack : error
);
});
}
}
})
.then(() => {
this.$('button.verify').removeAttr('disabled');
});
},
render_attributes() {
const s = this.securityNumber;
const chunks = [];
if (s) {
for (let i = 0; i < s.length; i += 5) {
chunks.push(s.substring(i, i + 5));
}
} else {
for (let i = 0; i < 12; i += 1) {
chunks.push('XXXXX');
}
}
const name = this.model.getTitle();
const yourSafetyNumberWith = i18n(
'yourSafetyNumberWith',
this.model.getTitle()
);
const isVerified = this.model.isVerified();
const verifyButton = isVerified ? i18n('unverify') : i18n('verify');
const verifiedStatus = isVerified
? i18n('isVerified', name)
: i18n('isNotVerified', name);
return {
learnMore: i18n('learnMore'),
theirKeyUnknown: i18n('theirIdentityUnknown'),
yourSafetyNumberWith,
verifyHelp: i18n('verifyHelp', this.model.getTitle()),
verifyButton,
hasTheirKey: this.theirKey !== undefined,
chunks,
isVerified,
verifiedStatus,
};
this.$('.key-verification-wrapper').append(view.el);
},
});
})();

View file

@ -0,0 +1,39 @@
/* global Whisper, Signal */
// eslint-disable-next-line func-names
(function() {
'use strict';
window.Whisper = window.Whisper || {};
Whisper.SafetyNumberChangeDialogView = Whisper.View.extend({
templateName: 'safety-number-change-dialog',
initialize(options) {
const dialog = new Whisper.ReactWrapperView({
Component: window.Signal.Components.SafetyNumberChangeDialog,
props: {
contacts: options.contacts.map(contact => contact.cachedProps),
i18n: window.i18n,
onCancel: () => {
dialog.remove();
this.remove();
options.reject();
},
onConfirm: () => {
dialog.remove();
this.remove();
options.resolve();
},
renderSafetyNumber(props) {
return Signal.State.Roots.createSafetyNumberViewer(
window.reduxStore,
props
);
},
},
});
this.$('.safety-number-change-dialog-wrapper').append(dialog.el);
},
});
})();