QR code completion
parent
798eb402cb
commit
659d4412bd
@ -0,0 +1,209 @@
|
||||
/* global
|
||||
Whisper,
|
||||
i18n,
|
||||
libloki,
|
||||
textsecure,
|
||||
ConversationController,
|
||||
$,
|
||||
QRCode,
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
Whisper.DevicePairingDialogView = Whisper.View.extend({
|
||||
className: 'loki-dialog device-pairing-dialog modal',
|
||||
templateName: 'device-pairing-dialog',
|
||||
initialize() {
|
||||
this.pubKeyRequests = [];
|
||||
this.reset();
|
||||
this.render();
|
||||
this.showView();
|
||||
this.qr = new QRCode(this.$('#qr')[0], {
|
||||
correctLevel: QRCode.CorrectLevel.L,
|
||||
});
|
||||
this.qr.makeCode(textsecure.storage.user.getNumber());
|
||||
},
|
||||
reset() {
|
||||
this.pubKey = null;
|
||||
this.accepted = false;
|
||||
this.isListening = false;
|
||||
this.pubKeyToUnpair = null;
|
||||
this.success = false;
|
||||
},
|
||||
events: {
|
||||
'click #startPairing': 'startReceivingRequests',
|
||||
'click #close': 'close',
|
||||
'click .waitingForRequestView .cancel': 'stopReceivingRequests',
|
||||
'click .requestReceivedView .skip': 'skipDevice',
|
||||
'click #allowPairing': 'allowDevice',
|
||||
'click .requestAcceptedView .ok': 'stopReceivingRequests',
|
||||
'click .confirmUnpairView .cancel': 'stopReceivingRequests',
|
||||
'click .confirmUnpairView .unpairDevice': 'confirmUnpairDevice',
|
||||
},
|
||||
render_attributes() {
|
||||
return {
|
||||
defaultTitle: i18n('pairedDevices'),
|
||||
waitingForRequestTitle: i18n('waitingForDeviceToRegister'),
|
||||
requestReceivedTitle: i18n('devicePairingReceived'),
|
||||
requestAcceptedTitle: i18n('devicePairingAccepted'),
|
||||
startPairingText: i18n('pairNewDevice'),
|
||||
cancelText: i18n('cancel'),
|
||||
unpairDevice: i18n('unpairDevice'),
|
||||
closeText: i18n('close'),
|
||||
skipText: i18n('skip'),
|
||||
okText: i18n('ok'),
|
||||
allowPairingText: i18n('allowPairing'),
|
||||
confirmUnpairViewTitle: i18n('confirmUnpairingTitle'),
|
||||
};
|
||||
},
|
||||
startReceivingRequests() {
|
||||
this.trigger('startReceivingRequests');
|
||||
this.isListening = true;
|
||||
this.showView();
|
||||
},
|
||||
stopReceivingRequests() {
|
||||
if (this.success) {
|
||||
const deviceAlias = this.$('#deviceAlias')[0].value.trim();
|
||||
const conv = ConversationController.get(this.pubKey);
|
||||
if (conv) {
|
||||
conv.setNickname(deviceAlias);
|
||||
}
|
||||
}
|
||||
this.trigger('stopReceivingRequests');
|
||||
this.reset();
|
||||
this.showView();
|
||||
},
|
||||
requestReceived(secondaryDevicePubKey) {
|
||||
// FIFO: push at the front of the array with unshift()
|
||||
this.pubKeyRequests.unshift(secondaryDevicePubKey);
|
||||
if (!this.pubKey) {
|
||||
this.nextPubKey();
|
||||
this.showView('requestReceived');
|
||||
}
|
||||
},
|
||||
allowDevice() {
|
||||
this.accepted = true;
|
||||
this.trigger('devicePairingRequestAccepted', this.pubKey, errors =>
|
||||
this.transmisssionCB(errors)
|
||||
);
|
||||
this.showView();
|
||||
},
|
||||
transmisssionCB(errors) {
|
||||
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.success = true;
|
||||
} else {
|
||||
this.$('.transmissionStatus').text(errors);
|
||||
this.$('.requestAcceptedView .ok').show();
|
||||
}
|
||||
},
|
||||
skipDevice() {
|
||||
this.trigger('devicePairingRequestRejected', this.pubKey);
|
||||
this.nextPubKey();
|
||||
this.showView();
|
||||
},
|
||||
nextPubKey() {
|
||||
// FIFO: pop at the back of the array using pop()
|
||||
this.pubKey = this.pubKeyRequests.pop();
|
||||
},
|
||||
async confirmUnpairDevice() {
|
||||
this.trigger('deviceUnpairingRequested', this.pubKeyToUnpair);
|
||||
this.reset();
|
||||
this.showView();
|
||||
},
|
||||
requestUnpairDevice(pubKey) {
|
||||
this.pubKeyToUnpair = pubKey;
|
||||
this.showView();
|
||||
},
|
||||
getPubkeyName(pubKey) {
|
||||
const secretWords = window.mnemonic.pubkey_to_secret_words(pubKey);
|
||||
const conv = ConversationController.get(pubKey);
|
||||
const deviceAlias = conv ? conv.getNickname() : 'Unnamed Device';
|
||||
return `${deviceAlias} (pairing secret: <i>${secretWords}</i>)`;
|
||||
},
|
||||
async showView() {
|
||||
const defaultView = this.$('.defaultView');
|
||||
const waitingForRequestView = this.$('.waitingForRequestView');
|
||||
const requestReceivedView = this.$('.requestReceivedView');
|
||||
const requestAcceptedView = this.$('.requestAcceptedView');
|
||||
const confirmUnpairView = this.$('.confirmUnpairView');
|
||||
if (this.pubKeyToUnpair) {
|
||||
defaultView.hide();
|
||||
requestReceivedView.hide();
|
||||
waitingForRequestView.hide();
|
||||
requestAcceptedView.hide();
|
||||
confirmUnpairView.show();
|
||||
const name = this.getPubkeyName(this.pubKeyToUnpair);
|
||||
this.$('.confirmUnpairView #pubkey').html(name);
|
||||
} else if (!this.isListening) {
|
||||
requestReceivedView.hide();
|
||||
waitingForRequestView.hide();
|
||||
requestAcceptedView.hide();
|
||||
confirmUnpairView.hide();
|
||||
|
||||
const ourPubKey = textsecure.storage.user.getNumber();
|
||||
defaultView.show();
|
||||
const pubKeys = await libloki.storage.getSecondaryDevicesFor(ourPubKey);
|
||||
this.$('#pairedPubKeys').empty();
|
||||
if (pubKeys && pubKeys.length > 0) {
|
||||
this.$('#startPairing').attr('disabled', true);
|
||||
pubKeys.forEach(x => {
|
||||
const name = this.getPubkeyName(x);
|
||||
const li = $('<li>').html(name);
|
||||
if (window.lokiFeatureFlags.multiDeviceUnpairing) {
|
||||
const link = $('<a>')
|
||||
.text('Unpair')
|
||||
.attr('href', '#');
|
||||
link.on('click', () => this.requestUnpairDevice(x));
|
||||
li.append(' - ');
|
||||
li.append(link);
|
||||
}
|
||||
this.$('#pairedPubKeys').append(li);
|
||||
});
|
||||
} else {
|
||||
this.$('#startPairing').removeAttr('disabled');
|
||||
this.$('#pairedPubKeys').append('<li>No paired devices</li>');
|
||||
}
|
||||
} else if (this.accepted) {
|
||||
defaultView.hide();
|
||||
requestReceivedView.hide();
|
||||
waitingForRequestView.hide();
|
||||
requestAcceptedView.show();
|
||||
} else if (this.pubKey) {
|
||||
const secretWords = window.mnemonic.pubkey_to_secret_words(this.pubKey);
|
||||
this.$('.secretWords').text(secretWords);
|
||||
requestReceivedView.show();
|
||||
waitingForRequestView.hide();
|
||||
requestAcceptedView.hide();
|
||||
defaultView.hide();
|
||||
} else {
|
||||
waitingForRequestView.show();
|
||||
requestReceivedView.hide();
|
||||
requestAcceptedView.hide();
|
||||
defaultView.hide();
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.remove();
|
||||
this.qr.clear();
|
||||
if (this.pubKey && !this.accepted) {
|
||||
this.trigger('devicePairingRequestRejected', this.pubKey);
|
||||
}
|
||||
this.trigger('close');
|
||||
},
|
||||
});
|
||||
})();
|
@ -0,0 +1,165 @@
|
||||
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 {
|
||||
accepted: boolean;
|
||||
isListening: boolean;
|
||||
success: boolean;
|
||||
loading: boolean;
|
||||
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 = {
|
||||
accepted: false,
|
||||
isListening: false,
|
||||
success: false,
|
||||
loading: true,
|
||||
data: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getSecondaryDevices();
|
||||
}
|
||||
|
||||
private async getSecondaryDevices(){
|
||||
const secondaryDevices = await window.libloki.storage.getSecondaryDevicesFor(this.props.pubKey);
|
||||
this.setState({
|
||||
data: secondaryDevices,
|
||||
loading: false
|
||||
});
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {i18n, } = this.props;
|
||||
|
||||
|
||||
const newData = ['053e18835c106a5f9f463a44a9d7ff9a26281d529285a047bd969cfc59d4ab8607'];
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
data: newData,
|
||||
});
|
||||
}, 2000);
|
||||
|
||||
return (
|
||||
<>
|
||||
{ ! this.state.loading ? (
|
||||
<SessionModal
|
||||
title={i18n('pairedDevices')}
|
||||
onOk={() => null}
|
||||
onClose={this.closeDialog}
|
||||
>
|
||||
{ this.state.isListening ? (
|
||||
<div>
|
||||
{i18n('waitingForDeviceToRegister')}
|
||||
<div className="spacer-lg"></div>
|
||||
|
||||
<div id="qr">
|
||||
<QRCode value={window.textsecure.storage.user.getNumber()}/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<>
|
||||
{this.state.data.length == 0 ? (
|
||||
<>
|
||||
<div>{i18n('noPairedDevices')}</div>
|
||||
<div className="spacer-lg"></div>
|
||||
|
||||
<div className="session-modal__button-group__center">
|
||||
<SessionButton
|
||||
text = {i18n('pairNewDevice')}
|
||||
onClick = {this.startReceivingRequests}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
: (
|
||||
<>
|
||||
{
|
||||
this.state.data.map((pubKey: any) => {
|
||||
const pubKeyInfo = this.getPubkeyName(pubKey);
|
||||
return (
|
||||
<p>
|
||||
{ pubKeyInfo.deviceAlias }
|
||||
<br/>
|
||||
<span className="text-subtle">Pairing Secret:</span> { pubKeyInfo.secretWords }
|
||||
</p>
|
||||
);
|
||||
})
|
||||
}
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
</>
|
||||
)}
|
||||
</SessionModal>
|
||||
) : null }
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private startReceivingRequests() {
|
||||
this.setState({
|
||||
isListening: true,
|
||||
});
|
||||
}
|
||||
|
||||
private getPubkeyName(pubKey: string) {
|
||||
const secretWords = window.mnemonic.pubkey_to_secret_words(pubKey);
|
||||
const conv = window.ConversationController.get(this.props.pubKey);
|
||||
const deviceAlias = conv ? conv.getNickname() : 'Unnamed Device';
|
||||
return {deviceAlias, secretWords};
|
||||
}
|
||||
|
||||
private stopReceivingRequests() {
|
||||
if (this.state.success) {
|
||||
const conv = window.ConversationController.get(this.props.pubKey);
|
||||
//if (conv) {
|
||||
// conv.setNickname(this.props.deviceAlias);
|
||||
//}
|
||||
}
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
|
||||
private onKeyUp(event: any) {
|
||||
switch (event.key) {
|
||||
case 'Esc':
|
||||
case 'Escape':
|
||||
this.closeDialog();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
private closeDialog() {
|
||||
window.removeEventListener('keyup', this.onKeyUp);
|
||||
this.props.onClose();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue