annotate src/main/kotlin/name/blackcap/passman/PasswordSubcommand.kt @ 19:7d80cbcb67bb

add shlex-style splitter and tests
author David Barts <n5jrn@me.com>
date Sun, 30 Jun 2024 20:37:36 -0700
parents 0fc90892a3ae
children ea65ab890f66
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 import kotlin.system.exitProcess
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
7
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
8 class PasswordSubcommand : Subcommand() {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
9 override fun run(args: Array<String>) {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
10 // Parse arguments
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
11 if (args.size > 0 && (args[0] == "-h" || args[0].startsWith("--h"))) {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
12 println("usage: passman password")
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
13 exitProcess(0)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
14 }
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
15 if (!args.isEmpty()) {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
16 die("unexpected arguments", 2)
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
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
19 // Open databases
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
20 println("Changing database encryption key...")
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
21 val oldPath = Path.of(DB_FILE)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
22 val oldDb = Database.open(fileName = DB_FILE, passwordPrompt = "Old database key: ")
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
23 val newPath = Path.of(NEW_DB_FILE)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
24 if (Files.exists(newPath)) {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
25 println("WARNING: deleting ${see(NEW_DB_FILE)}")
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
26 Files.delete(newPath)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
27 }
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
28 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
29
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
30 // Copy old to new
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
31 println("WARNING: do not interrupt this process or data may be lost!")
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
32 copyRecords(oldDb, newDb)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
33
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
34 // Wrap up
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
35 oldDb.connection.close()
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
36 newDb.connection.close()
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
37 Files.move(newPath, oldPath, StandardCopyOption.REPLACE_EXISTING)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
38 println("Database key changed.")
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
39 }
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 private fun copyRecords(oldDb: Database, newDb: Database) {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
42 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
43 val results = old.executeQuery()
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
44 while (results.next()) {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
45 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
46 // id and name
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
47 val name = results.getDecryptedString(1, oldDb.encryption)!!
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
48 new.setLong(1, newDb.makeKey(name))
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
49 new.setEncryptedString(2, name, newDb.encryption)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
50 // username
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
51 new.setEncryptedString(3,
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
52 results.getDecryptedString(2, oldDb.encryption)!!, newDb.encryption)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
53 // password
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
54 val password = results.getDecrypted(3, oldDb.encryption)!!
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
55 new.setEncrypted(4, password, newDb.encryption)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
56 password.clear()
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
57 // notes
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
58 new.setEncryptedString(5,
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
59 results.getDecryptedString(4, oldDb.encryption), newDb.encryption)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
60 // created, modified, accessed
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
61 new.setDateOrNull(6, results.getLong(5))
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
62 new.setDateOrNull(7, results.getLong(6))
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
63 new.setDateOrNull(8, results.getLong(7))
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
64 new.executeUpdate()
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents:
diff changeset
65 }
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 }