src/eric7/WebBrowser/WebAuth/Fido2ManagementDialog.py

branch
eric7
changeset 10857
abcb288e7e17
parent 10856
b19cefceca15
child 10859
399d19fc7eb5
diff -r b19cefceca15 -r abcb288e7e17 src/eric7/WebBrowser/WebAuth/Fido2ManagementDialog.py
--- a/src/eric7/WebBrowser/WebAuth/Fido2ManagementDialog.py	Mon Jul 22 10:15:41 2024 +0200
+++ b/src/eric7/WebBrowser/WebAuth/Fido2ManagementDialog.py	Mon Jul 22 15:24:27 2024 +0200
@@ -10,6 +10,7 @@
 from PyQt6.QtWidgets import (
     QDialog,
     QDialogButtonBox,
+    QInputDialog,
     QMenu,
     QToolButton,
     QTreeWidgetItem,
@@ -72,6 +73,8 @@
         self.reloadButton.clicked.connect(self.__populateDeviceSelector)
 
         self.__manager = Fido2Management(parent=self)
+        self.__manager.deviceConnected.connect(self.__deviceConnected)
+        self.__manager.deviceDisconnected.connect(self.__deviceDisconnected)
 
         QTimer.singleShot(0, self.__populateDeviceSelector)
 
@@ -86,10 +89,16 @@
         self.__mgmtMenu.addAction(
             self.tr("Reset Security Key"), self.__resetSecurityKey
         )
-        # TODO: potentially add these 'config' actions
-        #       - Force PIN Change
-        #       - Set Minimum PIN Length
-        #       - Toggle 'Always Require UV'
+        self.__mgmtMenu.addSeparator()
+        self.__forcePinChangeAct = self.__mgmtMenu.addAction(
+            self.tr("Force PIN Change"), self.__forcePinChange
+        )
+        self.__minPinLengthAct = self.__mgmtMenu.addAction(
+            self.tr("Set Minimum PIN Length"), self.__setMinimumPinLength
+        )
+        self.__toggleAlwaysUvAct = self.__mgmtMenu.addAction(
+            self.tr("Toggle 'Always Require User Verification'"), self.__toggleAlwaysUv
+        )
 
         self.__mgmtMenu.aboutToShow.connect(self.__aboutToShowManagementMenu)
 
@@ -100,8 +109,18 @@
         """
         Private slot to prepare the security key management menu before it is shown.
         """
-        # TODO: not implemented yet
-        pass
+        self.__forcePinChangeAct.setEnabled(
+            self.__manager.forcePinChangeSupported()
+            and not self.__manager.pinChangeRequired()
+        )
+        self.__minPinLengthAct.setEnabled(
+            self.__manager.canSetMinimumPinLength()
+            and not self.__manager.pinChangeRequired()
+        )
+        self.__toggleAlwaysUvAct.setEnabled(
+            self.__manager.canToggleAlwaysUv()
+            and not self.__manager.pinChangeRequired()
+        )
 
     ############################################################################
     ## methods related to device handling
@@ -114,7 +133,6 @@
         """
         self.__manager.disconnectFromDevice()
         self.securityKeysComboBox.clear()
-        self.reloadButton.setEnabled(False)
 
         securityKeys = self.__manager.getDevices()
 
@@ -128,8 +146,6 @@
                 securityKey,
             )
 
-        self.reloadButton.setEnabled(True)
-
         if len(securityKeys) == 0:
             EricMessageBox.information(
                 self,
@@ -148,39 +164,60 @@
         @param index index of the selected security key
         @type int
         """
-        self.lockButton.setChecked(False)
         self.__manager.disconnectFromDevice()
 
         securityKey = self.securityKeysComboBox.itemData(index)
-
-        self.lockButton.setEnabled(securityKey is not None)
-        self.pinButton.setEnabled(securityKey is not None)
-        self.menuButton.setEnabled(securityKey is not None)
-        self.loadPasskeysButton.setEnabled(securityKey is not None)
-
         if securityKey is not None:
             self.__manager.connectToDevice(securityKey)
-            hasPin = self.__manager.hasPin()
-            forcedPinChange = self.__manager.forcedPinChange()
-            if hasPin is True:
-                self.pinButton.setText(self.tr("Change PIN"))
-            elif hasPin is False:
-                self.pinButton.setText(self.tr("Set PIN"))
-            else:
-                self.pinButton.setEnabled(False)
-            if forcedPinChange or hasPin is False:
-                self.lockButton.setEnabled(False)
-                self.loadPasskeysButton.setEnabled(False)
-                msg = (
-                    self.tr("A PIN change is required.")
-                    if forcedPinChange
-                    else self.tr("You must set a PIN first.")
-                )
-                EricMessageBox.information(
-                    self,
-                    self.tr("FIDO2 Security Key Management"),
-                    msg,
-                )
+
+    @pyqtSlot()
+    def __deviceConnected(self):
+        """
+        Private slot handling the device connected signal.
+        """
+        self.lockButton.setEnabled(True)
+        self.pinButton.setEnabled(True)
+        self.menuButton.setEnabled(True)
+        self.loadPasskeysButton.setEnabled(True)
+
+        hasPin = self.__manager.hasPin()
+        forcedPinChange = self.__manager.pinChangeRequired()
+        if hasPin is True:
+            self.pinButton.setText(self.tr("Change PIN"))
+        elif hasPin is False:
+            self.pinButton.setText(self.tr("Set PIN"))
+        else:
+            self.pinButton.setEnabled(False)
+        if forcedPinChange or hasPin is False:
+            self.lockButton.setEnabled(False)
+            self.loadPasskeysButton.setEnabled(False)
+            msg = (
+                self.tr("A PIN change is required.")
+                if forcedPinChange
+                else self.tr("You must set a PIN first.")
+            )
+            EricMessageBox.information(
+                self,
+                self.tr("FIDO2 Security Key Management"),
+                msg,
+            )
+
+        self.passkeysList.clear()
+        self.on_passkeysList_itemSelectionChanged()
+
+    @pyqtSlot()
+    def __deviceDisconnected(self):
+        """
+        Private slot handling the device disconnected signal.
+        """
+        self.lockButton.setChecked(False)
+        self.passkeysList.clear()
+        self.on_passkeysList_itemSelectionChanged()
+
+        self.lockButton.setEnabled(False)
+        self.pinButton.setEnabled(False)
+        self.menuButton.setEnabled(False)
+        self.loadPasskeysButton.setEnabled(False)
 
         self.passkeysList.clear()
         self.on_passkeysList_itemSelectionChanged()
@@ -296,7 +333,7 @@
             )
         elif not hasPin:
             msg = self.tr("{0} requires having a PIN. Set a PIN first.").format(feature)
-        elif self.__manager.forcedPinChange():
+        elif self.__manager.pinChangeRequired():
             msg = self.tr("The security key is locked. Change the PIN first.")
         elif powerCycle:
             msg = self.tr(
@@ -372,11 +409,6 @@
             newPin = dlg.getPins()[1]
             ok, msg = self.__manager.setPin(newPin)
             if ok:
-                self.lockButton.setEnabled(True)
-                self.lockButton.setChecked(False)
-                self.pinButton.setText(self.tr("Change PIN"))
-                self.loadPasskeysButton.setEnabled(True)
-                self.__manager.reconnectToDevice()
                 EricMessageBox.information(self, title, msg)
             else:
                 EricMessageBox.warning(self, title, msg)
@@ -401,7 +433,6 @@
             oldPin, newPin = dlg.getPins()
             ok, msg = self.__manager.changePin(oldPin, newPin)
             if ok:
-                self.lockButton.setChecked(False)
                 EricMessageBox.information(self, title, msg)
             else:
                 EricMessageBox.warning(self, title, msg)
@@ -581,6 +612,89 @@
                 del rpItem
 
     ############################################################################
+    ## methods related to device configuration
+    ############################################################################
+
+    @pyqtSlot()
+    def __forcePinChange(self):
+        """
+        Private slot to force a PIN change before the next use.
+        """
+        pin = self.__getRequiredPin(feature=self.tr("Force PIN Change"))
+        try:
+            self.__manager.forcePinChange(pin=pin)
+        except (Fido2DeviceError, Fido2PinError) as err:
+            self.__handleError(
+                error=err,
+                title=self.tr("Force PIN Change"),
+                message=self.tr("The 'Force PIN Change' flag could not be set."),
+            )
+
+    @pyqtSlot()
+    def __setMinimumPinLength(self):
+        """
+        Private slot to set the minimum PIN length.
+        """
+        currMinLength = self.__manager.getMinimumPinLength()
+
+        minPinLength, ok = QInputDialog.getInt(
+            self,
+            self.tr("Set Minimum PIN Length"),
+            self.tr("Enter the minimum PIN length (between {0} and 63):").format(
+                currMinLength
+            ),
+            0,
+            currMinLength,
+            63,
+            1,
+        )
+        if ok and minPinLength != currMinLength:
+            pin = self.__getRequiredPin(feature=self.tr("Set Minimum PIN Length"))
+            try:
+                self.__manager.setMinimumPinLength(pin=pin, minLength=minPinLength)
+                EricMessageBox.information(
+                    self,
+                    self.tr("Set Minimum PIN Length"),
+                    self.tr("The minimum PIN length was set to be {0}.").format(
+                        minPinLength
+                    ),
+                )
+            except (Fido2DeviceError, Fido2PinError) as err:
+                self.__handleError(
+                    error=err,
+                    title=self.tr("Set Minimum PIN Length"),
+                    message=self.tr("The minimum PIN length could not be set."),
+                )
+
+    @pyqtSlot()
+    def __toggleAlwaysUv(self):
+        """
+        Private slot to toggle the state of the 'Always Require User Verification'
+        flag.
+        """
+        pin = self.__getRequiredPin(
+            feature=self.tr("Toggle 'Always Require User Verification'")
+        )
+        try:
+            self.__manager.toggleAlwaysUv(pin=pin)
+            EricMessageBox.information(
+                self,
+                self.tr("Always Require User Verification"),
+                self.tr("Always Require User Verification is now enabled.")
+                if self.__manager.getAlwaysUv()
+                else self.tr("Always Require User Verification is now disabled."),
+            )
+            
+        except (Fido2DeviceError, Fido2PinError) as err:
+            self.__handleError(
+                error=err,
+                title=self.tr("Toggle 'Always Require User Verification'"),
+                message=self.tr(
+                    "The 'Always Require User Verification' flag could not be toggled."
+                ),
+            )
+
+    ############################################################################
     ## utility methods
     ############################################################################
 

eric ide

mercurial