refactor: move serial port logic
This commit is contained in:
parent
4e9cfc0f74
commit
df7ebc6699
6 changed files with 628 additions and 578 deletions
|
|
@ -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>
|
||||||
|
|
@ -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 () {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,7 @@
|
||||||
<div>
|
<div>
|
||||||
<q-card>
|
<q-card>
|
||||||
<div class="row items-center no-wrap q-mb-md">
|
<div class="row items-center no-wrap q-mb-md">
|
||||||
<div class="col-11">
|
<div class="col-2 q-ml-lg">
|
||||||
<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">
|
|
||||||
<q-btn
|
<q-btn
|
||||||
unelevated
|
unelevated
|
||||||
@click="config.show = true"
|
@click="config.show = true"
|
||||||
|
|
@ -15,6 +10,14 @@
|
||||||
>
|
>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,7 @@ const watchOnly = async () => {
|
||||||
await feeRate('static/components/fee-rate/fee-rate.html')
|
await feeRate('static/components/fee-rate/fee-rate.html')
|
||||||
await sendTo('static/components/send-to/send-to.html')
|
await sendTo('static/components/send-to/send-to.html')
|
||||||
await payment('static/components/payment/payment.html')
|
await payment('static/components/payment/payment.html')
|
||||||
|
await serialSigner('static/components/serial-signer/serial-signer.html')
|
||||||
//emplate static/components/payment/payment.html
|
|
||||||
//lnbits/extensions/watchonly/static/components/payment/payment.html
|
|
||||||
|
|
||||||
Vue.filter('reverse', function (value) {
|
Vue.filter('reverse', function (value) {
|
||||||
// slice to make a copy of array, then reverse the copy
|
// slice to make a copy of array, then reverse the copy
|
||||||
|
|
@ -274,56 +272,7 @@ const watchOnly = async () => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
//################### SERIAL PORT ###################
|
//################### 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 () {
|
closeSerialPort: async function () {
|
||||||
try {
|
try {
|
||||||
console.log('### closeSerialPort', this.serial.selectedPort)
|
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 () {
|
sharePsbtWithAnimatedQRCode: async function () {
|
||||||
console.log('### sharePsbtWithAnimatedQRCode')
|
console.log('### sharePsbtWithAnimatedQRCode')
|
||||||
},
|
},
|
||||||
//################### HARDWARE WALLET ###################
|
//################### 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 ###################
|
//################### UTXOs ###################
|
||||||
scanAllAddresses: async function () {
|
scanAllAddresses: async function () {
|
||||||
await this.$refs.addressList.refreshAddresses()
|
await this.$refs.addressList.refreshAddresses()
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ const ACCOUNT_TYPES = {
|
||||||
|
|
||||||
const getAccountDescription = type => ACCOUNT_TYPES[type] || 'nonstandard'
|
const getAccountDescription = type => ACCOUNT_TYPES[type] || 'nonstandard'
|
||||||
|
|
||||||
const readFromSerialPort = serial => {
|
const readFromSerialPort = reader => {
|
||||||
let partialChunk
|
let partialChunk
|
||||||
let fulliness = []
|
let fulliness = []
|
||||||
|
|
||||||
|
|
@ -123,7 +123,7 @@ const readFromSerialPort = serial => {
|
||||||
partialChunk = undefined
|
partialChunk = undefined
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
const {value, done} = await serial.reader.read()
|
const {value, done} = await reader.read()
|
||||||
console.log('### serial read', value)
|
console.log('### serial read', value)
|
||||||
if (value) {
|
if (value) {
|
||||||
const values = value.split(separator)
|
const values = value.split(separator)
|
||||||
|
|
|
||||||
|
|
@ -230,96 +230,6 @@
|
||||||
:label="hww.authenticated ? 'Sign Tx' : 'Login'"
|
:label="hww.authenticated ? 'Sign Tx' : 'Login'"
|
||||||
@click="hwwExecuteDefaultCommand()"
|
@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>
|
</q-btn-dropdown>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
|
|
@ -577,139 +487,6 @@
|
||||||
</q-card>
|
</q-card>
|
||||||
</q-dialog>
|
</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 %}
|
{% endraw %}
|
||||||
</div>
|
</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/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/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/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>
|
<script src="{{ url_for('watchonly_static', path='js/index.js') }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue