safety-number-view
parent
134df7e389
commit
d823e2a758
@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||||
|
<path style="fill:#7C8287;" d="M380.942,124.942v109.475h-74.598V124.403c0-27.768-22.586-50.354-50.344-50.354
|
||||||
|
s-50.354,22.586-50.354,50.354v110.015h-74.588V124.942C131.058,56.046,187.104,0,256,0S380.942,56.046,380.942,124.942z"/>
|
||||||
|
<path style="fill:#596C76;" d="M380.942,124.942v109.475h-74.598V124.403c0-27.768-22.586-50.354-50.344-50.354V0
|
||||||
|
C324.896,0,380.942,56.046,380.942,124.942z"/>
|
||||||
|
<path style="fill:#FF5B5B;" d="M420.543,254.198v188.986c0,37.943-30.874,68.817-68.816,68.817H160.264
|
||||||
|
c-37.943,0-68.807-30.874-68.807-68.816V254.198c0-19.161,15.597-34.758,34.758-34.758h259.56
|
||||||
|
C404.946,219.44,420.543,235.037,420.543,254.198z"/>
|
||||||
|
<path style="fill:#FF193D;" d="M420.543,254.198v188.986c0,37.943-30.874,68.817-68.816,68.817H256V219.44h129.775
|
||||||
|
C404.946,219.44,420.543,235.037,420.543,254.198z"/>
|
||||||
|
<path style="fill:#D20041;" d="M297.747,387.572c5.851,5.851,5.851,15.337,0,21.188c-2.926,2.926-6.76,4.383-10.584,4.383
|
||||||
|
c-3.834,0-7.668-1.458-10.594-4.383l-20.899-20.899l-20.24,20.23c-2.926,2.926-6.76,4.393-10.594,4.393
|
||||||
|
c-3.824,0-7.658-1.468-10.584-4.393c-5.851-5.841-5.851-15.327,0-21.178l20.24-20.24l-21.388-21.378
|
||||||
|
c-5.851-5.851-5.851-15.337,0-21.178c5.851-5.851,15.337-5.851,21.178,0l21.388,21.378l22.047-22.047
|
||||||
|
c5.841-5.851,15.327-5.851,21.178,0c5.851,5.851,5.851,15.337,0,21.188l-22.047,22.037L297.747,387.572z"/>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||||
|
<path style="fill:#7C8287;" d="M380.942,124.942v109.475h-74.598V124.403c0-27.768-22.586-50.354-50.344-50.354
|
||||||
|
s-50.354,22.586-50.354,50.354v110.015h-74.588V124.942C131.058,56.046,187.104,0,256,0S380.942,56.046,380.942,124.942z"/>
|
||||||
|
<path style="fill:#596C76;" d="M380.942,124.942v109.475h-74.598V124.403c0-27.768-22.586-50.354-50.344-50.354V0
|
||||||
|
C324.896,0,380.942,56.046,380.942,124.942z"/>
|
||||||
|
<path style="fill:#00EE84;" d="M420.543,254.198v188.986c0,37.943-30.874,68.817-68.816,68.817H160.264
|
||||||
|
c-37.943,0-68.807-30.874-68.807-68.816V254.198c0-19.161,15.597-34.758,34.758-34.758h259.56
|
||||||
|
C404.946,219.44,420.543,235.037,420.543,254.198z"/>
|
||||||
|
<path style="fill:#00DD7B;" d="M420.543,254.198v188.986c0,37.943-30.874,68.817-68.816,68.817H256V219.44h129.775
|
||||||
|
C404.946,219.44,420.543,235.037,420.543,254.198z"/>
|
||||||
|
<path style="fill:#00AB5E;" d="M311.776,342.245L256,393.858l-5.382,4.983c-0.12,0.11-0.26,0.21-0.379,0.32
|
||||||
|
c-0.18,0.16-0.359,0.31-0.549,0.459c-0.2,0.15-0.399,0.3-0.609,0.449c-0.19,0.14-0.389,0.27-0.579,0.399
|
||||||
|
c-0.22,0.14-0.439,0.26-0.659,0.389c-0.2,0.11-0.389,0.23-0.589,0.329c-0.24,0.12-0.479,0.22-0.719,0.329
|
||||||
|
c-0.19,0.09-0.389,0.18-0.579,0.26c-0.26,0.1-0.519,0.18-0.779,0.27c-0.19,0.06-0.369,0.13-0.559,0.18
|
||||||
|
c-0.29,0.09-0.579,0.15-0.859,0.21c-0.18,0.04-0.339,0.09-0.519,0.12c-0.32,0.07-0.649,0.11-0.979,0.15
|
||||||
|
c-0.14,0.01-0.27,0.04-0.409,0.05c-0.469,0.05-0.939,0.07-1.398,0.07c0,0,0,0-0.01,0c-0.489,0-0.979-0.03-1.468-0.08
|
||||||
|
c-0.15-0.01-0.29-0.04-0.429-0.06c-0.349-0.04-0.689-0.09-1.038-0.15c-0.17-0.04-0.339-0.09-0.519-0.13
|
||||||
|
c-0.31-0.07-0.609-0.15-0.919-0.24c-0.19-0.06-0.369-0.13-0.559-0.2c-0.28-0.09-0.559-0.19-0.839-0.3
|
||||||
|
c-0.2-0.09-0.389-0.19-0.589-0.28c-0.26-0.12-0.509-0.23-0.759-0.369c-0.2-0.11-0.399-0.24-0.599-0.359
|
||||||
|
c-0.24-0.14-0.469-0.27-0.689-0.429c-0.2-0.14-0.399-0.29-0.599-0.439c-0.21-0.16-0.419-0.32-0.629-0.489
|
||||||
|
c-0.19-0.16-0.379-0.339-0.559-0.509c-0.13-0.12-0.27-0.23-0.389-0.349l-26.73-26.73c-5.841-5.851-5.841-15.327,0-21.178
|
||||||
|
c5.851-5.851,15.337-5.851,21.188,0l16.535,16.535L256,353.049l35.437-32.791c6.071-5.622,15.547-5.252,21.158,0.819
|
||||||
|
C318.216,327.148,317.847,336.624,311.776,342.245z"/>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
@ -1,58 +0,0 @@
|
|||||||
/* global Whisper: false */
|
|
||||||
/* global textsecure: false */
|
|
||||||
|
|
||||||
// eslint-disable-next-line func-names
|
|
||||||
(function() {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
window.Whisper = window.Whisper || {};
|
|
||||||
|
|
||||||
Whisper.ContactListView = Whisper.ListView.extend({
|
|
||||||
tagName: 'div',
|
|
||||||
itemView: Whisper.View.extend({
|
|
||||||
tagName: 'div',
|
|
||||||
className: 'contact',
|
|
||||||
templateName: 'contact',
|
|
||||||
initialize(options) {
|
|
||||||
this.ourNumber = textsecure.storage.user.getNumber();
|
|
||||||
this.listenBack = options.listenBack;
|
|
||||||
|
|
||||||
this.listenTo(this.model, 'change', this.render);
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
if (this.contactView) {
|
|
||||||
this.contactView.remove();
|
|
||||||
this.contactView = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isMe = this.ourNumber === this.model.id;
|
|
||||||
|
|
||||||
this.contactView = new Whisper.ReactWrapperView({
|
|
||||||
className: 'contact-wrapper',
|
|
||||||
Component: window.Signal.Components.ContactListItem,
|
|
||||||
props: {
|
|
||||||
isMe,
|
|
||||||
color: this.model.getColor(),
|
|
||||||
avatarPath: this.model.getAvatarPath(),
|
|
||||||
phoneNumber: this.model.getNumber(),
|
|
||||||
name: this.model.getName(),
|
|
||||||
profileName: this.model.getProfileName(),
|
|
||||||
verified: this.model.isVerified(),
|
|
||||||
onClick: this.showIdentity.bind(this),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this.$el.append(this.contactView.el);
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
showIdentity() {
|
|
||||||
if (this.model.id === this.ourNumber) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const view = new Whisper.KeyVerificationPanelView({
|
|
||||||
model: this.model,
|
|
||||||
});
|
|
||||||
this.listenBack(view);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
})();
|
|
@ -1,138 +0,0 @@
|
|||||||
/* global Whisper, textsecure, QRCode, dcodeIO, libsignal, i18n, _ */
|
|
||||||
|
|
||||||
/* eslint-disable more/no-then */
|
|
||||||
|
|
||||||
// eslint-disable-next-line func-names
|
|
||||||
(function() {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
window.Whisper = window.Whisper || {};
|
|
||||||
|
|
||||||
Whisper.KeyVerificationPanelView = Whisper.View.extend({
|
|
||||||
className: 'key-verification panel',
|
|
||||||
templateName: 'key-verification',
|
|
||||||
events: {
|
|
||||||
'click button.verify': 'toggleVerified',
|
|
||||||
},
|
|
||||||
initialize(options) {
|
|
||||||
this.ourNumber = textsecure.storage.user.getNumber();
|
|
||||||
if (options.newKey) {
|
|
||||||
this.theirKey = options.newKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loadKeys().then(() => {
|
|
||||||
this.listenTo(this.model, 'change', this.render);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
loadKeys() {
|
|
||||||
return Promise.all([this.loadTheirKey(), this.loadOurKey()])
|
|
||||||
.then(this.generateSecurityNumber.bind(this))
|
|
||||||
.then(this.render.bind(this));
|
|
||||||
// .then(this.makeQRCode.bind(this));
|
|
||||||
},
|
|
||||||
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() {
|
|
||||||
return textsecure.storage.protocol
|
|
||||||
.loadIdentityKey(this.model.id)
|
|
||||||
.then(theirKey => {
|
|
||||||
this.theirKey = theirKey;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
loadOurKey() {
|
|
||||||
return textsecure.storage.protocol
|
|
||||||
.loadIdentityKey(this.ourNumber)
|
|
||||||
.then(ourKey => {
|
|
||||||
this.ourKey = ourKey;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
generateSecurityNumber() {
|
|
||||||
return new libsignal.FingerprintGenerator(5200)
|
|
||||||
.createFor(this.ourNumber, this.ourKey, this.model.id, this.theirKey)
|
|
||||||
.then(securityNumber => {
|
|
||||||
this.securityNumber = securityNumber;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onSafetyNumberChanged() {
|
|
||||||
this.model.getProfiles().then(this.loadKeys.bind(this));
|
|
||||||
|
|
||||||
window.confirmationDialog({
|
|
||||||
title: i18n('changedSinceVerifiedTitle'),
|
|
||||||
message: i18n('changedRightAfterVerify', [
|
|
||||||
this.model.getTitle(),
|
|
||||||
this.model.getTitle(),
|
|
||||||
]),
|
|
||||||
hideCancel: true,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
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 = [];
|
|
||||||
for (let i = 0; i < s.length; i += 5) {
|
|
||||||
chunks.push(s.substring(i, i + 5));
|
|
||||||
}
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})();
|
|
@ -0,0 +1,248 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import {
|
||||||
|
SessionButton,
|
||||||
|
SessionButtonColor,
|
||||||
|
SessionButtonType,
|
||||||
|
} from './SessionButton';
|
||||||
|
import { UserUtil } from '../../util';
|
||||||
|
import { MultiDeviceProtocol } from '../../session/protocols';
|
||||||
|
import { PubKey } from '../../session/types';
|
||||||
|
import { ConversationModel } from '../../../js/models/conversations';
|
||||||
|
import { SessionSpinner } from './SessionSpinner';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { SessionIcon, SessionIconSize, SessionIconType } from './icon';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
conversation: ConversationModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
loading: boolean;
|
||||||
|
error?: 'verificationKeysLoadFail';
|
||||||
|
securityNumber?: string;
|
||||||
|
isVerified?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SessionKeyVerification extends React.Component<Props, State> {
|
||||||
|
constructor(props: any) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
loading: true,
|
||||||
|
error: undefined,
|
||||||
|
securityNumber: undefined,
|
||||||
|
isVerified: this.props.conversation.isVerified(),
|
||||||
|
};
|
||||||
|
|
||||||
|
this.toggleVerification = this.toggleVerification.bind(this);
|
||||||
|
this.onSafetyNumberChanged = this.onSafetyNumberChanged.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async componentWillMount() {
|
||||||
|
const securityNumber = await this.generateSecurityNumber();
|
||||||
|
|
||||||
|
if (!securityNumber) {
|
||||||
|
this.setState({
|
||||||
|
error: 'verificationKeysLoadFail',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finished loading
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
securityNumber,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const theirName = this.props.conversation.attributes.profileName;
|
||||||
|
const theirPubkey = this.props.conversation.id;
|
||||||
|
const isVerified = this.props.conversation.isVerified();
|
||||||
|
|
||||||
|
if (this.state.loading) {
|
||||||
|
return (
|
||||||
|
<div className="key-verification">
|
||||||
|
<SessionSpinner loading={this.state.loading} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const verificationIconColor = isVerified ? '#00f782' : '#ff453a';
|
||||||
|
const verificationButtonColor = isVerified
|
||||||
|
? SessionButtonColor.Warning
|
||||||
|
: SessionButtonColor.Success;
|
||||||
|
const verificationButton = (
|
||||||
|
<SessionButton
|
||||||
|
buttonType={SessionButtonType.DefaultOutline}
|
||||||
|
buttonColor={verificationButtonColor}
|
||||||
|
onClick={this.toggleVerification}
|
||||||
|
>
|
||||||
|
{window.i18n(isVerified ? 'unverify' : 'verify')}
|
||||||
|
</SessionButton>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="key-verification">
|
||||||
|
{this.state.error ? (
|
||||||
|
<h3>{window.i18n(this.state.error)}</h3>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div className={classNames('key-verification__header')}>
|
||||||
|
<h2>{window.i18n('safetyNumber')}</h2>
|
||||||
|
<small>{theirPubkey}</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'key-verification__key',
|
||||||
|
'session-info-box'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{this.renderSecurityNumber()}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="key-verification__help">
|
||||||
|
{window.i18n('verifyHelp', theirName)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="key-verification__is-verified">
|
||||||
|
<span>
|
||||||
|
<SessionIcon
|
||||||
|
iconType={SessionIconType.Lock}
|
||||||
|
iconSize={SessionIconSize.Large}
|
||||||
|
iconColor={verificationIconColor}
|
||||||
|
/>
|
||||||
|
{window.i18n(
|
||||||
|
isVerified ? 'isVerified' : 'isNotVerified',
|
||||||
|
theirName
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{verificationButton}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async onSafetyNumberChanged() {
|
||||||
|
const conversationModel = this.props.conversation;
|
||||||
|
await conversationModel.getProfiles();
|
||||||
|
|
||||||
|
const securityNumber = await this.generateSecurityNumber();
|
||||||
|
this.setState({ securityNumber });
|
||||||
|
|
||||||
|
window.confirmationDialog({
|
||||||
|
title: window.i18n('changedSinceVerifiedTitle'),
|
||||||
|
message: window.i18n('changedRightAfterVerify', [
|
||||||
|
conversationModel.attributes.profileName,
|
||||||
|
conversationModel.attributes.profileName,
|
||||||
|
]),
|
||||||
|
hideCancel: true,
|
||||||
|
centeredText: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async generateSecurityNumber(): Promise<string | undefined> {
|
||||||
|
const ourDeviceKey = await UserUtil.getCurrentDevicePubKey();
|
||||||
|
|
||||||
|
if (!ourDeviceKey) {
|
||||||
|
this.setState({
|
||||||
|
error: 'verificationKeysLoadFail',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const conversationId = this.props.conversation.id;
|
||||||
|
const ourPrimaryKey = (
|
||||||
|
await MultiDeviceProtocol.getPrimaryDevice(PubKey.cast(ourDeviceKey))
|
||||||
|
).key;
|
||||||
|
|
||||||
|
// Grab identity keys
|
||||||
|
const ourIdentityKey = await window.textsecure.storage.protocol.loadIdentityKey(
|
||||||
|
ourPrimaryKey
|
||||||
|
);
|
||||||
|
const theirIdentityKey = await window.textsecure.storage.protocol.loadIdentityKey(
|
||||||
|
this.props.conversation.id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!ourIdentityKey || !theirIdentityKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate security number
|
||||||
|
const fingerprintGenerator = new window.libsignal.FingerprintGenerator(
|
||||||
|
5200
|
||||||
|
);
|
||||||
|
return fingerprintGenerator.createFor(
|
||||||
|
ourPrimaryKey,
|
||||||
|
ourIdentityKey,
|
||||||
|
conversationId,
|
||||||
|
theirIdentityKey
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async toggleVerification() {
|
||||||
|
const conversationModel = this.props.conversation;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await conversationModel.toggleVerified();
|
||||||
|
this.setState({ isVerified: !this.state.isVerified });
|
||||||
|
|
||||||
|
await conversationModel.getProfiles();
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
|
if (e.name === 'OutgoingIdentityKeyError') {
|
||||||
|
await this.onSafetyNumberChanged();
|
||||||
|
} else {
|
||||||
|
window.log.error(
|
||||||
|
'failed to toggle verified:',
|
||||||
|
e && e.stack ? e.stack : e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const keyError = _.some(
|
||||||
|
e.errors,
|
||||||
|
error => error.name === 'OutgoingIdentityKeyError'
|
||||||
|
);
|
||||||
|
if (keyError) {
|
||||||
|
await this.onSafetyNumberChanged();
|
||||||
|
} else {
|
||||||
|
_.forEach(e.errors, error => {
|
||||||
|
window.log.error(
|
||||||
|
'failed to toggle verified:',
|
||||||
|
error && error.stack ? error.stack : error
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderSecurityNumber(): Array<JSX.Element> | undefined {
|
||||||
|
// Turns 32813902154726601686003948952478 ...
|
||||||
|
// into 32813 90215 47266 ...
|
||||||
|
const { loading, securityNumber } = this.state;
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const securityNumberChunks = _.chunk(
|
||||||
|
Array.from(securityNumber ?? []),
|
||||||
|
5
|
||||||
|
).map(chunk => chunk.join(''));
|
||||||
|
const securityNumberLines = _.chunk(securityNumberChunks, 4).map(chunk =>
|
||||||
|
chunk.join(' ')
|
||||||
|
);
|
||||||
|
|
||||||
|
const securityNumberElement = securityNumberLines.map(line => (
|
||||||
|
<div key={line}>{line}</div>
|
||||||
|
));
|
||||||
|
return securityNumberElement;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
export const reducer = (state: any, action: any) => {
|
export const reducer = (state: any, _action: any) => {
|
||||||
console.log(`[vince][redux] Action: `, action);
|
|
||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue