From c84bb56bc743b6a45c00a4543b7b27b7463566ab Mon Sep 17 00:00:00 2001 From: johnnyq Date: Mon, 17 Aug 2026 12:59:24 -0400 Subject: [PATCH] Fix Generate readable passwords --- agent/ajax.php | 2 +- functions/security.php | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/agent/ajax.php b/agent/ajax.php index 931221f4b..74cc0836c 100644 --- a/agent/ajax.php +++ b/agent/ajax.php @@ -591,7 +591,7 @@ if (isset($_GET['get_totp_token_via_id'])) { } if (isset($_GET['get_readable_pass'])) { - echo json_encode(GenerateReadablePassword(1)); + echo json_encode(generateReadablePassword()); } /* diff --git a/functions/security.php b/functions/security.php index ef59dd506..724b9e224 100644 --- a/functions/security.php +++ b/functions/security.php @@ -14,6 +14,36 @@ function randomString(int $length = 16): string { ); } +// Generate a pronounceable password - readable enough to dictate down the phone, while +// still carrying real entropy. Every syllable is one of 90 consonant-vowel pairs, so the +// default three words of three syllables plus the two-digit suffix is roughly 65 bits. +// The floors are deliberate: this feeds real user and contact logins, so a caller asking +// for one short word must not walk away with a guessable password. +function generateReadablePassword(int $word_count = 3, int $syllables_per_word = 3): string { + + $consonants = 'bcdfghjklmnprstvwz'; + $vowels = 'aeiou'; + + $word_count = max(2, $word_count); + $syllables_per_word = max(2, $syllables_per_word); + + $words = []; + + for ($word_index = 0; $word_index < $word_count; $word_index++) { + + $word = ''; + + for ($syllable_index = 0; $syllable_index < $syllables_per_word; $syllable_index++) { + $word .= $consonants[random_int(0, strlen($consonants) - 1)]; + $word .= $vowels[random_int(0, strlen($vowels) - 1)]; + } + + $words[] = ucfirst($word); + } + + return implode('-', $words) . '-' . random_int(10, 99); +} + // Generate a cryptographically secure 32-char base32 secret for TOTP function generateTotpSecret() { $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";