From: Tim Düsterhus Date: Fri, 6 Nov 2020 15:42:54 +0000 (+0100) Subject: Add barebones support for deleting TOTP devices X-Git-Tag: 5.4.0_Alpha_1~555^2~53^2~18 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=7f6d5b6ba6098d121f145292e3c3582ffec4c4f0;p=GitHub%2FWoltLab%2FWCF.git Add barebones support for deleting TOTP devices --- diff --git a/wcfsetup/install/files/lib/system/user/multifactor/TotpMultifactorMethod.class.php b/wcfsetup/install/files/lib/system/user/multifactor/TotpMultifactorMethod.class.php index d8c692cfb3..d350251662 100644 --- a/wcfsetup/install/files/lib/system/user/multifactor/TotpMultifactorMethod.class.php +++ b/wcfsetup/install/files/lib/system/user/multifactor/TotpMultifactorMethod.class.php @@ -3,6 +3,8 @@ namespace wcf\system\user\multifactor; use ParagonIE\ConstantTime\Hex; use wcf\system\form\builder\button\FormButton; use wcf\system\form\builder\container\FormContainer; +use wcf\system\form\builder\field\ButtonFormField; +use wcf\system\form\builder\field\dependency\IsNotClickedFormFieldDependency; use wcf\system\form\builder\field\HiddenFormField; use wcf\system\form\builder\field\IFormField; use wcf\system\form\builder\field\RadioButtonFormField; @@ -75,6 +77,34 @@ class TotpMultifactorMethod implements IMultifactorMethod { ->addClass('buttonPrimary'), ]); $form->appendChild($newDeviceContainer); + + // Note: The order of the two parts of the form is important. Pressing submit within an input + // will implicitly press the first submit button. If this container comes first the submit + // button will be a delete button. + if ($setupId) { + $sql = "SELECT deviceID, deviceName, createTime, useTime + FROM wcf".WCF_N."_user_multifactor_totp + WHERE setupID = ?"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute([$setupId]); + $devicesContainer = FormContainer::create('devices') + ->label('wcf.user.security.multifactor.totp.devices'); + while ($row = $statement->fetchArray()) { + $devicesContainer->appendChildren([ + $button = ButtonFormField::create('delete_'.$row['deviceID']) + ->buttonLabel($row['deviceName']) + ->objectProperty('delete') + ->value($row['deviceID']), + ]); + + $newDeviceContainer->addDependency( + IsNotClickedFormFieldDependency::create('delete_'.$row['deviceID']) + ->field($button) + ); + } + + $form->appendChild($devicesContainer); + } } /** @@ -82,17 +112,48 @@ class TotpMultifactorMethod implements IMultifactorMethod { */ public function processManagementForm(IFormDocument $form, int $setupId): void { $formData = $form->getData(); - - $sql = "INSERT INTO wcf".WCF_N."_user_multifactor_totp (setupID, deviceID, deviceName, secret, minCounter, createTime) VALUES (?, ?, ?, ?, ?, ?)"; - $statement = WCF::getDB()->prepareStatement($sql); - $statement->execute([ - $setupId, - Hex::encode(\random_bytes(16)), - $formData['data']['deviceName'], - $formData['data']['secret'], - $formData['data']['code']['minCounter'], - TIME_NOW, - ]); + + assert( + (!empty($formData['data']) && empty($formData['delete'])) || + (empty($formData['data']) && !empty($formData['delete'])) + ); + + if (!empty($formData['delete'])) { + $sql = "DELETE FROM wcf".WCF_N."_user_multifactor_totp + WHERE setupID = ? + AND deviceID = ?"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute([ + $setupId, + $formData['delete'], + ]); + + $sql = "SELECT COUNT(*) + FROM wcf".WCF_N."_user_multifactor_totp + WHERE setupID = ?"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute([ + $setupId, + ]); + + if (!$statement->fetchSingleColumn()) { + throw new \LogicException('Unreachable'); + } + } + else { + $sql = "INSERT INTO wcf".WCF_N."_user_multifactor_totp + (setupID, deviceID, deviceName, secret, minCounter, createTime) + VALUES (?, ?, ?, ?, ?, ?)"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute([ + $setupId, + Hex::encode(\random_bytes(16)), + $formData['data']['deviceName'], + $formData['data']['secret'], + $formData['data']['code']['minCounter'], + TIME_NOW, + ]); + } } /** diff --git a/wcfsetup/install/files/lib/system/user/multifactor/totp/Totp.class.php b/wcfsetup/install/files/lib/system/user/multifactor/totp/Totp.class.php index c884cd494e..f512549bf5 100644 --- a/wcfsetup/install/files/lib/system/user/multifactor/totp/Totp.class.php +++ b/wcfsetup/install/files/lib/system/user/multifactor/totp/Totp.class.php @@ -7,7 +7,7 @@ namespace wcf\system\user\multifactor\totp; * @author Tim Duesterhus * @copyright 2001-2020 WoltLab GmbH * @license GNU Lesser General Public License - * @package WoltLabSuite\System\User\Multifactor + * @package WoltLabSuite\System\User\Multifactor\Totp * @since 5.4 */ final class Totp { diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index 433815cee8..79e9e3773d 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -4855,6 +4855,7 @@ Die E-Mail-Adresse des neuen Benutzers lautet: {@$user->email} + diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 8cd607cfc4..88463d036a 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -4852,6 +4852,7 @@ Open the link below to access the user profile: +