* Setup TOTP & build QR PNG. */
($username)
| 854 | * Setup TOTP & build QR PNG. |
| 855 | */ |
| 856 | public static function setupTOTP($username) |
| 857 | { |
| 858 | global $encryptionKey; |
| 859 | $usersFile = USERS_DIR . USERS_FILE; |
| 860 | |
| 861 | if (!preg_match(REGEX_USER, $username)) { |
| 862 | return ['error' => 'Invalid username', 'statusCode' => 400]; |
| 863 | } |
| 864 | |
| 865 | if (!file_exists($usersFile)) { |
| 866 | return ['error' => 'Users file not found']; |
| 867 | } |
| 868 | |
| 869 | $lines = file($usersFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: []; |
| 870 | $userExists = false; |
| 871 | |
| 872 | foreach ($lines as $line) { |
| 873 | $parts = explode(':', trim($line)); |
| 874 | if (count($parts) >= 3 && strcasecmp($parts[0], $username) === 0) { |
| 875 | $userExists = true; |
| 876 | if (count($parts) >= 4 && !empty($parts[3])) { |
| 877 | return ['error' => 'TOTP is already configured for this account', 'statusCode' => 409]; |
| 878 | } |
| 879 | break; |
| 880 | } |
| 881 | } |
| 882 | if (!$userExists) { |
| 883 | return ['error' => 'User not found', 'statusCode' => 404]; |
| 884 | } |
| 885 | |
| 886 | $tfa = new \RobThree\Auth\TwoFactorAuth( |
| 887 | new \RobThree\Auth\Providers\Qr\GoogleChartsQrCodeProvider(), |
| 888 | 'FileRise', |
| 889 | 6, |
| 890 | 30, |
| 891 | \RobThree\Auth\Algorithm::Sha1 |
| 892 | ); |
| 893 | |
| 894 | $totpSecret = $tfa->createSecret(); |
| 895 | $encryptedSecret = encryptData($totpSecret, $encryptionKey); |
| 896 | |
| 897 | $newLines = []; |
| 898 | foreach ($lines as $line) { |
| 899 | $parts = explode(':', trim($line)); |
| 900 | if (count($parts) >= 3 && strcasecmp($parts[0], $username) === 0) { |
| 901 | if (count($parts) >= 4) { |
| 902 | $parts[3] = $encryptedSecret; |
| 903 | } else { |
| 904 | $parts[] = $encryptedSecret; |
| 905 | } |
| 906 | $newLines[] = implode(':', $parts); |
| 907 | } else { |
| 908 | $newLines[] = $line; |
| 909 | } |
| 910 | } |
| 911 | if (file_put_contents($usersFile, implode(PHP_EOL, $newLines) . PHP_EOL, LOCK_EX) === false) { |
| 912 | return ['error' => 'Failed to save TOTP secret']; |
| 913 | } |
no test coverage detected