#define _POSIX_C_SOURCE 200809L #include "jwt.h" #include #include #include #include #include #include #include #include #include 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 [...]\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; }