From cd51edcd8f4c05261c94d27252dfb4720366465c Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Thu, 3 Feb 2022 02:00:05 +0000 Subject: [PATCH] I think this fixes the questionable archaic sequence / author order issue. git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3813 ed5197a5-7fde-0310-b194-c3ffbd925b24 --- core/ssb.js | 55 ++++++++++++++++++++++++---------------------------- src/ssb.c | 37 ++++++++++++++++++++++++++++++++--- src/ssb.db.c | 8 +++++--- src/ssb.db.h | 2 +- src/ssb.h | 2 +- src/ssb.js.c | 5 +++-- 6 files changed, 69 insertions(+), 40 deletions(-) diff --git a/core/ssb.js b/core/ssb.js index 0bbad759..f74d49a1 100644 --- a/core/ssb.js +++ b/core/ssb.js @@ -240,16 +240,27 @@ function ebtReplicateSendClock(request, have) { } function formatMessage(row) { - var message = { - previous: row.previous, - author: row.author, - sequence: row.sequence, - timestamp: row.timestamp, - hash: row.hash, - content: JSON.parse(row.content), - signature: row.signature, - }; - return message; + if (row.sequence_before_author) { + return { + previous: row.previous, + sequence: row.sequence, + author: row.author, + timestamp: row.timestamp, + hash: row.hash, + content: JSON.parse(row.content), + signature: row.signature, + }; + } else { + return { + previous: row.previous, + author: row.author, + sequence: row.sequence, + timestamp: row.timestamp, + hash: row.hash, + content: JSON.parse(row.content), + signature: row.signature, + }; + } } function ebtReplicateRegisterMessageCallback(request) { @@ -308,37 +319,21 @@ ssb.addRpc(['createHistoryStream'], function(request) { if (keys) { var message = { key: row.id, - value: { - previous: row.previous, - author: row.author, - sequence: row.sequence, - timestamp: row.timestamp, - hash: row.hash, - content: JSON.parse(row.content), - signature: row.signature, - }, + value: formatMessage(row), timestamp: row.timestamp, }; } else { - var message = { - previous: row.previous, - author: row.author, - sequence: row.sequence, - timestamp: row.timestamp, - hash: row.hash, - content: JSON.parse(row.content), - signature: row.signature, - }; + var message = formatMessage(row); } request.send_json(message); } ssb.sqlStream( - 'SELECT previous, author, id, sequence, timestamp, hash, content, signature FROM messages WHERE author = ?1 AND sequence >= ?2 ORDER BY sequence', + 'SELECT previous, author, id, sequence, timestamp, hash, content, signature, sequence_before_author FROM messages WHERE author = ?1 AND sequence >= ?2 ORDER BY sequence', [id, seq ?? 0], sendMessage); ssb.addEventListener('message', function(message_id) { ssb.sqlStream( - 'SELECT previous, author, id, sequence, timestamp, hash, content, signature FROM messages WHERE id = ?1 AND author = ?2', + 'SELECT previous, author, id, sequence, timestamp, hash, content, signature, sequence_before_author FROM messages WHERE id = ?1 AND author = ?2', [message_id, id], function (row) { sendMessage(row); diff --git a/src/ssb.c b/src/ssb.c index d6c2c7b3..025936dc 100644 --- a/src/ssb.c +++ b/src/ssb.c @@ -489,7 +489,7 @@ void tf_ssb_calculate_message_id(JSContext* context, JSValue message, char* out_ JS_FreeValue(context, idval); } -bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* out_signature, size_t out_signature_size) +static bool _tf_ssb_verify_and_strip_signature_internal(JSContext* context, JSValue val, char* out_signature, size_t out_signature_size) { bool verified = false; JSValue signature = JS_GetPropertyStr(context, val, "signature"); @@ -553,6 +553,37 @@ bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* ou return verified; } +bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* out_signature, size_t out_signature_size, bool* out_sequence_before_author) +{ + if (_tf_ssb_verify_and_strip_signature_internal(context, val, out_signature, out_signature_size)) + { + if (out_sequence_before_author) + { + *out_sequence_before_author = false; + } + return true; + } + else if (out_sequence_before_author) + { + JSValue reordered = JS_NewObject(context); + JS_SetPropertyStr(context, reordered, "previous", JS_GetPropertyStr(context, val, "previous")); + JS_SetPropertyStr(context, reordered, "sequence", JS_GetPropertyStr(context, val, "sequence")); + JS_SetPropertyStr(context, reordered, "author", JS_GetPropertyStr(context, val, "author")); + JS_SetPropertyStr(context, reordered, "timestamp", JS_GetPropertyStr(context, val, "timestamp")); + JS_SetPropertyStr(context, reordered, "hash", JS_GetPropertyStr(context, val, "hash")); + JS_SetPropertyStr(context, reordered, "content", JS_GetPropertyStr(context, val, "content")); + JS_SetPropertyStr(context, reordered, "signature", JS_GetPropertyStr(context, val, "signature")); + bool result = _tf_ssb_verify_and_strip_signature_internal(context, reordered, out_signature, out_signature_size); + JS_FreeValue(context, reordered); + if (result) + { + *out_sequence_before_author = true; + return true; + } + } + return false; +} + void tf_ssb_send_close(tf_ssb_t* ssb) { for (tf_ssb_connection_t* connection = ssb->connections; connection; connection = connection->next) @@ -1183,12 +1214,12 @@ void tf_ssb_append_message(tf_ssb_t* ssb, JSValue message) char id[sodium_base64_ENCODED_LEN(crypto_hash_sha256_BYTES, sodium_base64_VARIANT_ORIGINAL) + 7 + 1]; tf_ssb_calculate_message_id(ssb->context, root, id, sizeof(id)); if (valid && - !tf_ssb_db_store_message(ssb, ssb->context, id, root, signature_base64)) + !tf_ssb_db_store_message(ssb, ssb->context, id, root, signature_base64, false)) { printf("message not stored.\n"); } - if (!tf_ssb_verify_and_strip_signature(ssb->context, root, NULL, 0)) + if (!tf_ssb_verify_and_strip_signature(ssb->context, root, NULL, 0, NULL)) { printf("Failed to verify message signature.\n"); } diff --git a/src/ssb.db.c b/src/ssb.db.c index 41bcb20d..b1faf30e 100644 --- a/src/ssb.db.c +++ b/src/ssb.db.c @@ -27,6 +27,7 @@ void tf_ssb_db_init(tf_ssb_t* ssb) " UNIQUE(author, sequence)" ")", NULL, NULL, NULL); + sqlite3_exec(db, "ALTER TABLE messages ADD COLUMN sequence_before_author INTEGER", NULL, NULL, NULL); sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_id_index ON messages (author, id)", NULL, NULL, NULL); sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_sequence_index ON messages (author, sequence)", NULL, NULL, NULL); sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_timestamp_index ON messages (author, timestamp)", NULL, NULL, NULL); @@ -62,7 +63,7 @@ void tf_ssb_db_init(tf_ssb_t* ssb) NULL, NULL, NULL); } -bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature) +bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, bool sequence_before_author) { bool stored = false; JSValue previousval = JS_GetPropertyStr(context, val, "previous"); @@ -83,7 +84,7 @@ bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, sqlite3* db = tf_ssb_get_db(ssb); sqlite3_stmt* statement; int64_t last_row_id = -1; - const char* query = "INSERT INTO messages (id, previous, author, sequence, timestamp, content, hash, signature) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT DO NOTHING"; + const char* query = "INSERT INTO messages (id, previous, author, sequence, timestamp, content, hash, signature, sequence_before_author) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT DO NOTHING"; if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK && @@ -93,7 +94,8 @@ bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, sqlite3_bind_int64(statement, 5, timestamp) == SQLITE_OK && sqlite3_bind_text(statement, 6, contentstr, content_len, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 7, "sha256", 6, NULL) == SQLITE_OK && - sqlite3_bind_text(statement, 8, signature, -1, NULL) == SQLITE_OK) + sqlite3_bind_text(statement, 8, signature, -1, NULL) == SQLITE_OK && + sqlite3_bind_int(statement, 9, sequence_before_author) == SQLITE_OK) { int r = sqlite3_step(statement); if (r != SQLITE_DONE) diff --git a/src/ssb.db.h b/src/ssb.db.h index 895dd19b..ec03d1d7 100644 --- a/src/ssb.db.h +++ b/src/ssb.db.h @@ -6,7 +6,7 @@ typedef struct _tf_ssb_t tf_ssb_t; void tf_ssb_db_init(tf_ssb_t* ssb); -bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature); +bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, bool sequence_before_author); bool tf_ssb_db_message_content_get(tf_ssb_t* ssb, const char* id, uint8_t** out_blob, size_t* out_size); bool tf_ssb_db_blob_get(tf_ssb_t* ssb, const char* id, uint8_t** out_blob, size_t* out_size); bool tf_ssb_db_blob_store(tf_ssb_t* ssb, const uint8_t* blob, size_t size, char* out_id, size_t out_id_size); diff --git a/src/ssb.h b/src/ssb.h index ae025da9..f860cb4c 100644 --- a/src/ssb.h +++ b/src/ssb.h @@ -72,7 +72,7 @@ void tf_ssb_send_close(tf_ssb_t* ssb); bool tf_ssb_id_str_to_bin(uint8_t* bin, const char* str); bool tf_ssb_id_bin_to_str(char* str, size_t str_size, const uint8_t* bin); -bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* out_signature, size_t out_signature_size); +bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* out_signature, size_t out_signature_size, bool* out_sequence_before_author); void tf_ssb_calculate_message_id(JSContext* context, JSValue message, char* out_id, size_t out_id_size); const char* tf_ssb_connection_get_host(tf_ssb_connection_t* connection); diff --git a/src/ssb.js.c b/src/ssb.js.c index 5d0250d8..55d05d35 100644 --- a/src/ssb.js.c +++ b/src/ssb.js.c @@ -225,9 +225,10 @@ static JSValue _tf_ssb_storeMessage(JSContext* context, JSValueConst this_val, i char signature[crypto_sign_BYTES + 128]; char id[crypto_hash_sha256_BYTES * 2 + 1]; tf_ssb_calculate_message_id(context, argv[0], id, sizeof(id)); - if (tf_ssb_verify_and_strip_signature(context, argv[0], signature, sizeof(signature))) + bool sequence_before_author = false; + if (tf_ssb_verify_and_strip_signature(context, argv[0], signature, sizeof(signature), &sequence_before_author)) { - if (tf_ssb_db_store_message(ssb, context, id, argv[0], signature)) + if (tf_ssb_db_store_message(ssb, context, id, argv[0], signature, sequence_before_author)) { tf_ssb_notify_message_added(ssb, id); }