forked from shaba/openuds
Adding support for several network cards ond unmanaged
This commit is contained in:
parent
b34b12ec9f
commit
0b05009d3f
@ -49,6 +49,7 @@ if typing.TYPE_CHECKING:
|
||||
|
||||
logger = logging.getLogger('actor')
|
||||
|
||||
|
||||
class UDSConfigDialog(QDialog):
|
||||
_host: str = ''
|
||||
_config: udsactor.types.ActorConfigurationType
|
||||
@ -60,65 +61,98 @@ class UDSConfigDialog(QDialog):
|
||||
self.ui = Ui_UdsActorSetupDialog()
|
||||
self.ui.setupUi(self)
|
||||
self.ui.host.setText(self._config.host)
|
||||
self.ui.validateCertificate.setCurrentIndex(1 if self._config.validateCertificate else 0)
|
||||
self.ui.validateCertificate.setCurrentIndex(
|
||||
1 if self._config.validateCertificate else 0
|
||||
)
|
||||
self.ui.logLevelComboBox.setCurrentIndex(self._config.log_level)
|
||||
self.ui.serviceToken.setText(self._config.master_token or '')
|
||||
self.ui.restrictNet.setText(self._config.restrict_net or '')
|
||||
|
||||
self.ui.testButton.setEnabled(bool(self._config.master_token and self._config.host))
|
||||
self.ui.testButton.setEnabled(
|
||||
bool(self._config.master_token and self._config.host)
|
||||
)
|
||||
|
||||
@property
|
||||
def api(self) -> udsactor.rest.UDSServerApi:
|
||||
return udsactor.rest.UDSServerApi(self.ui.host.text(), self.ui.validateCertificate.currentIndex() == 1)
|
||||
return udsactor.rest.UDSServerApi(
|
||||
self.ui.host.text(), self.ui.validateCertificate.currentIndex() == 1
|
||||
)
|
||||
|
||||
def finish(self) -> None:
|
||||
self.close()
|
||||
|
||||
def configChanged(self, text: str) -> None:
|
||||
self.ui.testButton.setEnabled(self.ui.host.text() == self._config.host and self.ui.serviceToken.text() == self._config.master_token)
|
||||
self.ui.testButton.setEnabled(
|
||||
self.ui.host.text() == self._config.host
|
||||
and self.ui.serviceToken.text() == self._config.master_token
|
||||
and self._config.restrict_net == self.ui.restrictNet.text()
|
||||
)
|
||||
|
||||
def testUDSServer(self) -> None:
|
||||
if not self._config.master_token or not self._config.host:
|
||||
self.ui.testButton.setEnabled(False)
|
||||
return
|
||||
try:
|
||||
api = udsactor.rest.UDSServerApi(self._config.host, self._config.validateCertificate)
|
||||
api = udsactor.rest.UDSServerApi(
|
||||
self._config.host, self._config.validateCertificate
|
||||
)
|
||||
if not api.test(self._config.master_token, udsactor.types.UNMANAGED):
|
||||
QMessageBox.information(
|
||||
self,
|
||||
'UDS Test',
|
||||
'Service token seems to be invalid . Please, check token validity.',
|
||||
QMessageBox.Ok
|
||||
QMessageBox.Ok,
|
||||
)
|
||||
else:
|
||||
QMessageBox.information(
|
||||
self,
|
||||
'UDS Test',
|
||||
'Configuration for {} seems to be correct.'.format(self._config.host),
|
||||
QMessageBox.Ok
|
||||
'Configuration for {} seems to be correct.'.format(
|
||||
self._config.host
|
||||
),
|
||||
QMessageBox.Ok,
|
||||
)
|
||||
except Exception:
|
||||
QMessageBox.information(
|
||||
self,
|
||||
'UDS Test',
|
||||
'Configured host {} seems to be inaccesible.'.format(self._config.host),
|
||||
QMessageBox.Ok
|
||||
QMessageBox.Ok,
|
||||
)
|
||||
|
||||
def saveConfig(self) -> None:
|
||||
# Ensure restrict_net is empty or a valid subnet
|
||||
restrictNet = self.ui.restrictNet.text().strip()
|
||||
try:
|
||||
subnet = udsactor.tools.strToNoIPV4Network(restrictNet)
|
||||
if not subnet:
|
||||
raise Exception('Invalid subnet')
|
||||
except Exception:
|
||||
QMessageBox.information(
|
||||
self,
|
||||
'Invalid subnet',
|
||||
'Invalid subnet {}. Please, check it.'.format(restrictNet),
|
||||
QMessageBox.Ok,
|
||||
)
|
||||
return
|
||||
|
||||
# Store parameters on register for later use, notify user of registration
|
||||
self._config = udsactor.types.ActorConfigurationType(
|
||||
actorType=udsactor.types.UNMANAGED,
|
||||
host=self.ui.host.text(),
|
||||
validateCertificate=self.ui.validateCertificate.currentIndex() == 1,
|
||||
master_token=self.ui.serviceToken.text(),
|
||||
log_level=self.ui.logLevelComboBox.currentIndex()
|
||||
master_token=self.ui.serviceToken.text().strip(),
|
||||
restrict_net=restrictNet,
|
||||
log_level=self.ui.logLevelComboBox.currentIndex(),
|
||||
)
|
||||
|
||||
udsactor.platform.store.writeConfig(self._config)
|
||||
# Enables test button
|
||||
self.ui.testButton.setEnabled(True)
|
||||
# Informs the user
|
||||
QMessageBox.information(self, 'UDS Configuration', 'Configuration saved.', QMessageBox.Ok)
|
||||
QMessageBox.information(
|
||||
self, 'UDS Configuration', 'Configuration saved.', QMessageBox.Ok
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@ -129,7 +163,7 @@ if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
if udsactor.platform.operations.checkPermissions() is False:
|
||||
QMessageBox.critical(None, 'UDS Actor', 'This Program must be executed as administrator', QMessageBox.Ok)
|
||||
QMessageBox.critical(None, 'UDS Actor', 'This Program must be executed as administrator', QMessageBox.Ok) # type: ignore
|
||||
sys.exit(1)
|
||||
|
||||
if len(sys.argv) > 2:
|
||||
|
@ -10,8 +10,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>595</width>
|
||||
<height>220</height>
|
||||
<width>591</width>
|
||||
<height>243</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -55,7 +55,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>180</y>
|
||||
<y>210</y>
|
||||
<width>181</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
@ -83,7 +83,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>410</x>
|
||||
<y>180</y>
|
||||
<y>210</y>
|
||||
<width>171</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
@ -117,7 +117,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>210</x>
|
||||
<y>180</y>
|
||||
<y>210</y>
|
||||
<width>181</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
@ -144,7 +144,7 @@
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>571</width>
|
||||
<height>161</height>
|
||||
<height>228</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
@ -221,14 +221,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_loglevel">
|
||||
<property name="text">
|
||||
<string>Log Level</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="logLevelComboBox">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
@ -258,6 +258,23 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_restrictNet">
|
||||
<property name="text">
|
||||
<string>Restrict Net</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="restrictNet">
|
||||
<property name="toolTip">
|
||||
<string>UDS user with administration rights (Will not be stored on template)</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string><html><head/><body><p>Administrator user on UDS Server.</p><p>Note: This credential will not be stored on client. Will be used to obtain an unique token for this image.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>label_host</zorder>
|
||||
<zorder>host</zorder>
|
||||
@ -267,6 +284,8 @@
|
||||
<zorder>label_security</zorder>
|
||||
<zorder>label_loglevel</zorder>
|
||||
<zorder>logLevelComboBox</zorder>
|
||||
<zorder>label_restrictNet</zorder>
|
||||
<zorder>restrictNet</zorder>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources>
|
||||
@ -353,6 +372,22 @@
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>restrictNet</sender>
|
||||
<signal>textChanged(QString)</signal>
|
||||
<receiver>UdsActorSetupDialog</receiver>
|
||||
<slot>configChanged()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>341</x>
|
||||
<y>139</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>295</x>
|
||||
<y>121</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<slot>finish()</slot>
|
||||
|
@ -31,6 +31,7 @@
|
||||
from . import types
|
||||
from . import rest
|
||||
from . import platform
|
||||
from . import tools
|
||||
|
||||
__title__ = 'udsactor'
|
||||
__author__ = 'Adolfo Gómez <dkmaster@dkmon.com>'
|
||||
|
@ -56,6 +56,7 @@ def readConfig() -> types.ActorConfigurationType:
|
||||
validateCertificate=uds.getboolean('validate', fallback=False),
|
||||
master_token=uds.get('master_token', None),
|
||||
own_token=uds.get('own_token', None),
|
||||
restrict_net=uds.get('restrict_net', None),
|
||||
pre_command=uds.get('pre_command', None),
|
||||
runonce_command=uds.get('runonce_command', None),
|
||||
post_command=uds.get('post_command', None),
|
||||
@ -78,6 +79,7 @@ def writeConfig(config: types.ActorConfigurationType) -> None:
|
||||
writeIfValue(config.actorType, 'type')
|
||||
writeIfValue(config.master_token, 'master_token')
|
||||
writeIfValue(config.own_token, 'own_token')
|
||||
writeIfValue(config.restrict_net, 'restrict_net')
|
||||
writeIfValue(config.pre_command, 'pre_command')
|
||||
writeIfValue(config.post_command, 'post_command')
|
||||
writeIfValue(config.runonce_command, 'runonce_command')
|
||||
|
@ -39,6 +39,7 @@ import typing
|
||||
from . import platform
|
||||
from . import rest
|
||||
from . import types
|
||||
from . import tools
|
||||
|
||||
from .log import logger, DEBUG, INFO, ERROR, FATAL
|
||||
from .http import clients_pool, server, cert
|
||||
@ -245,7 +246,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
||||
return
|
||||
|
||||
while self._isAlive:
|
||||
self._interfaces = list(platform.operations.getNetworkInfo())
|
||||
self._interfaces = tools.validNetworkCards(self._cfg.restrict_net, platform.operations.getNetworkInfo())
|
||||
if self._interfaces:
|
||||
break
|
||||
self.doWait(5000)
|
||||
|
@ -28,11 +28,17 @@
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
# pylint: disable=invalid-name
|
||||
from re import I
|
||||
import threading
|
||||
import ipaddress
|
||||
import typing
|
||||
|
||||
from udsactor.log import logger
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from udsactor.types import ActorConfigurationType, InterfaceInfoType
|
||||
|
||||
|
||||
class ScriptExecutorThread(threading.Thread):
|
||||
def __init__(self, script: str) -> None:
|
||||
super(ScriptExecutorThread, self).__init__()
|
||||
@ -45,3 +51,36 @@ class ScriptExecutorThread(threading.Thread):
|
||||
except Exception as e:
|
||||
logger.error('Error executing script: {}'.format(e))
|
||||
logger.exception()
|
||||
|
||||
|
||||
# Convert "X.X.X.X/X" to ipaddress.IPv4Network
|
||||
def strToNoIPV4Network(net: typing.Optional[str]) -> typing.Optional[ipaddress.IPv4Network]:
|
||||
if not net: # Empty or None
|
||||
return None
|
||||
try:
|
||||
return ipaddress.IPv4Interface(net).network
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def validNetworkCards(
|
||||
net: typing.Optional[str], cards: typing.Iterable[InterfaceInfoType]
|
||||
) -> typing.List[InterfaceInfoType]:
|
||||
try:
|
||||
subnet = strToNoIPV4Network(net)
|
||||
except Exception as e:
|
||||
logger.error('Invalid network: {}'.format(e))
|
||||
subnet = None
|
||||
|
||||
if subnet is None:
|
||||
return list(cards)
|
||||
|
||||
def isValid(ip: str, subnet: ipaddress.IPv4Network) -> bool:
|
||||
if not ip:
|
||||
return False
|
||||
try:
|
||||
return ipaddress.IPv4Address(ip) in subnet
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
return [c for c in cards if isValid(c.ip, subnet)]
|
||||
|
@ -35,6 +35,7 @@ class ActorConfigurationType(typing.NamedTuple):
|
||||
actorType: typing.Optional[str] = None
|
||||
master_token: typing.Optional[str] = None
|
||||
own_token: typing.Optional[str] = None
|
||||
restrict_net: typing.Optional[str] = None
|
||||
|
||||
pre_command: typing.Optional[str] = None
|
||||
runonce_command: typing.Optional[str] = None
|
||||
|
@ -2,9 +2,10 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'setup-dialog.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.13.2
|
||||
# Created by: PyQt5 UI code generator 5.15.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
@ -2,9 +2,10 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'setup-dialog-unmanaged.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.13.2
|
||||
# Created by: PyQt5 UI code generator 5.15.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
@ -14,7 +15,7 @@ class Ui_UdsActorSetupDialog(object):
|
||||
def setupUi(self, UdsActorSetupDialog):
|
||||
UdsActorSetupDialog.setObjectName("UdsActorSetupDialog")
|
||||
UdsActorSetupDialog.setWindowModality(QtCore.Qt.WindowModal)
|
||||
UdsActorSetupDialog.resize(595, 220)
|
||||
UdsActorSetupDialog.resize(591, 243)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
@ -34,12 +35,12 @@ class Ui_UdsActorSetupDialog(object):
|
||||
UdsActorSetupDialog.setModal(True)
|
||||
self.saveButton = QtWidgets.QPushButton(UdsActorSetupDialog)
|
||||
self.saveButton.setEnabled(True)
|
||||
self.saveButton.setGeometry(QtCore.QRect(10, 180, 181, 23))
|
||||
self.saveButton.setGeometry(QtCore.QRect(10, 210, 181, 23))
|
||||
self.saveButton.setMinimumSize(QtCore.QSize(181, 0))
|
||||
self.saveButton.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
|
||||
self.saveButton.setObjectName("saveButton")
|
||||
self.closeButton = QtWidgets.QPushButton(UdsActorSetupDialog)
|
||||
self.closeButton.setGeometry(QtCore.QRect(410, 180, 171, 23))
|
||||
self.closeButton.setGeometry(QtCore.QRect(410, 210, 171, 23))
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
@ -49,11 +50,11 @@ class Ui_UdsActorSetupDialog(object):
|
||||
self.closeButton.setObjectName("closeButton")
|
||||
self.testButton = QtWidgets.QPushButton(UdsActorSetupDialog)
|
||||
self.testButton.setEnabled(False)
|
||||
self.testButton.setGeometry(QtCore.QRect(210, 180, 181, 23))
|
||||
self.testButton.setGeometry(QtCore.QRect(210, 210, 181, 23))
|
||||
self.testButton.setMinimumSize(QtCore.QSize(181, 0))
|
||||
self.testButton.setObjectName("testButton")
|
||||
self.layoutWidget = QtWidgets.QWidget(UdsActorSetupDialog)
|
||||
self.layoutWidget.setGeometry(QtCore.QRect(10, 10, 571, 161))
|
||||
self.layoutWidget.setGeometry(QtCore.QRect(10, 10, 571, 228))
|
||||
self.layoutWidget.setObjectName("layoutWidget")
|
||||
self.formLayout = QtWidgets.QFormLayout(self.layoutWidget)
|
||||
self.formLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
|
||||
@ -84,7 +85,7 @@ class Ui_UdsActorSetupDialog(object):
|
||||
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.serviceToken)
|
||||
self.label_loglevel = QtWidgets.QLabel(self.layoutWidget)
|
||||
self.label_loglevel.setObjectName("label_loglevel")
|
||||
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_loglevel)
|
||||
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_loglevel)
|
||||
self.logLevelComboBox = QtWidgets.QComboBox(self.layoutWidget)
|
||||
self.logLevelComboBox.setFrame(True)
|
||||
self.logLevelComboBox.setObjectName("logLevelComboBox")
|
||||
@ -96,7 +97,13 @@ class Ui_UdsActorSetupDialog(object):
|
||||
self.logLevelComboBox.setItemText(2, "ERROR")
|
||||
self.logLevelComboBox.addItem("")
|
||||
self.logLevelComboBox.setItemText(3, "FATAL")
|
||||
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.logLevelComboBox)
|
||||
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.logLevelComboBox)
|
||||
self.label_restrictNet = QtWidgets.QLabel(self.layoutWidget)
|
||||
self.label_restrictNet.setObjectName("label_restrictNet")
|
||||
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_restrictNet)
|
||||
self.restrictNet = QtWidgets.QLineEdit(self.layoutWidget)
|
||||
self.restrictNet.setObjectName("restrictNet")
|
||||
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.restrictNet)
|
||||
self.label_host.raise_()
|
||||
self.host.raise_()
|
||||
self.label_serviceToken.raise_()
|
||||
@ -105,6 +112,8 @@ class Ui_UdsActorSetupDialog(object):
|
||||
self.label_security.raise_()
|
||||
self.label_loglevel.raise_()
|
||||
self.logLevelComboBox.raise_()
|
||||
self.label_restrictNet.raise_()
|
||||
self.restrictNet.raise_()
|
||||
|
||||
self.retranslateUi(UdsActorSetupDialog)
|
||||
self.logLevelComboBox.setCurrentIndex(1)
|
||||
@ -113,6 +122,7 @@ class Ui_UdsActorSetupDialog(object):
|
||||
self.saveButton.clicked.connect(UdsActorSetupDialog.saveConfig)
|
||||
self.host.textChanged['QString'].connect(UdsActorSetupDialog.configChanged)
|
||||
self.serviceToken.textChanged['QString'].connect(UdsActorSetupDialog.configChanged)
|
||||
self.restrictNet.textChanged['QString'].connect(UdsActorSetupDialog.configChanged)
|
||||
QtCore.QMetaObject.connectSlotsByName(UdsActorSetupDialog)
|
||||
|
||||
def retranslateUi(self, UdsActorSetupDialog):
|
||||
@ -139,4 +149,7 @@ class Ui_UdsActorSetupDialog(object):
|
||||
self.serviceToken.setToolTip(_translate("UdsActorSetupDialog", "UDS user with administration rights (Will not be stored on template)"))
|
||||
self.serviceToken.setWhatsThis(_translate("UdsActorSetupDialog", "<html><head/><body><p>Administrator user on UDS Server.</p><p>Note: This credential will not be stored on client. Will be used to obtain an unique token for this image.</p></body></html>"))
|
||||
self.label_loglevel.setText(_translate("UdsActorSetupDialog", "Log Level"))
|
||||
self.label_restrictNet.setText(_translate("UdsActorSetupDialog", "Restrict Net"))
|
||||
self.restrictNet.setToolTip(_translate("UdsActorSetupDialog", "UDS user with administration rights (Will not be stored on template)"))
|
||||
self.restrictNet.setWhatsThis(_translate("UdsActorSetupDialog", "<html><head/><body><p>Administrator user on UDS Server.</p><p>Note: This credential will not be stored on client. Will be used to obtain an unique token for this image.</p></body></html>"))
|
||||
from ui import uds_rc
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
# Resource object code
|
||||
#
|
||||
# Created by: The Resource Compiler for PyQt5 (Qt v5.13.2)
|
||||
# Created by: The Resource Compiler for PyQt5 (Qt v5.15.2)
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
|
@ -234,8 +234,8 @@ def verifySignature(script: bytes, signature: bytes) -> bool:
|
||||
)
|
||||
|
||||
try:
|
||||
public_key.verify(
|
||||
base64.b64decode(signature), script, padding.PKCS1v15(), hashes.SHA256()
|
||||
public_key.verify( # type: ignore
|
||||
base64.b64decode(signature), script, padding.PKCS1v15(), hashes.SHA256() # type: ignore
|
||||
)
|
||||
except Exception: # InvalidSignature
|
||||
return False
|
||||
|
Loading…
Reference in New Issue
Block a user