You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-desktop/ts/components/DevicePairingDialog.tsx

294 lines
7.6 KiB
TypeScript

import React from 'react';
import { QRCode } from 'react-qrcode';
import { SessionModal } from './session/SessionModal';
import { SessionButton } from './session/SessionButton';
interface Props {
i18n: any;
onClose: any;
pubKeyToUnpair: string | null;
pubKey: string | null;
}
interface State {
currentPubKey: string | null;
accepted: boolean;
isListening: boolean;
success: boolean;
loading: boolean;
view:
| 'default'
| 'waitingForRequest'
| 'requestReceived'
| 'requestAccepted'
| 'confirmUnpair';
pubKeyRequests: Array<any>;
data: Array<any>;
}
export class DevicePairingDialog extends React.Component<Props, State> {
constructor(props: any) {
super(props);
this.closeDialog = this.closeDialog.bind(this);
this.onKeyUp = this.onKeyUp.bind(this);
this.startReceivingRequests = this.startReceivingRequests.bind(this);
this.stopReceivingRequests = this.stopReceivingRequests.bind(this);
this.getPubkeyName = this.getPubkeyName.bind(this);
this.state = {
currentPubKey: this.props.pubKey,
accepted: false,
isListening: false,
success: false,
loading: true,
view: 'default',
pubKeyRequests: [],
data: [],
};
}
componentDidMount() {
this.getSecondaryDevices();
}
private async getSecondaryDevices() {
const secondaryDevices = await window.libloki.storage.getSecondaryDevicesFor(
this.state.currentPubKey
);
this.setState({
data: secondaryDevices,
loading: false,
});
}
public render() {
const { i18n } = this.props;
const newData = [
'053e18835c106a5f9f463a44a9d7ff9a26281d529285a047bd969cfc59d4ab8607',
'053e18835c106a5f9f463a44a9d7ff9a26281d529285a047bd969cfc59d4ab8604',
];
setTimeout(() => {
this.setState({
data: newData,
});
}, 2000);
return (
<>
{!this.state.loading ? (
<SessionModal
title={i18n('pairedDevices')}
onOk={() => null}
onClose={this.closeDialog}
>
{this.state.view === 'waitingForRequest' ? (
<div className="session-modal__centered">
<h3>{i18n('waitingForDeviceToRegister')}</h3>
<small className="text-subtle">
{i18n('pairNewDevicePrompt')}
</small>
<div className="spacer-lg" />
<div id="qr">
<QRCode value={window.textsecure.storage.user.getNumber()} />
</div>
<div className="spacer-lg" />
<div className="session-modal__button-group__center">
<SessionButton
text={i18n('cancel')}
onClick={this.stopReceivingRequests}
/>
</div>
</div>
) : (
<>
{this.state.data.length == 0 ? (
<div className="session-modal__centered">
<div>{i18n('noPairedDevices')}</div>
</div>
) : (
<div className="session-modal__centered">
{this.state.data.map((pubKey: any) => {
const pubKeyInfo = this.getPubkeyName(pubKey);
const isFinalItem =
this.state.data[this.state.data.length - 1] === pubKey;
return (
<div key={pubKey}>
<p>
{pubKeyInfo.deviceAlias}
<br />
<span className="text-subtle">
Pairing Secret:
</span>{' '}
{pubKeyInfo.secretWords}
</p>
{!isFinalItem ? (
<hr className="text-soft fullwidth" />
) : null}
</div>
);
})}
</div>
)}
<div className="spacer-lg" />
<div className="session-modal__button-group__center">
<SessionButton
text={i18n('pairNewDevice')}
onClick={this.startReceivingRequests}
/>
</div>
</>
)}
</SessionModal>
) : null}
</>
);
}
private showView(
view?:
| 'default'
| 'waitingForRequest'
| 'requestReceived'
| 'requestAccepted'
| 'confirmUnpair'
) {
if (!view) {
this.setState({
view: 'default',
});
return;
}
this.setState({ view });
}
private startReceivingRequests() {
this.setState({
isListening: true,
});
this.showView('waitingForRequest');
//TESTING
//TESTING
//TESTING
setTimeout(() => {
this.setState({
accepted: true,
success: true,
});
}, 3000);
}
private getPubkeyName(pubKey: string | null) {
if (!pubKey) {
return {};
}
const secretWords = window.mnemonic.pubkey_to_secret_words(pubKey);
const conv = window.ConversationController.get(this.state.currentPubKey);
const deviceAlias = conv ? conv.getNickname() : 'Unnamed Device';
return { deviceAlias, secretWords };
}
private stopReceivingRequests() {
if (this.state.success) {
const deviceAlias = this.getPubkeyName(this.state.currentPubKey)[
'deviceAlias'
];
const conv = window.ConversationController.get(this.state.currentPubKey);
if (conv) {
conv.setNickname(deviceAlias);
}
}
this.showView();
}
private requestReceived(secondaryDevicePubKey: string | EventHandlerNonNull) {
// FIFO: push at the front of the array with unshift()
this.state.pubKeyRequests.unshift(secondaryDevicePubKey);
if (!this.state.currentPubKey) {
this.nextPubKey();
this.showView('requestReceived');
}
}
allowDevice() {
this.setState({
accepted: true,
});
window.Whisper.trigger(
'devicePairingRequestAccepted',
this.state.currentPubKey,
(errors: any) => this.transmisssionCB(errors)
);
this.showView();
}
transmisssionCB(errors: any) {
if (!errors) {
// this.$('.transmissionStatus').text(i18n('provideDeviceAlias'));
// this.$('#deviceAliasView').show();
// this.$('#deviceAlias').on('input', e => {
// if (e.target.value.trim()) {
// this.$('.requestAcceptedView .ok').removeAttr('disabled');
// } else {
// this.$('.requestAcceptedView .ok').attr('disabled', true);
// }
// });
// this.$('.requestAcceptedView .ok').show();
// this.$('.requestAcceptedView .ok').attr('disabled', true);
this.setState({
success: true,
});
} else {
// this.$('.transmissionStatus').text(errors);
// this.$('.requestAcceptedView .ok').show();
}
}
skipDevice() {
window.Whisper.trigger(
'devicePairingRequestRejected',
this.state.currentPubKey
);
this.nextPubKey();
this.showView();
}
nextPubKey() {
// FIFO: pop at the back of the array using pop()
const pubKeyRequests = this.state.pubKeyRequests;
this.setState({
currentPubKey: pubKeyRequests.pop(),
});
}
private onKeyUp(event: any) {
switch (event.key) {
case 'Esc':
case 'Escape':
this.closeDialog();
break;
default:
}
}
private closeDialog() {
window.removeEventListener('keyup', this.onKeyUp);
this.stopReceivingRequests();
this.props.onClose();
}
}