view src/main/kotlin/name/blackcap/passman/Generate.kt @ 11:c69665ff37d0

Add merge subcommand (untested).
author David Barts <n5jrn@me.com>
date Sat, 21 Jan 2023 15:39:42 -0800
parents 698c4a3d758d
children
line wrap: on
line source

package name.blackcap.passman

import java.lang.IllegalArgumentException
import java.security.SecureRandom
import java.util.Random

/* ASCII, alphanumeric, no 0's, 1's, I's, O's or l's to avoid confusion. */
private const val DIGITS = "23456789"
private const val UPPERS = "ABCDEFGHJKLMNPQRSTUVWXYZ"
private const val LOWERS = "abcdefghijkmnopqrstuvwxyz"
/* \ can confuse *NIX, |, ', and ` invite confusion */
private const val SYMBOLS = "!\"#$%&()*+,-./:;<=>?@[]^_{}~"
const val MIN_GENERATED_LENGTH = 6
const val DEFAULT_GENERATED_LENGTH = 12

fun generate(length: Int, allowSymbols: Boolean): CharArray {
    /* insecure, and if REALLY short, causes bugs */
    if (length < MIN_GENERATED_LENGTH) {
        throw IllegalArgumentException("length of $length is less than $MIN_GENERATED_LENGTH")
    }

    /* determine allowed characters */
    val passchars = if (allowSymbols) {
        DIGITS + UPPERS + LOWERS + SYMBOLS
    } else {
        DIGITS + UPPERS + LOWERS
    }

    /* ensure we get one of each class of characters */
    val randomizer = SecureRandom()
    val generated = CharArray(length)
    generated[0] = randomized(DIGITS, randomizer)
    generated[1] = randomized(UPPERS, randomizer)
    generated[2] = randomized(LOWERS, randomizer)
    var i = 3
    if (allowSymbols) {
        generated[3] = randomized(SYMBOLS, randomizer)
        i = 4
    }

    /* generate the rest of the characters */
    while (i < length) {
        generated[i++] = randomized(passchars, randomizer)
    }

    /* scramble them */
    for (j in 0 until length) {
        val k = randomizer.nextInt(length)
        if (j != k) {
            val temp = generated[j]
            generated[j] = generated[k]
            generated[k] = temp
        }
    }

    /* AMF... */
    return generated
}

private fun randomized(passchars: String, randomizer: Random): Char =
    passchars[randomizer.nextInt(passchars.length)]