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; data: Array; } export class DevicePairingDialog extends React.Component { 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: [], }; } public componentDidMount() { this.getSecondaryDevices(); } public render() { const { i18n } = this.props; const waitingForRequest = this.state.view === 'waitingForRequest'; const nothingPaired = this.state.data.length === 0; const renderPairedDevices = this.state.data.map((pubKey: any) => { const pubKeyInfo = this.getPubkeyName(pubKey); const isFinalItem = this.state.data[this.state.data.length - 1] === pubKey; return (

{pubKeyInfo.deviceAlias}
Pairing Secret:{' '} {pubKeyInfo.secretWords}

{!isFinalItem ?
: null}
); }); return ( <> {!this.state.loading && ( null} onClose={this.closeDialog} > {waitingForRequest ? (

{i18n('waitingForDeviceToRegister')}

{i18n('pairNewDevicePrompt')}
) : ( <> {nothingPaired ? (
{i18n('noPairedDevices')}
) : (
{renderPairedDevices}
)}
)} )} ); } private showView( view?: | 'default' | 'waitingForRequest' | 'requestReceived' | 'requestAccepted' | 'confirmUnpair' ) { if (!view) { this.setState({ view: 'default', }); return; } if (view === 'waitingForRequest') { this.setState({ view, isListening: true, }); return; } this.setState({ view }); } private getSecondaryDevices() { const secondaryDevices = window.libloki.storage .getSecondaryDevicesFor(this.state.currentPubKey) .then(() => { this.setState({ data: secondaryDevices, loading: false, }); }); } private startReceivingRequests() { this.showView('waitingForRequest'); } 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 aliasKey = 'deviceAlias'; const deviceAlias = this.getPubkeyName(this.state.currentPubKey)[ aliasKey ]; 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'); } } private allowDevice() { this.setState({ accepted: true, }); window.Whisper.trigger( 'devicePairingRequestAccepted', this.state.currentPubKey, (errors: any) => { this.transmisssionCB(errors); return true; } ); this.showView(); } private transmisssionCB(errors: any) { if (!errors) { this.setState({ success: true, }); } else { return; } } private skipDevice() { window.Whisper.trigger( 'devicePairingRequestRejected', this.state.currentPubKey ); this.nextPubKey(); this.showView(); } private 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(); } }