forked from cory/tildefriends
		
	Fix numerous issues around setting the first registered used as an admin.
This commit is contained in:
		
							
								
								
									
										159
									
								
								src/httpd.js.c
									
									
									
									
									
								
							
							
						
						
									
										159
									
								
								src/httpd.js.c
									
									
									
									
									
								
							@@ -1213,6 +1213,94 @@ static bool _verify_password(const char* password, const char* hash)
 | 
			
		||||
	return out_hash && strcmp(hash, out_hash) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char* _get_code_of_conduct(tf_ssb_t* ssb)
 | 
			
		||||
{
 | 
			
		||||
	JSContext* context = tf_ssb_get_context(ssb);
 | 
			
		||||
	const char* settings = tf_ssb_db_get_property(ssb, "core", "settings");
 | 
			
		||||
	JSValue settings_value = settings ? JS_ParseJSON(context, settings, strlen(settings), NULL) : JS_UNDEFINED;
 | 
			
		||||
	JSValue code_of_conduct_value = JS_GetPropertyStr(context, settings_value, "code_of_conduct");
 | 
			
		||||
	const char* code_of_conduct = JS_ToCString(context, code_of_conduct_value);
 | 
			
		||||
	const char* result = tf_strdup(code_of_conduct);
 | 
			
		||||
	JS_FreeCString(context, code_of_conduct);
 | 
			
		||||
	JS_FreeValue(context, code_of_conduct_value);
 | 
			
		||||
	JS_FreeValue(context, settings_value);
 | 
			
		||||
	tf_free((void*)settings);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _make_administrator_if_first(tf_ssb_t* ssb, const char* account_name_copy, bool may_become_first_admin)
 | 
			
		||||
{
 | 
			
		||||
	JSContext* context = tf_ssb_get_context(ssb);
 | 
			
		||||
	const char* settings = tf_ssb_db_get_property(ssb, "core", "settings");
 | 
			
		||||
	JSValue settings_value = settings ? JS_ParseJSON(context, settings, strlen(settings), NULL) : JS_UNDEFINED;
 | 
			
		||||
	if (JS_IsUndefined(settings_value))
 | 
			
		||||
	{
 | 
			
		||||
		settings_value = JS_NewObject(context);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool have_administrator = false;
 | 
			
		||||
	JSValue permissions = JS_GetPropertyStr(context, settings_value, "permissions");
 | 
			
		||||
 | 
			
		||||
	JSPropertyEnum* ptab = NULL;
 | 
			
		||||
	uint32_t plen = 0;
 | 
			
		||||
	JS_GetOwnPropertyNames(context, &ptab, &plen, permissions, JS_GPN_STRING_MASK);
 | 
			
		||||
	for (int i = 0; i < (int)plen; i++)
 | 
			
		||||
	{
 | 
			
		||||
		JSPropertyDescriptor desc = { 0 };
 | 
			
		||||
		if (JS_GetOwnProperty(context, &desc, permissions, ptab[i].atom) == 1)
 | 
			
		||||
		{
 | 
			
		||||
			int permission_length = tf_util_get_length(context, desc.value);
 | 
			
		||||
			for (int i = 0; i < permission_length; i++)
 | 
			
		||||
			{
 | 
			
		||||
				JSValue entry = JS_GetPropertyUint32(context, desc.value, i);
 | 
			
		||||
				const char* permission = JS_ToCString(context, entry);
 | 
			
		||||
				if (permission && strcmp(permission, "administration") == 0)
 | 
			
		||||
				{
 | 
			
		||||
					have_administrator = true;
 | 
			
		||||
				}
 | 
			
		||||
				JS_FreeCString(context, permission);
 | 
			
		||||
				JS_FreeValue(context, entry);
 | 
			
		||||
			}
 | 
			
		||||
			JS_FreeValue(context, desc.setter);
 | 
			
		||||
			JS_FreeValue(context, desc.getter);
 | 
			
		||||
			JS_FreeValue(context, desc.value);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for (uint32_t i = 0; i < plen; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		JS_FreeAtom(context, ptab[i].atom);
 | 
			
		||||
	}
 | 
			
		||||
	js_free(context, ptab);
 | 
			
		||||
 | 
			
		||||
	if (!have_administrator && may_become_first_admin)
 | 
			
		||||
	{
 | 
			
		||||
		if (JS_IsUndefined(permissions))
 | 
			
		||||
		{
 | 
			
		||||
			permissions = JS_NewObject(context);
 | 
			
		||||
			JS_SetPropertyStr(context, settings_value, "permissions", JS_DupValue(context, permissions));
 | 
			
		||||
		}
 | 
			
		||||
		JSValue user = JS_GetPropertyStr(context, permissions, account_name_copy);
 | 
			
		||||
		if (JS_IsUndefined(user))
 | 
			
		||||
		{
 | 
			
		||||
			user = JS_NewArray(context);
 | 
			
		||||
			JS_SetPropertyStr(context, permissions, account_name_copy, JS_DupValue(context, user));
 | 
			
		||||
		}
 | 
			
		||||
		JS_SetPropertyUint32(context, user, tf_util_get_length(context, user), JS_NewString(context, "administration"));
 | 
			
		||||
		JS_FreeValue(context, user);
 | 
			
		||||
 | 
			
		||||
		JSValue settings_json = JS_JSONStringify(context, settings_value, JS_NULL, JS_NULL);
 | 
			
		||||
		const char* settings_string = JS_ToCString(context, settings_json);
 | 
			
		||||
		tf_ssb_db_set_property(ssb, "core", "settings", settings_string);
 | 
			
		||||
		JS_FreeCString(context, settings_string);
 | 
			
		||||
		JS_FreeValue(context, settings_json);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	JS_FreeValue(context, permissions);
 | 
			
		||||
	JS_FreeValue(context, settings_value);
 | 
			
		||||
	tf_free((void*)settings);
 | 
			
		||||
	return have_administrator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _httpd_endpoint_login(tf_http_request_t* request)
 | 
			
		||||
{
 | 
			
		||||
	tf_task_t* task = request->user_data;
 | 
			
		||||
@@ -1310,6 +1398,8 @@ static void _httpd_endpoint_login(tf_http_request_t* request)
 | 
			
		||||
		tf_free(post_form_data);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool have_administrator = _make_administrator_if_first(ssb, account_name_copy, may_become_first_admin);
 | 
			
		||||
 | 
			
		||||
	if (session_is_new && _form_data_get(form_data, "return") && !login_error)
 | 
			
		||||
	{
 | 
			
		||||
		const char* return_url = _form_data_get(form_data, "return");
 | 
			
		||||
@@ -1334,69 +1424,8 @@ static void _httpd_endpoint_login(tf_http_request_t* request)
 | 
			
		||||
	{
 | 
			
		||||
		tf_http_request_ref(request);
 | 
			
		||||
 | 
			
		||||
		const char* settings = tf_ssb_db_get_property(ssb, "core", "settings");
 | 
			
		||||
		JSValue settings_value = settings ? JS_ParseJSON(context, settings, strlen(settings), NULL) : JS_UNDEFINED;
 | 
			
		||||
		JSValue code_of_conduct_value = JS_GetPropertyStr(context, settings_value, "code_of_conduct");
 | 
			
		||||
		const char* code_of_conduct = JS_ToCString(context, code_of_conduct_value);
 | 
			
		||||
 | 
			
		||||
		bool have_administrator = false;
 | 
			
		||||
		JSValue permissions = JS_GetPropertyStr(context, settings_value, "permissions");
 | 
			
		||||
 | 
			
		||||
		JSPropertyEnum* ptab = NULL;
 | 
			
		||||
		uint32_t plen = 0;
 | 
			
		||||
		JS_GetOwnPropertyNames(context, &ptab, &plen, permissions, JS_GPN_STRING_MASK);
 | 
			
		||||
		for (int i = 0; i < (int)plen; i++)
 | 
			
		||||
		{
 | 
			
		||||
			JSPropertyDescriptor desc = { 0 };
 | 
			
		||||
			if (JS_GetOwnProperty(context, &desc, permissions, ptab[i].atom) == 1)
 | 
			
		||||
			{
 | 
			
		||||
				int permission_length = tf_util_get_length(context, desc.value);
 | 
			
		||||
				for (int i = 0; i < permission_length; i++)
 | 
			
		||||
				{
 | 
			
		||||
					JSValue entry = JS_GetPropertyUint32(context, desc.value, i);
 | 
			
		||||
					const char* permission = JS_ToCString(context, entry);
 | 
			
		||||
					if (permission && strcmp(permission, "administration") == 0)
 | 
			
		||||
					{
 | 
			
		||||
						have_administrator = true;
 | 
			
		||||
					}
 | 
			
		||||
					JS_FreeCString(context, permission);
 | 
			
		||||
					JS_FreeValue(context, entry);
 | 
			
		||||
				}
 | 
			
		||||
				JS_FreeValue(context, desc.setter);
 | 
			
		||||
				JS_FreeValue(context, desc.getter);
 | 
			
		||||
				JS_FreeValue(context, desc.value);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for (uint32_t i = 0; i < plen; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			JS_FreeAtom(context, ptab[i].atom);
 | 
			
		||||
		}
 | 
			
		||||
		js_free(context, ptab);
 | 
			
		||||
 | 
			
		||||
		if (!have_administrator && may_become_first_admin)
 | 
			
		||||
		{
 | 
			
		||||
			if (JS_IsUndefined(permissions))
 | 
			
		||||
			{
 | 
			
		||||
				permissions = JS_NewObject(context);
 | 
			
		||||
				JS_SetPropertyStr(context, settings_value, "permissions", permissions);
 | 
			
		||||
			}
 | 
			
		||||
			JSValue user = JS_GetPropertyStr(context, permissions, account_name_copy);
 | 
			
		||||
			if (JS_IsUndefined(user))
 | 
			
		||||
			{
 | 
			
		||||
				user = JS_NewArray(context);
 | 
			
		||||
				JS_SetPropertyStr(context, permissions, account_name_copy, user);
 | 
			
		||||
			}
 | 
			
		||||
			JS_SetPropertyUint32(context, user, tf_util_get_length(context, user), JS_NewString(context, "administration"));
 | 
			
		||||
 | 
			
		||||
			JSValue settings_json = JS_JSONStringify(context, settings_value, JS_NULL, JS_NULL);
 | 
			
		||||
			const char* settings_string = JS_ToCString(context, settings_json);
 | 
			
		||||
			tf_ssb_db_set_property(ssb, "core", "settings", settings_string);
 | 
			
		||||
			JS_FreeCString(context, settings_string);
 | 
			
		||||
			JS_FreeValue(context, settings_json);
 | 
			
		||||
		}
 | 
			
		||||
		JS_FreeValue(context, permissions);
 | 
			
		||||
 | 
			
		||||
		login_request_t* login = tf_malloc(sizeof(login_request_t));
 | 
			
		||||
		const char* code_of_conduct = _get_code_of_conduct(ssb);
 | 
			
		||||
		*login = (login_request_t) {
 | 
			
		||||
			.request = request,
 | 
			
		||||
			.name = account_name_copy,
 | 
			
		||||
@@ -1404,14 +1433,10 @@ static void _httpd_endpoint_login(tf_http_request_t* request)
 | 
			
		||||
			.error = login_error,
 | 
			
		||||
			.session_cookie = send_session,
 | 
			
		||||
			.session_is_new = session_is_new,
 | 
			
		||||
			.code_of_conduct = tf_strdup(code_of_conduct),
 | 
			
		||||
			.code_of_conduct = code_of_conduct,
 | 
			
		||||
			.have_administrator = have_administrator,
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		JS_FreeCString(context, code_of_conduct);
 | 
			
		||||
		JS_FreeValue(context, code_of_conduct_value);
 | 
			
		||||
		JS_FreeValue(context, settings_value);
 | 
			
		||||
		tf_free((void*)settings);
 | 
			
		||||
		tf_file_read(request->user_data, "core/auth.html", _httpd_endpoint_login_file_read_callback, login);
 | 
			
		||||
		jwt = JS_UNDEFINED;
 | 
			
		||||
		account_name_copy = NULL;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user