From 0f573ce09eece9e61ed1b9e85a5712f24f205c3b Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Sat, 1 Mar 2025 20:44:52 -0500 Subject: [PATCH] ssb: Move identity info gathering to db. --- src/ssb.db.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/ssb.db.h | 25 +++++++++++ src/ssb.js.c | 95 ++++------------------------------------- 3 files changed, 150 insertions(+), 87 deletions(-) diff --git a/src/ssb.db.c b/src/ssb.db.c index 0f619b18..9943c139 100644 --- a/src/ssb.db.c +++ b/src/ssb.db.c @@ -2331,3 +2331,120 @@ bool tf_ssb_db_has_invite(sqlite3* db, const char* id) } return has; } + +static void _tf_ssb_db_get_identity_info_visit(const char* identity, void* user_data) +{ + tf_ssb_identity_info_t* info = user_data; + info->identity = tf_resize_vec(info->identity, (info->count + 1) * sizeof(char*)); + info->name = tf_resize_vec(info->name, (info->count + 1) * sizeof(char*)); + char buffer[k_id_base64_len]; + snprintf(buffer, sizeof(buffer), "@%s", identity); + info->identity[info->count] = tf_strdup(buffer); + info->name[info->count] = NULL; + info->count++; +} + +tf_ssb_identity_info_t* tf_ssb_db_get_identity_info(tf_ssb_t* ssb, const char* user, const char* package_owner, const char* package_name) +{ + tf_ssb_identity_info_t* info = tf_malloc(sizeof(tf_ssb_identity_info_t)); + *info = (tf_ssb_identity_info_t) { 0 }; + + char id[k_id_base64_len] = ""; + if (tf_ssb_db_user_has_permission(ssb, NULL, user, "administration")) + { + if (tf_ssb_whoami(ssb, id, sizeof(id))) + { + _tf_ssb_db_get_identity_info_visit(*id == '@' ? id + 1 : id, info); + } + } + tf_ssb_db_identity_visit(ssb, user, _tf_ssb_db_get_identity_info_visit, info); + + sqlite3* db = tf_ssb_acquire_db_reader(ssb); + sqlite3_stmt* statement = NULL; + int result = sqlite3_prepare(db, + "SELECT author, name FROM ( " + " SELECT " + " messages.author, " + " RANK() OVER (PARTITION BY messages.author ORDER BY messages.sequence DESC) AS author_rank, " + " messages.content ->> 'name' AS name " + " FROM messages " + " JOIN identities ON messages.author = ('@' || identities.public_key) " + " WHERE " + " (identities.user = ? OR identities.public_key = ?) AND " + " json_extract(messages.content, '$.type') = 'about' AND " + " content ->> 'about' = messages.author AND name IS NOT NULL) " + "WHERE author_rank = 1 ", + -1, &statement, NULL); + if (result == SQLITE_OK) + { + if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, *id == '@' ? id + 1 : id, -1, NULL) == SQLITE_OK) + { + int r = SQLITE_OK; + while ((r = sqlite3_step(statement)) == SQLITE_ROW) + { + const char* identity = (const char*)sqlite3_column_text(statement, 0); + const char* name = (const char*)sqlite3_column_text(statement, 1); + for (int i = 0; i < info->count; i++) + { + if (!info->name[i] && strcmp(info->identity[i], identity) == 0) + { + info->name[i] = tf_strdup(name); + break; + } + } + } + } + sqlite3_finalize(statement); + } + else + { + tf_printf("prepare failed: %s.\n", sqlite3_errmsg(db)); + } + + tf_ssb_db_identity_get_active(db, user, package_owner, package_name, info->active_identity, sizeof(info->active_identity)); + if (!*info->active_identity && info->count) + { + snprintf(info->active_identity, sizeof(info->active_identity), "%s", info->identity[0]); + } + tf_ssb_release_db_reader(ssb, db); + + size_t size = sizeof(tf_ssb_identity_info_t) + sizeof(char*) * info->count * 2; + for (int i = 0; i < info->count; i++) + { + size += strlen(info->identity[i]) + 1; + size += info->name[i] ? strlen(info->name[i]) + 1 : 0; + } + tf_ssb_identity_info_t* copy = tf_malloc(size); + *copy = *info; + + copy->identity = (const char**)(copy + 1); + copy->name = (const char**)(copy + 1) + copy->count; + + char* p = (char*)((const char**)(copy + 1) + copy->count * 2); + + for (int i = 0; i < info->count; i++) + { + size_t length = strlen(info->identity[i]); + memcpy(p, info->identity[i], length + 1); + copy->identity[i] = p; + p += length + 1; + tf_free((void*)info->identity[i]); + + if (info->name[i]) + { + length = strlen(info->name[i]); + memcpy(p, info->name[i], length + 1); + copy->name[i] = p; + p += length + 1; + tf_free((void*)info->name[i]); + } + else + { + copy->name[i] = NULL; + } + } + tf_free(info->name); + tf_free(info->identity); + tf_free(info); + return copy; +} diff --git a/src/ssb.db.h b/src/ssb.db.h index ba5fdc11..26546b32 100644 --- a/src/ssb.db.h +++ b/src/ssb.db.h @@ -564,4 +564,29 @@ int tf_ssb_sqlite_authorizer(void* user_data, int action_code, const char* arg0, */ bool tf_ssb_db_has_invite(sqlite3* db, const char* id); +/** +** Identity information +*/ +typedef struct _tf_ssb_identity_info_t +{ + /** An array of identities. */ + const char** identity; + /** A array of identities, one for each identity. */ + const char** name; + /** The number of elements in both the identity and name arrays. */ + int count; + /** The active identity. */ + char active_identity[k_id_base64_len]; +} tf_ssb_identity_info_t; + +/** +** Get available identities, names, and the active identity for a user. +** @param ssb The SSB instance. +** @param user The user name. +** @param package_owner The owner of the package for which identity info is being fetched. +** @param package_name The name of the package for which identity info is being fetched. +** @return A struct of identities, names, and the active identity. Free with tf_free(). +*/ +tf_ssb_identity_info_t* tf_ssb_db_get_identity_info(tf_ssb_t* ssb, const char* user, const char* package_owner, const char* package_name); + /** @} */ diff --git a/src/ssb.js.c b/src/ssb.js.c index e71e4219..dfcf8bb3 100644 --- a/src/ssb.js.c +++ b/src/ssb.js.c @@ -613,87 +613,14 @@ typedef struct _identity_info_work_t const char* name; const char* package_owner; const char* package_name; - int count; - char** identities; - char** names; - int result; - char active_identity[k_id_base64_len]; + tf_ssb_identity_info_t* info; JSValue promise[2]; } identity_info_work_t; -static void _tf_ssb_getIdentityInfo_visit(const char* identity, void* data) -{ - identity_info_work_t* request = data; - request->identities = tf_resize_vec(request->identities, (request->count + 1) * sizeof(char*)); - request->names = tf_resize_vec(request->names, (request->count + 1) * sizeof(char*)); - char buffer[k_id_base64_len]; - snprintf(buffer, sizeof(buffer), "@%s", identity); - request->identities[request->count] = tf_strdup(buffer); - request->names[request->count] = NULL; - request->count++; -} - 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, NULL, request->name, "administration")) - { - if (tf_ssb_whoami(ssb, id, sizeof(id))) - { - _tf_ssb_getIdentityInfo_visit(*id == '@' ? id + 1 : id, request); - } - } - tf_ssb_db_identity_visit(ssb, request->name, _tf_ssb_getIdentityInfo_visit, request); - - sqlite3* db = tf_ssb_acquire_db_reader(ssb); - sqlite3_stmt* statement = NULL; - request->result = sqlite3_prepare(db, - "SELECT author, name FROM ( " - " SELECT " - " messages.author, " - " RANK() OVER (PARTITION BY messages.author ORDER BY messages.sequence DESC) AS author_rank, " - " messages.content ->> 'name' AS name " - " FROM messages " - " JOIN identities ON messages.author = ('@' || identities.public_key) " - " WHERE " - " (identities.user = ? OR identities.public_key = ?) AND " - " json_extract(messages.content, '$.type') = 'about' AND " - " content ->> 'about' = messages.author AND name IS NOT NULL) " - "WHERE author_rank = 1 ", - -1, &statement, NULL); - if (request->result == SQLITE_OK) - { - if (sqlite3_bind_text(statement, 1, request->name, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, *id == '@' ? id + 1 : id, -1, NULL) == SQLITE_OK) - { - int r = SQLITE_OK; - while ((r = sqlite3_step(statement)) == SQLITE_ROW) - { - const char* identity = (const char*)sqlite3_column_text(statement, 0); - const char* name = (const char*)sqlite3_column_text(statement, 1); - for (int i = 0; i < request->count; i++) - { - if (!request->names[i] && strcmp(request->identities[i], identity) == 0) - { - request->names[i] = tf_strdup(name); - break; - } - } - } - } - sqlite3_finalize(statement); - } - else - { - tf_printf("prepare failed: %s.\n", sqlite3_errmsg(db)); - } - - tf_ssb_db_identity_get_active(db, request->name, request->package_owner, request->package_name, request->active_identity, sizeof(request->active_identity)); - if (!*request->active_identity && request->count) - { - snprintf(request->active_identity, sizeof(request->active_identity), "%s", request->identities[0]); - } - tf_ssb_release_db_reader(ssb, db); + request->info = tf_ssb_db_get_identity_info(ssb, request->name, request->package_owner, request->package_name); } static void _tf_ssb_getIdentityInfo_after_work(tf_ssb_t* ssb, int status, void* user_data) @@ -703,20 +630,20 @@ static void _tf_ssb_getIdentityInfo_after_work(tf_ssb_t* ssb, int status, void* JSValue result = JS_NewObject(context); JSValue identities = JS_NewArray(context); - for (int i = 0; i < request->count; i++) + for (int i = 0; i < request->info->count; i++) { - JS_SetPropertyUint32(context, identities, i, JS_NewString(context, request->identities[i])); + JS_SetPropertyUint32(context, identities, i, JS_NewString(context, request->info->identity[i])); } JS_SetPropertyStr(context, result, "identities", identities); JSValue names = JS_NewObject(context); - for (int i = 0; i < request->count; i++) + for (int i = 0; i < request->info->count; i++) { - JS_SetPropertyStr(context, names, request->identities[i], JS_NewString(context, request->names[i] ? request->names[i] : request->identities[i])); + JS_SetPropertyStr(context, names, request->info->identity[i], JS_NewString(context, request->info->name[i] ? request->info->name[i] : request->info->identity[i])); } JS_SetPropertyStr(context, result, "names", names); - JS_SetPropertyStr(context, result, "identity", JS_NewString(context, request->active_identity)); + JS_SetPropertyStr(context, result, "identity", JS_NewString(context, request->info->active_identity)); JSValue error = JS_Call(context, request->promise[0], JS_UNDEFINED, 1, &result); tf_util_report_error(context, error); @@ -725,16 +652,10 @@ static void _tf_ssb_getIdentityInfo_after_work(tf_ssb_t* ssb, int status, void* JS_FreeValue(context, request->promise[0]); JS_FreeValue(context, request->promise[1]); - for (int i = 0; i < request->count; i++) - { - tf_free(request->identities[i]); - tf_free(request->names[i]); - } - tf_free(request->identities); - tf_free(request->names); tf_free((void*)request->name); tf_free((void*)request->package_owner); tf_free((void*)request->package_name); + tf_free(request->info); tf_free(request); }