aboutsummaryrefslogtreecommitdiff
path: root/tokengen.c
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2025-09-22 17:32:44 +0200
committerXavier Del Campo Romero <xavi92@disroot.org>2026-02-13 09:57:39 +0100
commit78bf2fe4a5bf37514f6dfd203ef969da0bf40c2e (patch)
tree33f9440b8ee0fa7a3b3ad033616d722d2101bb4d /tokengen.c
parent107a2e43d54f9a42fb85b00b83cb0d9abb194680 (diff)
Setup project skeletonHEADmaster
Diffstat (limited to 'tokengen.c')
-rw-r--r--tokengen.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/tokengen.c b/tokengen.c
new file mode 100644
index 0000000..9b88085
--- /dev/null
+++ b/tokengen.c
@@ -0,0 +1,155 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include "jwt.h"
+#include <cjson/cJSON.h>
+#include <dynstr.h>
+#include <sodium.h>
+#include <sqlite3.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+static int tokenkey(void *const args, const int n, char **const values,
+ char **const keys)
+{
+ char *key;
+
+ if (n != 1)
+ {
+ fprintf(stderr, "%s: expected 1 key only, got %d\n", __func__, n);
+ return -1;
+ }
+ else if (!(key = strdup(*values)))
+ {
+ fprintf(stderr, "%s: strdup(3): %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ *(char **)args = key;
+ return 0;
+}
+
+static int process(sqlite3 *const db, const char *const user)
+{
+ static const char query[] = "SELECT value FROM globals "
+ "WHERE key = 'tokenkey';";
+ int ret = -1, error;
+ cJSON *j = NULL;
+ char *s = NULL, *key = NULL, *jwt = NULL;
+ unsigned char dkey[32];
+ time_t t;
+
+ if ((error = sqlite3_exec(db, query, tokenkey, &key, &s)) != SQLITE_OK)
+ {
+ fprintf(stderr, "%s: sqlite3_exec \"%s\": %s (%s)\n", __func__, query,
+ sqlite3_errstr(error), s);
+ goto end;
+ }
+ else if (strlen(key) != sizeof dkey * 2)
+ {
+ fprintf(stderr, "%s: unexpected key length: %zu\n", __func__,
+ strlen(key));
+ goto end;
+ }
+ else if (sodium_hex2bin(dkey, sizeof dkey, key, strlen(key), NULL, NULL,
+ NULL))
+ {
+ fprintf(stderr, "%s: sodium_hex2bin failed\n", __func__);
+ goto end;
+ }
+ else if (!(j = cJSON_CreateObject()))
+ {
+ fprintf(stderr, "%s: cJSON_CreateObject failed\n", __func__);
+ goto end;
+ }
+ else if (!cJSON_AddStringToObject(j, "name", user))
+ {
+ fprintf(stderr, "%s: cJSON_AddStringToObject failed\n", __func__);
+ goto end;
+ }
+ else if ((t = time(NULL)) == (time_t)-1)
+ {
+ fprintf(stderr, "%s: time(2): %s\n", __func__, strerror(errno));
+ goto end;
+ }
+ else if (!cJSON_AddNumberToObject(j, "exp", t + 24 * 60 * 60))
+ {
+ fprintf(stderr, "%s: cJSON_AddNumberToObject failed\n", __func__);
+ goto end;
+ }
+ else if (!(jwt = jwt_encode(j, dkey, sizeof dkey)))
+ {
+ fprintf(stderr, "%s: jwt_encode failed\n", __func__);
+ goto end;
+ }
+
+ printf("%s %s\n", user, jwt);
+ ret = 0;
+
+end:
+ free(jwt);
+ free(key);
+ sqlite3_free(s);
+ cJSON_Delete(j);
+ return ret;
+}
+
+static sqlite3 *open_db(const char *const dir)
+{
+ sqlite3 *ret = NULL, *db = NULL;
+ struct dynstr d;
+ int error;
+
+ dynstr_init(&d);
+
+ if (dynstr_append(&d, "%s/nanobbs.db", dir))
+ {
+ fprintf(stderr, "%s: dynstr_append failed\n", __func__);
+ goto end;
+ }
+ else if ((error = sqlite3_open(d.str, &db)) != SQLITE_OK)
+ {
+ fprintf(stderr, "%s: sqlite3_open %s: %s\n", __func__, d.str,
+ sqlite3_errstr(error));
+ goto end;
+ }
+
+ ret = db;
+
+end:
+ dynstr_free(&d);
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_FAILURE, error;
+ sqlite3 *db = NULL;
+
+ if (argc < 3)
+ {
+ fprintf(stderr, "%s <dir> <user> [...]\n", *argv);
+ goto end;
+ }
+ else if (!(db = open_db(argv[1])))
+ goto end;
+
+ for (int i = 2; i < argc; i++)
+ if (process(db, argv[i]))
+ goto end;
+
+ ret = EXIT_SUCCESS;
+
+end:
+
+ if ((error = sqlite3_close(db)) != SQLITE_OK)
+ {
+ fprintf(stderr, "%s: sqlite3_close: %s\n", __func__,
+ sqlite3_errstr(error));
+ ret = EXIT_FAILURE;
+ }
+
+ return ret;
+}