refactor: move serial port logic

This commit is contained in:
Vlad Stan 2022-07-26 20:06:07 +03:00
parent 4e9cfc0f74
commit df7ebc6699
6 changed files with 628 additions and 578 deletions

View File

@ -0,0 +1,234 @@
<div>
<q-btn-dropdown
split
unelevated
color="primary"
icon="usb"
:text-color="selectedPort ? 'orange' : 'white'"
@click="openSerialPort"
>
<q-list>
<q-item v-if="!selectedPort" clickable v-close-popup>
<q-item-section >
<q-item-label>Configure</q-item-label>
<q-item-label caption
>Set the Serial Port communication parameters</q-item-label
>
</q-item-section>
</q-item>
<q-item
v-if="!hww.authenticated"
clickable
v-close-popup
@click="hwwShowPasswordDialog()"
>
<q-item-section v-if="selectedPort">
<q-item-label>Login</q-item-label>
<q-item-label caption
>Enter password for Hardware Wallet.</q-item-label
>
</q-item-section>
</q-item>
<q-item
v-if="hww.authenticated"
clickable
v-close-popup
@click="hwwLogout()"
>
<q-item-section>
<q-item-label>Logout</q-item-label>
<q-item-label caption>Clear password for HWW.</q-item-label>
</q-item-section>
</q-item>
<q-item
v-if="selectedPort"
clickable
v-close-popup
@click="hwwShowRestoreDialog()"
>
<q-item-section>
<q-item-label>Restore</q-item-label>
<q-item-label caption
>Restore wallet from existing word list.</q-item-label
>
</q-item-section>
</q-item>
<q-item
v-if="hww.authenticated"
clickable
v-close-popup
@click="hwwShowSeed()"
>
<q-item-section>
<q-item-label>Show Seed</q-item-label>
<q-item-label caption
>Show seed on the Hardware Wallet display.</q-item-label
>
</q-item-section>
</q-item>
<q-item
v-if="selectedPort"
@click="hwwShowWipeDialog()"
clickable
v-close-popup
>
<q-item-section>
<q-item-label>Wipe</q-item-label>
<q-item-label caption
>Clean-up the wallet. New random seed.</q-item-label
>
</q-item-section>
</q-item>
<q-item v-if="selectedPort" @click="hwwHelp()" clickable v-close-popup>
<q-item-section>
<q-item-label>Help</q-item-label>
<q-item-label caption>View available comands.</q-item-label>
</q-item-section>
</q-item>
<q-item v-if="selectedPort" clickable v-close-popup>
<q-item-section>
<q-item-label>Console</q-item-label>
<q-item-label caption
>Show the serial port communication messages</q-item-label
>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
<q-dialog v-model="hww.showPasswordDialog" position="top">
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
<q-form @submit="hwwLogin" class="q-gutter-md">
<span>Enter password for Hardware Wallet (8 numbers/letters)</span>
<q-input
filled
dense
v-model.trim="hww.password"
type="password"
label="Password"
></q-input>
<div class="row q-mt-lg">
<q-btn
unelevated
color="primary"
:disable="!selectedPort"
type="submit"
>Login</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Cancel</q-btn
>
</div>
</q-form>
</q-card>
</q-dialog>
<q-dialog v-model="hww.showWipeDialog" position="top">
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
<q-form @submit="hwwWipe" class="q-gutter-md">
<q-badge color="pink" text-color="black">
This action will remove all data from the Hardware Wallet. Please
create a back-up for the seed!
</q-badge>
<span>Enter new password for Hardware Wallet (8 numbers/letters)</span>
<q-input
filled
dense
v-model.trim="hww.password"
type="password"
label="Password"
></q-input>
<q-badge color="pink" text-color="black">
This action cannot be reversed!
</q-badge>
<div class="row q-mt-lg">
<q-btn
unelevated
color="primary"
:disable="!selectedPort"
type="submit"
>Wipe</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Cancel</q-btn
>
</div>
</q-form>
</q-card>
</q-dialog>
<q-dialog v-model="hww.showRestoreDialog" position="top">
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
<q-form @submit="hwwRestore" class="q-gutter-md">
<q-badge
color="pink"
text-color="black"
class="text-subtitle2"
multi-line
>
For test purposes only. Do not enter word list with real funds!!!
</q-badge>
<br /><br /><br />
<span>Enter new word list separated by space</span>
<q-input
v-model.trim="hww.mnemonic"
filled
:type="hww.showMnemonic ? 'text' : 'password'"
filled
dense
hint="Word List"
>
<template v-slot:append>
<q-icon
:name="hww.showMnemonic ? 'visibility' : 'visibility_off'"
class="cursor-pointer"
@click="hww.showMnemonic = !hww.showMnemonic"
/>
</template>
</q-input>
<br />
<span>Enter new password (8 numbers/letters)</span>
<q-input
v-model.trim="hww.password"
filled
:type="hww.showPassword ? 'text' : 'password'"
filled
dense
hint="New Password"
>
<template v-slot:append>
<q-icon
:name="hww.showPassword ? 'visibility' : 'visibility_off'"
class="cursor-pointer"
@click="hww.showPassword = !hww.showPassword"
/>
</template>
</q-input>
<br /><br />
<q-badge
color="pink"
text-color="black"
class="text-subtitle2"
multi-line
>
For test purposes only. Do not enter word list with real funds.
</q-badge>
<div class="row q-mt-lg">
<q-btn
unelevated
color="primary"
:disable="!selectedPort"
type="submit"
>Restore</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Cancel</q-btn
>
</div>
</q-form>
</q-card>
</q-dialog>
</div>

View File

@ -0,0 +1,380 @@
async function serialSigner(path) {
const t = await loadTemplateAsync(path)
Vue.component('serial-signer', {
name: 'serial-signer',
template: t,
props: [],
data: function () {
return {
selectedPort: null,
writableStreamClosed: null,
writer: null,
readableStreamClosed: null,
reader: null,
showAdvancedConfig: false,
receivedData: '',
config: {},
hww: {
password: null,
showPassword: false,
mnemonic: null,
showMnemonic: false,
authenticated: false,
showPasswordDialog: false,
showWipeDialog: false,
showRestoreDialog: false,
showConsole: false,
showSignedPsbt: false,
sendingPsbt: false,
signingPsbt: false,
psbtSent: false
}
}
},
methods: {
openSerialPort: async function () {
if (!this.checkSerialPortSupported()) return
console.log('### openSerialPort', this.selectedPort)
try {
navigator.serial.addEventListener('connect', event => {
console.log('### navigator.serial event: connected!', event)
})
navigator.serial.addEventListener('disconnect', () => {
this.hww.authenticated = false
this.$q.notify({
type: 'warning',
message: 'Disconnected from Serial Port!',
timeout: 10000
})
})
this.selectedPort = await navigator.serial.requestPort()
// Wait for the serial port to open.
await this.selectedPort.open({baudRate: 9600})
this.startSerialPortReading()
const textEncoder = new TextEncoderStream()
this.writableStreamClosed = textEncoder.readable.pipeTo(
this.selectedPort.writable
)
this.writer = textEncoder.writable.getWriter()
} catch (error) {
this.selectedPort = null
this.$q.notify({
type: 'warning',
message: 'Cannot open serial port!',
caption: `${error}`,
timeout: 10000
})
}
},
checkSerialPortSupported: function () {
if (!navigator.serial) {
this.$q.notify({
type: 'warning',
message: 'Serial port communication not supported!',
caption:
'Make sure your browser supports Serial Port and that you are using HTTPS.',
timeout: 10000
})
return false
}
return true
},
startSerialPortReading: async function () {
const port = this.selectedPort
while (port && port.readable) {
const textDecoder = new TextDecoderStream()
this.readableStreamClosed = port.readable.pipeTo(textDecoder.writable)
this.reader = textDecoder.readable.getReader()
const readStringUntil = readFromSerialPort(this.reader)
try {
while (true) {
const {value, done} = await readStringUntil('\n')
console.log('### value', value)
if (value) {
this.handleSerialPortResponse(value)
this.updateSerialPortConsole(value)
}
console.log('### startSerialPortReading DONE', done)
if (done) return
}
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Serial port communication error!',
caption: `${error}`,
timeout: 10000
})
}
}
console.log('### startSerialPortReading port', port)
},
handleSerialPortResponse: function (value) {
const msg = value.split(' ')
if (msg[0] == COMMAND_SIGN_PSBT) this.handleSignResponse(msg[1])
else if (msg[0] == COMMAND_PASSWORD) this.handleLoginResponse(msg[1])
else if (msg[0] == COMMAND_PASSWORD_CLEAR)
this.handleLogoutResponse(msg[1])
else if (msg[0] == COMMAND_SEND_PSBT)
this.handleSendPsbtResponse(msg[1])
else if (msg[0] == COMMAND_WIPE) this.handleWipeResponse(msg[1])
else console.log('### handleSerialPortResponse', value)
},
updateSerialPortConsole: function (value) {
this.receivedData += value + '\n'
const textArea = document.getElementById(
'watchonly-serial-port-data-input'
)
if (textArea) textArea.scrollTop = textArea.scrollHeight
},
hwwShowPasswordDialog: async function () {
try {
this.hww.showPasswordDialog = true
await this.writer.write(COMMAND_PASSWORD + '\n')
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to connect to Hardware Wallet!',
caption: `${error}`,
timeout: 10000
})
}
},
hwwShowWipeDialog: async function () {
try {
this.hww.showWipeDialog = true
await this.writer.write(COMMAND_WIPE + '\n')
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to connect to Hardware Wallet!',
caption: `${error}`,
timeout: 10000
})
}
},
hwwShowRestoreDialog: async function () {
try {
this.hww.showRestoreDialog = true
await this.writer.write(COMMAND_WIPE + '\n')
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to connect to Hardware Wallet!',
caption: `${error}`,
timeout: 10000
})
}
},
hwwLogin: async function () {
try {
await this.writer.write(
COMMAND_PASSWORD + ' ' + this.hww.password + '\n'
)
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to send password to Hardware Wallet!',
caption: `${error}`,
timeout: 10000
})
} finally {
this.hww.showPasswordDialog = false
this.hww.password = null
this.hww.showPassword = false
}
},
handleLoginResponse: function (res = '') {
this.hww.authenticated = res.trim() === '1'
if (this.hww.authenticated) {
this.$q.notify({
type: 'positive',
message: 'Login successfull!',
timeout: 10000
})
} else {
this.$q.notify({
type: 'warning',
message: 'Wrong password, try again!',
timeout: 10000
})
}
},
hwwLogout: async function () {
try {
await this.writer.write(COMMAND_PASSWORD_CLEAR + '\n')
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to logout from Hardware Wallet!',
caption: `${error}`,
timeout: 10000
})
}
},
handleLogoutResponse: function (res = '') {
this.hww.authenticated = !(res.trim() === '1')
if (this.hww.authenticated) {
this.$q.notify({
type: 'warning',
message: 'Failed to logout from Hardware Wallet',
timeout: 10000
})
}
},
hwwExecuteDefaultCommand: function () {
if (this.hww.authenticated) {
this.hwwSendPsbt()
} else {
this.hwwShowPasswordDialog()
}
},
hwwSendPsbt: async function () {
try {
this.hww.sendingPsbt = true
await this.writer.write(
COMMAND_SEND_PSBT + ' ' + this.payment.psbtBase64 + '\n'
)
this.$q.notify({
type: 'positive',
message: 'Data sent to serial port device!',
timeout: 5000
})
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to send data to serial port!',
caption: `${error}`,
timeout: 10000
})
}
},
handleSendPsbtResponse: function (res = '') {
this.hww.psbtSent = true
this.hww.sendingPsbt = false
},
hwwSignPsbt: async function () {
try {
this.hww.signingPsbt = true
await this.writer.write(COMMAND_SIGN_PSBT + '\n')
this.$q.notify({
type: 'positive',
message: 'PSBT signed!',
timeout: 5000
})
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to sign PSBT!',
caption: `${error}`,
timeout: 10000
})
}
},
handleSignResponse: function (res = '') {
this.hww.signingPsbt = false
this.updateSignedPsbt(res)
if (this.hww.authenticated) {
this.$q.notify({
type: 'positive',
message: 'Transaction Signed',
timeout: 10000
})
}
},
hwwHelp: async function () {
try {
await this.writer.write(COMMAND_HELP + '\n')
this.$q.notify({
type: 'positive',
message: 'Check display or console for details!',
timeout: 5000
})
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to ask for help!',
caption: `${error}`,
timeout: 10000
})
}
},
hwwWipe: async function () {
try {
this.hww.showWipeDialog = false
await this.writer.write(COMMAND_WIPE + ' ' + this.hww.password + '\n')
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to ask for help!',
caption: `${error}`,
timeout: 10000
})
} finally {
this.hww.password = null
this.hww.showPassword = false
}
},
handleWipeResponse: function (res = '') {
const wiped = res.trim() === '1'
console.log('### wiped', wiped)
if (wiped) {
this.$q.notify({
type: 'positive',
message: 'Wallet wiped!',
timeout: 10000
})
} else {
this.$q.notify({
type: 'warning',
message: 'Failed to wipe wallet!',
caption: `${error}`,
timeout: 10000
})
}
},
hwwShowSeed: async function () {
try {
await this.writer.write(COMMAND_SEED + '\n')
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to show seed!',
caption: `${error}`,
timeout: 10000
})
}
},
hwwRestore: async function () {
try {
await this.writer.write(
COMMAND_RESTORE + ' ' + this.hww.mnemonic + '\n'
)
await this.writer.write(
COMMAND_PASSWORD + ' ' + this.hww.password + '\n'
)
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to restore from seed!',
caption: `${error}`,
timeout: 10000
})
} finally {
this.hww.showRestoreDialog = false
this.hww.mnemonic = null
this.hww.showMnemonic = false
this.hww.password = null
this.hww.showPassword = false
}
}
},
created: async function () {}
})
}

View File

@ -1,12 +1,7 @@
<div>
<q-card>
<div class="row items-center no-wrap q-mb-md">
<div class="col-11">
<div class="row justify-center q-gutter-x-md items-center">
<div class="text-h3 q-pa-sm">{{satBtc(total)}}</div>
</div>
</div>
<div class="col-1">
<div class="col-2 q-ml-lg">
<q-btn
unelevated
@click="config.show = true"
@ -15,6 +10,14 @@
>
</q-btn>
</div>
<div class="col-8">
<div class="row justify-center q-gutter-x-md items-center">
<div class="text-h3">{{satBtc(total)}}</div>
</div>
</div>
<div class="col-2 float-right">
<serial-signer></serial-signer>
</div>
</div>
</q-card>

View File

@ -9,9 +9,7 @@ const watchOnly = async () => {
await feeRate('static/components/fee-rate/fee-rate.html')
await sendTo('static/components/send-to/send-to.html')
await payment('static/components/payment/payment.html')
//emplate static/components/payment/payment.html
//lnbits/extensions/watchonly/static/components/payment/payment.html
await serialSigner('static/components/serial-signer/serial-signer.html')
Vue.filter('reverse', function (value) {
// slice to make a copy of array, then reverse the copy
@ -274,56 +272,7 @@ const watchOnly = async () => {
}
},
//################### SERIAL PORT ###################
checkSerialPortSupported: function () {
if (!navigator.serial) {
this.$q.notify({
type: 'warning',
message: 'Serial port communication not supported!',
caption:
'Make sure your browser supports Serial Port and that you are using HTTPS.',
timeout: 10000
})
return false
}
return true
},
openSerialPort: async function () {
if (!this.checkSerialPortSupported()) return
console.log('### openSerialPort', this.serial.selectedPort)
try {
navigator.serial.addEventListener('connect', event => {
console.log('### navigator.serial event: connected!', event)
})
navigator.serial.addEventListener('disconnect', () => {
this.hww.authenticated = false
this.$q.notify({
type: 'warning',
message: 'Disconnected from Serial Port!',
timeout: 10000
})
})
this.serial.selectedPort = await navigator.serial.requestPort()
// Wait for the serial port to open.
await this.serial.selectedPort.open({baudRate: 9600})
this.startSerialPortReading()
const textEncoder = new TextEncoderStream()
this.serial.writableStreamClosed = textEncoder.readable.pipeTo(
this.serial.selectedPort.writable
)
this.serial.writer = textEncoder.writable.getWriter()
} catch (error) {
this.serial.selectedPort = null
this.$q.notify({
type: 'warning',
message: 'Cannot open serial port!',
caption: `${error}`,
timeout: 10000
})
}
},
closeSerialPort: async function () {
try {
console.log('### closeSerialPort', this.serial.selectedPort)
@ -354,305 +303,11 @@ const watchOnly = async () => {
}
},
startSerialPortReading: async function () {
const port = this.serial.selectedPort
while (port && port.readable) {
const textDecoder = new TextDecoderStream()
this.serial.readableStreamClosed = port.readable.pipeTo(
textDecoder.writable
)
this.serial.reader = textDecoder.readable.getReader()
const readStringUntil = readFromSerialPort(this.serial)
try {
while (true) {
const {value, done} = await readStringUntil('\n')
console.log('### value', value)
if (value) {
this.handleSerialPortResponse(value)
this.updateSerialPortConsole(value)
}
console.log('### startSerialPortReading DONE', done)
if (done) return
}
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Serial port communication error!',
caption: `${error}`,
timeout: 10000
})
}
}
console.log('### startSerialPortReading port', port)
},
handleSerialPortResponse: function (value) {
const msg = value.split(' ')
if (msg[0] == COMMAND_SIGN_PSBT) this.handleSignResponse(msg[1])
else if (msg[0] == COMMAND_PASSWORD) this.handleLoginResponse(msg[1])
else if (msg[0] == COMMAND_PASSWORD_CLEAR)
this.handleLogoutResponse(msg[1])
else if (msg[0] == COMMAND_SEND_PSBT)
this.handleSendPsbtResponse(msg[1])
else if (msg[0] == COMMAND_WIPE) this.handleWipeResponse(msg[1])
else console.log('### handleSerialPortResponse', value)
},
updateSerialPortConsole: function (value) {
this.serial.receivedData += value + '\n'
const textArea = document.getElementById(
'watchonly-serial-port-data-input'
)
if (textArea) textArea.scrollTop = textArea.scrollHeight
},
sharePsbtWithAnimatedQRCode: async function () {
console.log('### sharePsbtWithAnimatedQRCode')
},
//################### HARDWARE WALLET ###################
hwwShowPasswordDialog: async function () {
try {
this.hww.showPasswordDialog = true
await this.serial.writer.write(COMMAND_PASSWORD + '\n')
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to connect to Hardware Wallet!',
caption: `${error}`,
timeout: 10000
})
}
},
hwwShowWipeDialog: async function () {
try {
this.hww.showWipeDialog = true
await this.serial.writer.write(COMMAND_WIPE + '\n')
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to connect to Hardware Wallet!',
caption: `${error}`,
timeout: 10000
})
}
},
hwwShowRestoreDialog: async function () {
try {
this.hww.showRestoreDialog = true
await this.serial.writer.write(COMMAND_WIPE + '\n')
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to connect to Hardware Wallet!',
caption: `${error}`,
timeout: 10000
})
}
},
hwwLogin: async function () {
try {
await this.serial.writer.write(
COMMAND_PASSWORD + ' ' + this.hww.password + '\n'
)
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to send password to Hardware Wallet!',
caption: `${error}`,
timeout: 10000
})
} finally {
this.hww.showPasswordDialog = false
this.hww.password = null
this.hww.showPassword = false
}
},
handleLoginResponse: function (res = '') {
this.hww.authenticated = res.trim() === '1'
if (this.hww.authenticated) {
this.$q.notify({
type: 'positive',
message: 'Login successfull!',
timeout: 10000
})
} else {
this.$q.notify({
type: 'warning',
message: 'Wrong password, try again!',
timeout: 10000
})
}
},
hwwLogout: async function () {
try {
await this.serial.writer.write(COMMAND_PASSWORD_CLEAR + '\n')
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to logout from Hardware Wallet!',
caption: `${error}`,
timeout: 10000
})
}
},
handleLogoutResponse: function (res = '') {
this.hww.authenticated = !(res.trim() === '1')
if (this.hww.authenticated) {
this.$q.notify({
type: 'warning',
message: 'Failed to logout from Hardware Wallet',
timeout: 10000
})
}
},
hwwExecuteDefaultCommand: function () {
if (this.hww.authenticated) {
this.hwwSendPsbt()
} else {
this.hwwShowPasswordDialog()
}
},
hwwSendPsbt: async function () {
try {
this.hww.sendingPsbt = true
await this.serial.writer.write(
COMMAND_SEND_PSBT + ' ' + this.payment.psbtBase64 + '\n'
)
this.$q.notify({
type: 'positive',
message: 'Data sent to serial port device!',
timeout: 5000
})
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to send data to serial port!',
caption: `${error}`,
timeout: 10000
})
}
},
handleSendPsbtResponse: function (res = '') {
this.hww.psbtSent = true
this.hww.sendingPsbt = false
},
hwwSignPsbt: async function () {
try {
this.hww.signingPsbt = true
await this.serial.writer.write(COMMAND_SIGN_PSBT + '\n')
this.$q.notify({
type: 'positive',
message: 'PSBT signed!',
timeout: 5000
})
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to sign PSBT!',
caption: `${error}`,
timeout: 10000
})
}
},
handleSignResponse: function (res = '') {
this.hww.signingPsbt = false
this.updateSignedPsbt(res)
if (this.hww.authenticated) {
this.$q.notify({
type: 'positive',
message: 'Transaction Signed',
timeout: 10000
})
}
},
hwwHelp: async function () {
try {
await this.serial.writer.write(COMMAND_HELP + '\n')
this.$q.notify({
type: 'positive',
message: 'Check display or console for details!',
timeout: 5000
})
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to ask for help!',
caption: `${error}`,
timeout: 10000
})
}
},
hwwWipe: async function () {
try {
this.hww.showWipeDialog = false
await this.serial.writer.write(
COMMAND_WIPE + ' ' + this.hww.password + '\n'
)
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to ask for help!',
caption: `${error}`,
timeout: 10000
})
} finally {
this.hww.password = null
this.hww.showPassword = false
}
},
handleWipeResponse: function (res = '') {
const wiped = res.trim() === '1'
console.log('### wiped', wiped)
if (wiped) {
this.$q.notify({
type: 'positive',
message: 'Wallet wiped!',
timeout: 10000
})
} else {
this.$q.notify({
type: 'warning',
message: 'Failed to wipe wallet!',
caption: `${error}`,
timeout: 10000
})
}
},
hwwShowSeed: async function () {
try {
await this.serial.writer.write(COMMAND_SEED + '\n')
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to show seed!',
caption: `${error}`,
timeout: 10000
})
}
},
hwwRestore: async function () {
try {
await this.serial.writer.write(
COMMAND_RESTORE + ' ' + this.hww.mnemonic + '\n'
)
await this.serial.writer.write(
COMMAND_PASSWORD + ' ' + this.hww.password + '\n'
)
} catch (error) {
this.$q.notify({
type: 'warning',
message: 'Failed to restore from seed!',
caption: `${error}`,
timeout: 10000
})
} finally {
this.hww.showRestoreDialog = false
this.hww.mnemonic = null
this.hww.showMnemonic = false
this.hww.password = null
this.hww.showPassword = false
}
},
//################### UTXOs ###################
scanAllAddresses: async function () {
await this.$refs.addressList.refreshAddresses()

View File

@ -110,7 +110,7 @@ const ACCOUNT_TYPES = {
const getAccountDescription = type => ACCOUNT_TYPES[type] || 'nonstandard'
const readFromSerialPort = serial => {
const readFromSerialPort = reader => {
let partialChunk
let fulliness = []
@ -123,7 +123,7 @@ const readFromSerialPort = serial => {
partialChunk = undefined
}
while (true) {
const {value, done} = await serial.reader.read()
const {value, done} = await reader.read()
console.log('### serial read', value)
if (value) {
const values = value.split(separator)

View File

@ -230,96 +230,6 @@
:label="hww.authenticated ? 'Sign Tx' : 'Login'"
@click="hwwExecuteDefaultCommand()"
>
<q-list>
<q-item
v-if="!hww.authenticated"
clickable
v-close-popup
@click="hwwShowPasswordDialog()"
>
<q-item-section>
<q-item-label>Login</q-item-label>
<q-item-label caption
>Enter password for Hardware Wallet.</q-item-label
>
</q-item-section>
</q-item>
<q-item
v-if="hww.authenticated"
clickable
v-close-popup
@click="hwwLogout()"
>
<q-item-section>
<q-item-label>Logout</q-item-label>
<q-item-label caption
>Clear password for HWW.</q-item-label
>
</q-item-section>
</q-item>
<q-item
:disabled="!hww.authenticated"
clickable
v-close-popup
@click="hwwSendPsbt()"
>
<q-item-section>
<q-item-label>Sign</q-item-label>
<q-item-label caption
>Sign transaction on Hardware Wallet</q-item-label
>
</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@click="hwwShowRestoreDialog()"
>
<q-item-section>
<q-item-label>Restore</q-item-label>
<q-item-label caption
>Restore wallet from existing word
list.</q-item-label
>
</q-item-section>
</q-item>
<q-item
:disabled="!hww.authenticated"
clickable
v-close-popup
@click="hwwShowSeed()"
>
<q-item-section>
<q-item-label>Show Seed</q-item-label>
<q-item-label caption
>Show seed on the Hardware Wallet
display.</q-item-label
>
</q-item-section>
</q-item>
<q-item
@click="hwwShowWipeDialog()"
clickable
v-close-popup
>
<q-item-section>
<q-item-label>Wipe</q-item-label>
<q-item-label caption
>Clean-up the wallet. New random
seed.</q-item-label
>
</q-item-section>
</q-item>
<q-item @click="hwwHelp()" clickable v-close-popup>
<q-item-section>
<q-item-label>Help</q-item-label>
<q-item-label caption
>View available comands.</q-item-label
>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</div>
<div class="col-3">
@ -577,139 +487,6 @@
</q-card>
</q-dialog>
<q-dialog v-model="hww.showPasswordDialog" position="top">
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
<q-form @submit="hwwLogin" class="q-gutter-md">
<span>Enter password for Hardware Wallet (8 numbers/letters)</span>
<q-input
filled
dense
v-model.trim="hww.password"
type="password"
label="Password"
></q-input>
<div class="row q-mt-lg">
<q-btn
unelevated
color="primary"
:disable="!serial.selectedPort"
type="submit"
>Login</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Cancel</q-btn
>
</div>
</q-form>
</q-card>
</q-dialog>
<q-dialog v-model="hww.showWipeDialog" position="top">
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
<q-form @submit="hwwWipe" class="q-gutter-md">
<q-badge color="pink" text-color="black">
This action will remove all data from the Hardware Wallet. Please
create a back-up for the seed!
</q-badge>
<span>Enter new password for Hardware Wallet (8 numbers/letters)</span>
<q-input
filled
dense
v-model.trim="hww.password"
type="password"
label="Password"
></q-input>
<q-badge color="pink" text-color="black">
This action cannot be reversed!
</q-badge>
<div class="row q-mt-lg">
<q-btn
unelevated
color="primary"
:disable="!serial.selectedPort"
type="submit"
>Wipe</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Cancel</q-btn
>
</div>
</q-form>
</q-card>
</q-dialog>
<q-dialog v-model="hww.showRestoreDialog" position="top">
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
<q-form @submit="hwwRestore" class="q-gutter-md">
<q-badge
color="pink"
text-color="black"
class="text-subtitle2"
multi-line
>
For test purposes only. Do not enter word list with real funds!!!
</q-badge>
<br /><br /><br />
<span>Enter new word list separated by space</span>
<q-input
v-model.trim="hww.mnemonic"
filled
:type="hww.showMnemonic ? 'text' : 'password'"
filled
dense
hint="Word List"
>
<template v-slot:append>
<q-icon
:name="hww.showMnemonic ? 'visibility' : 'visibility_off'"
class="cursor-pointer"
@click="hww.showMnemonic = !hww.showMnemonic"
/>
</template>
</q-input>
<br />
<span>Enter new password (8 numbers/letters)</span>
<q-input
v-model.trim="hww.password"
filled
:type="hww.showPassword ? 'text' : 'password'"
filled
dense
hint="New Password"
>
<template v-slot:append>
<q-icon
:name="hww.showPassword ? 'visibility' : 'visibility_off'"
class="cursor-pointer"
@click="hww.showPassword = !hww.showPassword"
/>
</template>
</q-input>
<br /><br />
<q-badge
color="pink"
text-color="black"
class="text-subtitle2"
multi-line
>
For test purposes only. Do not enter word list with real funds.
</q-badge>
<div class="row q-mt-lg">
<q-btn
unelevated
color="primary"
:disable="!serial.selectedPort"
type="submit"
>Restore</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Cancel</q-btn
>
</div>
</q-form>
</q-card>
</q-dialog>
{% endraw %}
</div>
@ -733,5 +510,6 @@
<script src="{{ url_for('watchonly_static', path='components/fee-rate/fee-rate.js') }}"></script>
<script src="{{ url_for('watchonly_static', path='components/send-to/send-to.js') }}"></script>
<script src="{{ url_for('watchonly_static', path='components/payment/payment.js') }}"></script>
<script src="{{ url_for('watchonly_static', path='components/serial-signer/serial-signer.js') }}"></script>
<script src="{{ url_for('watchonly_static', path='js/index.js') }}"></script>
{% endblock %}