diff --git a/src/httpd.js.c b/src/httpd.js.c index 2387c8fa..8f5a8d8b 100644 --- a/src/httpd.js.c +++ b/src/httpd.js.c @@ -1360,7 +1360,7 @@ static void _httpd_endpoint_save_work(tf_ssb_t* ssb, void* user_data) user_app_t* user_app = _parse_user_app_from_path(request->path, "/save"); if (user_app) { - if (strcmp(user_string, user_app->user) == 0 || (strcmp(user_app->user, "core") == 0 && tf_ssb_db_user_has_permission(ssb, user_string, "administration"))) + if (strcmp(user_string, user_app->user) == 0 || (strcmp(user_app->user, "core") == 0 && tf_ssb_db_user_has_permission(ssb, NULL, user_string, "administration"))) { size_t path_length = strlen("path:") + strlen(user_app->app) + 1; char* app_path = tf_malloc(path_length); @@ -1516,7 +1516,7 @@ static void _httpd_endpoint_delete_work(tf_ssb_t* ssb, void* user_data) user_app_t* user_app = _parse_user_app_from_path(request->path, "/delete"); if (user_app) { - if (strcmp(user_string, user_app->user) == 0 || (strcmp(user_app->user, "core") == 0 && tf_ssb_db_user_has_permission(ssb, user_string, "administration"))) + if (strcmp(user_string, user_app->user) == 0 || (strcmp(user_app->user, "core") == 0 && tf_ssb_db_user_has_permission(ssb, NULL, user_string, "administration"))) { size_t path_length = strlen("path:") + strlen(user_app->app) + 1; char* app_path = tf_malloc(path_length); diff --git a/src/ssb.db.c b/src/ssb.db.c index dcd49eef..0f670c2a 100644 --- a/src/ssb.db.c +++ b/src/ssb.db.c @@ -2007,12 +2007,12 @@ bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id) return verified; } -bool tf_ssb_db_user_has_permission(tf_ssb_t* ssb, const char* id, const char* permission) +bool tf_ssb_db_user_has_permission(tf_ssb_t* ssb, sqlite3* db, const char* id, const char* permission) { bool has_permission = false; - sqlite3* db = tf_ssb_acquire_db_reader(ssb); + sqlite3* reader = db ? db : tf_ssb_acquire_db_reader(ssb); sqlite3_stmt* statement = NULL; - if (sqlite3_prepare(db, + if (sqlite3_prepare(reader, "SELECT COUNT(*) FROM properties, json_each(properties.value -> 'permissions' -> ?) AS permission WHERE properties.id = 'core' AND properties.key = 'settings' AND " "permission.value = ?", -1, &statement, NULL) == SQLITE_OK) @@ -2024,6 +2024,9 @@ bool tf_ssb_db_user_has_permission(tf_ssb_t* ssb, const char* id, const char* pe } sqlite3_finalize(statement); } - tf_ssb_release_db_reader(ssb, db); + if (reader != db) + { + tf_ssb_release_db_reader(ssb, reader); + } return has_permission; } diff --git a/src/ssb.db.h b/src/ssb.db.h index 6a5c1368..53045bc3 100644 --- a/src/ssb.db.h +++ b/src/ssb.db.h @@ -448,11 +448,12 @@ bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id); /** ** Check if a user has a specific permission. ** @param ssb The SSB instance. +** @param db Optional database instance. If NULL, one will be acquired from ssb. ** @param id The user ID. ** @param permission The name of the permission. ** @return true If the user has the requested permission. */ -bool tf_ssb_db_user_has_permission(tf_ssb_t* ssb, const char* id, const char* permission); +bool tf_ssb_db_user_has_permission(tf_ssb_t* ssb, sqlite3* db, const char* id, const char* permission); /** ** An SQLite authorizer callback. See https://www.sqlite.org/c3ref/set_authorizer.html for use. diff --git a/src/ssb.js.c b/src/ssb.js.c index 425e0cd6..cb00ca5d 100644 --- a/src/ssb.js.c +++ b/src/ssb.js.c @@ -368,9 +368,9 @@ typedef struct _swap_with_server_identity_t static void _tf_ssb_swap_with_server_identity_work(tf_ssb_t* ssb, void* user_data) { swap_with_server_identity_t* work = user_data; - if (tf_ssb_db_user_has_permission(ssb, work->user, "administration")) + sqlite3* db = tf_ssb_acquire_db_writer(ssb); + if (tf_ssb_db_user_has_permission(ssb, db, work->user, "administration")) { - sqlite3* db = tf_ssb_acquire_db_writer(ssb); char* error = NULL; if (sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &error) == SQLITE_OK) { @@ -404,12 +404,12 @@ static void _tf_ssb_swap_with_server_identity_work(tf_ssb_t* ssb, void* user_dat { work->error = error ? tf_strdup(error) : tf_strdup(sqlite3_errmsg(db)); } - tf_ssb_release_db_writer(ssb, db); } else { work->error = tf_strdup("not administrator"); } + tf_ssb_release_db_writer(ssb, db); } static void _tf_ssb_swap_with_server_identity_after_work(tf_ssb_t* ssb, int status, void* user_data) @@ -480,7 +480,7 @@ static void _tf_ssb_getIdentities_visit(const char* identity, void* user_data) static void _tf_ssb_get_identities_work(tf_ssb_t* ssb, void* user_data) { identities_visit_t* work = user_data; - if (tf_ssb_db_user_has_permission(ssb, work->user, "administration")) + if (tf_ssb_db_user_has_permission(ssb, NULL, work->user, "administration")) { char id[k_id_base64_len] = ""; if (tf_ssb_whoami(ssb, id, sizeof(id))) @@ -552,7 +552,7 @@ static void _tf_ssb_get_private_key_work(tf_ssb_t* ssb, void* user_data) { get_private_key_t* work = user_data; work->got_private_key = tf_ssb_db_identity_get_private_key(ssb, work->user, work->id, work->private_key, sizeof(work->private_key)); - if (!work->got_private_key && tf_ssb_db_user_has_permission(ssb, work->user, "administration")) + if (!work->got_private_key && tf_ssb_db_user_has_permission(ssb, NULL, work->user, "administration")) { work->got_private_key = tf_ssb_db_identity_get_private_key(ssb, ":admin", work->id, work->private_key, sizeof(work->private_key)); } @@ -658,7 +658,7 @@ static void _tf_ssb_getActiveIdentity_work(tf_ssb_t* ssb, void* user_data) tf_ssb_db_identity_visit(ssb, request->name, _tf_ssb_getActiveIdentity_visit, request); } - if (!*request->identity && tf_ssb_db_user_has_permission(ssb, request->name, "administration")) + if (!*request->identity && tf_ssb_db_user_has_permission(ssb, NULL, request->name, "administration")) { tf_ssb_whoami(ssb, request->identity, sizeof(request->identity)); } @@ -742,7 +742,7 @@ static void _tf_ssb_getIdentityInfo_work(tf_ssb_t* ssb, void* user_data) { identity_info_work_t* request = user_data; char id[k_id_base64_len] = ""; - if (tf_ssb_db_user_has_permission(ssb, request->name, "administration")) + if (tf_ssb_db_user_has_permission(ssb, NULL, request->name, "administration")) { if (tf_ssb_whoami(ssb, id, sizeof(id))) { @@ -904,7 +904,7 @@ static void _tf_ssb_append_message_with_identity_get_key_work(tf_ssb_t* ssb, voi { append_message_t* work = user_data; work->got_private_key = tf_ssb_db_identity_get_private_key(ssb, work->user, work->id, work->private_key, sizeof(work->private_key)); - if (!work->got_private_key && tf_ssb_db_user_has_permission(ssb, work->user, "administration")) + if (!work->got_private_key && tf_ssb_db_user_has_permission(ssb, NULL, work->user, "administration")) { work->got_private_key = tf_ssb_db_identity_get_private_key(ssb, ":admin", work->id, work->private_key, sizeof(work->private_key)); } @@ -1974,7 +1974,7 @@ enum k_max_private_message_recipients = 8 }; -static bool _tf_ssb_get_private_key_curve25519(sqlite3* db, const char* user, const char* identity, uint8_t out_private_key[static crypto_sign_SECRETKEYBYTES]) +static bool _tf_ssb_get_private_key_curve25519_internal(sqlite3* db, const char* user, const char* identity, uint8_t out_private_key[static crypto_sign_SECRETKEYBYTES]) { if (!user || !identity) { @@ -2003,6 +2003,21 @@ static bool _tf_ssb_get_private_key_curve25519(sqlite3* db, const char* user, co return success; } +static bool _tf_ssb_get_private_key_curve25519(tf_ssb_t* ssb, sqlite3* db, const char* user, const char* identity, uint8_t out_private_key[static crypto_sign_SECRETKEYBYTES]) +{ + if (_tf_ssb_get_private_key_curve25519_internal(db, user, identity, out_private_key)) + { + return true; + } + + if (tf_ssb_db_user_has_permission(ssb, db, user, "administration")) + { + return _tf_ssb_get_private_key_curve25519_internal(db, ":admin", identity, out_private_key); + } + + return false; +} + typedef struct _private_message_encrypt_t { const char* signer_user; @@ -2025,7 +2040,7 @@ static void _tf_ssb_private_message_encrypt_work(tf_ssb_t* ssb, void* user_data) uint8_t private_key[crypto_sign_SECRETKEYBYTES] = { 0 }; sqlite3* db = tf_ssb_acquire_db_reader(ssb); - bool found = _tf_ssb_get_private_key_curve25519(db, work->signer_user, work->signer_identity, private_key); + bool found = _tf_ssb_get_private_key_curve25519(ssb, db, work->signer_user, work->signer_identity, private_key); tf_ssb_release_db_reader(ssb, db); if (found) @@ -2214,7 +2229,7 @@ static void _tf_ssb_private_message_decrypt_work(tf_ssb_t* ssb, void* user_data) uint8_t private_key[crypto_sign_SECRETKEYBYTES] = { 0 }; sqlite3* db = tf_ssb_acquire_db_reader(ssb); - bool found = _tf_ssb_get_private_key_curve25519(db, work->user, work->identity, private_key); + bool found = _tf_ssb_get_private_key_curve25519(ssb, db, work->user, work->identity, private_key); tf_ssb_release_db_reader(ssb, db); if (found)