diff --git a/lam/HISTORY b/lam/HISTORY index c290bace8..79ad33e40 100644 --- a/lam/HISTORY +++ b/lam/HISTORY @@ -1,4 +1,5 @@ March 2025 9.1 + - Usability improvements (360) - Fixed bugs: -> Ambiguous tooltip on profile editor for Shadow users (#394) diff --git a/lam/lib/2factor.inc b/lam/lib/2factor.inc index 2c14fec1a..45e01c6df 100644 --- a/lam/lib/2factor.inc +++ b/lam/lib/2factor.inc @@ -990,7 +990,9 @@ class WebauthnProvider extends BaseProvider { $errorMessageDiv->addDataAttribute('button', _('Ok')); $errorMessageDiv->addDataAttribute('title', _('WebAuthn failed')); $row->add($errorMessageDiv); - $row->add(new htmlJavaScript('window.lam.webauthn.start(\'' . $pathPrefix . '\', ' . $selfServiceParam . ');'), 0); + $row->add(new htmlJavaScript('window.lam.webauthn.start(\'' . $pathPrefix . '\', ' . $selfServiceParam . ',' . + ' \'' . _('Do you want to set a name for this device?') . '\', \'' . _('Name') . '\',' . + ' \'' . _('Ok') . '\', \'' . _('Cancel') . '\');'), 0); } /** @@ -1024,7 +1026,14 @@ class WebauthnProvider extends BaseProvider { } $response = base64_decode($_POST['sig_response']); $registrationObject = PublicKeyCredentialCreationOptions::createFromString($_SESSION['webauthn_registration']); - return $webauthnManager->storeNewRegistration($registrationObject, $response); + if (!$webauthnManager->storeNewRegistration($registrationObject, $response)) { + return false; + } + if (!empty($_POST['newName'])) { + $deviceList = $webauthnManager->getDatabase()->findAllForUserDn($userDn); + $webauthnManager->getDatabase()->updateDeviceName($userDn, base64_encode($deviceList[0]->getPublicKeyCredentialId()), $_POST['newName']); + } + return true; } else { logNewMessage(LOG_DEBUG, 'Checking WebAuthn response of ' . $userDn); diff --git a/lam/templates/lib/500_lam.js b/lam/templates/lib/500_lam.js index e5dc1d7c0..e6b01c352 100644 --- a/lam/templates/lib/500_lam.js +++ b/lam/templates/lib/500_lam.js @@ -1863,10 +1863,14 @@ window.lam.webauthn.charAt = function (c) { * * @param prefix path prefix for Ajax endpoint * @param isSelfService runs as part of self service + * @param newDeviceNameTitle title for new device name dialog + * @param newDeviceNameLabel label for new device name + * @param okText text for Ok button + * @param cancelText text for cancelButton */ -window.lam.webauthn.start = function(prefix, isSelfService) { +window.lam.webauthn.start = function(prefix, isSelfService, newDeviceNameTitle, newDeviceNameLabel, okText, cancelText) { document.addEventListener("DOMContentLoaded", function(){ - window.lam.webauthn.run(prefix, isSelfService); + window.lam.webauthn.run(prefix, isSelfService, newDeviceNameTitle, newDeviceNameLabel, okText, cancelText); }); } @@ -1874,9 +1878,13 @@ window.lam.webauthn.start = function(prefix, isSelfService) { * Checks if the user is registered and starts login/registration. * * @param prefix path prefix for Ajax endpoint - * @param isSelfService runs as part of self service + * @param isSelfService runs as part of self-service + * @param newDeviceNameTitle title for new device name dialog + * @param newDeviceNameLabel label for new device name + * @param okText text for Ok button + * @param cancelText text for cancelButton */ -window.lam.webauthn.run = function(prefix, isSelfService) { +window.lam.webauthn.run = function(prefix, isSelfService, newDeviceNameTitle, newDeviceNameLabel, okText, cancelText) { const skipButton = document.getElementById('btn_skip_webauthn'); if (skipButton) { skipButton.onclick = function () { @@ -1909,8 +1917,24 @@ window.lam.webauthn.run = function(prefix, isSelfService) { const jsonData = await response.json(); if (jsonData.action === 'register') { const registerFunction = function() { - const successCallback = function (publicKeyCredential) { + const successCallback = async function (publicKeyCredential) { + const {value: newName} = await Swal.fire({ + title: newDeviceNameTitle, + confirmButtonText: okText, + cancelButtonText: cancelText, + showCancelButton: true, + input: 'text', + inputLabel: newDeviceNameLabel, + width: 'auto' + }); const form = document.getElementById("2faform"); + if (newName) { + const newNameElement = document.createElement('input'); + newNameElement.type = 'hidden'; + newNameElement.name = 'newName'; + newNameElement.value = newName; + form.appendChild(newNameElement); + } const response = btoa(JSON.stringify(publicKeyCredential)); const hiddenResponse = document.createElement('input'); hiddenResponse.type = 'hidden';