Make storing messages async. Phew.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4355 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
2023-07-20 01:02:50 +00:00
parent 6fcebd7a08
commit fb73fd0afc
7 changed files with 417 additions and 162 deletions

124
src/ssb.c
View File

@ -237,6 +237,8 @@ typedef struct _tf_ssb_t
void (*hitch_callback)(const char* name, uint64_t duration, void* user_data);
void* hitch_user_data;
tf_ssb_store_queue_t store_queue;
} tf_ssb_t;
typedef struct _tf_ssb_connection_message_request_t
@ -1666,7 +1668,7 @@ static bool _tf_ssb_connection_box_stream_recv(tf_ssb_connection_t* connection)
return true;
}
bool tf_ssb_append_message_with_keys(tf_ssb_t* ssb, const char* author, const uint8_t* private_key, JSValue message, char* out_id, size_t out_id_size)
JSValue tf_ssb_sign_message(tf_ssb_t* ssb, const char* author, const uint8_t* private_key, JSValue message)
{
char previous_id[crypto_hash_sha256_BYTES * 2];
int64_t previous_sequence = 0;
@ -1675,14 +1677,7 @@ bool tf_ssb_append_message_with_keys(tf_ssb_t* ssb, const char* author, const ui
JSContext* context = ssb->context;
JSValue root = JS_NewObject(context);
if (have_previous)
{
JS_SetPropertyStr(context, root, "previous", JS_NewString(context, previous_id));
}
else
{
JS_SetPropertyStr(context, root, "previous", JS_NULL);
}
JS_SetPropertyStr(context, root, "previous", have_previous ? JS_NewString(context, previous_id) : JS_NULL);
JS_SetPropertyStr(context, root, "author", JS_NewString(context, author));
JS_SetPropertyStr(context, root, "sequence", JS_NewInt64(context, previous_sequence + 1));
@ -1696,53 +1691,29 @@ bool tf_ssb_append_message_with_keys(tf_ssb_t* ssb, const char* author, const ui
JSValue jsonval = JS_JSONStringify(context, root, JS_NULL, JS_NewInt32(context, 2));
size_t len = 0;
const char* json = JS_ToCStringLen(context, &len, jsonval);
JS_FreeValue(context, jsonval);
uint8_t signature[crypto_sign_BYTES];
unsigned long long siglen;
bool valid = crypto_sign_detached(signature, &siglen, (const uint8_t*)json, len, private_key) == 0;
JS_FreeCString(context, json);
if (!valid)
{
tf_printf("crypto_sign_detached failed\n");
}
char signature_base64[crypto_sign_BYTES * 2];
tf_base64_encode(signature, sizeof(signature), signature_base64, sizeof(signature_base64));
strcat(signature_base64, ".sig.ed25519");
JSValue sigstr = JS_NewString(context, signature_base64);
JS_SetPropertyStr(context, root, "signature", sigstr);
bool stored = false;
char id[sodium_base64_ENCODED_LEN(crypto_hash_sha256_BYTES, sodium_base64_VARIANT_ORIGINAL) + 7 + 1];
if (valid && tf_ssb_verify_and_strip_signature(ssb->context, root, id, sizeof(id), NULL, 0, NULL))
{
if (tf_ssb_db_store_message(ssb, ssb->context, id, root, signature_base64, false))
{
tf_ssb_notify_message_added(ssb, id);
snprintf(out_id, out_id_size, "%s", id);
stored = true;
}
else
{
tf_printf("message not stored.\n");
}
JS_FreeValue(context, root);
root = JS_UNDEFINED;
}
else
{
tf_printf("Failed to verify message signature.\n");
tf_printf("json = %s\n", json);
tf_printf("sig = %s\n", signature_base64);
char signature_base64[crypto_sign_BYTES * 2];
tf_base64_encode(signature, sizeof(signature), signature_base64, sizeof(signature_base64));
strcat(signature_base64, ".sig.ed25519");
JSValue sigstr = JS_NewString(context, signature_base64);
JS_SetPropertyStr(context, root, "signature", sigstr);
}
if (!stored && out_id && out_id_size)
{
*out_id = '\0';
}
JS_FreeCString(context, json);
JS_FreeValue(context, jsonval);
JS_FreeValue(context, root);
return stored;
return root;
}
static void _tf_ssb_connection_dispatch_scheduled(tf_ssb_connection_t* connection)
@ -2123,7 +2094,7 @@ tf_ssb_t* tf_ssb_create(uv_loop_t* loop, JSContext* context, const char* db_path
JS_NewClass(JS_GetRuntime(ssb->context), _connection_class_id, &def);
ssb->db_path = tf_strdup(db_path);
sqlite3_open_v2(db_path, &ssb->db_writer, SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI, NULL);
sqlite3_open_v2(db_path, &ssb->db_writer, SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI | SQLITE_OPEN_CREATE, NULL);
tf_ssb_db_init(ssb);
if (loop)
@ -3419,32 +3390,54 @@ tf_ssb_blob_wants_t* tf_ssb_connection_get_blob_wants_state(tf_ssb_connection_t*
return connection ? &connection->blob_wants : NULL;
}
bool tf_ssb_verify_strip_and_store_message(tf_ssb_t* ssb, JSValue value, bool* out_is_new)
typedef struct _store_t
{
tf_ssb_t* ssb;
bool verified;
bool stored;
char id[crypto_hash_sha256_BYTES * 2 + 1];
tf_ssb_verify_strip_store_callback_t* callback;
void* user_data;
} store_t;
static void _tf_ssb_verify_strip_and_store_finish(store_t* store)
{
if (store->callback)
{
store->callback(store->id, store->verified, store->stored, store->user_data);
}
tf_free(store);
}
static void _tf_ssb_verify_strip_and_store_callback(const char* id, bool stored, void* user_data)
{
store_t* store = user_data;
store->stored = stored;
_tf_ssb_verify_strip_and_store_finish(store);
}
void tf_ssb_verify_strip_and_store_message(tf_ssb_t* ssb, JSValue value, tf_ssb_verify_strip_store_callback_t* callback, void* user_data)
{
JSContext* context = tf_ssb_get_context(ssb);
store_t* async = tf_malloc(sizeof(store_t));
*async = (store_t)
{
.ssb = ssb,
.callback = callback,
.user_data = user_data,
};
char signature[crypto_sign_BYTES + 128] = { 0 };
char id[crypto_hash_sha256_BYTES * 2 + 1] = { 0 };
bool sequence_before_author = false;
if (out_is_new)
if (tf_ssb_verify_and_strip_signature(context, value, async->id, sizeof(async->id), signature, sizeof(signature), &sequence_before_author))
{
*out_is_new = false;
}
if (tf_ssb_verify_and_strip_signature(context, value, id, sizeof(id), signature, sizeof(signature), &sequence_before_author))
{
if (tf_ssb_db_store_message(ssb, context, id, value, signature, sequence_before_author))
{
tf_ssb_notify_message_added(ssb, id);
if (out_is_new)
{
*out_is_new = true;
}
}
return true;
async->verified = true;
tf_ssb_db_store_message(ssb, context, async->id, value, signature, sequence_before_author, _tf_ssb_verify_strip_and_store_callback, async);
}
else
{
tf_printf("failed to verify message\n");
return false;
printf("nope\n");
_tf_ssb_verify_strip_and_store_finish(async);
}
}
@ -3555,3 +3548,8 @@ void tf_ssb_set_hitch_callback(tf_ssb_t* ssb, void (*callback)(const char* name,
ssb->hitch_callback = callback;
ssb->hitch_user_data = user_data;
}
tf_ssb_store_queue_t* tf_ssb_get_store_queue(tf_ssb_t* ssb)
{
return &ssb->store_queue;
}