# HG changeset patch # User David Barts # Date 1662953766 25200 # Node ID eafa3779aef8ee1b35affc16e8e7ba88ec83d92c # Parent 3c792ad36b3d2f1a0acec3cb2d8da367400af933 More bug fixes, quote strings in diagnostics. diff -r 3c792ad36b3d -r eafa3779aef8 pom.xml --- a/pom.xml Sun Sep 11 18:24:55 2022 -0700 +++ b/pom.xml Sun Sep 11 20:36:06 2022 -0700 @@ -81,24 +81,23 @@ maven-assembly-plugin + make-assembly package single - - - - - name.blackcap.passman.MainKt - - - - - jar-with-dependencies - - + + + + name.blackcap.passman.MainKt + + + + jar-with-dependencies + + diff -r 3c792ad36b3d -r eafa3779aef8 src/main/kotlin/name/blackcap/passman/CreateSubcommand.kt --- a/src/main/kotlin/name/blackcap/passman/CreateSubcommand.kt Sun Sep 11 18:24:55 2022 -0700 +++ b/src/main/kotlin/name/blackcap/passman/CreateSubcommand.kt Sun Sep 11 20:36:06 2022 -0700 @@ -29,7 +29,7 @@ val length = try { rawLength?.toInt() ?: DEFAULT_GENERATED_LENGTH } catch (e: NumberFormatException) { - die("$rawLength - invalid length") + die("${see(rawLength)} - invalid length") -1 /* will never happen */ } val symbols = commandLine.hasOption("symbols") @@ -46,7 +46,7 @@ result.next() val count = result.getInt(1) if (count > 0) { - die("record matching ${entry.name} already exists") + die("record matching ${see(entry.name)} already exists") } } diff -r 3c792ad36b3d -r eafa3779aef8 src/main/kotlin/name/blackcap/passman/Database.kt --- a/src/main/kotlin/name/blackcap/passman/Database.kt Sun Sep 11 18:24:55 2022 -0700 +++ b/src/main/kotlin/name/blackcap/passman/Database.kt Sun Sep 11 20:36:06 2022 -0700 @@ -18,9 +18,9 @@ val exists = Files.exists(Path.of(fileName)) if (!exists) { if (create) { - error("initializing database $fileName") + error("initializing database ${see(fileName, simple = true)}") } else { - die("$fileName not found") + die("${see(fileName, simple = true)} not found") } } val masterPassword = getPassword(passwordPrompt, !exists) @@ -99,8 +99,6 @@ val readFromDb = result.getDecryptedString(1, database.encryption) if (readFromDb != PLAINTEXT) { /* might also get thrown by getDecryptedString if bad */ - println(" got: " + dump(readFromDb)) - println("expected: " + dump(PLAINTEXT)) throw GeneralSecurityException("bad key!") } } diff -r 3c792ad36b3d -r eafa3779aef8 src/main/kotlin/name/blackcap/passman/DeleteSubcommand.kt --- a/src/main/kotlin/name/blackcap/passman/DeleteSubcommand.kt Sun Sep 11 18:24:55 2022 -0700 +++ b/src/main/kotlin/name/blackcap/passman/DeleteSubcommand.kt Sun Sep 11 20:36:06 2022 -0700 @@ -2,6 +2,19 @@ class DeleteSubcommand(): Subcommand() { override fun run(args: Array) { - println("Not yet implemented") + if (args.isEmpty()) { + die("expecting a site name", 2) + } + if (args.size > 1) { + die("unexpected trailing arguments", 2) + } + val nameIn = args[0] + val db = Database.open() + db.connection.prepareStatement("delete from passwords where id = ?").use { + it.setLong(1, db.makeKey(nameIn)) + if (it.executeUpdate() == 0) { + die("no record matches ${see(nameIn)}") + } + } } } \ No newline at end of file diff -r 3c792ad36b3d -r eafa3779aef8 src/main/kotlin/name/blackcap/passman/Main.kt --- a/src/main/kotlin/name/blackcap/passman/Main.kt Sun Sep 11 18:24:55 2022 -0700 +++ b/src/main/kotlin/name/blackcap/passman/Main.kt Sun Sep 11 20:36:06 2022 -0700 @@ -21,7 +21,7 @@ fun runSubcommand(name: String, args: Array): Unit { val instance = getInstanceForClass(getClassForSubcommand(name)) if (instance == null) { - die("$name - unknown subcommand", 2) + die("${see(name)} - unknown subcommand", 2) } else { instance.run(args) } diff -r 3c792ad36b3d -r eafa3779aef8 src/main/kotlin/name/blackcap/passman/ReadSubcommand.kt --- a/src/main/kotlin/name/blackcap/passman/ReadSubcommand.kt Sun Sep 11 18:24:55 2022 -0700 +++ b/src/main/kotlin/name/blackcap/passman/ReadSubcommand.kt Sun Sep 11 20:36:06 2022 -0700 @@ -31,7 +31,7 @@ it.setLong(1, id) val result = it.executeQuery() if (!result.next()) { - die("no record matches $nameIn") + die("no record matches ${see(nameIn)}") } val entry = Entry( name = result.getDecryptedString(1, db.encryption), @@ -63,4 +63,4 @@ it.execute() } } -} \ No newline at end of file +} diff -r 3c792ad36b3d -r eafa3779aef8 src/main/kotlin/name/blackcap/passman/See.kt --- a/src/main/kotlin/name/blackcap/passman/See.kt Sun Sep 11 18:24:55 2022 -0700 +++ b/src/main/kotlin/name/blackcap/passman/See.kt Sun Sep 11 20:36:06 2022 -0700 @@ -1,56 +1,46 @@ package name.blackcap.passman +/* Would be nice if there was a more programmatic and comprehensive way of + doing this, but alas. Even the oft-recommended StringEscapeUtils does + something cruder than the below. Le sigh. */ + import java.util.Formatter -private val UNPRINTABLE = setOf( - Character.UnicodeBlock.COMBINING_DIACRITICAL_MARKS, - Character.UnicodeBlock.COMBINING_DIACRITICAL_MARKS_EXTENDED, - Character.UnicodeBlock.COMBINING_HALF_MARKS, - Character.UnicodeBlock.COMBINING_DIACRITICAL_MARKS_SUPPLEMENT, - Character.UnicodeBlock.COMBINING_MARKS_FOR_SYMBOLS, - Character.UnicodeBlock.HIGH_PRIVATE_USE_SURROGATES, - Character.UnicodeBlock.HIGH_SURROGATES, - Character.UnicodeBlock.LOW_SURROGATES, - Character.UnicodeBlock.PRIVATE_USE_AREA, - Character.UnicodeBlock.SPECIALS, +private const val DELIM = '"' -) +private val STD_ESC_MAP = mapOf('\t' to 't', '\b' to 'b', '\n' to 'n', + '\r' to 'r', '\u000c' to 'f', '\"' to '"', '\\' to '\\') +private const val MIN_ASCII = ' ' +private const val MAX_ASCII = '~' +private const val MIN_8859 = '\u00a1' +private const val MAX_8859 = '\u00ff' +private const val SHY = '\u00ad' -private val DELIM = '"' +fun see(input: String, simple: Boolean = false): String = + if (simple) seeSimple(input) else seeAggressive(input) -private val EXEMPT = setOf(' ') -private val PREFIXED = setOf(DELIM, '\\') +private fun seeSimple(input: String): String = StringBuilder().run { + append(DELIM) + append(input) + append(DELIM) + toString() +} -fun see(input: String): String { - val accum = StringBuilder() - val formatter = Formatter(accum) - accum.append(DELIM) +private fun seeAggressive(input: String): String { + val accum = Formatter() + accum.format("%c", DELIM) for (ch in input) { - val block = Character.UnicodeBlock.of(ch) - if (ch in EXEMPT) { - accum.append(ch) - } else if (block == null || block in UNPRINTABLE || Character.isSpaceChar(ch) || Character.isWhitespace(ch)) { - formatter.format("\\u%04x", ch.code) - } else if (ch in PREFIXED) { - accum.append('\\') - accum.append(ch) + if ((ch in MIN_ASCII..MAX_ASCII) || ((ch != SHY) && (ch in MIN_8859 .. MAX_8859))) { + accum.format("%c", ch) + continue + } + val mapped = STD_ESC_MAP[ch] + if (mapped != null) { + accum.format("\\%c", mapped) } else { - accum.append(ch) + accum.format("\\u%04x", ch.code) } } - accum.append(DELIM) + accum.format("%c", DELIM) return accum.toString() } - -fun dump(input: String): String { - val accum = StringBuilder() - var needSpace = false - for (ch in input) { - if (needSpace) { - accum.append(' ') - } - accum.append(ch.code) - needSpace = true - } - return accum.toString() -} diff -r 3c792ad36b3d -r eafa3779aef8 src/main/kotlin/name/blackcap/passman/UpdateSubcommand.kt --- a/src/main/kotlin/name/blackcap/passman/UpdateSubcommand.kt Sun Sep 11 18:24:55 2022 -0700 +++ b/src/main/kotlin/name/blackcap/passman/UpdateSubcommand.kt Sun Sep 11 20:36:06 2022 -0700 @@ -53,7 +53,7 @@ try { rawLength?.toInt() ?: DEFAULT_GENERATED_LENGTH } catch (e: NumberFormatException) { - die("$rawLength - invalid length") + die("${see(rawLength)} - invalid length") -1 /* will never happen */ } } @@ -90,7 +90,7 @@ result.next() val count = result.getInt(1) if (count < 1) { - die("no record matches $nameIn") + die("no record matches " + see(nameIn)) } } } @@ -167,4 +167,4 @@ addOne("password", newPassword) } -} \ No newline at end of file +}