Welcome to little lamb

Code » ssp » commit cc02b77

Add support for comments

author Olivier Brunel
2023-04-18 10:31:49 UTC
committer Olivier Brunel
2023-04-18 10:31:49 UTC
parent 793e22a91dc2cb00f8cad0b3e7f08fd7ebbcfaf4

Add support for comments

Much like site's name, they can be given enclosed within double-quotes
in which case they'll be unescaped as usual.

src/include/ssp.h +1 -0
src/ssp/add.c +32 -13
src/ssp/show.c +4 -0
src/ssp/ssp.c +16 -7

diff --git a/src/include/ssp.h b/src/include/ssp.h
index 0086654..3359b00 100644
--- a/src/include/ssp.h
+++ b/src/include/ssp.h
@@ -63,6 +63,7 @@ struct otp
 
 /* ssp.c */
 int exitcode_from_errno(int e);
+ssize_t unesc(char *dst, size_t dlen, const char *sce, size_t slen);
 const char *get_site_name(const char *s, struct ssp *ctx);
 
 /* database.c */
diff --git a/src/ssp/add.c b/src/ssp/add.c
index a9104d6..681dc95 100644
--- a/src/ssp/add.c
+++ b/src/ssp/add.c
@@ -5,12 +5,18 @@
 #include <limb/base32.h>
 #include <limb/bytestr.h>
 #include <limb/command.h>
+#include <limb/esc.h>
 #include <limb/exitcode.h>
 #include <limb/output.h>
 #include <limb/parseopt.h>
 #include <limb/u16.h>
 #include "ssp.h"
 
+struct add {
+    struct otp otp;
+    const char *comments;
+};
+
 COMMAND(add, "Add a new site to the database",
         "<site> [OPTION..] <secret>",
 " -a, --algo ALGO                       Set ALGO as hashing algorithm [sha256]\n"
@@ -22,7 +28,7 @@ COMMAND(add, "Add a new site to the database",
 
 
 static int
-parse_cmdline(int argc, const char *argv[], const char usage[], struct otp *otp)
+parse_cmdline(int argc, const char *argv[], const char usage[], struct add *add)
 {
     const struct option options[] = {
         OPTION_ARG_REQ ('a', "algo",                    0, OPTID_SHORTOPT),
@@ -53,29 +59,32 @@ parse_cmdline(int argc, const char *argv[], const char usage[], struct otp *otp)
                                      first, algos);
                     diecmdusage(EX_USAGE, usage, &command_add);
                 }
-                otp->algo = i;
+                add->otp.algo = i;
             }
             break;
+        case 'c':
+            add->comments = po.arg;
+            break;
         case 'd':
-            otp->type = TYPE_COUNTER;
-            otp->digits = *po.arg - '0';
-            if (po.arg[1] || otp->digits < 5 || otp->digits > 9) {
+            add->otp.type = TYPE_COUNTER;
+            add->otp.digits = *po.arg - '0';
+            if (po.arg[1] || add->otp.digits < 5 || add->otp.digits > 9) {
                 warn("invalid number of digits, must be between 5 and 9: ", po.arg);
                 diecmdusage(EX_USAGE, usage, &command_add);
             }
             break;
         case 't':
             if (!po.arg) {
-                otp->precision = 30;
+                add->otp.precision = 30;
             } else {
                 u16 u;
                 if (!u160_scan(&u, po.arg) || u < 10 || u > 120) {
                     warn("invalid precision argument, must be between 10 and 120: ", po.arg);
                     diecmdusage(EX_USAGE, usage, &command_add);
                 }
-                otp->precision = u;
+                add->otp.precision = u;
             }
-            otp->type = TYPE_TIME;
+            add->otp.type = TYPE_TIME;
             break;
         case -1:
             diecmdusage(EX_USAGE, usage, &command_add);
@@ -90,7 +99,8 @@ int
 add_main(int argc, const char *argv[], const char *env[], const char usage[], void *ctx_)
 {
     struct ssp *ctx = ctx_;
-    struct otp otp = { .type = TYPE_COUNTER, .algo = ALGO_SHA256, .digits = 6 };
+    struct add add = { .otp.type = TYPE_COUNTER, .otp.algo = ALGO_SHA256,
+        .otp.digits = 6, .comments = "" };
     const char *site;
     int i;
 
@@ -108,7 +118,7 @@ add_main(int argc, const char *argv[], const char *env[], const char usage[], vo
 
     --argc;
     ++argv;
-    i = parse_cmdline(argc, argv, usage, &otp);
+    i = parse_cmdline(argc, argv, usage, &add);
 
     if (i == argc) {
         warn("argument \"secret\" missing");
@@ -125,12 +135,21 @@ add_main(int argc, const char *argv[], const char *env[], const char usage[], vo
     if (!l)
         dief(EX_DATA_ERR, "secret is empty");
 
-    char buf[sizeof(otp) + l + 1];
+    size_t clen = strlen(add.comments);
+    char buf[sizeof(add.otp) + l + clen + 1];
     struct otp *p = (struct otp *) buf;
-    memcpy(p, &otp, sizeof(otp));
+    memcpy(p, &add.otp, sizeof(add.otp));
     p->slen = l;
     base32_scan(p->data, secret, strlen(secret));
-    p->data[l] = 0;
+    if (clen >= 2 && add.comments[0] == '"' && add.comments[clen - 1] == '"') {
+        ++add.comments;
+        clen -= 2;
+        l = unesc(p->data + l, clen, add.comments, clen);
+        if (l < 0)
+            diefusys(EX_DATA_ERR, "read comments");
+    } else {
+        memcpy(p->data + l, add.comments, clen + 1);
+    }
 
     if (open_db(ctx) < 0)
         diefu(exitcode_from_errno(errno), "open database");
diff --git a/src/ssp/show.c b/src/ssp/show.c
index 3a87b8c..9fa36cc 100644
--- a/src/ssp/show.c
+++ b/src/ssp/show.c
@@ -70,6 +70,8 @@ show_site(unsigned options, struct ssp *ctx)
         buf[l] = 0;
         out("   Secret: ", buf);
     }
+    if (otp->data[otp->slen])
+        out("   Comments:\n", otp->data + otp->slen);
 }
 
 void
@@ -90,6 +92,8 @@ show_site_ini(struct ssp *ctx)
     base32_fmt(buf, otp->data, otp->slen, 0);
     buf[l] = 0;
     out("secret=", buf);
+    if (otp->data[otp->slen])
+        out("comments=", ESC, otp->data + otp->slen, ESC);
 }
 
 int
diff --git a/src/ssp/ssp.c b/src/ssp/ssp.c
index 6c3f7e3..2d0088e 100644
--- a/src/ssp/ssp.c
+++ b/src/ssp/ssp.c
@@ -36,6 +36,19 @@ exitcode_from_errno(int e)
     }
 }
 
+ssize_t
+unesc(char *dst, size_t dlen, const char *sce, size_t slen)
+{
+    /* unescape it */
+    ssize_t l = esc_scan(dst, dlen, sce, slen);
+    if (l < 0) return -1;
+    /* make sure there was no encoded NUL byte */
+    if (byte_chr(dst, l, 0) < (size_t) l)
+        return (errno = EINVAL, -1);
+    dst[l++] = 0;
+    return l;
+}
+
 const char *
 get_site_name(const char *s, struct ssp *ctx)
 {
@@ -49,14 +62,10 @@ get_site_name(const char *s, struct ssp *ctx)
     l -= 2;
     if (!stralloc_readyplus(&ctx->sa, l + 1))
         return NULL;
+
     /* unescape it */
-    l = esc_scan(ctx->sa.s + ctx->sa.len, l, s + 1, l);
-    if (l < 0)
-        return NULL;
-    /* make sure there was no encoded NUL byte */
-    if (byte_chr(ctx->sa.s + ctx->sa.len, l, 0) < l)
-        return (errno = EINVAL, NULL);
-    ctx->sa.s[l++] = 0;
+    l = unesc(ctx->sa.s + ctx->sa.len, l, s + 1, l);
+    if (l < 0) return NULL;
     ctx->sa.len += l;
     return ctx->sa.s + salen;
 }