package com.zeapo.pwdstore.pwgen internal object Phonemes { private const val CONSONANT = 0x0001 private const val VOWEL = 0x0002 private const val DIPTHONG = 0x0004 private const val NOT_FIRST = 0x0008 private val elements = arrayOf( Element("a", VOWEL), Element("ae", VOWEL or DIPTHONG), Element("ah", VOWEL or DIPTHONG), Element("ai", VOWEL or DIPTHONG), Element("b", CONSONANT), Element("c", CONSONANT), Element("ch", CONSONANT or DIPTHONG), Element("d", CONSONANT), Element("e", VOWEL), Element("ee", VOWEL or DIPTHONG), Element("ei", VOWEL or DIPTHONG), Element("f", CONSONANT), Element("g", CONSONANT), Element("gh", CONSONANT or DIPTHONG or NOT_FIRST), Element("h", CONSONANT), Element("i", VOWEL), Element("ie", VOWEL or DIPTHONG), Element("j", CONSONANT), Element("k", CONSONANT), Element("l", CONSONANT), Element("m", CONSONANT), Element("n", CONSONANT), Element("ng", CONSONANT or DIPTHONG or NOT_FIRST), Element("o", VOWEL), Element("oh", VOWEL or DIPTHONG), Element("oo", VOWEL or DIPTHONG), Element("p", CONSONANT), Element("ph", CONSONANT or DIPTHONG), Element("qu", CONSONANT or DIPTHONG), Element("r", CONSONANT), Element("s", CONSONANT), Element("sh", CONSONANT or DIPTHONG), Element("t", CONSONANT), Element("th", CONSONANT or DIPTHONG), Element("u", VOWEL), Element("v", CONSONANT), Element("w", CONSONANT), Element("x", CONSONANT), Element("y", CONSONANT), Element("z", CONSONANT) ) private val NUM_ELEMENTS = elements.size private class Element internal constructor(internal var str: String, internal var flags: Int) /** * Generates a human-readable password. * * @param size length of password to generate * @param pwFlags flag field where set bits indicate conditions the * generated password must meet * * * * * * *
BitCondition
0include at least one number
1include at least one uppercase letter
2include at least one symbol
3don't include ambiguous characters
5include at least one lowercase letter
* * @return the generated password */ fun phonemes(size: Int, pwFlags: Int): String { var password: String var curSize: Int var i: Int var length: Int var flags: Int var featureFlags: Int var prev: Int var shouldBe: Int var first: Boolean var str: String var cha: Char do { password = "" featureFlags = pwFlags curSize = 0 prev = 0 first = true shouldBe = if (RandomNumberGenerator.number(2) == 1) VOWEL else CONSONANT while (curSize < size) { i = RandomNumberGenerator.number(NUM_ELEMENTS) str = elements[i].str length = str.length flags = elements[i].flags // Filter on the basic type of the next Element if (flags and shouldBe == 0) { continue } // Handle the NOT_FIRST flag if (first && flags and NOT_FIRST > 0) { continue } // Don't allow VOWEL followed a Vowel/Dipthong pair if (prev and VOWEL > 0 && flags and VOWEL > 0 && flags and DIPTHONG > 0 ) { continue } // Don't allow us to overflow the buffer if (length > size - curSize) { continue } // OK, we found an Element which matches our criteria, let's do // it password += str // Handle UPPERS if (pwFlags and PasswordGenerator.UPPERS > 0) { if ((pwFlags and PasswordGenerator.LOWERS == 0) || (first || flags and CONSONANT > 0) && RandomNumberGenerator.number(10) < 2) { val index = password.length - length password = password.substring(0, index) + str.toUpperCase() featureFlags = featureFlags and PasswordGenerator.UPPERS.inv() } } // Handle the AMBIGUOUS flag if (pwFlags and PasswordGenerator.AMBIGUOUS > 0) { for (ambiguous in PasswordGenerator.AMBIGUOUS_STR.toCharArray()) { if (password.contains(ambiguous.toString())) { password = password.substring(0, curSize) // Still have upper letters if ((pwFlags and PasswordGenerator.UPPERS) > 0) { featureFlags = featureFlags or PasswordGenerator.UPPERS for (upper in PasswordGenerator.UPPERS_STR.toCharArray()) { if (password.contains(upper.toString())) { featureFlags = featureFlags and PasswordGenerator.UPPERS.inv() break } } } break } } if (password.length == curSize) continue } curSize += length // Time to stop? if (curSize >= size) break // Handle DIGITS if (pwFlags and PasswordGenerator.DIGITS > 0) { if (!first && RandomNumberGenerator.number(10) < 3) { var character: String do { cha = Character.forDigit(RandomNumberGenerator.number(10), 10) character = cha.toString() } while (pwFlags and PasswordGenerator.AMBIGUOUS > 0 && PasswordGenerator.AMBIGUOUS_STR.contains(character)) password += character curSize++ featureFlags = featureFlags and PasswordGenerator.DIGITS.inv() first = true prev = 0 shouldBe = if (RandomNumberGenerator.number(2) == 1) VOWEL else CONSONANT continue } } // Handle SYMBOLS if (pwFlags and PasswordGenerator.SYMBOLS > 0) { if (!first && RandomNumberGenerator.number(10) < 2) { var character: String var num: Int do { num = RandomNumberGenerator.number(PasswordGenerator.SYMBOLS_STR.length) cha = PasswordGenerator.SYMBOLS_STR.toCharArray()[num] character = cha.toString() } while (pwFlags and PasswordGenerator.AMBIGUOUS > 0 && PasswordGenerator.AMBIGUOUS_STR.contains(character)) password += character curSize++ featureFlags = featureFlags and PasswordGenerator.SYMBOLS.inv() } } // OK, figure out what the next Element should be shouldBe = if (shouldBe == CONSONANT) { VOWEL } else { if (prev and VOWEL > 0 || flags and DIPTHONG > 0 || RandomNumberGenerator.number(10) > 3 ) { CONSONANT } else { VOWEL } } prev = flags first = false } } while (featureFlags and (PasswordGenerator.UPPERS or PasswordGenerator.DIGITS or PasswordGenerator.SYMBOLS) > 0) return password } }