From 659d4412bd9a67247261a30beda51e0ba5069a8e Mon Sep 17 00:00:00 2001 From: Vincent Date: Mon, 23 Dec 2019 17:40:48 +1100 Subject: [PATCH] QR code completion --- _locales/en/messages.json | 3 + js/modules/signal.js | 6 +- js/views/device_pairing_dialog_view.js | 199 ++------------------ js/views/device_pairing_dialog_view_old.js | 209 +++++++++++++++++++++ package.json | 2 + stylesheets/_session.scss | 18 +- ts/components/DevicePairingDialog.tsx | 165 ++++++++++++++++ ts/global.d.ts | 1 + yarn.lock | 66 ++++++- 9 files changed, 482 insertions(+), 187 deletions(-) create mode 100644 js/views/device_pairing_dialog_view_old.js create mode 100644 ts/components/DevicePairingDialog.tsx diff --git a/_locales/en/messages.json b/_locales/en/messages.json index dc6d4183d..5669e21c3 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -960,6 +960,9 @@ "pairedDevices": { "message": "Paired Devices" }, + "noPairedDevices": { + "message": "No paired devices" + }, "allowPairing": { "message": "Allow Pairing" }, diff --git a/js/modules/signal.js b/js/modules/signal.js index f13542db1..d3d7380fe 100644 --- a/js/modules/signal.js +++ b/js/modules/signal.js @@ -50,8 +50,9 @@ const { } = require('../../ts/components/conversation/CreateGroupDialog'); const { EditProfileDialog } = require('../../ts/components/EditProfileDialog'); const { UserDetailsDialog } = require('../../ts/components/UserDetailsDialog'); -const { - SessionSettings, +const { DevicePairingDialog } = require('../../ts/components/DevicePairingDialog'); + +const { SessionSettings, } = require('../../ts/components/session/SessionSettings'); const { SessionToast } = require('../../ts/components/session/SessionToast'); const { SessionToggle } = require('../../ts/components/session/SessionToggle'); @@ -251,6 +252,7 @@ exports.setup = (options = {}) => { CreateGroupDialog, EditProfileDialog, UserDetailsDialog, + DevicePairingDialog, SessionRegistrationView, ConfirmDialog, UpdateGroupDialog, diff --git a/js/views/device_pairing_dialog_view.js b/js/views/device_pairing_dialog_view.js index 80d6b4f61..b371ac759 100644 --- a/js/views/device_pairing_dialog_view.js +++ b/js/views/device_pairing_dialog_view.js @@ -5,7 +5,6 @@ textsecure, ConversationController, $, - QRCode, */ // eslint-disable-next-line func-names @@ -16,194 +15,30 @@ Whisper.DevicePairingDialogView = Whisper.View.extend({ className: 'loki-dialog device-pairing-dialog modal', - templateName: 'device-pairing-dialog', initialize() { - this.pubKeyRequests = []; - this.reset(); + this.close = this.close.bind(this); + 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: ${secretWords})`; - }, - 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 = $('
  • ').html(name); - if (window.lokiFeatureFlags.multiDeviceUnpairing) { - const link = $('') - .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('
  • No paired devices
  • '); - } - } 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(); - } + render(){ + this.dialogView = new Whisper.ReactWrapperView({ + className: 'device-pairing-dialog', + Component: window.Signal.Components.DevicePairingDialog, + props: { + i18n, + onClose: this.close, + }, + }); + + this.$el.append(this.dialogView.el); + return this; }, + + close() { this.remove(); - this.qr.clear(); - if (this.pubKey && !this.accepted) { - this.trigger('devicePairingRequestRejected', this.pubKey); - } - this.trigger('close'); }, }); })(); diff --git a/js/views/device_pairing_dialog_view_old.js b/js/views/device_pairing_dialog_view_old.js new file mode 100644 index 000000000..80d6b4f61 --- /dev/null +++ b/js/views/device_pairing_dialog_view_old.js @@ -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: ${secretWords})`; + }, + 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 = $('
  • ').html(name); + if (window.lokiFeatureFlags.multiDeviceUnpairing) { + const link = $('') + .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('
  • No paired devices
  • '); + } + } 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'); + }, + }); +})(); diff --git a/package.json b/package.json index 2dd44aa85..a2305a59a 100644 --- a/package.json +++ b/package.json @@ -101,10 +101,12 @@ "pify": "3.0.0", "protobufjs": "6.8.6", "proxy-agent": "3.0.3", + "qrcode": "^1.4.4", "react": "16.8.3", "react-contextmenu": "2.11.0", "react-dom": "16.8.3", "react-portal": "^4.2.0", + "react-qrcode": "^0.2.0", "react-redux": "6.0.1", "react-virtualized": "9.21.0", "read-last-lines": "1.3.0", diff --git a/stylesheets/_session.scss b/stylesheets/_session.scss index 5628d0c6f..1b9634cbd 100644 --- a/stylesheets/_session.scss +++ b/stylesheets/_session.scss @@ -74,6 +74,7 @@ $session-color-light-grey: #a0a0a0; $session-shadow-opacity: 0.15; $session-overlay-opacity: 0.3; +$session-margin-xs: 5px; $session-margin-sm: 10px; $session-margin-md: 15px; $session-margin-lg: 20px; @@ -92,6 +93,10 @@ div.spacer-lg { color: rgba($color, 0.6); } +.text-subtle { + opacity: 0.6; +} + $session-transition-duration: 0.25s; $session-icon-size-sm: 15px; @@ -560,14 +565,23 @@ label { &__button-group { display: flex; justify-content: flex-end; + + .session-button { + margin-left: $session-margin-sm; + } &__center { - align-items: center; + display: flex; + justify-content: center; } + .session-button { - margin-left: $session-margin-sm; + margin: 0 $session-margin-xs; + } + } + } .session-toggle { diff --git a/ts/components/DevicePairingDialog.tsx b/ts/components/DevicePairingDialog.tsx new file mode 100644 index 000000000..563cfc926 --- /dev/null +++ b/ts/components/DevicePairingDialog.tsx @@ -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; +} + +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 = { + 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 ? ( + null} + onClose={this.closeDialog} + > + { this.state.isListening ? ( +
    + {i18n('waitingForDeviceToRegister')} +
    + +
    + +
    + +
    + ) + : ( + <> + {this.state.data.length == 0 ? ( + <> +
    {i18n('noPairedDevices')}
    +
    + +
    + +
    + + ) + : ( + <> + { + this.state.data.map((pubKey: any) => { + const pubKeyInfo = this.getPubkeyName(pubKey); + return ( +

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

    + ); + }) + } + + )} + + + + )} +
    + ) : 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(); + } +} \ No newline at end of file diff --git a/ts/global.d.ts b/ts/global.d.ts index 3a85cc274..4a84f6da6 100644 --- a/ts/global.d.ts +++ b/ts/global.d.ts @@ -4,6 +4,7 @@ interface Window { passwordUtil: any; dcodeIO: any; libsignal: any; + libloki: any; displayNameRegex: any; Signal: any; Whisper: any; diff --git a/yarn.lock b/yarn.lock index 75bf08394..c1e935c49 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1243,6 +1243,19 @@ buble@^0.19.3: os-homedir "^1.0.1" vlq "^1.0.0" +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + buffer-crc32@0.2.13, buffer-crc32@^0.2.1: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -1252,10 +1265,20 @@ buffer-equal@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + buffer-from@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" +buffer-from@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + buffer-indexof@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" @@ -1272,6 +1295,14 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" +buffer@^5.4.3: + version "5.4.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115" + integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + buffers@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" @@ -2522,6 +2553,11 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" +dijkstrajs@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.1.tgz#d3cd81221e3ea40742cfcde556d4e99e98ddc71b" + integrity sha1-082BIh4+pAdCz83lVtTpnpjdxxs= + dir-glob@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" @@ -4982,6 +5018,11 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" +isarray@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isbinaryfile@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.2.tgz#bfc45642da645681c610cca831022e30af426488" @@ -6981,6 +7022,11 @@ pngjs@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.0.1.tgz#b15086ac1ac47298c8fd3f9cdf364fa9879c4db6" +pngjs@^3.3.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" + integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== + portfinder@^1.0.9: version "1.0.13" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" @@ -7474,6 +7520,19 @@ q@^1.1.2, q@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" +qrcode@^1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.4.4.tgz#f0c43568a7e7510a55efc3b88d9602f71963ea83" + integrity sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q== + dependencies: + buffer "^5.4.3" + buffer-alloc "^1.2.0" + buffer-from "^1.1.1" + dijkstrajs "^1.0.1" + isarray "^2.0.1" + pngjs "^3.3.0" + yargs "^13.2.4" + qs@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/qs/-/qs-5.2.0.tgz#a9f31142af468cb72b25b30136ba2456834916be" @@ -7699,6 +7758,11 @@ react-portal@^4.2.0: dependencies: prop-types "^15.5.8" +react-qrcode@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/react-qrcode/-/react-qrcode-0.2.0.tgz#a05cf2ae5ac57c3a9751e512132a821ed60533f9" + integrity sha512-3JzSzkTUUMb26sbq5/u75zw9l3gQ1BLvdCAYgRnAZ1wGJj1Su94pzv4g/XfzaJEj6h8Y0H9mYX4djmKBGZQHSQ== + react-redux@6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-6.0.1.tgz#0d423e2c1cb10ada87293d47e7de7c329623ba4d" @@ -10374,7 +10438,7 @@ yargs@^10.0.3: y18n "^3.2.1" yargs-parser "^8.0.0" -yargs@^13.3.0: +yargs@^13.2.4, yargs@^13.3.0: version "13.3.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==