From 7d1f0df8ae81dc71ec66cd217b28a6680bc629a7 Mon Sep 17 00:00:00 2001 From: Traxo7 Date: Sat, 16 Jul 2022 23:23:35 +0200 Subject: [PATCH] Adds qr-login settings view - renders the QR code which can be used to unlock (restore) the wallet on other device by using the set password --- .../config/default.build.options.js | 4 + qortal-ui-core/language/us.json | 5 + .../components/settings-view/qr-login-view.js | 140 ++++++++++++++++++ .../components/settings-view/user-settings.js | 8 + 4 files changed, 157 insertions(+) create mode 100644 qortal-ui-core/src/components/settings-view/qr-login-view.js diff --git a/qortal-ui-core/config/default.build.options.js b/qortal-ui-core/config/default.build.options.js index 5c3ef43a..361b1f47 100644 --- a/qortal-ui-core/config/default.build.options.js +++ b/qortal-ui-core/config/default.build.options.js @@ -109,6 +109,10 @@ const elementComponents = { file: 'components/settings-view/security-view.js', className: 'SecurityView' }, + 'qr-login-view': { + file: 'components/settings-view/qr-login-view.js', + className: 'QRLoginView' + }, 'notifications-view': { file: 'components/settings-view/notifications-view.js', className: 'NotificationsView' diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index b7f4bec6..cc63254c 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -93,6 +93,11 @@ "settings": "Settings", "account": "Account", "security": "Security", + "qr_login_menu_item": "QR Login", + "qr_login_description_1": "Scan this code to unlock your wallet on other device using the same password which you logged in with.", + "qr_login_description_2": "Choose a password which you will use to unlock your wallet on other device after scanning the QR code.", + "qr_login_button_1": "Show login QR code", + "qr_login_button_2": "Generate login QR code", "notifications": "Notifications", "accountsecurity": "Account Security", "password": "Password", diff --git a/qortal-ui-core/src/components/settings-view/qr-login-view.js b/qortal-ui-core/src/components/settings-view/qr-login-view.js new file mode 100644 index 00000000..606ee323 --- /dev/null +++ b/qortal-ui-core/src/components/settings-view/qr-login-view.js @@ -0,0 +1,140 @@ +import { css, html, LitElement } from 'lit' +import { connect } from 'pwa-helpers' +import { store } from '../../store.js' +import { translate } from 'lit-translate' + +import '@material/mwc-textfield' +import '@material/mwc-icon' +import '@vaadin/password-field/vaadin-password-field.js' +import '../../../../qortal-ui-plugins/plugins/core/components/QortalQrcodeGenerator.js' + +class QRLoginView extends connect(store)(LitElement) { + static get properties() { + return { + theme: { type: String, reflect: true }, + savedWalletDataJson: { type: String }, + translateDescriptionKey: { type: String }, // Description text + translateButtonKey: { type: String }, // Button text + } + } + + static get styles() { + return css` + * { + --lumo-primary-text-color: rgb(0, 167, 245); + --lumo-primary-color-50pct: rgba(0, 167, 245, 0.5); + --lumo-primary-color-10pct: rgba(0, 167, 245, 0.1); + --lumo-primary-color: hsl(199, 100%, 48%); + --lumo-base-color: var(--white); + --lumo-body-text-color: var(--black); + --lumo-secondary-text-color: var(--sectxt); + --lumo-contrast-60pct: var(--vdicon); + } + + .center-box { + position: relative; + top: 45%; + left: 50%; + transform: translate(-50%, 0%); + text-align: center; + } + + .q-button { + display: inline-flex; + flex-direction: column; + justify-content: center; + align-content: center; + border: none; + border-radius: 20px; + padding-left: 25px; + padding-right: 25px; + color: white; + background: #03a9f4; + width: 50%; + font-size: 17px; + cursor: pointer; + height: 50px; + margin-top: 1rem; + text-transform: uppercase; + text-decoration: none; + transition: all .2s; + position: relative; + } + + .q-button.outlined { + background: unset; + border: 1px solid #03a9f4; + } + + :host([theme="light"]) .q-button.outlined { + color: #03a9f4; + } + + #qr-toggle-button { + margin-left: 12px; + } + + #login-qr-code { + margin: auto; + } + ` + } + + constructor() { + super() + this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light' + this.translateDescriptionKey = 'settings.qr_login_description_' + (this.isWalletStored() ? '1' : '2') + this.translateButtonKey = 'settings.qr_login_button_' + (this.isWalletStored() ? '1' : '2') + } + + render() { + return html` +
+
+

+ ${translate(this.translateDescriptionKey)} +

+
+ password + +
+
+
this.showQRCode()} class="q-button outlined"> ${translate(this.translateButtonKey)}
+
+ + +
+
+ ` + } + + isWalletStored() { + const state = store.getState() + const address0 = state.app.wallet._addresses[0].address + const savedWalletData = state.user.storedWallets && state.user.storedWallets[address0] + return !!savedWalletData + } + + async setSavedWalletDataJson() { + const state = store.getState() + let data + if (this.isWalletStored()) { // if the wallet is stored, we use the existing encrypted backup + const address0 = state.app.wallet._addresses[0].address + data = state.user.storedWallets[address0] + } else { // if the wallet is not stored, we generate new `saveWalletData` backup encrypted with the new password + const password = this.shadowRoot.getElementById('newWalletPassword').value + data = await state.app.wallet.generateSaveWalletData(password, state.config.crypto.kdfThreads, () => { }) + } + this.savedWalletDataJson = JSON.stringify(data) + } + + async showQRCode() { + await this.setSavedWalletDataJson() + let el = this.shadowRoot.getElementById('login-qr-code') + el.style.display = 'flex' + } +} + +window.customElements.define('qr-login-view', QRLoginView) diff --git a/qortal-ui-core/src/components/settings-view/user-settings.js b/qortal-ui-core/src/components/settings-view/user-settings.js index 7665c9ba..4d522f17 100644 --- a/qortal-ui-core/src/components/settings-view/user-settings.js +++ b/qortal-ui-core/src/components/settings-view/user-settings.js @@ -9,6 +9,7 @@ import '@material/mwc-button' import './account-view.js' import './security-view.js' import './notifications-view.js' +import './qr-login-view.js' import { doLogout } from '../../redux/app/app-actions.js' @@ -225,6 +226,7 @@ class UserSettings extends connect(store)(LitElement) { @@ -250,6 +252,8 @@ class UserSettings extends connect(store)(LitElement) { return html``; } else if (selectedView.id === 'notification') { return html``; + } else if (selectedView.id === 'qr-login') { + return html``; } } @@ -260,6 +264,8 @@ class UserSettings extends connect(store)(LitElement) { return html`${translate("settings.accountsecurity")}`; } else if (this.selectedView.id === 'notification') { return html`UI ${translate("settings.notifications")}`; + } else if (this.selectedView.id === 'qr-login') { + return html`${translate("settings.qr_login_menu_item")}`; } } @@ -270,6 +276,8 @@ class UserSettings extends connect(store)(LitElement) { return this.selectedView = { id: 'security', name: 'Account Security' } } else if (pageId === 'notification') { return this.selectedView = { id: 'notification', name: 'UI Notifications' } + } else if (pageId === 'qr-login') { + return this.selectedView = { id: 'qr-login', name: 'QR Login' } } }