Get the code of conduct and JWT signing key without hitting the database from the main thread.

This commit is contained in:
Cory McWilliams 2024-06-10 16:37:12 -04:00
parent c259defab5
commit 3fff706848
2 changed files with 36 additions and 43 deletions

View File

@ -1066,6 +1066,7 @@ typedef struct _login_request_t
JSValue jwt;
const char* name;
const char* error;
const char* settings;
const char* code_of_conduct;
bool have_administrator;
bool session_is_new;
@ -1260,25 +1261,6 @@ static bool _is_name_valid(const char* name)
return true;
}
static void _visit_auth_identity(const char* identity, void* user_data)
{
if (!*(char*)user_data)
{
snprintf((char*)user_data, k_id_base64_len, "%s", identity);
}
}
static bool _get_auth_private_key(tf_ssb_t* ssb, uint8_t* out_private_key)
{
char id[k_id_base64_len] = { 0 };
tf_ssb_db_identity_visit(ssb, ":admin", _visit_auth_identity, id);
if (*id)
{
return tf_ssb_db_identity_get_private_key(ssb, ":admin", id, out_private_key, crypto_sign_SECRETKEYBYTES);
}
return false;
}
static const char* _make_session_jwt(tf_ssb_t* ssb, const char* name)
{
if (!name || !*name)
@ -1309,17 +1291,16 @@ static const char* _make_session_jwt(tf_ssb_t* ssb, const char* name)
char signature_base64[256] = { 0 };
uint8_t private_key[crypto_sign_SECRETKEYBYTES] = { 0 };
if (_get_auth_private_key(ssb, private_key))
tf_ssb_get_private_key(ssb, private_key, sizeof(private_key));
if (crypto_sign_detached(signature, &signature_length, (const uint8_t*)payload_base64, strlen(payload_base64), private_key) == 0)
{
if (crypto_sign_detached(signature, &signature_length, (const uint8_t*)payload_base64, strlen(payload_base64), private_key) == 0)
{
sodium_bin2base64(signature_base64, sizeof(signature_base64), signature, sizeof(signature), sodium_base64_VARIANT_URLSAFE_NO_PADDING);
size_t size = strlen(header_base64) + 1 + strlen(payload_base64) + 1 + strlen(signature_base64) + 1;
result = tf_malloc(size);
snprintf(result, size, "%s.%s.%s", header_base64, payload_base64, signature_base64);
}
sodium_memzero(private_key, sizeof(private_key));
sodium_bin2base64(signature_base64, sizeof(signature_base64), signature, sizeof(signature), sodium_base64_VARIANT_URLSAFE_NO_PADDING);
size_t size = strlen(header_base64) + 1 + strlen(payload_base64) + 1 + strlen(signature_base64) + 1;
result = tf_malloc(size);
snprintf(result, size, "%s.%s.%s", header_base64, payload_base64, signature_base64);
}
sodium_memzero(private_key, sizeof(private_key));
JS_FreeCString(context, payload_string);
JS_FreeValue(context, payload_json);
@ -1335,19 +1316,31 @@ 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)
static void _httpd_endpoint_login_get_code_of_conduct_work(tf_ssb_t* ssb, void* user_data)
{
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;
login_request_t* login = user_data;
login->settings = tf_ssb_db_get_property(ssb, "core", "settings");
}
static void _httpd_endpoint_login_get_code_of_conduct_after_work(tf_ssb_t* ssb, int status, void* user_data)
{
login_request_t* login = user_data;
if (login->settings)
{
JSContext* context = tf_ssb_get_context(ssb);
JSValue settings_value = JS_ParseJSON(context, login->settings, strlen(login->settings), NULL);
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*)login->settings);
login->settings = NULL;
login->code_of_conduct = result;
}
tf_file_read(login->request->user_data, "core/auth.html", _httpd_endpoint_login_file_read_callback, login);
}
static bool _make_administrator_if_first(tf_ssb_t* ssb, const char* account_name_copy, bool may_become_first_admin)
@ -1547,7 +1540,6 @@ static void _httpd_endpoint_login(tf_http_request_t* request)
tf_http_request_ref(request);
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,
@ -1555,11 +1547,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 = code_of_conduct,
.have_administrator = have_administrator,
};
tf_file_read(request->user_data, "core/auth.html", _httpd_endpoint_login_file_read_callback, login);
tf_ssb_run_work(ssb, _httpd_endpoint_login_get_code_of_conduct_work, _httpd_endpoint_login_get_code_of_conduct_after_work, login);
jwt = JS_UNDEFINED;
account_name_copy = NULL;
}

View File

@ -1087,6 +1087,8 @@ bool tf_ssb_db_identity_create(tf_ssb_t* ssb, const char* user, uint8_t* out_pub
if (out_private_key)
{
tf_ssb_id_str_to_bin(out_private_key, private);
/* HACK: tf_ssb_id_str_to_bin only produces 32 bytes even though the full private key is 32 + 32. */
tf_ssb_id_str_to_bin(out_private_key + crypto_sign_PUBLICKEYBYTES, public);
}
return true;
}