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
This commit is contained in:
Cory McWilliams 2022-02-03 02:00:05 +00:00
parent a98a848bb7
commit cd51edcd8f
6 changed files with 69 additions and 40 deletions

View File

@ -240,7 +240,18 @@ function ebtReplicateSendClock(request, have) {
} }
function formatMessage(row) { function formatMessage(row) {
var 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, previous: row.previous,
author: row.author, author: row.author,
sequence: row.sequence, sequence: row.sequence,
@ -249,7 +260,7 @@ function formatMessage(row) {
content: JSON.parse(row.content), content: JSON.parse(row.content),
signature: row.signature, signature: row.signature,
}; };
return message; }
} }
function ebtReplicateRegisterMessageCallback(request) { function ebtReplicateRegisterMessageCallback(request) {
@ -308,37 +319,21 @@ ssb.addRpc(['createHistoryStream'], function(request) {
if (keys) { if (keys) {
var message = { var message = {
key: row.id, key: row.id,
value: { value: formatMessage(row),
previous: row.previous,
author: row.author,
sequence: row.sequence,
timestamp: row.timestamp,
hash: row.hash,
content: JSON.parse(row.content),
signature: row.signature,
},
timestamp: row.timestamp, timestamp: row.timestamp,
}; };
} else { } else {
var message = { var message = formatMessage(row);
previous: row.previous,
author: row.author,
sequence: row.sequence,
timestamp: row.timestamp,
hash: row.hash,
content: JSON.parse(row.content),
signature: row.signature,
};
} }
request.send_json(message); request.send_json(message);
} }
ssb.sqlStream( 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], [id, seq ?? 0],
sendMessage); sendMessage);
ssb.addEventListener('message', function(message_id) { ssb.addEventListener('message', function(message_id) {
ssb.sqlStream( 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], [message_id, id],
function (row) { function (row) {
sendMessage(row); sendMessage(row);

View File

@ -489,7 +489,7 @@ void tf_ssb_calculate_message_id(JSContext* context, JSValue message, char* out_
JS_FreeValue(context, idval); 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; bool verified = false;
JSValue signature = JS_GetPropertyStr(context, val, "signature"); 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; 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) void tf_ssb_send_close(tf_ssb_t* ssb)
{ {
for (tf_ssb_connection_t* connection = ssb->connections; connection; connection = connection->next) 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]; 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)); tf_ssb_calculate_message_id(ssb->context, root, id, sizeof(id));
if (valid && 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"); 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"); printf("Failed to verify message signature.\n");
} }

View File

@ -27,6 +27,7 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
" UNIQUE(author, sequence)" " UNIQUE(author, sequence)"
")", ")",
NULL, NULL, NULL); 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_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_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); 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); 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; bool stored = false;
JSValue previousval = JS_GetPropertyStr(context, val, "previous"); 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* db = tf_ssb_get_db(ssb);
sqlite3_stmt* statement; sqlite3_stmt* statement;
int64_t last_row_id = -1; 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_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
{ {
if (sqlite3_bind_text(statement, 1, id, -1, 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_int64(statement, 5, timestamp) == SQLITE_OK &&
sqlite3_bind_text(statement, 6, contentstr, content_len, NULL) == 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, 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); int r = sqlite3_step(statement);
if (r != SQLITE_DONE) if (r != SQLITE_DONE)

View File

@ -6,7 +6,7 @@
typedef struct _tf_ssb_t tf_ssb_t; typedef struct _tf_ssb_t tf_ssb_t;
void tf_ssb_db_init(tf_ssb_t* ssb); 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_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_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); 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);

View File

@ -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_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_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); 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); const char* tf_ssb_connection_get_host(tf_ssb_connection_t* connection);

View File

@ -225,9 +225,10 @@ static JSValue _tf_ssb_storeMessage(JSContext* context, JSValueConst this_val, i
char signature[crypto_sign_BYTES + 128]; char signature[crypto_sign_BYTES + 128];
char id[crypto_hash_sha256_BYTES * 2 + 1]; char id[crypto_hash_sha256_BYTES * 2 + 1];
tf_ssb_calculate_message_id(context, argv[0], id, sizeof(id)); 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); tf_ssb_notify_message_added(ssb, id);
} }