[PATCH himitsu] hiq: add -M to store/query for multi-line secrets
Export this patch
Signed-off-by: Willow Barraco <contact@willowbarraco.fr>
---
cmd/hiq/main.ha | 68 +++++++++++++++++++++++++++++++++++++++++++++ ----
docs/hiq.1.scd | 7 ++++ -
2 files changed, 69 insertions(+), 6 deletions(-)
diff --git a/cmd/hiq/main.ha b/cmd/hiq/main.ha
index 6386423..6d9fa59 100644
--- a/cmd/hiq/main.ha
+++ b/cmd/hiq/main.ha
@@ -30,6 +30,7 @@ export fn main() void = {
('d', "decrypt private keys"),
('D', "delete matching keys"),
('F', "field", "select a field for output"),
+ ('M', "field", "multi-line field data"),
('l', "soft lock the keyring"),
('L', "hard lock the keyring"),
('Q', "terminate the daemon (if started with -D)"),
@@ -42,6 +43,7 @@ export fn main() void = {
let op = client::operation::QUERY;
let flags: client::flags = 0;
let field: (str | void) = void;
+ let multiline: (str | void) = void;
let one = false;
let lock = lockop::NONE;
@@ -57,6 +59,8 @@ export fn main() void = {
op = client::operation::DEL;
case 'F' =>
field = opt.1;
+ case 'M' =>
+ multiline = opt.1;
case 'l' =>
lock = lockop::SOFT;
case 'L' =>
@@ -97,7 +101,43 @@ export fn main() void = {
};
};
- if (op == client::operation::ADD && len(cmd.args) == 0) {
+ if (op == client::operation::ADD && len(cmd.args) != 0 && !(multiline is void)) {
+ if (tty::isatty(os::stderr_file) && tty::isatty(os::stdin_file)) {
+ fmt::errorln("Enter the content of the value then press ^d:")!;
+ };
+ const multiline = multiline as str;
+
+ let scan = bufio::newscanner(os::stdin);
+ defer bufio::finish(&scan);
+
+ let lines: []str = [];
+ defer strings::freeall(lines);
+ for (let line => bufio::scan_line(&scan)) {
+ let line = match (line) {
+ case let line: const str =>
+ yield line;
+ case let e: io::error =>
+ fmt::fatal("Error reading data", io::strerror(e));
+ case utf8::invalid =>
+ fmt::fatal("Error: Query is not valid UTF-8");
+ };
+ append(lines, strings::dup(line));
+ };
+ const secret = strings::join("\0", lines...);
+ defer free(secret);
+
+ const item = strings::concat(multiline, "=", secret);
+ append(cmd.args, item);
+
+ const query = match (query::parse_items(cmd.args)) {
+ case let q: query::query =>
+ yield q;
+ case let err: query::error =>
+ fmt::fatal(query::strerror(err));
+ };
+ defer query::finish(&query);
+ send(conn, op, &query, flags, field, multiline, one);
+ } else if (op == client::operation::ADD && len(cmd.args) == 0) {
if (tty::isatty(os::stderr_file) && tty::isatty(os::stdin_file)) {
fmt::errorln("Enter new keys, one per line, then press ^d:")!;
};
@@ -125,7 +165,7 @@ export fn main() void = {
strings::dup(line));
};
defer query::finish(&query);
- send(conn, client::operation::ADD, &query, flags, field, one);
+ send(conn, client::operation::ADD, &query, flags, field, multiline, one);
};
} else {
const query = match (query::parse_items(cmd.args)) {
@@ -135,7 +175,7 @@ export fn main() void = {
fmt::fatal(query::strerror(err));
};
defer query::finish(&query);
- send(conn, op, &query, flags, field, one);
+ send(conn, op, &query, flags, field, multiline, one);
};
};
@@ -145,6 +185,7 @@ fn send(
query: *query::query,
flags: client::flags,
field: (str | void),
+ multiline: (str | void),
one: bool,
) void = {
const keys = match (client::query(conn, op, query, flags)) {
@@ -168,6 +209,7 @@ fn send(
fmt::fatal("Error executing query:", client::strerror(err));
case done => break;
};
+
match (field) {
case let field: str =>
for (let item &.. key.items) {
@@ -175,9 +217,25 @@ fn send(
fmt::fprintln(&buf, item.value)!;
};
};
- case void =>
- query::unparse(&buf, &key)!;
+ continue;
+ case void => yield;
};
+
+ match (multiline) {
+ case let multiline: str =>
+ for (let item &.. key.items) {
+ if (item.key == multiline) {
+ let lines = strings::split(item.value, "\0");
+ for (const line .. lines) {
+ fmt::fprintln(&buf, line)!;
+ };
+ };
+ };
+ continue;
+ case void => yield;
+ };
+
+ query::unparse(&buf, &key)!;
};
fmt::print(memio::string(&buf)!)!;
diff --git a/docs/hiq.1.scd b/docs/hiq.1.scd
index 221ae35..ab54661 100644
--- a/docs/hiq.1.scd
+++ b/docs/hiq.1.scd
@@ -6,7 +6,7 @@ hiq - query the *himitsu*(7) key store
# SYNOPSIS
- *hiq* [-h1adDlLQs] [-F _field_] _query_...
+ *hiq* [-h1adDlLQs] [-F _field_] [-M _field_] _query_...
# DESCRIPTION
@@ -47,6 +47,11 @@ have already been quoted properly.
Select a specific field to print. By default, the full key is printed in
the format described by *KEY FORMAT* in *himitsu*(7).
+ *-M* _field_
+ Select a specific field to use as a multi-line value. It use the stdin
+ while adding, and the stdout when querying. The data is encoded using
+ NULL char as line return.
+
*-l*
Soft locks the keyring by removing the secret key from memory. Keeps
non-private data of entries in memory.
--
2.46.0
I'm not in favor of introducing multiline field support into hiq, since
it breaks the query format once applied. Multiline values do not play
well with other unix tools.
There are some other cases this can fail easily:
* When the value contains already an "\0" before adding it as a
multiline value, it will introduce another unintended line break.
* When your query returns more than one entry with a multiline value
You won't be able to tell where one begins and the next one stops.
Also how can one store an entry with more than one multiline fields?
The intended way to store values, that contain control characters, is to
encode them with external tools. E.g. base64. Before adding them to
himitsu.