view src/main/kotlin/name/blackcap/passman/Console.kt @ 28:287eadf5ab30 default tip

Check for timeouts inside subcommands while in interactive mode as well.
author David Barts <n5jrn@me.com>
date Wed, 31 Jul 2024 11:21:18 -0700
parents ea65ab890f66
children
line wrap: on
line source

package name.blackcap.passman

fun readLine(prompt: String): String =
    doConsoleIo({ System.console()?.readLine(prompt) }, "unable to read line")

fun getPassword(prompt: String, verify: Boolean = false): CharArray {
    while (true) {
        val pw1 = _getPassword(prompt)
        if (!verify) {
            return pw1
        }
        val pw2 = _getPassword("Verification: ")
        if (pw1 contentEquals pw2) {
            return pw1
        }
        error("mismatch, try again")
    }
}

fun mustReadLine(prompt: String): String = must({ readLine(prompt) }, { it.isNotEmpty() })

fun mustGetPassword(prompt: String, verify: Boolean = false): CharArray =
    must({ getPassword(prompt, verify) }, { it.isNotEmpty() })

fun printPassword(password: CharArray) {
    print("Password: ")
    password.forEach { print(it) }
    println()
}

private fun _getPassword(prompt: String): CharArray =
    doConsoleIo({ System.console()?.readPassword(prompt) }, "unable to read password")

private fun <T> must(getter: () -> T, checker: (T) -> Boolean): T {
    while (true) {
        val got = getter()
        if (checker(got)) {
            return got
        }
        error("entry must not be empty, try again")
    }
}

private fun <T> doConsoleIo(getter: () -> T?, message: String): T {
    val ret = getter() ?: throw ConsoleException(message)
    return ret
}

class ConsoleException(message: String, cause: Throwable? = null) : MessagedException(message, cause)