annotate src/main/kotlin/name/blackcap/passman/PasswordSubcommand.kt @ 27:3a3067ba673b

Add idle-time detection to interactive mode, clean up imports.
author David Barts <n5jrn@me.com>
date Sat, 27 Jul 2024 09:50:54 -0700
parents ea65ab890f66
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
15
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
1 package name.blackcap.passman
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
2
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
3 import java.nio.file.Files
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
4 import java.nio.file.Path
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
5 import java.nio.file.StandardCopyOption
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
6
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
7 class PasswordSubcommand : Subcommand() {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
8 override fun run(args: Array<String>) {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
9 // Parse arguments
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
10 if (args.size > 0 && (args[0] == "-h" || args[0].startsWith("--h"))) {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
11 println("usage: passman password")
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 15
diff changeset
12 return
15
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
13 }
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
14 if (!args.isEmpty()) {
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 15
diff changeset
15 throw SubcommandException(message = "unexpected arguments", status = 2)
15
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
16 }
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
17
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
18 // Open databases
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
19 println("Changing database encryption key...")
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
20 val oldPath = Path.of(DB_FILE)
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 15
diff changeset
21 val oldDb = Database.default
15
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
22 val newPath = Path.of(NEW_DB_FILE)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
23 if (Files.exists(newPath)) {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
24 println("WARNING: deleting ${see(NEW_DB_FILE)}")
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
25 Files.delete(newPath)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
26 }
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
27 val newDb = Database.open(fileName = NEW_DB_FILE, passwordPrompt = "New database key: ", create = true)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
28
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
29 // Copy old to new
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
30 println("WARNING: do not interrupt this process or data may be lost!")
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
31 copyRecords(oldDb, newDb)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
32
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 15
diff changeset
33 // Wrap up. XXX - this closes Database.default, so this subcommand may
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 15
diff changeset
34 // only be invoked directly from the shell prompt, never in interactive
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 15
diff changeset
35 // mode.
15
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
36 oldDb.connection.close()
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
37 newDb.connection.close()
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
38 Files.move(newPath, oldPath, StandardCopyOption.REPLACE_EXISTING)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
39 println("Database key changed.")
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
40 }
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
41
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
42 private fun copyRecords(oldDb: Database, newDb: Database) {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
43 oldDb.connection.prepareStatement("select name, username, password, notes, created, modified, accessed from passwords").use { old ->
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
44 val results = old.executeQuery()
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
45 while (results.next()) {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
46 newDb.connection.prepareStatement("insert into passwords (id, name, username, password, notes, created, modified, accessed) values (?, ?, ?, ?, ?, ?, ?, ?)").use { new ->
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
47 // id and name
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
48 val name = results.getDecryptedString(1, oldDb.encryption)!!
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
49 new.setLong(1, newDb.makeKey(name))
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
50 new.setEncryptedString(2, name, newDb.encryption)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
51 // username
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
52 new.setEncryptedString(3,
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
53 results.getDecryptedString(2, oldDb.encryption)!!, newDb.encryption)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
54 // password
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
55 val password = results.getDecrypted(3, oldDb.encryption)!!
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
56 new.setEncrypted(4, password, newDb.encryption)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
57 password.clear()
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
58 // notes
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
59 new.setEncryptedString(5,
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
60 results.getDecryptedString(4, oldDb.encryption), newDb.encryption)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
61 // created, modified, accessed
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
62 new.setDateOrNull(6, results.getLong(5))
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
63 new.setDateOrNull(7, results.getLong(6))
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
64 new.setDateOrNull(8, results.getLong(7))
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
65 new.executeUpdate()
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
66 }
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
67 }
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
68 }
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
69 }
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
70 }