wip otp on pay
This commit is contained in:
53
electrum/gui/qml/components/OtpDialog.qml
Normal file
53
electrum/gui/qml/components/OtpDialog.qml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import QtQuick 2.6
|
||||||
|
import QtQuick.Layouts 1.0
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
import QtQuick.Controls.Material 2.0
|
||||||
|
|
||||||
|
import org.electrum 1.0
|
||||||
|
|
||||||
|
import "controls"
|
||||||
|
|
||||||
|
ElDialog {
|
||||||
|
id: dialog
|
||||||
|
|
||||||
|
title: qsTr('OTP auth')
|
||||||
|
|
||||||
|
property string otpauth
|
||||||
|
|
||||||
|
// property var lnurlData
|
||||||
|
// property InvoiceParser invoiceParser
|
||||||
|
// property alias lnurlData: dialog.invoiceParser.lnurlData
|
||||||
|
|
||||||
|
standardButtons: Dialog.Cancel
|
||||||
|
|
||||||
|
modal: true
|
||||||
|
parent: Overlay.overlay
|
||||||
|
Overlay.modal: Rectangle {
|
||||||
|
color: "#aa000000"
|
||||||
|
}
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
columns: 2
|
||||||
|
implicitWidth: parent.width
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr('code')
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: otpEdit
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr('Proceed')
|
||||||
|
onClicked: {
|
||||||
|
// dialog.close()
|
||||||
|
otpauth = otpEdit.text
|
||||||
|
dialog.accept()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -256,6 +256,19 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: Daemon.currentWallet
|
||||||
|
function onOtpRequested() {
|
||||||
|
console.log('OTP requested')
|
||||||
|
var dialog = otpDialog.createObject(mainView)
|
||||||
|
dialog.accepted.connect(function() {
|
||||||
|
console.log('accepted ' + dialog.otpauth)
|
||||||
|
Daemon.currentWallet.finish_otp(dialog.otpauth)
|
||||||
|
})
|
||||||
|
dialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: sendDialog
|
id: sendDialog
|
||||||
SendDialog {
|
SendDialog {
|
||||||
@@ -304,5 +317,15 @@ Item {
|
|||||||
onClosed: destroy()
|
onClosed: destroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: otpDialog
|
||||||
|
OtpDialog {
|
||||||
|
width: parent.width * 0.9
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
onClosed: destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import queue
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from typing import Optional, TYPE_CHECKING
|
from typing import Optional, TYPE_CHECKING
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer
|
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@ from electrum.logging import get_logger
|
|||||||
from electrum.network import TxBroadcastError, BestEffortRequestFailed
|
from electrum.network import TxBroadcastError, BestEffortRequestFailed
|
||||||
from electrum.transaction import PartialTxOutput
|
from electrum.transaction import PartialTxOutput
|
||||||
from electrum.util import (parse_max_spend, InvalidPassword, event_listener)
|
from electrum.util import (parse_max_spend, InvalidPassword, event_listener)
|
||||||
|
from electrum.plugin import run_hook
|
||||||
|
|
||||||
from .auth import AuthMixin, auth_protect
|
from .auth import AuthMixin, auth_protect
|
||||||
from .qeaddresslistmodel import QEAddressListModel
|
from .qeaddresslistmodel import QEAddressListModel
|
||||||
@@ -63,6 +65,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
|||||||
#broadcastSucceeded = pyqtSignal([str], arguments=['txid'])
|
#broadcastSucceeded = pyqtSignal([str], arguments=['txid'])
|
||||||
broadcastFailed = pyqtSignal([str,str,str], arguments=['txid','code','reason'])
|
broadcastFailed = pyqtSignal([str,str,str], arguments=['txid','code','reason'])
|
||||||
labelsUpdated = pyqtSignal()
|
labelsUpdated = pyqtSignal()
|
||||||
|
otpRequested = pyqtSignal()
|
||||||
|
|
||||||
_network_signal = pyqtSignal(str, object)
|
_network_signal = pyqtSignal(str, object)
|
||||||
|
|
||||||
@@ -423,6 +426,16 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
|||||||
|
|
||||||
@auth_protect
|
@auth_protect
|
||||||
def sign(self, tx, *, broadcast: bool = False):
|
def sign(self, tx, *, broadcast: bool = False):
|
||||||
|
sign_hook = run_hook('tc_sign_wrapper', self.wallet, tx, partial(self.on_sign_complete, broadcast), None)
|
||||||
|
if sign_hook:
|
||||||
|
self.do_sign(tx, False)
|
||||||
|
self._logger.debug('plugin needs to sign tx too')
|
||||||
|
sign_hook(tx)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.do_sign(tx, broadcast)
|
||||||
|
|
||||||
|
def do_sign(self, tx, broadcast):
|
||||||
tx = self.wallet.sign_transaction(tx, self.password)
|
tx = self.wallet.sign_transaction(tx, self.password)
|
||||||
|
|
||||||
if tx is None:
|
if tx is None:
|
||||||
@@ -441,6 +454,18 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
|||||||
if broadcast:
|
if broadcast:
|
||||||
self.broadcast(tx)
|
self.broadcast(tx)
|
||||||
|
|
||||||
|
def on_sign_complete(self, broadcast, tx):
|
||||||
|
if broadcast:
|
||||||
|
self.broadcast(tx)
|
||||||
|
|
||||||
|
def request_otp(self, on_submit):
|
||||||
|
self._otp_on_submit = on_submit
|
||||||
|
self.otpRequested.emit()
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def finish_otp(self, otp):
|
||||||
|
self._otp_on_submit(otp)
|
||||||
|
|
||||||
def broadcast(self, tx):
|
def broadcast(self, tx):
|
||||||
assert tx.is_complete()
|
assert tx.is_complete()
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot
|
|||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.plugin import hook
|
from electrum.plugin import hook
|
||||||
from electrum.bip32 import xpub_type
|
from electrum.bip32 import xpub_type
|
||||||
|
from electrum.util import UserFacingException
|
||||||
from electrum import keystore
|
from electrum import keystore
|
||||||
|
|
||||||
from electrum.gui.qml.qewallet import QEWallet
|
from electrum.gui.qml.qewallet import QEWallet
|
||||||
@@ -18,8 +19,6 @@ from .trustedcoin import (TrustedCoinPlugin, server, ErrorConnectingServer,
|
|||||||
class Plugin(TrustedCoinPlugin):
|
class Plugin(TrustedCoinPlugin):
|
||||||
|
|
||||||
class QSignalObject(PluginQObject):
|
class QSignalObject(PluginQObject):
|
||||||
requestView = pyqtSignal([str], arguments=['component'])
|
|
||||||
|
|
||||||
canSignWithoutServerChanged = pyqtSignal()
|
canSignWithoutServerChanged = pyqtSignal()
|
||||||
_canSignWithoutServer = False
|
_canSignWithoutServer = False
|
||||||
termsAndConditionsChanged = pyqtSignal()
|
termsAndConditionsChanged = pyqtSignal()
|
||||||
@@ -37,6 +36,8 @@ class Plugin(TrustedCoinPlugin):
|
|||||||
shortIdChanged = pyqtSignal()
|
shortIdChanged = pyqtSignal()
|
||||||
_shortId = ''
|
_shortId = ''
|
||||||
|
|
||||||
|
requestOtp = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, plugin, parent):
|
def __init__(self, plugin, parent):
|
||||||
super().__init__(plugin, parent)
|
super().__init__(plugin, parent)
|
||||||
|
|
||||||
@@ -307,26 +308,24 @@ class Plugin(TrustedCoinPlugin):
|
|||||||
def prompt_user_for_otp(self, wallet, tx, on_success, on_failure):
|
def prompt_user_for_otp(self, wallet, tx, on_success, on_failure):
|
||||||
self.logger.debug('prompt_user_for_otp')
|
self.logger.debug('prompt_user_for_otp')
|
||||||
self.on_success = on_success
|
self.on_success = on_success
|
||||||
self.on_failure = on_failure
|
self.on_failure = on_failure if on_failure else lambda x: self.logger.error(x)
|
||||||
self.wallet = wallet
|
self.wallet = wallet
|
||||||
self.tx = tx
|
self.tx = tx
|
||||||
self.so.requestView.emit('../../../../plugins/trustedcoin/qml/OTP.qml')
|
qewallet = QEWallet.getInstanceFor(wallet)
|
||||||
|
qewallet.request_otp(self.on_otp)
|
||||||
|
|
||||||
def on_otp(self, otp):
|
def on_otp(self, otp):
|
||||||
|
self.logger.debug(f'on_otp {otp} for tx {repr(self.tx)}')
|
||||||
try:
|
try:
|
||||||
self.wallet.on_otp(self.tx, otp)
|
self.wallet.on_otp(self.tx, otp)
|
||||||
|
except UserFacingException as e:
|
||||||
|
self.on_failure(_('Invalid one-time password.'))
|
||||||
except TrustedCoinException as e:
|
except TrustedCoinException as e:
|
||||||
if e.status_code == 400: # invalid OTP
|
if e.status_code == 400: # invalid OTP
|
||||||
# Clock.schedule_once(lambda dt:
|
self.on_failure(_('Invalid one-time password.'))
|
||||||
self.on_failure(_('Invalid one-time password.'))
|
|
||||||
# )
|
|
||||||
else:
|
else:
|
||||||
# Clock.schedule_once(lambda dt, bound_e=e:
|
self.on_failure(_('Error') + ':\n' + str(e))
|
||||||
self.on_failure(_('Error') + ':\n' + str(bound_e))
|
|
||||||
# )
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Clock.schedule_once(lambda dt, bound_e=e:
|
self.on_failure(_('Error') + ':\n' + str(e))
|
||||||
self.on_failure(_('Error') + ':\n' + str(bound_e))
|
|
||||||
# )
|
|
||||||
else:
|
else:
|
||||||
self.on_success(tx)
|
self.on_success(self.tx)
|
||||||
|
|||||||
Reference in New Issue
Block a user