view src/main/kotlin/name/blackcap/passman/CreateSubcommand.kt @ 1:8aacca5c2d53

Should have not committed this one.
author David Barts <n5jrn@me.com>
date Sun, 11 Sep 2022 16:12:47 -0700
parents a6cfdffcaa94
children eafa3779aef8
line wrap: on
line source

package name.blackcap.passman

import org.apache.commons.cli.CommandLine
import org.apache.commons.cli.DefaultParser
import org.apache.commons.cli.Options
import org.apache.commons.cli.ParseException
import kotlin.system.exitProcess

class CreateSubcommand(): Subcommand() {
    private lateinit var commandLine: CommandLine

    override fun run(args: Array<String>) {
        val options = Options().apply {
            addOption("g", "generate", false, "Use password generator.")
            addOption("l", "length", true, "Length of generated password.")
            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) {
            die(e.message ?: "syntax error", 2)
        }
        checkArguments()
        val db = Database.open()

        val entry = if (commandLine.hasOption("generate")) {
            val rawLength = commandLine.getOptionValue("length")
            val length = try {
                rawLength?.toInt() ?: DEFAULT_GENERATED_LENGTH
            } catch (e: NumberFormatException) {
                die("$rawLength - invalid length")
                -1  /* will never happen */
            }
            val symbols = commandLine.hasOption("symbols")
            val verbose = commandLine.hasOption("verbose")
            Entry.withGeneratedPassword(length, symbols, 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) {
                die("record matching ${entry.name} already exists")
            }
        }

        try {
            if (entry.notes.isBlank()) {
                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 (commandLine.args.isNotEmpty()) {
            error("unexpected trailing arguments")
        }
        if (bad) {
            exitProcess(2);
        }
    }
}