Mercurial > cgi-bin > hgweb.cgi > PassMan
annotate src/main/kotlin/name/blackcap/passman/PasswordSubcommand.kt @ 28:287eadf5ab30 default tip
Check for timeouts inside subcommands while in interactive mode as well.
author | David Barts <n5jrn@me.com> |
---|---|
date | Wed, 31 Jul 2024 11:21:18 -0700 |
parents | ea65ab890f66 |
children |
rev | line source |
---|---|
15 | 1 package name.blackcap.passman |
2 | |
3 import java.nio.file.Files | |
4 import java.nio.file.Path | |
5 import java.nio.file.StandardCopyOption | |
6 | |
7 class PasswordSubcommand : Subcommand() { | |
8 override fun run(args: Array<String>) { | |
9 // Parse arguments | |
10 if (args.size > 0 && (args[0] == "-h" || args[0].startsWith("--h"))) { | |
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 | 13 } |
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 | 16 } |
17 | |
18 // Open databases | |
19 println("Changing database encryption key...") | |
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 | 22 val newPath = Path.of(NEW_DB_FILE) |
23 if (Files.exists(newPath)) { | |
24 println("WARNING: deleting ${see(NEW_DB_FILE)}") | |
25 Files.delete(newPath) | |
26 } | |
27 val newDb = Database.open(fileName = NEW_DB_FILE, passwordPrompt = "New database key: ", create = true) | |
28 | |
29 // Copy old to new | |
30 println("WARNING: do not interrupt this process or data may be lost!") | |
31 copyRecords(oldDb, newDb) | |
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 | 36 oldDb.connection.close() |
37 newDb.connection.close() | |
38 Files.move(newPath, oldPath, StandardCopyOption.REPLACE_EXISTING) | |
39 println("Database key changed.") | |
40 } | |
41 | |
42 private fun copyRecords(oldDb: Database, newDb: Database) { | |
43 oldDb.connection.prepareStatement("select name, username, password, notes, created, modified, accessed from passwords").use { old -> | |
44 val results = old.executeQuery() | |
45 while (results.next()) { | |
46 newDb.connection.prepareStatement("insert into passwords (id, name, username, password, notes, created, modified, accessed) values (?, ?, ?, ?, ?, ?, ?, ?)").use { new -> | |
47 // id and name | |
48 val name = results.getDecryptedString(1, oldDb.encryption)!! | |
49 new.setLong(1, newDb.makeKey(name)) | |
50 new.setEncryptedString(2, name, newDb.encryption) | |
51 // username | |
52 new.setEncryptedString(3, | |
53 results.getDecryptedString(2, oldDb.encryption)!!, newDb.encryption) | |
54 // password | |
55 val password = results.getDecrypted(3, oldDb.encryption)!! | |
56 new.setEncrypted(4, password, newDb.encryption) | |
57 password.clear() | |
58 // notes | |
59 new.setEncryptedString(5, | |
60 results.getDecryptedString(4, oldDb.encryption), newDb.encryption) | |
61 // created, modified, accessed | |
62 new.setDateOrNull(6, results.getLong(5)) | |
63 new.setDateOrNull(7, results.getLong(6)) | |
64 new.setDateOrNull(8, results.getLong(7)) | |
65 new.executeUpdate() | |
66 } | |
67 } | |
68 } | |
69 } | |
70 } |