view src/main/kotlin/name/blackcap/passman/RenameSubcommand.kt @ 12:a38a2a1036c3

Add import subcommand.
author David Barts <n5jrn@me.com>
date Sun, 22 Jan 2023 09:22:53 -0800
parents c69665ff37d0
children 4dae7a15ee48
line wrap: on
line source

package name.blackcap.passman

import org.apache.commons.cli.*
import kotlin.system.exitProcess

class RenameSubcommand(): Subcommand() {
    private companion object {
        const val FORCE = "force"
        const val HELP = "help"
    }
    private lateinit var commandLine: CommandLine
    private lateinit var source: String
    private lateinit var destination: String
    private lateinit var db: Database

    override fun run(args: Array<String>) {
        parseArguments(args)
        db = Database.open()
        renameIt()
    }

    private fun parseArguments(args: Array<String>) {
        val options = Options().apply {
            addOption("f", FORCE, false, "If destination exists exists, force overwrite.")
            addOption("h", HELP, false, "Print this help message.")
        }
        try {
            commandLine = DefaultParser().parse(options, args)
        } catch (e: ParseException) {
            die(e.message ?: "syntax error", 2)
        }
        if (commandLine.hasOption(HELP)) {
            HelpFormatter().printHelp("$SHORTNAME rename [options] source destination", options)
            exitProcess(0)
        }
        if (commandLine.args.size < 2) {
            die("expecting source and destination", 2)
        }
        if (commandLine.args.size > 2) {
            die("unexpected trailing arguments", 2)
        }
        source = commandLine.args[0]
        destination = commandLine.args[1]
    }

    private fun renameIt(): Unit {
        val sid = db.makeKey(source)
        val did = db.makeKey(destination)

        if(!recordExists(sid)) {
            die("no record matches ${see(source)}")
        }
        if (recordExists(did)) {
            if (commandLine.hasOption(FORCE)) {
                deleteRecord(did)
            } else {
                die("record matching ${see(destination)} already exists")
            }
        }

        db.connection.prepareStatement("select username, password, notes, created, modified, accessed from passwords where id = ?").use { sourceStmt ->
            sourceStmt.setLong(1, did)
            val result = sourceStmt.executeQuery()
            result.next()
            db.connection.prepareStatement("insert into passwords (id, name, username, password, notes, created, modified, accessed) values (?, ?, ?, ?, ?, ?, ?, ?)").run {
                setLong(1, did)
                setEncryptedString(2, destination, db.encryption)
                setBytes(3, result.getBytes(1))
                setBytes(4, result.getBytes(2))
                setBytesOrNull(5, result.getBytes(3))
                setLong(6, result.getLong(4))
                setLong(7, System.currentTimeMillis())
                setLongOrNull(8, result.getLong(6))
                executeUpdate()
            }
        }

        deleteRecord(sid)
    }

    private fun recordExists(id: Long): Boolean {
        db.connection.prepareStatement("select count(*) from passwords where id = ?").use {
            it.setLong(1, id)
            val result = it.executeQuery()
            result.next()
            return result.getInt(1) > 0
        }
    }

    private fun deleteRecord(id: Long): Unit {
        db.connection.prepareStatement("delete from passwords where id = ?").use {
            it.setLong(1, id);
            it.executeUpdate()
        }
    }
}