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:
		
							
								
								
									
										39
									
								
								core/ssb.js
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								core/ssb.js
									
									
									
									
									
								
							@@ -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);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										37
									
								
								src/ssb.c
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								src/ssb.c
									
									
									
									
									
								
							@@ -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");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user