Mercurial > cgi-bin > hgweb.cgi > PassMan
view src/main/kotlin/name/blackcap/passman/CreateSubcommand.kt @ 21:ea65ab890f66
More work to support interactive feature.
author | David Barts <n5jrn@me.com> |
---|---|
date | Tue, 02 Jul 2024 11:27:39 -0700 |
parents | 302d224bbd57 |
children | 07406c4af4a5 |
line wrap: on
line source
package name.blackcap.passman import org.apache.commons.cli.* class CreateSubcommand(): Subcommand() { private companion object { const val GENERATE = "generate" const val HELP = "help" const val LENGTH = "length" const val SYMBOLS = "symbols" const val VERBOSE = "verbose" } private lateinit var commandLine: CommandLine override fun run(args: Array<String>): { val options = Options().apply { addOption("g", GENERATE, false, "Use password generator.") addOption("h", HELP, false, "Print this help message.") addOption("l", LENGTH, true, "Length of generated password (default $DEFAULT_GENERATED_LENGTH).") addOption("s", SYMBOLS, false, "Use symbol characters in generated password.") addOption("v", VERBOSE, false, "Print the generated password.") } try { commandLine = DefaultParser().parse(options, args) } catch (e: ParseException) { throw SubcommandException(message = e.message ?: "syntax error", status = 2, cause = e) } if (commandLine.hasOption(HELP)) { HelpFormatter().printHelp("$SHORTNAME create [options]", options) return } checkArguments() val db = Database.default val entry = if (commandLine.hasOption(GENERATE)) { val rawLength = commandLine.getOptionValue(LENGTH) val length = try { rawLength?.toInt() ?: DEFAULT_GENERATED_LENGTH } catch (e: NumberFormatException) { -1 } if (length < MIN_GENERATED_LENGTH) { throw SubcommandException(message = "${see(rawLength)} - invalid length") } Entry.withGeneratedPassword(length, commandLine.hasOption(SYMBOLS), commandLine.hasOption(VERBOSE)) } else { Entry.withPromptedPassword() } val id = db.makeKey(entry.name) db.connection.prepareStatement("select count(*) from passwords where id = ?").use { it.setLong(1, id) val result = it.executeQuery() result.next() val count = result.getInt(1) if (count > 0) { throw SubcommandException(message = "record matching ${see(entry.name)} already exists") } } try { if (entry.notes.isNullOrBlank()) { db.connection.prepareStatement("insert into passwords (id, name, username, password, created) values (?, ?, ?, ?, ?)") .use { it.setLong(1, id) it.setEncryptedString(2, entry.name, db.encryption) it.setEncryptedString(3, entry.username, db.encryption) it.setEncrypted(4, entry.password, db.encryption) it.setLong(5, System.currentTimeMillis()) it.execute() } } else { db.connection.prepareStatement("insert into passwords (id, name, username, password, notes, created) values (?, ?, ?, ?, ?, ?)") .use { it.setLong(1, db.makeKey(entry.name)) it.setEncryptedString(2, entry.name, db.encryption) it.setEncryptedString(3, entry.username, db.encryption) it.setEncrypted(4, entry.password, db.encryption) it.setEncryptedString(5, entry.notes, db.encryption) it.setLong(6, System.currentTimeMillis()) it.execute() } } } finally { entry.password.clear() } } private fun checkArguments(): Unit { var bad = false if (!commandLine.hasOption(GENERATE)) { for (option in listOf<String>(LENGTH, SYMBOLS, VERBOSE)) { if (commandLine.hasOption(option)) { error("--$option requires --$GENERATE") bad = true } } } if (bad) { throw SubcommandException(status = 2) } if (commandLine.args.isNotEmpty()) { throw SubcommandException(message = "unexpected trailing arguments", status = 2) } } }