getIdentityInfo => C.

This commit is contained in:
Cory McWilliams 2024-05-05 13:48:22 -04:00
parent a28f6985ed
commit 421955f2a0
5 changed files with 179 additions and 48 deletions

View File

@ -149,7 +149,7 @@ function socket(request, response, client) {
parentApp: parentApp, parentApp: parentApp,
id: blobId, id: blobId,
}, },
await core.getIdentityInfo( await ssb.getIdentityInfo(
credentials?.session?.name, credentials?.session?.name,
packageOwner, packageOwner,
packageName packageName

View File

@ -545,7 +545,7 @@ async function getProcessBlob(blobId, key, options) {
{ {
action: 'identities', action: 'identities',
}, },
await getIdentityInfo( await ssb.getIdentityInfo(
process?.credentials?.session?.name, process?.credentials?.session?.name,
options?.packageOwner, options?.packageOwner,
options?.packageName options?.packageName
@ -785,6 +785,7 @@ async function getProcessBlob(blobId, key, options) {
); );
} }
}; };
imports.ssb.getIdentityInfo = undefined;
imports.fetch = function (url, options) { imports.fetch = function (url, options) {
return http.fetch(url, options, gGlobalSettings.fetch_hosts); return http.fetch(url, options, gGlobalSettings.fetch_hosts);
}; };
@ -1553,43 +1554,10 @@ function storePermission(user, packageOwner, packageName, permission, allow) {
} }
} }
async function getIdentityInfo(user, packageOwner, packageName) {
let identities = await ssb.getIdentities(user);
let names = new Object();
for (let identity of identities) {
names[identity] = identity;
}
await ssb.sqlAsync(
`
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 json_each(?) AS ids
ON messages.author = ids.value
WHERE json_extract(messages.content, '$.type') = 'about' AND content ->> 'about' = messages.author AND name IS NOT NULL)
WHERE author_rank = 1
`,
[JSON.stringify(identities)],
function (row) {
names[row.author] = row.name;
}
);
return {
identities: identities,
identity: await ssb.getActiveIdentity(user, packageOwner, packageName),
names: names,
};
}
export { export {
gGlobalSettings as globalSettings, gGlobalSettings as globalSettings,
setGlobalSettings, setGlobalSettings,
enableStats, enableStats,
invoke, invoke,
getSessionProcessBlob, getSessionProcessBlob,
getIdentityInfo,
}; };

View File

@ -1735,3 +1735,22 @@ bool tf_ssb_db_set_property(tf_ssb_t* ssb, const char* id, const char* key, cons
tf_ssb_release_db_writer(ssb, db); tf_ssb_release_db_writer(ssb, db);
return result; return result;
} }
bool tf_ssb_db_identity_get_active(sqlite3* db, const char* user, const char* package_owner, const char* package_name, char* out_identity, size_t out_identity_size)
{
sqlite3_stmt* statement = NULL;
bool found = false;
if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = ? AND key = 'id:' || ? || ':' || ?", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK &&
sqlite3_bind_text(statement, 2, package_owner, -1, NULL) == SQLITE_OK &&
sqlite3_bind_text(statement, 3, package_name, -1, NULL) == SQLITE_OK &&
sqlite3_step(statement) == SQLITE_ROW)
{
snprintf(out_identity, out_identity_size, "%s", (const char*)sqlite3_column_text(statement, 0));
found = true;
}
sqlite3_finalize(statement);
}
return found;
}

View File

@ -195,6 +195,18 @@ bool tf_ssb_db_identity_delete(tf_ssb_t* ssb, const char* user, const char* publ
*/ */
bool tf_ssb_db_identity_add(tf_ssb_t* ssb, const char* user, const char* public_key, const char* private_key); bool tf_ssb_db_identity_add(tf_ssb_t* ssb, const char* user, const char* public_key, const char* private_key);
/**
** Get the active identity for a user for a given package.
** @param db An sqlite3 database.
** @param user The username.
** @param package_owner The username of the package owner.
** @param package_name The name of the package.
** @param[out] out_identity Populated with the identity.
** @param out_identity_size The size of the out_identity buffer.
** @return true If the identity was retrieved.
*/
bool tf_ssb_db_identity_get_active(sqlite3* db, const char* user, const char* package_owner, const char* package_name, char* out_identity, size_t out_identity_size);
/** /**
** Call a function for each identity owned by a user. ** Call a function for each identity owned by a user.
** @param ssb The SSB instance. ** @param ssb The SSB instance.

View File

@ -330,19 +330,7 @@ static void _tf_ssb_getActiveIdentity_work(uv_work_t* work)
tf_trace_begin(trace, "_tf_ssb_getActiveIdentity_work"); tf_trace_begin(trace, "_tf_ssb_getActiveIdentity_work");
sqlite3* db = tf_ssb_acquire_db_reader(request->ssb); sqlite3* db = tf_ssb_acquire_db_reader(request->ssb);
sqlite3_stmt* statement = NULL; tf_ssb_db_identity_get_active(db, request->name, request->package_owner, request->package_name, request->identity, sizeof(request->identity));
request->result = sqlite3_prepare(db, "SELECT value FROM properties WHERE id = ? AND key = 'id:' || ? || ':' || ?", -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, request->package_owner, -1, NULL) == SQLITE_OK &&
sqlite3_bind_text(statement, 3, request->package_name, -1, NULL) == SQLITE_OK &&
sqlite3_step(statement) == SQLITE_ROW)
{
snprintf(request->identity, sizeof(request->identity), "%s", (const char*)sqlite3_column_text(statement, 0));
}
sqlite3_finalize(statement);
}
tf_ssb_release_db_reader(request->ssb, db); tf_ssb_release_db_reader(request->ssb, db);
if (!*request->identity) if (!*request->identity)
@ -408,6 +396,149 @@ static JSValue _tf_ssb_getActiveIdentity(JSContext* context, JSValueConst this_v
return result; return result;
} }
typedef struct _identity_info_work_t
{
uv_work_t request;
tf_ssb_t* ssb;
JSContext* context;
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];
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*));
request->identities[request->count] = tf_strdup(identity);
request->names[request->count] = NULL;
request->count++;;
}
static void _tf_ssb_getIdentityInfo_work(uv_work_t* work)
{
identity_info_work_t* request = work->data;
tf_ssb_db_identity_visit(request->ssb, request->name, _tf_ssb_getIdentityInfo_visit, request);
sqlite3* db = tf_ssb_acquire_db_reader(request->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 = ids.value "
" WHERE WHERE identities.user = ? 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)
{
int r = SQLITE_OK;
while ((r = sqlite3_step(statement)) == SQLITE_OK)
{
for (int i = 0; i < request->count; i++)
{
const char* identity = (const char*)sqlite3_column_text(statement, 0);
const char* name = (const char*)sqlite3_column_text(statement, 1);
if (strcmp(request->identities[i], identity) == 0 && !request->names[i])
{
request->names[i] = tf_strdup(name);
}
break;
}
}
}
sqlite3_finalize(statement);
}
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(request->ssb, db);
}
static void _tf_ssb_getIdentityInfo_after_work(uv_work_t* work, int status)
{
identity_info_work_t* request = work->data;
JSContext* context = request->context;
JSValue result = JS_NewObject(context);
JSValue identities = JS_NewArray(context);
for (int i = 0; i < request->count; i++)
{
JS_SetPropertyUint32(context, identities, i, JS_NewString(context, request->identities[i]));
}
JS_SetPropertyStr(context, result, "identities", identities);
JSValue names = JS_NewObject(context);
for (int i = 0; i < request->count; i++)
{
JS_SetPropertyStr(context, names, request->identities[i], JS_NewString(context, request->names[i] ? request->names[i] : request->identities[i]));
}
JS_SetPropertyStr(context, result, "names", names);
JS_SetPropertyStr(context, result, "identity", JS_NewString(context, request->active_identity));
JSValue error = JS_Call(context, request->promise[0], JS_UNDEFINED, 1, &result);
tf_util_report_error(context, error);
JS_FreeValue(context, error);
JS_FreeValue(context, result);
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);
}
static JSValue _tf_ssb_getIdentityInfo(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
const char* name = JS_ToCString(context, argv[0]);
const char* package_owner = JS_ToCString(context, argv[1]);
const char* package_name = JS_ToCString(context, argv[2]);
identity_info_work_t* work = tf_malloc(sizeof(identity_info_work_t));
*work = (identity_info_work_t)
{
.request = { .data = work },
.ssb = JS_GetOpaque(this_val, _tf_ssb_classId),
.context = context,
.name = tf_strdup(name),
.package_owner = tf_strdup(package_owner),
.package_name = tf_strdup(package_name),
};
JSValue result = JS_NewPromiseCapability(context, work->promise);
JS_FreeCString(context, name);
JS_FreeCString(context, package_owner);
JS_FreeCString(context, package_name);
int r = uv_queue_work(tf_ssb_get_loop(work->ssb), &work->request, _tf_ssb_getIdentityInfo_work, _tf_ssb_getIdentityInfo_after_work);
if (r)
{
_tf_ssb_getIdentityInfo_after_work(&work->request, r);
}
return result;
}
typedef struct _append_message_t typedef struct _append_message_t
{ {
JSContext* context; JSContext* context;
@ -1812,6 +1943,7 @@ void tf_ssb_register(JSContext* context, tf_ssb_t* ssb)
JS_SetPropertyStr(context, object, "getServerIdentity", JS_NewCFunction(context, _tf_ssb_getServerIdentity, "getServerIdentity", 0)); JS_SetPropertyStr(context, object, "getServerIdentity", JS_NewCFunction(context, _tf_ssb_getServerIdentity, "getServerIdentity", 0));
JS_SetPropertyStr(context, object, "getAllIdentities", JS_NewCFunction(context, _tf_ssb_getAllIdentities, "getAllIdentities", 0)); JS_SetPropertyStr(context, object, "getAllIdentities", JS_NewCFunction(context, _tf_ssb_getAllIdentities, "getAllIdentities", 0));
JS_SetPropertyStr(context, object, "getActiveIdentity", JS_NewCFunction(context, _tf_ssb_getActiveIdentity, "getActiveIdentity", 3)); JS_SetPropertyStr(context, object, "getActiveIdentity", JS_NewCFunction(context, _tf_ssb_getActiveIdentity, "getActiveIdentity", 3));
JS_SetPropertyStr(context, object, "getIdentityInfo", JS_NewCFunction(context, _tf_ssb_getIdentityInfo, "getIdentityInfo", 3));
JS_SetPropertyStr(context, object, "getMessage", JS_NewCFunction(context, _tf_ssb_getMessage, "getMessage", 2)); JS_SetPropertyStr(context, object, "getMessage", JS_NewCFunction(context, _tf_ssb_getMessage, "getMessage", 2));
JS_SetPropertyStr(context, object, "blobGet", JS_NewCFunction(context, _tf_ssb_blobGet, "blobGet", 1)); JS_SetPropertyStr(context, object, "blobGet", JS_NewCFunction(context, _tf_ssb_blobGet, "blobGet", 1));
JS_SetPropertyStr(context, object, "messageContentGet", JS_NewCFunction(context, _tf_ssb_messageContentGet, "messageContentGet", 1)); JS_SetPropertyStr(context, object, "messageContentGet", JS_NewCFunction(context, _tf_ssb_messageContentGet, "messageContentGet", 1));