Files
pallectrum/electrum/gui/qml/auth.py
Sander van Grieken 7cb8c347b5 Add @auth_protect decorator.
This guards function calls by storing the function, args and kwargs into
an added attribute '__auth_fcall' on the object using the decorator,
then emits a signal that can be handled by the UI.

The UI can signal auth-success or auth-failure back to the object by
calling either the authProceed() slot or the authCancel slot.

The object utilizing this decorator MUST inherit/mixin the AuthMixin
class, which provides the above two slots, and handling of state.

The decorator also accepts a 'reject' parameter, containing the name of
a parameterless function on the object, which is called when
authentication has failed/is cancelled.
2022-07-07 18:29:01 +02:00

59 lines
1.9 KiB
Python

from functools import wraps, partial
from PyQt5.QtCore import pyqtSignal, pyqtSlot
from electrum.logging import get_logger
def auth_protect(func=None, reject=None):
if func is None:
return partial(auth_protect, reject=reject)
@wraps(func)
def wrapper(self, *args, **kwargs):
self._logger.debug(str(self))
if hasattr(self, '__auth_fcall'):
self._logger.debug('object already has a pending authed function call')
raise Exception('object already has a pending authed function call')
setattr(self, '__auth_fcall', (func,args,kwargs,reject))
getattr(self, 'authRequired').emit()
return wrapper
class AuthMixin:
_auth_logger = get_logger(__name__)
authRequired = pyqtSignal()
@pyqtSlot()
def authProceed(self):
self._auth_logger.debug('Proceeding with authed fn()')
try:
self._auth_logger.debug(str(getattr(self, '__auth_fcall')))
(func,args,kwargs,reject) = getattr(self, '__auth_fcall')
r = func(self, *args, **kwargs)
return r
except Exception as e:
self._auth_logger.error('Error executing wrapped fn(): %s' % repr(e))
raise e
finally:
delattr(self,'__auth_fcall')
@pyqtSlot()
def authCancel(self):
self._auth_logger.debug('Cancelling authed fn()')
if not hasattr(self, '__auth_fcall'):
return
try:
(func,args,kwargs,reject) = getattr(self, '__auth_fcall')
if reject is not None:
if hasattr(self, reject):
getattr(self, reject)()
else:
self._auth_logger.error('Reject method \'%s\' not defined' % reject)
except Exception as e:
self._auth_logger.error('Error executing reject function \'%s\': %s' % (reject, repr(e)))
raise e
finally:
delattr(self, '__auth_fcall')