diff --git a/src/ssb.c b/src/ssb.c index 4fd2d044..fd63a541 100644 --- a/src/ssb.c +++ b/src/ssb.c @@ -1003,14 +1003,13 @@ static bool _tf_ssb_verify_and_strip_signature_internal(JSContext* context, JSVa return verified; } -bool tf_ssb_verify_and_strip_signature( - JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, bool* out_sequence_before_author) +bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, int* out_flags) { if (_tf_ssb_verify_and_strip_signature_internal(context, val, out_id, out_id_size, out_signature, out_signature_size)) { - if (out_sequence_before_author) + if (out_flags) { - *out_sequence_before_author = false; + *out_flags = 0; } return true; } @@ -1028,9 +1027,9 @@ bool tf_ssb_verify_and_strip_signature( JS_FreeValue(context, reordered); if (result) { - if (out_sequence_before_author) + if (out_flags) { - *out_sequence_before_author = true; + *out_flags = k_tf_ssb_message_flag_sequence_before_author; } return true; } @@ -3562,11 +3561,11 @@ void tf_ssb_verify_strip_and_store_message(tf_ssb_t* ssb, JSValue value, tf_ssb_ .user_data = user_data, }; char signature[crypto_sign_BYTES + 128] = { 0 }; - bool sequence_before_author = false; - if (tf_ssb_verify_and_strip_signature(context, value, async->id, sizeof(async->id), signature, sizeof(signature), &sequence_before_author)) + int flags = 0; + if (tf_ssb_verify_and_strip_signature(context, value, async->id, sizeof(async->id), signature, sizeof(signature), &flags)) { 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); + tf_ssb_db_store_message(ssb, context, async->id, value, signature, flags, _tf_ssb_verify_strip_and_store_callback, async); } else { diff --git a/src/ssb.db.c b/src/ssb.db.c index 4fc52ba2..0a6dde1c 100644 --- a/src/ssb.db.c +++ b/src/ssb.db.c @@ -103,7 +103,7 @@ void tf_ssb_db_init(tf_ssb_t* ssb) " hash TEXT," " content BLOB," " signature TEXT," - " sequence_before_author INTEGER," + " flags INTEGER," " UNIQUE(author, sequence)" ")"); @@ -123,6 +123,12 @@ void tf_ssb_db_init(tf_ssb_t* ssb) _tf_ssb_db_exec(db, "COMMIT TRANSACTION"); } + if (_tf_ssb_db_has_rows(db, "SELECT name FROM pragma_table_info('messages') WHERE name = 'sequence_before_author'")) + { + tf_printf("Renaming sequence_before_author -> flags.\n"); + _tf_ssb_db_exec(db, "ALTER TABLE messages RENAME COLUMN sequence_before_author TO flags"); + } + _tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_id_index ON messages (author, id)"); _tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_sequence_index ON messages (author, sequence)"); _tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_timestamp_index ON messages (author, timestamp)"); @@ -232,7 +238,7 @@ void tf_ssb_db_init(tf_ssb_t* ssb) " AND LENGTH(messages_refs.ref) = 52 " " AND messages_refs.ref LIKE '&%.sha256'"); - bool need_add_sequence_before_author = true; + bool need_add_flags = true; bool need_convert_timestamp_to_real = false; if (sqlite3_prepare(db, "PRAGMA table_info(messages)", -1, &statement, NULL) == SQLITE_OK) @@ -246,9 +252,9 @@ void tf_ssb_db_init(tf_ssb_t* ssb) { need_convert_timestamp_to_real = true; } - if (name && strcmp(name, "sequence_before_author") == 0) + if (name && strcmp(name, "flags") == 0) { - need_add_sequence_before_author = false; + need_add_flags = false; } } sqlite3_finalize(statement); @@ -266,10 +272,10 @@ void tf_ssb_db_init(tf_ssb_t* ssb) _tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_timestamp_index ON messages (author, timestamp)"); _tf_ssb_db_exec(db, "COMMIT TRANSACTION"); } - if (need_add_sequence_before_author) + if (need_add_flags) { - tf_printf("Adding sequence_before_author column.\n"); - _tf_ssb_db_exec(db, "ALTER TABLE messages ADD COLUMN sequence_before_author INTEGER"); + tf_printf("Adding flags column.\n"); + _tf_ssb_db_exec(db, "ALTER TABLE messages ADD COLUMN flags INTEGER"); } tf_ssb_release_db_writer(ssb, db); } @@ -298,14 +304,14 @@ static bool _tf_ssb_db_previous_message_exists(sqlite3* db, const char* author, } static int64_t _tf_ssb_db_store_message_raw(tf_ssb_t* ssb, const char* id, const char* previous, const char* author, int64_t sequence, double timestamp, const char* content, - size_t content_len, const char* signature, bool sequence_before_author) + size_t content_len, const char* signature, int flags) { sqlite3* db = tf_ssb_acquire_db_writer(ssb); int64_t last_row_id = -1; if (_tf_ssb_db_previous_message_exists(db, author, sequence, previous)) { - const char* query = "INSERT INTO messages (id, previous, author, sequence, timestamp, content, hash, signature, sequence_before_author) VALUES (?, ?, ?, ?, ?, jsonb(?), " + const char* query = "INSERT INTO messages (id, previous, author, sequence, timestamp, content, hash, signature, flags) VALUES (?, ?, ?, ?, ?, jsonb(?), " "?, ?, ?) ON CONFLICT DO NOTHING"; sqlite3_stmt* statement; if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK) @@ -315,7 +321,7 @@ static int64_t _tf_ssb_db_store_message_raw(tf_ssb_t* ssb, const char* id, const sqlite3_bind_text(statement, 3, author, -1, NULL) == SQLITE_OK && sqlite3_bind_int64(statement, 4, sequence) == SQLITE_OK && sqlite3_bind_double(statement, 5, timestamp) == SQLITE_OK && sqlite3_bind_text(statement, 6, content, 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_int(statement, 9, sequence_before_author) == SQLITE_OK) + sqlite3_bind_int(statement, 9, flags) == SQLITE_OK) { int r = sqlite3_step(statement); if (r != SQLITE_DONE) @@ -397,7 +403,7 @@ typedef struct _message_store_t tf_ssb_t* ssb; char id[k_id_base64_len]; char signature[512]; - bool sequence_before_author; + int flags; char previous[k_id_base64_len]; char author[k_id_base64_len]; int64_t sequence; @@ -421,7 +427,7 @@ static void _tf_ssb_db_store_message_work(uv_work_t* work) tf_trace_t* trace = tf_ssb_get_trace(store->ssb); tf_trace_begin(trace, "message_store_work"); int64_t last_row_id = _tf_ssb_db_store_message_raw(store->ssb, store->id, *store->previous ? store->previous : NULL, store->author, store->sequence, store->timestamp, - store->content, store->length, store->signature, store->sequence_before_author); + store->content, store->length, store->signature, store->flags); if (last_row_id != -1) { store->out_stored = true; @@ -477,8 +483,8 @@ static void _tf_ssb_db_store_message_after_work(uv_work_t* work, int status) { tf_trace_begin(trace, "notify_message_added"); JSContext* context = tf_ssb_get_context(store->ssb); - JSValue formatted = tf_ssb_format_message( - context, store->previous, store->author, store->sequence, store->timestamp, "sha256", store->content, store->signature, store->sequence_before_author); + JSValue formatted = + tf_ssb_format_message(context, store->previous, store->author, store->sequence, store->timestamp, "sha256", store->content, store->signature, store->flags); JSValue message = JS_NewObject(context); JS_SetPropertyStr(context, message, "key", JS_NewString(context, store->id)); JS_SetPropertyStr(context, message, "value", formatted); @@ -503,8 +509,8 @@ static void _tf_ssb_db_store_message_after_work(uv_work_t* work, int status) tf_trace_end(trace); } -void tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, bool sequence_before_author, - tf_ssb_db_store_message_callback_t* callback, void* user_data) +void tf_ssb_db_store_message( + tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, int flags, tf_ssb_db_store_message_callback_t* callback, void* user_data) { JSValue previousval = JS_GetPropertyStr(context, val, "previous"); const char* previous = JS_IsNull(previousval) ? NULL : JS_ToCString(context, previousval); @@ -543,7 +549,7 @@ void tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, .timestamp = timestamp, .content = contentstr, .length = content_len, - .sequence_before_author = sequence_before_author, + .flags = flags, .callback = callback, .user_data = user_data, @@ -1002,12 +1008,12 @@ JSValue tf_ssb_db_visit_query(tf_ssb_t* ssb, const char* query, const JSValue bi return result; } -JSValue tf_ssb_format_message(JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content, - const char* signature, bool sequence_before_author) +JSValue tf_ssb_format_message( + JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content, const char* signature, int flags) { JSValue value = JS_NewObject(context); JS_SetPropertyStr(context, value, "previous", (previous && *previous) ? JS_NewString(context, previous) : JS_NULL); - if (sequence_before_author) + if (flags & k_tf_ssb_message_flag_sequence_before_author) { JS_SetPropertyStr(context, value, "sequence", JS_NewInt64(context, sequence)); JS_SetPropertyStr(context, value, "author", JS_NewString(context, author)); @@ -1499,8 +1505,8 @@ JSValue tf_ssb_db_get_message_by_id(tf_ssb_t* ssb, const char* id, bool is_keys) JSContext* context = tf_ssb_get_context(ssb); sqlite3* db = tf_ssb_acquire_db_reader(ssb); sqlite3_stmt* statement; - if (sqlite3_prepare(db, "SELECT previous, author, id, sequence, timestamp, hash, json(content), signature, sequence_before_author FROM messages WHERE id = ?", -1, &statement, - NULL) == SQLITE_OK) + if (sqlite3_prepare(db, "SELECT previous, author, id, sequence, timestamp, hash, json(content), signature, flags FROM messages WHERE id = ?", -1, &statement, NULL) == + SQLITE_OK) { if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK) { diff --git a/src/ssb.db.h b/src/ssb.db.h index fa39bda4..eaf4a87d 100644 --- a/src/ssb.db.h +++ b/src/ssb.db.h @@ -70,12 +70,12 @@ typedef void(tf_ssb_db_store_message_callback_t)(const char* id, bool stored, vo ** @param id The message identifier. ** @param val The message object. ** @param signature The signature of the message. -** @param sequence_before_author The order of the message fields. +** @param flags tf_ssb_message_flags_t describing the message. ** @param callback A callback to call upon completion. ** @param user_data User data for the callback. */ -void tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, bool sequence_before_author, - tf_ssb_db_store_message_callback_t* callback, void* user_data); +void tf_ssb_db_store_message( + tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, int flags, tf_ssb_db_store_message_callback_t* callback, void* user_data); /** ** A function called when a block is stored in the database. @@ -233,10 +233,10 @@ bool tf_ssb_db_identity_get_private_key(tf_ssb_t* ssb, const char* user, const c ** @param hash The hash type (probably "sha256"). ** @param content The message content. ** @param signature The signature of the message. -** @param sequence_before_author The order of the message fields (prefer false). +** @param flags tf_ssb_message_flags_t describing the message. */ -JSValue tf_ssb_format_message(JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content, - const char* signature, bool sequence_before_author); +JSValue tf_ssb_format_message( + JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content, const char* signature, int flags); /** Information about a single followed account. */ typedef struct _tf_ssb_following_t diff --git a/src/ssb.h b/src/ssb.h index 4ee6c6bf..7f516cb2 100644 --- a/src/ssb.h +++ b/src/ssb.h @@ -40,6 +40,11 @@ typedef enum _tf_ssb_change_t k_tf_ssb_change_remove, } tf_ssb_change_t; +typedef enum _tf_ssb_message_flags_t +{ + k_tf_ssb_message_flag_sequence_before_author = 1, +} tf_ssb_message_flags_t; + /** An SSB instance. */ typedef struct _tf_ssb_t tf_ssb_t; /** An SSB connection. */ @@ -363,11 +368,10 @@ bool tf_ssb_id_bin_to_str(char* str, size_t str_size, const uint8_t* bin); ** @param out_id_size The size of out_id. ** @param[out] out_signature A buffer to receive the message's signature. ** @param out_signature_size The size of out_signature. -** @param[out] out_sequence_before_author A flag describing the order of the sequence and author fields. +** @param[out] out_flags tf_ssb_message_flags_t describing the message. ** @return True if the signature is valid and was successfully extracted. */ -bool tf_ssb_verify_and_strip_signature( - JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, bool* out_sequence_before_author); +bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, int* out_flags); /** ** Determine the message identifier. diff --git a/src/ssb.rpc.c b/src/ssb.rpc.c index eea4b5c3..4c366882 100644 --- a/src/ssb.rpc.c +++ b/src/ssb.rpc.c @@ -678,7 +678,7 @@ static void _tf_ssb_connection_send_history_stream_work(tf_ssb_connection_t* con sqlite3_stmt* statement; const int k_max = 32; if (sqlite3_prepare(db, - "SELECT previous, author, id, sequence, timestamp, hash, json(content), signature, sequence_before_author FROM messages WHERE author = ?1 AND sequence > ?2 AND " + "SELECT previous, author, id, sequence, timestamp, hash, json(content), signature, flags FROM messages WHERE author = ?1 AND sequence > ?2 AND " "sequence " "< ?3 ORDER BY sequence", -1, &statement, NULL) == SQLITE_OK)