Skip to content

Commit 5c8a19e

Browse files
committed
fix(ui): use cryptographically secure RNG for password generation
- Replace Math.random() with crypto.getRandomValues() for security - Ensure minimum password length of 4 characters to include all required character categories
1 parent e8feb79 commit 5c8a19e

1 file changed

Lines changed: 17 additions & 8 deletions

File tree

ui/packages/shared/helpers/getEntropy.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,16 @@ function logPow(expBase: number, pow: number, logBase: number): number {
170170
return total
171171
}
172172

173+
function getSecureRandomInt(max: number): number {
174+
const array = new Uint32Array(1)
175+
crypto.getRandomValues(array)
176+
return array[0] % max
177+
}
178+
173179
export function generatePassword(length: number = 16): string {
180+
const minLength = 4
181+
const actualLength = Math.max(length, minLength)
182+
174183
const lowercase = 'abcdefghijklmnopqrstuvwxyz'
175184
const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
176185
const digits = '0123456789'
@@ -179,20 +188,20 @@ export function generatePassword(length: number = 16): string {
179188

180189
let password = ''
181190
// ensure at least one character from each category
182-
password += lowercase[Math.floor(Math.random() * lowercase.length)]
183-
password += uppercase[Math.floor(Math.random() * uppercase.length)]
184-
password += digits[Math.floor(Math.random() * digits.length)]
185-
password += special[Math.floor(Math.random() * special.length)]
191+
password += lowercase[getSecureRandomInt(lowercase.length)]
192+
password += uppercase[getSecureRandomInt(uppercase.length)]
193+
password += digits[getSecureRandomInt(digits.length)]
194+
password += special[getSecureRandomInt(special.length)]
186195

187196
// fill the rest with random characters
188-
for (let i = password.length; i < length; i++) {
189-
password += allChars[Math.floor(Math.random() * allChars.length)]
197+
for (let i = password.length; i < actualLength; i++) {
198+
password += allChars[getSecureRandomInt(allChars.length)]
190199
}
191200

192-
// shuffle the password to randomize positions
201+
// shuffle the password to randomize positions (Fisher-Yates)
193202
const shuffled = password.split('')
194203
for (let i = shuffled.length - 1; i > 0; i--) {
195-
const j = Math.floor(Math.random() * (i + 1))
204+
const j = getSecureRandomInt(i + 1)
196205
;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]
197206
}
198207

0 commit comments

Comments
 (0)