ssb: Move identity info gathering to db.
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Build Tilde Friends / Build-All (push) Successful in 26m52s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Build Tilde Friends / Build-All (push) Successful in 26m52s
				
			This commit is contained in:
		
							
								
								
									
										117
									
								
								src/ssb.db.c
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								src/ssb.db.h
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								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);
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										95
									
								
								src/ssb.js.c
									
									
									
									
									
								
							
							
						
						
									
										95
									
								
								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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user