diff --git a/jest.config.js b/jest.config.js index bc9e57ad..3a0857ca 100644 --- a/jest.config.js +++ b/jest.config.js @@ -3,6 +3,7 @@ const config = require('@polkadot/dev-react/config/jest'); module.exports = Object.assign({}, config, { moduleNameMapper: { + '@polkadot/react-(qr)(.*)$': '/packages/react-$1/src/$2', '@polkadot/ui-(assets|identicon|keyring|settings)(.*)$': '/packages/ui-$1/src/$2', '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'empty/object', '\\.(css|less)$': 'empty/object' diff --git a/packages/react-qr/LICENSE b/packages/react-qr/LICENSE new file mode 100644 index 00000000..0d381b2e --- /dev/null +++ b/packages/react-qr/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/packages/react-qr/README.md b/packages/react-qr/README.md new file mode 100644 index 00000000..93f01f39 --- /dev/null +++ b/packages/react-qr/README.md @@ -0,0 +1,3 @@ +# @polkadot/react-qr + +A Qr-code component that allows for the transfer of addresses and transaction payloads to and from external readers diff --git a/packages/react-qr/package.json b/packages/react-qr/package.json new file mode 100644 index 00000000..646688b7 --- /dev/null +++ b/packages/react-qr/package.json @@ -0,0 +1,17 @@ +{ + "name": "@polkadot/react-qr", + "version": "0.34.0-beta.87", + "description": "Generates and reads QR codes", + "main": "index.js", + "author": "Jaco Greeff ", + "maintainers": [ + "Jaco Greeff " + ], + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@types/react-qr-reader": "^2.1.1", + "qrcode-generator": "^1.4.3", + "react-qr-reader": "^2.2.1" + } +} diff --git a/packages/react-qr/src/Display.tsx b/packages/react-qr/src/Display.tsx new file mode 100644 index 00000000..4127ea8e --- /dev/null +++ b/packages/react-qr/src/Display.tsx @@ -0,0 +1,160 @@ +// Copyright 2017-2019 @polkadot/react-qr authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { BaseProps } from './types'; + +import React from 'react'; +import qrcode from 'qrcode-generator'; +import styled from 'styled-components'; +import { u8aConcat } from '@polkadot/util'; +import { xxhashAsHex } from '@polkadot/util-crypto'; + +import { createSize } from './constants'; +import { encodeNumber, decodeString } from './util'; + +interface Props extends BaseProps { + size?: number; + value: Uint8Array; + withMulti?: boolean; +} + +interface State { + frames: string[]; + frameIdx: number; + image: string | null; + timerId: NodeJS.Timeout | null; + valueHash: string | null; +} + +const FRAME_DELAY = 2100; +const FRAME_SIZE = 1716; +const MULTIPART = new Uint8Array([0]); + +function getDataUrl (value: string): string { + const qr = qrcode(0, 'M'); + + qr.addData(value, 'Byte'); + qr.make(); + + return qr.createDataURL(16, 0); +} + +function createFrames (input: Uint8Array): string[] { + const frames = []; + let idx = 0; + + while (idx < input.length) { + frames.push(input.subarray(idx, idx + FRAME_SIZE)); + + idx += FRAME_SIZE; + } + + return frames.map((frame, index: number): string => + decodeString(u8aConcat( + MULTIPART, + encodeNumber(frames.length), + encodeNumber(index), + frame + )) + ); +} + +class Display extends React.PureComponent { + public state: State = { + frames: [], + frameIdx: 0, + image: null, + timerId: null, + valueHash: null + }; + + public static getDerivedStateFromProps ({ value, withMulti = true }: Props, prevState: State): Pick | null { + const valueHash = xxhashAsHex(value); + + if (valueHash === prevState.valueHash) { + return null; + } + + const frames: string[] = withMulti + ? createFrames(value) + : [decodeString(value)]; + + return { + frames, + frameIdx: 0, + image: getDataUrl(frames[0]), + valueHash + }; + } + + public componentDidMount (): void { + this.setState({ + timerId: setInterval(this.nextFrame, FRAME_DELAY) + }); + } + + public componentWillUnmount (): void { + const { timerId } = this.state; + + if (timerId) { + clearInterval(timerId); + } + } + + public render (): React.ReactNode { + const { className, size, style } = this.props; + const { image } = this.state; + + if (!image) { + return null; + } + + return ( +
+
+ +
+
+ ); + } + + private nextFrame = (): void => { + const { frames, frameIdx } = this.state; + + if (!frames || frames.length <= 1) { + return; + } + + const nextIdx = frameIdx === frames.length - 1 + ? 0 + : frameIdx + 1; + + this.setState({ + frameIdx: nextIdx, + image: getDataUrl(frames[nextIdx]) + }); + } +} + +export default styled(Display as React.ComponentClass)` + .ui--qr-Display { + height: 100%; + width: 100%; + + img, + svg { + background: white; + height: auto !important; + max-height: 100%; + max-width: 100%; + width: auto !important; + } + } +`; diff --git a/packages/react-qr/src/DisplayAddress.tsx b/packages/react-qr/src/DisplayAddress.tsx new file mode 100644 index 00000000..801a8c64 --- /dev/null +++ b/packages/react-qr/src/DisplayAddress.tsx @@ -0,0 +1,62 @@ +// Copyright 2017-2019 @polkadot/react-qr authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { BaseProps } from './types'; + +import React from 'react'; +import { u8aConcat } from '@polkadot/util'; +import { xxhashAsHex } from '@polkadot/util-crypto'; + +import { ADDRESS_PREFIX } from './constants'; +import { encodeString } from './util'; +import QrDisplay from './Display'; + +interface Props extends BaseProps { + address: string; +} + +interface State { + data: Uint8Array | null; + dataHash: string | null; +} + +const PREFIX = encodeString(ADDRESS_PREFIX); + +export default class DisplayExtrinsic extends React.PureComponent { + public state: State = { + data: null, + dataHash: null + }; + + public getDerivedStateFromProps ({ address }: Props, prevState: State): State | null { + const data = u8aConcat( + PREFIX, + encodeString(address) + ); + const dataHash = xxhashAsHex(data); + + if (dataHash === prevState.dataHash) { + return null; + } + + return { data, dataHash }; + } + + public render (): React.ReactNode { + const { className, style } = this.props; + const { data } = this.state; + + if (!data) { + return null; + } + + return ( + + ); + } +} diff --git a/packages/react-qr/src/DisplayPayload.tsx b/packages/react-qr/src/DisplayPayload.tsx new file mode 100644 index 00000000..e8a9d817 --- /dev/null +++ b/packages/react-qr/src/DisplayPayload.tsx @@ -0,0 +1,66 @@ +// Copyright 2017-2019 @polkadot/react-qr authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { BaseProps } from './types'; + +import React from 'react'; +import { u8aConcat } from '@polkadot/util'; +import { decodeAddress, xxhashAsHex } from '@polkadot/util-crypto'; + +import QrDisplay from './Display'; + +interface Props extends BaseProps { + address: string; + payload: Uint8Array; +} + +interface State { + data: Uint8Array | null; + dataHash: string | null; +} + +const SUBSTRATE = new Uint8Array([0x53]); +const CRYPTO_SR25519 = new Uint8Array([0x01]); +const SIGN_TX = new Uint8Array([0x00]); + +export default class DisplayPayload extends React.PureComponent { + public state: State = { + data: null, + dataHash: null + }; + + public getDerivedStateFromProps ({ address, payload }: Props, prevState: State): State | null { + const data = u8aConcat( + SUBSTRATE, + CRYPTO_SR25519, + SIGN_TX, + decodeAddress(address), + payload + ); + const dataHash = xxhashAsHex(data); + + if (dataHash === prevState.dataHash) { + return null; + } + + return { data, dataHash }; + } + + public render (): React.ReactNode { + const { className, style } = this.props; + const { data } = this.state; + + if (!data) { + return null; + } + + return ( + + ); + } +} diff --git a/packages/react-qr/src/Scan.tsx b/packages/react-qr/src/Scan.tsx new file mode 100644 index 00000000..cecb6d83 --- /dev/null +++ b/packages/react-qr/src/Scan.tsx @@ -0,0 +1,72 @@ +// Copyright 2017-2019 @polkadot/react-qr authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { BaseProps } from './types'; + +import React from 'react'; +import Reader from 'react-qr-reader'; +import styled from 'styled-components'; + +import { createSize } from './constants'; + +interface Props extends BaseProps { + delay?: number; + onError?: (error: Error) => void; + onScan?: (data: string) => void; + size?: number; +} + +const DEFAULT_DELAY = 150; +const DEFAULT_ERROR = (error: Error): void => { + console.error('@polkadot/react-qr:Scan', error.message); +}; + +class Scan extends React.PureComponent { + public render (): React.ReactNode { + const { className, delay = DEFAULT_DELAY, size, style } = this.props; + + return ( +
+ +
+ ); + } + + private onError = (error: Error): void => { + const { onError = DEFAULT_ERROR } = this.props; + + onError(error); + } + + private onScan = (data: string | null): void => { + const { onScan } = this.props; + + if (!data || !onScan) { + return; + } + + onScan(data); + } +} + +export default styled(Scan)` + .ui--qr-Scan { + display: inline-block; + height: 100%; + width: 100%; + + video { + margin: 0; + } + } +`; diff --git a/packages/react-qr/src/ScanAddress.tsx b/packages/react-qr/src/ScanAddress.tsx new file mode 100644 index 00000000..6eb126de --- /dev/null +++ b/packages/react-qr/src/ScanAddress.tsx @@ -0,0 +1,48 @@ +// Copyright 2017-2019 @polkadot/react-qr authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { BaseProps } from './types'; + +import React from 'react'; + +import { ADDRESS_PREFIX } from './constants'; +import QrScan from './Scan'; +import { decodeAddress } from '@polkadot/util-crypto'; + +interface Props extends BaseProps { + onError?: (error: Error) => void; + onScan?: (data: string) => void; +} + +export default class ScanAddress extends React.PureComponent { + public render (): React.ReactNode { + const { className, onError, style } = this.props; + + return ( + + ); + } + + private onScan = (data: string | null): void => { + const { onScan } = this.props; + + if (!data || !onScan || !data.startsWith(ADDRESS_PREFIX)) { + return; + } + + const address = data.substr(ADDRESS_PREFIX.length); + + try { + decodeAddress(address); + onScan(address); + } catch (error) { + console.error('@polkadot/react-qr:QrScanAddress', error.message); + } + } +} diff --git a/packages/react-qr/src/ScanSignature.tsx b/packages/react-qr/src/ScanSignature.tsx new file mode 100644 index 00000000..c9b69b3e --- /dev/null +++ b/packages/react-qr/src/ScanSignature.tsx @@ -0,0 +1,40 @@ +// Copyright 2017-2019 @polkadot/react-qr authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { BaseProps } from './types'; + +import React from 'react'; + +import QrScan from './Scan'; +import { encodeString } from './util'; + +interface Props extends BaseProps { + onError?: (error: Error) => void; + onScan?: (data: Uint8Array) => void; +} + +export default class ScanSignature extends React.PureComponent { + public render (): React.ReactNode { + const { className, onError, style } = this.props; + + return ( + + ); + } + + private onScan = (data: string | null): void => { + const { onScan } = this.props; + + if (!data || !onScan) { + return; + } + + onScan(encodeString(data)); + } +} diff --git a/packages/react-qr/src/constants.ts b/packages/react-qr/src/constants.ts new file mode 100644 index 00000000..6925085e --- /dev/null +++ b/packages/react-qr/src/constants.ts @@ -0,0 +1,21 @@ +// Copyright 2017-2019 @polkadot/react-qr authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +const DEFAULT_SIZE = 300; +const ADDRESS_PREFIX = 'substrate:'; + +function createSize (size: number = DEFAULT_SIZE): Record { + const height = `${size}px`; + + return { + height, + width: height + }; +} + +export { + ADDRESS_PREFIX, + DEFAULT_SIZE, + createSize +}; diff --git a/packages/react-qr/src/index.tsx b/packages/react-qr/src/index.tsx new file mode 100644 index 00000000..c0b4fd27 --- /dev/null +++ b/packages/react-qr/src/index.tsx @@ -0,0 +1,8 @@ +// Copyright 2017-2019 @polkadot/react-qr authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +export { default as QrDisplayAddress } from './DisplayAddress'; +export { default as QrDisplayPayload } from './DisplayPayload'; +export { default as QrScanAddress } from './ScanAddress'; +export { default as QrScanSignature } from './ScanSignature'; diff --git a/packages/react-qr/src/types.ts b/packages/react-qr/src/types.ts new file mode 100644 index 00000000..a8d7131d --- /dev/null +++ b/packages/react-qr/src/types.ts @@ -0,0 +1,8 @@ +// Copyright 2017-2019 @polkadot/react-qr authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +export interface BaseProps { + className?: string; + style?: Record; +} diff --git a/packages/react-qr/src/util.ts b/packages/react-qr/src/util.ts new file mode 100644 index 00000000..459b0976 --- /dev/null +++ b/packages/react-qr/src/util.ts @@ -0,0 +1,23 @@ +// Copyright 2017-2019 @polkadot/react-qr authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +export function encodeNumber (value: number): Uint8Array { + return new Uint8Array([value >> 8, value & 256]); +} + +export function encodeString (value: string): Uint8Array { + const u8a = new Uint8Array(value.length); + + for (let i = 0; i < value.length; i++) { + u8a[i] = value.charCodeAt(i); + } + + return u8a; +} + +export function decodeString (value: Uint8Array): string { + return value.reduce((str, code): string => { + return str + String.fromCharCode(code); + }, ''); +} diff --git a/tsconfig.json b/tsconfig.json index 11dc769a..3df95ef2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,8 @@ "compilerOptions": { "baseUrl": ".", "paths": { + "@polkadot/react-qr": [ "packages/react-qr/src" ], + "@polkadot/react-qr/*": [ "packages/react-qr/src/*" ], "@polkadot/ui-assets": [ "packages/ui-assets/src" ], "@polkadot/ui-assets/*": [ "packages/ui-assets/src/*" ], "@polkadot/ui-identicon": [ "packages/ui-identicon/src" ], diff --git a/yarn.lock b/yarn.lock index 0cd24f0f..70496aa7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2253,6 +2253,13 @@ dependencies: "@types/react" "*" +"@types/react-qr-reader@^2.1.1": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@types/react-qr-reader/-/react-qr-reader-2.1.2.tgz#da7a674cf9e3ceb1c026e89d5aa41fb1587fc66b" + integrity sha512-tDLqqiQMZlTKBKtWedcf7QZ3L9fyz8nPHNq/j+1mcJoEvrdM3Y89i3/FKwdmZ4H7G6uUk4JqShpWXLCuYpZK+w== + dependencies: + "@types/react" "*" + "@types/react@*", "@types/react@^16.8.23": version "16.8.23" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.23.tgz#ec6be3ceed6353a20948169b6cb4c97b65b97ad2" @@ -8175,6 +8182,11 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +jsqr@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/jsqr/-/jsqr-1.2.0.tgz#f93fc65fa7d1ded78b1bcb020fa044352b04261a" + integrity sha512-wKcQS9QC2VHGk7aphWCp1RrFyC0CM6fMgC5prZZ2KV/Lk6OKNoCod9IR6bao+yx3KPY0gZFC5dc+h+KFzCI0Wg== + jstransform@^11.0.3: version "11.0.3" resolved "https://registry.yarnpkg.com/jstransform/-/jstransform-11.0.3.tgz#09a78993e0ae4d4ef4487f6155a91f6190cb4223" @@ -10741,6 +10753,11 @@ q@^1.1.2, q@^1.5.1: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= +qrcode-generator@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/qrcode-generator/-/qrcode-generator-1.4.3.tgz#4876e8f280e65b6c94615f4c19c484f6b964b199" + integrity sha512-++rVRvMRq5BlHfmAafl8a4ppUntzUxCCUTT2t0siUgqKwdnqRzY8IH6f6WSX5dZUhD2Ul5/MIKuTJddflwrGzw== + qs@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" @@ -10899,6 +10916,15 @@ react-lifecycles-compat@^3.0.4: resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== +react-qr-reader@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/react-qr-reader/-/react-qr-reader-2.2.1.tgz#dc89046d1c1a1da837a683dd970de5926817d55b" + integrity sha512-EL5JEj53u2yAOgtpAKAVBzD/SiKWn0Bl7AZy6ZrSf1lub7xHwtaXe6XSx36Wbhl1VMGmvmrwYMRwO1aSCT2fwA== + dependencies: + jsqr "^1.2.0" + prop-types "^15.7.2" + webrtc-adapter "^7.2.1" + react-test-renderer@^16.0.0-0: version "16.8.6" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.8.6.tgz#188d8029b8c39c786f998aa3efd3ffe7642d5ba1" @@ -11400,6 +11426,13 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== +rtcpeerconnection-shim@^1.2.15: + version "1.2.15" + resolved "https://registry.yarnpkg.com/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz#e7cc189a81b435324c4949aa3dfb51888684b243" + integrity sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw== + dependencies: + sdp "^2.6.0" + run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" @@ -11501,6 +11534,11 @@ schema-utils@^2.0.0: ajv "^6.1.0" ajv-keywords "^3.1.0" +sdp@^2.6.0, sdp@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/sdp/-/sdp-2.9.0.tgz#2eed2d9c0b26c81ff87593107895c68d6fb9a0a6" + integrity sha512-XAVZQO4qsfzVTHorF49zCpkdxiGmPNjA8ps8RcJGtGP3QJ/A8I9/SVg/QnkAFDMXIyGbHZBBFwYBw6WdnhT96w== + secp256k1@^3.7.0: version "3.7.1" resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.7.1.tgz#12e473e0e9a7c2f2d4d4818e722ad0e14cc1e2f1" @@ -13349,6 +13387,14 @@ webpackbar@3.2.0: text-table "^0.2.0" wrap-ansi "^5.1.0" +webrtc-adapter@^7.2.1: + version "7.2.8" + resolved "https://registry.yarnpkg.com/webrtc-adapter/-/webrtc-adapter-7.2.8.tgz#1373fa874559c655aa713830c2836511588d77ab" + integrity sha512-d/rZVIIqqPqu/1I9rabhI+hmVhNtT+MoJk0eipCJasiVM9L9ZOTBoVhZmtC/naB4G8GTvnCaassrDz5IqWZP6w== + dependencies: + rtcpeerconnection-shim "^1.2.15" + sdp "^2.9.0" + websocket-driver@>=0.5.1: version "0.7.3" resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.3.tgz#a2d4e0d4f4f116f1e6297eba58b05d430100e9f9"