comparison src/main/kotlin/name/blackcap/passman/CreateSubcommand.kt @ 0:a6cfdffcaa94

Initial commit, incomplete but it runs sorta.
author David Barts <n5jrn@me.com>
date Sun, 11 Sep 2022 16:11:37 -0700
parents
children eafa3779aef8
comparison
equal deleted inserted replaced
-1:000000000000 0:a6cfdffcaa94
1 package name.blackcap.passman
2
3 import org.apache.commons.cli.CommandLine
4 import org.apache.commons.cli.DefaultParser
5 import org.apache.commons.cli.Options
6 import org.apache.commons.cli.ParseException
7 import kotlin.system.exitProcess
8
9 class CreateSubcommand(): Subcommand() {
10 private lateinit var commandLine: CommandLine
11
12 override fun run(args: Array<String>) {
13 val options = Options().apply {
14 addOption("g", "generate", false, "Use password generator.")
15 addOption("l", "length", true, "Length of generated password.")
16 addOption("s", "symbols", false, "Use symbol characters in generated password.")
17 addOption("v", "verbose", false, "Print the generated password.")
18 }
19 try {
20 commandLine = DefaultParser().parse(options, args)
21 } catch (e: ParseException) {
22 die(e.message ?: "syntax error", 2)
23 }
24 checkArguments()
25 val db = Database.open()
26
27 val entry = if (commandLine.hasOption("generate")) {
28 val rawLength = commandLine.getOptionValue("length")
29 val length = try {
30 rawLength?.toInt() ?: DEFAULT_GENERATED_LENGTH
31 } catch (e: NumberFormatException) {
32 die("$rawLength - invalid length")
33 -1 /* will never happen */
34 }
35 val symbols = commandLine.hasOption("symbols")
36 val verbose = commandLine.hasOption("verbose")
37 Entry.withGeneratedPassword(length, symbols, verbose)
38 } else {
39 Entry.withPromptedPassword()
40 }
41 val id = db.makeKey(entry.name)
42
43 db.connection.prepareStatement("select count(*) from passwords where id = ?").use {
44 it.setLong(1, id)
45 val result = it.executeQuery()
46 result.next()
47 val count = result.getInt(1)
48 if (count > 0) {
49 die("record matching ${entry.name} already exists")
50 }
51 }
52
53 try {
54 if (entry.notes.isBlank()) {
55 db.connection.prepareStatement("insert into passwords (id, name, username, password, created) values (?, ?, ?, ?, ?)")
56 .use {
57 it.setLong(1, id)
58 it.setEncryptedString(2, entry.name, db.encryption)
59 it.setEncryptedString(3, entry.username, db.encryption)
60 it.setEncrypted(4, entry.password, db.encryption)
61 it.setLong(5, System.currentTimeMillis())
62 it.execute()
63 }
64 } else {
65 db.connection.prepareStatement("insert into passwords (id, name, username, password, notes, created) values (?, ?, ?, ?, ?, ?)")
66 .use {
67 it.setLong(1, db.makeKey(entry.name))
68 it.setEncryptedString(2, entry.name, db.encryption)
69 it.setEncryptedString(3, entry.username, db.encryption)
70 it.setEncrypted(4, entry.password, db.encryption)
71 it.setEncryptedString(5, entry.notes, db.encryption)
72 it.setLong(6, System.currentTimeMillis())
73 it.execute()
74 }
75 }
76 } finally {
77 entry.password.clear()
78 }
79 }
80
81 private fun checkArguments(): Unit {
82 var bad = false
83 if (!commandLine.hasOption("generate")) {
84 for (option in listOf<String>("length", "symbols", "verbose")) {
85 if (commandLine.hasOption(option)) {
86 error("--$option requires --generate")
87 bad = true
88 }
89 }
90 }
91 if (commandLine.args.isNotEmpty()) {
92 error("unexpected trailing arguments")
93 }
94 if (bad) {
95 exitProcess(2);
96 }
97 }
98 }