#pragma once /** ** \defgroup ssb_db SSB Database ** This is the main interface to SSB persistence. Everything about getting and ** storing messages and blobs goes through here. ** @{ */ #include "ssb.h" #include "quickjs.h" #include /** An SSB instance. */ typedef struct _tf_ssb_t tf_ssb_t; /** ** Initialize the database writer for an SSB instance. ** @param ssb The SSB instance. */ void tf_ssb_db_init(tf_ssb_t* ssb); /** ** Configure an opened SQLite database for reading. */ void tf_ssb_db_init_reader(sqlite3* db); /** ** Get message content by ID. ** @param ssb The SSB instance. ** @param id The message identifier. ** @param[out] out_blob Populated with the message content. ** @param[out] out_size POpulated with the size of the message content. ** @return true If the message content was found and retrieved. */ bool tf_ssb_db_message_content_get(tf_ssb_t* ssb, const char* id, uint8_t** out_blob, size_t* out_size); /** ** Determine whether a blob is in the database by ID. ** @param ssb The SSB instasnce. ** @param id The blob identifier. ** @return true If the blob is in the database. */ bool tf_ssb_db_blob_has(tf_ssb_t* ssb, const char* id); /** ** Retrieve a blob from the database. ** @param ssb The SSB instance. ** @param id The blob identifier. ** @param[out] out_blob Populated with the blob data. ** @param[out] out_size The size of the blob data. ** @return true If the blob was found and retrieved. */ bool tf_ssb_db_blob_get(tf_ssb_t* ssb, const char* id, uint8_t** out_blob, size_t* out_size); /** ** A function called when a blob is retrieved from the database. ** @param found Whether the blob was found. ** @param data The blob data if found. ** @param size The size of the blob data if found, in bytes. ** @param user_data The user data. */ typedef void(tf_ssb_db_blob_get_callback_t)(bool found, const uint8_t* data, size_t size, void* user_data); /** ** Retrieve a blob from the database asynchronously. ** @param ssb The SSB instance. ** @param id The blob identifier. ** @param callback Callback called with the result. ** @param user_data The user data. */ void tf_ssb_db_blob_get_async(tf_ssb_t* ssb, const char* id, tf_ssb_db_blob_get_callback_t* callback, void* user_data); /** ** A function called when a message is stored in the database. ** @param id The message identifier. ** @param stored True if the message wasn't already in the database. ** @param user_data The user data. */ typedef void(tf_ssb_db_store_message_callback_t)(const char* id, bool stored, void* user_data); /** ** Store a message in the database. ** @param ssb The SSB instance. ** @param context The JS context. ** @param id The message identifier. ** @param val The message object. ** @param signature The signature of the message. ** @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, int flags, tf_ssb_db_store_message_callback_t* callback, void* user_data); /** ** A function called when a block is stored in the database. ** @param id The blob identifier. ** @param is_new True if the blob wasn't already in the database. ** @param user_data The user data. */ typedef void(tf_ssb_db_blob_store_callback_t)(const char* id, bool is_new, void* user_data); /** ** Store a blob in the database asynchronously. ** @param ssb The SSB instance. ** @param blob The blob data. ** @param size The size of the blob data. ** @param callback A callback to call upon completion. ** @param user_data User data for the callback. */ void tf_ssb_db_blob_store_async(tf_ssb_t* ssb, const uint8_t* blob, size_t size, tf_ssb_db_blob_store_callback_t* callback, void* user_data); /** ** Store a blob in the database and wait for the operation to complete. ** @param ssb The SSB instance. ** @param blob The blob data. ** @param size The size of the blob. ** @param[out] out_id Populated with the blob identifier. ** @param out_id_size The size of the out_id buffer. ** @param[out] out_new True if the blob wasn't already in the datbase. */ 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* out_new); /** ** Get a message by its identifier. ** @param ssb The SSB instance. ** @param id The message identifier. ** @param is_keys Whether to produce {"key": id, "value": message, "timestamp": ts} or just the message. ** @return The message. */ JSValue tf_ssb_db_get_message_by_id(tf_ssb_t* ssb, const char* id, bool is_keys); /** ** Get a message by its author and sequence number. ** @param ssb The SSB instance. ** @param author The author's identity. ** @param sequence The message sequence number. ** @param[out] out_message_id Populated with the message identifier. ** @param out_message_id_size The size of the out_message_id buffer. ** @param[out] out_previous Populated with the previous message identifier. ** @param out_previous_size The size of the out_previous buffer. ** @param[out] out_timestamp Populated with the timestamp. ** @param[out] out_content Populated with the message content. Free with tf_free(). ** @param[out] out_hash Populated with the message hash format. ** @param out_hash_size The size of the out_hash buffer. ** @param[out] out_signature Populated with the message signature. ** @param out_signature_size The size of the out_signature buffer. ** @param[out] out_flags Populated with flags describing the format of the message. ** @return True if the message was found and retrieved. */ bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* author, int64_t sequence, char* out_message_id, size_t out_message_id_size, char* out_previous, size_t out_previous_size, double* out_timestamp, char** out_content, char* out_hash, size_t out_hash_size, char* out_signature, size_t out_signature_size, int* out_flags); /** ** Get information about the last message from an author. ** @param ssb The SSB instance. ** @param author The author's identity. ** @param[out] out_sequence Populated with the message sequence number. ** @param[out] out_message_id Populated with the message identifier. ** @param out_message_id_size The size of the out_message_id buffer. ** @return True if the message was found and information was retrieved. */ bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, int64_t* out_sequence, char* out_message_id, size_t out_message_id_size); /** ** Call a function for each result row of an SQL query. ** @param ssb The SSB instance. ** @param query The SQL query. ** @param binds An array of values to bind to SQL parameters. ** @param callback A callback to call for each result row. ** @param user_data User data to pass to the callback. ** @return A promise resolved when the query completes or rejected if it fails. */ JSValue tf_ssb_db_visit_query(tf_ssb_t* ssb, const char* query, const JSValue binds, void (*callback)(JSValue row, void* user_data), void* user_data); /** ** Sanity check the feed for the given author. ** @param db The SQLite database instance to use. ** @param author The identity of the author to check. ** @return True if the author's feed is fully valid. */ bool tf_ssb_db_check(sqlite3* db, const char* author); /** ** Get the number of SSB identities a Tilde Friends user has. ** @param ssb The SSB instance. ** @param user The user's username. ** @return The number of identities found. */ int tf_ssb_db_identity_get_count_for_user(tf_ssb_t* ssb, const char* user); /** ** Create a new identity for a user. ** @param ssb The SSB instance. ** @param user The user's username. ** @param[out] out_public_key A buffer populated with the new public key. ** @param[out] out_private_key A buffer populated with the new private key. ** @return True if the identity was created. */ bool tf_ssb_db_identity_create(tf_ssb_t* ssb, const char* user, uint8_t* out_public_key, uint8_t* out_private_key); /** ** Delete an identity for a user from the database. This is an unrecoverable operation. ** @param ssb The SSB instance. ** @param user The user's username. ** @param public_key The identity to delete. ** @return True if the identity was deleted. */ bool tf_ssb_db_identity_delete(tf_ssb_t* ssb, const char* user, const char* public_key); /** ** Add an identity for a user to the database. ** @param ssb The SSB instance. ** @param user The user's username. ** @param public_key The public key of the identity. ** @param private_key The private key of the identity. */ bool tf_ssb_db_identity_add(tf_ssb_t* ssb, const char* user, const char* public_key, const char* private_key); /** ** Get the active identity for a user for a given package. ** @param db An sqlite3 database. ** @param user The username. ** @param package_owner The username of the package owner. ** @param package_name The name of the package. ** @param[out] out_identity Populated with the identity. ** @param out_identity_size The size of the out_identity buffer. ** @return true If the identity was retrieved. */ bool tf_ssb_db_identity_get_active(sqlite3* db, const char* user, const char* package_owner, const char* package_name, char* out_identity, size_t out_identity_size); /** ** Call a function for each identity owned by a user. ** @param ssb The SSB instance. ** @param user The user's username. ** @param callback The function to call for each identity. ** @param user_data User data to pass to the callback. */ void tf_ssb_db_identity_visit(tf_ssb_t* ssb, const char* user, void (*callback)(const char* identity, void* user_data), void* user_data); /** ** Call a function for all identities in the database. ** @param ssb The SSB instance. ** @param callback The callback to call for each identity. ** @param user_data User data to pass to the callback. */ void tf_ssb_db_identity_visit_all(tf_ssb_t* ssb, void (*callback)(const char* identity, void* user_data), void* user_data); /** ** Get the private key for an identity in the database. ** @param ssb The SSB instance. ** @param user The owning user's username. ** @param public_key The public key of the identity. ** @param[out] out_private_key A buffer to receive the private key of the identity. ** @param private_key_size The size of the out_private_key buffer. ** @return True if the private key was found and retrieved. */ bool tf_ssb_db_identity_get_private_key(tf_ssb_t* ssb, const char* user, const char* public_key, uint8_t* out_private_key, size_t private_key_size); /** ** Format a message in the standard format for SSB signing. ** @param context A JS context. ** @param previous The previous message identifier. ** @param author The author's public key. ** @param sequence The message sequence number. ** @param timestamp The message timestamp. ** @param hash The hash type (probably "sha256"). ** @param content The message content. ** @param signature The signature of the message. ** @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, int flags); /** Information about a single followed account. */ typedef struct _tf_ssb_following_t { /** The number of known users the account is following. */ int following_count; /** The number of known users the account is blocking. */ int blocking_count; /** The number of known users following the account. */ int followed_by_count; /** The number of known users blocking the account. */ int blocked_by_count; /** The account's identity. */ char id[k_id_base64_len]; } tf_ssb_following_t; /** ** Get all the identities visible from a set of identities given known follows and blocks. ** @param ssb The SSB instance. ** @param ids An array of identities. ** @param count The number of identities. ** @param depth The following depth to use (prefer 2). ** @return An array of identities. Free with tf_free(). */ const char** tf_ssb_db_following_deep_ids(tf_ssb_t* ssb, const char** ids, int count, int depth); /** ** Return information about identities visible from a set of identities given known follows and blocks. ** @param ssb The SSB instance. ** @param ids An array of identities. ** @param count The number of identities. ** @param depth The following depth to use (prefer 2). ** @return An array of information about visible accounts. Fere with tf_free(). */ tf_ssb_following_t* tf_ssb_db_following_deep(tf_ssb_t* ssb, const char** ids, int count, int depth); /** ** Get all visible identities from all local accounts. ** @param ssb The SSB instance. ** @param depth The following depth to consider (prefer 2). ** @return The visible identities. Free with tf_free(). */ const char** tf_ssb_db_get_all_visible_identities(tf_ssb_t* ssb, int depth); /** ** Information about a stored SHS connection. */ typedef struct _tf_ssb_db_stored_connection_t { /** The connection's address. */ char address[256]; /** The network port number of the connection. */ int port; /** The identity. */ char pubkey[k_id_base64_len]; } tf_ssb_db_stored_connection_t; /** ** Get the list of stored connections from the SSB connection tracker. ** @param ssb The SSB instance. ** @param[out] out_count Populated with the number of returned connections. ** @return Information about all the stored connections. */ tf_ssb_db_stored_connection_t* tf_ssb_db_get_stored_connections(tf_ssb_t* ssb, int* out_count); /** ** Remove a stored connection. ** @param ssb The SSB instance. ** @param address The connection address. ** @param port The connection network port number. ** @param pubkey The identity of the connection. */ void tf_ssb_db_forget_stored_connection(tf_ssb_t* ssb, const char* address, int port, const char* pubkey); /** ** Retrieve a user's hashed password from the database. ** @param ssb The SSB instance. ** @param name The username. ** @param[out] out_password Populated with the password. ** @param password_size The size of the out_password buffer. ** @return true if the password hash was successfully retrieved. */ bool tf_ssb_db_get_account_password_hash(tf_ssb_t* ssb, const char* name, char* out_password, size_t password_size); /** ** Insert or update a user's hashed password in the database. ** @param loop The event loop. ** @param db A DB writer. ** @param context A JS context. ** @param name The username. ** @param password The raw password. ** @return true if the hash of the password was successfully stored. */ bool tf_ssb_db_set_account_password(uv_loop_t* loop, sqlite3* db, JSContext* context, const char* name, const char* password); /** ** Add a user account to the database. ** @param loop The event loop. ** @param db A DB writer. ** @param context A JS context. ** @param name The username to add. ** @param password The user's raw password. ** @return true If the user was added successfully. */ bool tf_ssb_db_register_account(uv_loop_t* loop, sqlite3* db, JSContext* context, const char* name, const char* password); /** ** Get an entry from the properties table. ** @param ssb The SSB instance. ** @param id The user. ** @param key The property key. ** @return The property value or null. Free with tf_free(). */ const char* tf_ssb_db_get_property(tf_ssb_t* ssb, const char* id, const char* key); /** ** Store an entry in the properties table. ** @param ssb The SSB instance. ** @param id The user. ** @param key The property key. ** @param value The property value. ** @return true if the property was stored successfully. */ bool tf_ssb_db_set_property(tf_ssb_t* ssb, const char* id, const char* key, const char* value); /** ** Remove an entry in the properties table. ** @param ssb The SSB instance. ** @param id The user. ** @param key The property key. ** @return true if the property was removed successfully. */ bool tf_ssb_db_remove_property(tf_ssb_t* ssb, const char* id, const char* key); /** ** Remove a value from an entry in the properties table that is a JSON array. ** @param ssb The SSB instance. ** @param id The user. ** @param key The property key. ** @param value The value to remove from the JSON array. ** @return true if the property was updated. */ bool tf_ssb_db_remove_value_from_array_property(tf_ssb_t* ssb, const char* id, const char* key, const char* value); /** ** Ensure a value is in an entry in the properties table that is a JSON array. ** @param ssb The SSB instance. ** @param id The user. ** @param key The property key. ** @param value The value to add to the JSON array. ** @return true if the property was updated. */ bool tf_ssb_db_add_value_to_array_property(tf_ssb_t* ssb, const char* id, const char* key, const char* value); /** ** Resolve a hostname to its index path by global settings. ** @param ssb The SSB instance. ** @param host The hostname. ** @param callback The callback. ** @param user_data The callback user data. */ void tf_ssb_db_resolve_index_async(tf_ssb_t* ssb, const char* host, void (*callback)(const char* path, void* user_data), void* user_data); /** ** Verify an author's feed. ** @param ssb The SSB instance. ** @param id The author'd identity. ** @return true If the feed verified successfully. */ bool tf_ssb_db_verify(tf_ssb_t* ssb, const char* id); /** ** Check if a user has a specific permission. ** @param ssb The SSB instance. ** @param id The user ID. ** @param permission The name of the permission. ** @return true If the user has the requested permission. */ bool tf_ssb_db_user_has_permission(tf_ssb_t* ssb, const char* id, const char* permission); /** ** An SQLite authorizer callback. See https://www.sqlite.org/c3ref/set_authorizer.html for use. ** @param user_data User data registered with the authorizer. ** @param action_code The type of action. ** @param arg0 Depends on the action. ** @param arg1 Depends on the action. ** @param arg2 Depends on the action. ** @param arg3 Depends on the action. ** @return A value indicating whether the operation is allowed. */ int tf_ssb_sqlite_authorizer(void* user_data, int action_code, const char* arg0, const char* arg1, const char* arg2, const char* arg3); /** @} */