2021-01-02 13:10:00 -05:00
# include "ssb.h"
2022-06-04 13:04:51 -04:00
# include "mem.h"
2021-01-02 13:10:00 -05:00
# include "ssb.connections.h"
2021-08-22 15:34:28 -04:00
# include "ssb.db.h"
2022-11-16 20:36:24 -05:00
# include "ssb.rpc.h"
2021-01-02 13:10:00 -05:00
# include "trace.h"
2022-07-09 11:13:35 -04:00
# include "util.js.h"
2021-01-02 13:10:00 -05:00
# include <assert.h>
# include <quickjs.h>
# include <sodium/crypto_auth.h>
# include <sodium/crypto_box.h>
# include <sodium/crypto_hash_sha256.h>
# include <sodium/crypto_scalarmult.h>
# include <sodium/crypto_scalarmult_curve25519.h>
# include <sodium/crypto_secretbox.h>
# include <sodium/crypto_sign.h>
# include <sodium/utils.h>
# include <sqlite3.h>
# include <stdbool.h>
# include <stdio.h>
# include <string.h>
# include <time.h>
# include <uv.h>
2023-01-15 16:23:28 -05:00
# include <backtrace.h>
# ifndef _WIN32
# ifndef __ANDROID__
# include <execinfo.h>
# endif
# include <unistd.h>
# endif
2021-12-21 14:06:44 -05:00
# if !defined(_countof)
# define _countof(a) ((int)(sizeof((a)) / sizeof(*(a))))
# endif
2022-11-02 19:34:44 -04:00
# define GREEN "\e[1;32m"
# define MAGENTA "\e[1;35m"
# define CYAN "\e[1;36m"
# define RESET "\e[0m"
2021-10-24 15:23:21 -04:00
static_assert ( k_id_base64_len = = sodium_base64_ENCODED_LEN ( 9 + crypto_box_PUBLICKEYBYTES , sodium_base64_VARIANT_ORIGINAL ) , " k_id_base64_len " ) ;
static_assert ( k_id_bin_len = = crypto_box_PUBLICKEYBYTES , " k_id_bin_len " ) ;
static_assert ( k_blob_id_len = = ( sodium_base64_ENCODED_LEN ( crypto_hash_sha256_BYTES , sodium_base64_VARIANT_ORIGINAL ) + 8 ) , " k_blob_id_len " ) ;
2021-01-02 13:10:00 -05:00
const uint8_t k_ssb_network [ ] = {
0xd4 , 0xa1 , 0xcb , 0x88 , 0xa6 , 0x6f , 0x02 , 0xf8 ,
0xdb , 0x63 , 0x5c , 0xe2 , 0x64 , 0x41 , 0xcc , 0x5d ,
0xac , 0x1b , 0x08 , 0x42 , 0x0c , 0xea , 0xac , 0x23 ,
0x08 , 0x39 , 0xb7 , 0x55 , 0x84 , 0x5a , 0x9f , 0xfb
} ;
typedef enum {
k_tf_ssb_state_invalid ,
k_tf_ssb_state_connected ,
k_tf_ssb_state_sent_hello ,
k_tf_ssb_state_sent_identity ,
k_tf_ssb_state_verified ,
k_tf_ssb_state_server_wait_hello ,
k_tf_ssb_state_server_wait_client_identity ,
k_tf_ssb_state_server_verified ,
k_tf_ssb_state_closing ,
} tf_ssb_state_t ;
enum {
2021-09-06 13:50:38 -04:00
k_connections_changed_callbacks_max = 8 ,
2023-01-14 08:27:19 -05:00
k_tf_ssb_rpc_message_body_length_max = 1 * 1024 * 1024 ,
2023-01-22 15:37:19 -05:00
k_debug_close_message_count = 32 ,
k_debug_close_connection_count = 8 ,
2021-01-02 13:10:00 -05:00
} ;
typedef struct _tf_ssb_broadcast_t tf_ssb_broadcast_t ;
typedef struct _tf_ssb_connection_t tf_ssb_connection_t ;
typedef struct _tf_ssb_request_t tf_ssb_request_t ;
2023-01-22 15:37:19 -05:00
typedef struct _tf_ssb_debug_message_t
{
bool outgoing ;
int flags ;
int32_t request_number ;
size_t size ;
uint8_t data [ ] ;
} tf_ssb_debug_message_t ;
typedef struct _tf_ssb_debug_close_t
{
char id [ k_id_base64_len ] ;
char tunnel [ k_id_base64_len ] ;
char reason [ 128 ] ;
tf_ssb_debug_message_t * messages [ k_debug_close_message_count ] ;
} tf_ssb_debug_close_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_request_t
{
2021-01-02 13:10:00 -05:00
int32_t request_number ;
tf_ssb_rpc_callback_t * callback ;
2022-11-02 19:34:44 -04:00
tf_ssb_callback_cleanup_t * cleanup ;
2021-01-02 13:10:00 -05:00
void * user_data ;
2022-11-06 21:57:29 -05:00
tf_ssb_connection_t * dependent_connection ;
2021-01-02 13:10:00 -05:00
} tf_ssb_request_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_broadcast_t
{
2021-01-02 13:10:00 -05:00
tf_ssb_broadcast_t * next ;
time_t ctime ;
time_t mtime ;
char host [ 256 ] ;
struct sockaddr_in addr ;
2022-11-02 19:34:44 -04:00
tf_ssb_connection_t * tunnel_connection ;
2021-01-02 13:10:00 -05:00
uint8_t pub [ crypto_sign_PUBLICKEYBYTES ] ;
} tf_ssb_broadcast_t ;
typedef struct _tf_ssb_rpc_callback_node_t tf_ssb_rpc_callback_node_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_rpc_callback_node_t
{
2021-01-02 13:10:00 -05:00
const char * * name ;
2023-02-03 10:06:18 -05:00
const char * flattened_name ;
2021-01-02 13:10:00 -05:00
tf_ssb_rpc_callback_t * callback ;
2021-11-07 17:28:58 -05:00
tf_ssb_callback_cleanup_t * cleanup ;
2021-01-02 13:10:00 -05:00
void * user_data ;
tf_ssb_rpc_callback_node_t * next ;
} tf_ssb_rpc_callback_node_t ;
2021-11-07 17:28:58 -05:00
typedef struct _tf_ssb_connections_changed_callback_node_t tf_ssb_connections_changed_callback_node_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_connections_changed_callback_node_t
{
2021-11-07 17:28:58 -05:00
tf_ssb_connections_changed_callback_t * callback ;
tf_ssb_callback_cleanup_t * cleanup ;
void * user_data ;
tf_ssb_connections_changed_callback_node_t * next ;
} tf_ssb_connections_changed_callback_node_t ;
2021-11-10 19:05:07 -05:00
typedef struct _tf_ssb_message_added_callback_node_t tf_ssb_message_added_callback_node_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_message_added_callback_node_t
{
2021-11-10 19:05:07 -05:00
tf_ssb_message_added_callback_t * callback ;
tf_ssb_callback_cleanup_t * cleanup ;
void * user_data ;
tf_ssb_message_added_callback_node_t * next ;
} tf_ssb_message_added_callback_node_t ;
2021-09-06 13:50:38 -04:00
typedef struct _tf_ssb_blob_want_added_callback_node_t tf_ssb_blob_want_added_callback_node_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_blob_want_added_callback_node_t
{
2021-11-07 17:28:58 -05:00
tf_ssb_blob_want_added_callback_t * callback ;
tf_ssb_callback_cleanup_t * cleanup ;
2021-09-06 13:50:38 -04:00
void * user_data ;
tf_ssb_blob_want_added_callback_node_t * next ;
} tf_ssb_blob_want_added_callback_node_t ;
2021-11-07 17:28:58 -05:00
typedef struct _tf_ssb_broadcasts_changed_callback_node_t tf_ssb_broadcasts_changed_callback_node_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_broadcasts_changed_callback_node_t
{
2021-11-07 17:28:58 -05:00
tf_ssb_broadcasts_changed_callback_t * callback ;
tf_ssb_callback_cleanup_t * cleanup ;
void * user_data ;
tf_ssb_broadcasts_changed_callback_node_t * next ;
} tf_ssb_broadcasts_changed_callback_node_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_t
{
2021-01-02 13:10:00 -05:00
bool own_context ;
JSRuntime * runtime ;
JSContext * context ;
tf_trace_t * trace ;
2023-02-07 20:29:44 -05:00
const char * db_path ;
2021-01-02 13:10:00 -05:00
sqlite3 * db ;
2023-02-07 20:29:44 -05:00
uv_mutex_t db_readers_lock ;
sqlite3 * * db_readers ;
int db_readers_count ;
2021-01-02 13:10:00 -05:00
uv_loop_t own_loop ;
uv_loop_t * loop ;
uv_udp_t broadcast_listener ;
uv_udp_t broadcast_sender ;
2022-01-19 22:35:03 -05:00
uv_timer_t broadcast_cleanup_timer ;
2021-01-02 13:10:00 -05:00
uv_timer_t broadcast_timer ;
2021-12-21 14:06:44 -05:00
uv_timer_t trace_timer ;
2021-01-02 13:10:00 -05:00
uv_tcp_t server ;
uint8_t pub [ crypto_sign_PUBLICKEYBYTES ] ;
uint8_t priv [ crypto_sign_SECRETKEYBYTES ] ;
2022-12-31 13:59:29 -05:00
bool verbose ;
2022-02-05 15:18:58 -05:00
int messages_stored ;
2023-01-18 17:52:54 -05:00
int blobs_stored ;
2022-02-05 15:18:58 -05:00
int rpc_in ;
int rpc_out ;
2021-01-02 13:10:00 -05:00
tf_ssb_connection_t * connections ;
2022-01-12 20:08:17 -05:00
int connections_count ;
2022-07-09 18:00:33 -04:00
int request_count ;
2021-01-02 13:10:00 -05:00
tf_ssb_connections_t * connections_tracker ;
tf_ssb_broadcast_t * broadcasts ;
2022-01-12 20:08:17 -05:00
int broadcasts_count ;
2021-01-02 13:10:00 -05:00
tf_ssb_rpc_callback_node_t * rpc ;
2022-01-12 20:08:17 -05:00
int rpc_count ;
2021-11-07 17:28:58 -05:00
tf_ssb_connections_changed_callback_node_t * connections_changed ;
2022-01-12 20:08:17 -05:00
int connections_changed_count ;
2021-11-10 19:05:07 -05:00
tf_ssb_message_added_callback_node_t * message_added ;
2022-01-12 20:08:17 -05:00
int message_added_count ;
2021-09-06 13:50:38 -04:00
tf_ssb_blob_want_added_callback_node_t * blob_want_added ;
2022-01-12 20:08:17 -05:00
int blob_want_added_count ;
2021-11-07 17:28:58 -05:00
tf_ssb_broadcasts_changed_callback_node_t * broadcasts_changed ;
2022-01-12 20:08:17 -05:00
int broadcasts_changed_count ;
2023-01-22 15:37:19 -05:00
tf_ssb_debug_close_t debug_close [ k_debug_close_connection_count ] ;
2021-01-02 13:10:00 -05:00
} tf_ssb_t ;
2023-01-08 12:45:15 -05:00
typedef struct _tf_ssb_connection_message_request_t
{
char author [ k_id_base64_len ] ;
int32_t request_number ;
bool keys ;
} tf_ssb_connection_message_request_t ;
2023-01-16 21:17:29 -05:00
typedef struct _tf_ssb_connection_scheduled_t
{
tf_ssb_scheduled_callback_t * callback ;
void * user_data ;
} tf_ssb_connection_scheduled_t ;
2022-07-11 21:51:15 -04:00
typedef struct _tf_ssb_connection_t
{
2021-01-02 13:10:00 -05:00
tf_ssb_t * ssb ;
uv_tcp_t tcp ;
uv_connect_t connect ;
2022-01-22 15:13:14 -05:00
uv_async_t async ;
2021-01-02 13:10:00 -05:00
2022-11-02 19:34:44 -04:00
tf_ssb_connection_t * tunnel_connection ;
int32_t tunnel_request_number ;
2023-01-04 19:52:23 -05:00
tf_ssb_blob_wants_t blob_wants ;
2023-01-08 15:01:35 -05:00
bool sent_clock ;
int32_t ebt_request_number ;
JSValue ebt_send_clock ;
2023-01-04 19:52:23 -05:00
2021-09-06 13:50:38 -04:00
JSValue object ;
2022-11-02 19:34:44 -04:00
char name [ 32 ] ;
2021-01-02 13:10:00 -05:00
char host [ 256 ] ;
int port ;
tf_ssb_state_t state ;
2023-01-07 19:25:38 -05:00
bool is_attendant ;
int32_t attendant_request_number ;
2021-01-02 13:10:00 -05:00
uint8_t epub [ crypto_box_PUBLICKEYBYTES ] ;
uint8_t epriv [ crypto_box_SECRETKEYBYTES ] ;
uint8_t serverpub [ crypto_box_PUBLICKEYBYTES ] ;
uint8_t serverepub [ crypto_box_PUBLICKEYBYTES ] ;
uint8_t detached_signature_A [ crypto_sign_BYTES ] ;
uint8_t s_to_c_box_key [ crypto_hash_sha256_BYTES ] ;
uint8_t c_to_s_box_key [ crypto_hash_sha256_BYTES ] ;
2023-01-01 19:58:15 -05:00
uint8_t recv_buffer [ 128 * 1024 ] ;
2021-01-02 13:10:00 -05:00
size_t recv_size ;
uint8_t nonce [ crypto_secretbox_NONCEBYTES ] ;
uint8_t send_nonce [ crypto_secretbox_NONCEBYTES ] ;
uint16_t body_len ;
uint8_t body_auth_tag [ 16 ] ;
uint8_t rpc_recv_buffer [ 8 * 1024 * 1024 ] ;
uint8_t pad ;
size_t rpc_recv_size ;
2023-01-14 08:27:19 -05:00
uint8_t box_stream_buf [ 16 + k_tf_ssb_rpc_message_body_length_max ] ;
uint8_t secretbox_buf [ k_tf_ssb_rpc_message_body_length_max ] ;
2021-01-02 13:10:00 -05:00
uint32_t send_request_number ;
tf_ssb_connection_t * next ;
tf_ssb_request_t * requests ;
2022-07-11 21:51:15 -04:00
int requests_count ;
2022-01-25 20:15:04 -05:00
const char * destroy_reason ;
2023-01-08 12:45:15 -05:00
tf_ssb_connection_message_request_t * message_requests ;
int message_requests_count ;
2023-01-16 21:17:29 -05:00
tf_ssb_connection_scheduled_t * scheduled ;
int scheduled_count ;
2023-01-22 15:37:19 -05:00
tf_ssb_debug_message_t * debug_messages [ k_debug_close_message_count ] ;
2021-01-02 13:10:00 -05:00
} tf_ssb_connection_t ;
2021-09-06 13:50:38 -04:00
static JSClassID _connection_class_id ;
2022-11-02 19:34:44 -04:00
static int s_connection_index ;
static int s_tunnel_index ;
2021-09-06 13:50:38 -04:00
2022-01-25 20:15:04 -05:00
static void _tf_ssb_connection_destroy ( tf_ssb_connection_t * connection , const char * reason ) ;
2022-11-02 19:34:44 -04:00
static void _tf_ssb_connection_client_send_hello ( tf_ssb_connection_t * connection ) ;
2021-01-02 13:10:00 -05:00
static void _tf_ssb_connection_on_close ( uv_handle_t * handle ) ;
static void _tf_ssb_connection_close ( tf_ssb_connection_t * connection , const char * reason ) ;
static void _tf_ssb_nonce_inc ( uint8_t * nonce ) ;
static void _tf_ssb_write ( tf_ssb_connection_t * connection , void * data , size_t size ) ;
2021-09-06 13:50:38 -04:00
static void _tf_ssb_connection_finalizer ( JSRuntime * runtime , JSValue value ) ;
2021-01-02 13:10:00 -05:00
2023-01-22 15:37:19 -05:00
static void _tf_ssb_add_debug_close ( tf_ssb_t * ssb , tf_ssb_connection_t * connection , const char * reason )
{
for ( int i = 0 ; i < k_debug_close_message_count ; i + + )
{
tf_free ( ssb - > debug_close [ k_debug_close_connection_count - 1 ] . messages [ i ] ) ;
}
for ( int i = k_debug_close_connection_count - 1 ; i > 0 ; i - - )
{
ssb - > debug_close [ i ] = ssb - > debug_close [ i - 1 ] ;
}
tf_ssb_id_bin_to_str ( ssb - > debug_close [ 0 ] . id , sizeof ( ssb - > debug_close [ 0 ] . id ) , connection - > serverpub ) ;
if ( connection - > tunnel_connection )
{
tf_ssb_id_bin_to_str ( ssb - > debug_close [ 0 ] . tunnel , sizeof ( ssb - > debug_close [ 0 ] . tunnel ) , connection - > tunnel_connection - > serverpub ) ;
}
else
{
memset ( ssb - > debug_close [ 0 ] . tunnel , 0 , sizeof ( ssb - > debug_close [ 0 ] . tunnel ) ) ;
}
memcpy ( ssb - > debug_close [ 0 ] . messages , connection - > debug_messages , sizeof ( connection - > debug_messages ) ) ;
memset ( connection - > debug_messages , 0 , sizeof ( connection - > debug_messages ) ) ;
snprintf ( ssb - > debug_close [ 0 ] . reason , sizeof ( ssb - > debug_close [ 0 ] . reason ) , " %s " , reason ) ;
}
static void _tf_ssb_connection_add_debug_message ( tf_ssb_connection_t * connection , bool outgoing , int flags , int32_t request_number , const uint8_t * data , size_t size )
{
if ( connection - > debug_messages [ k_debug_close_message_count - 1 ] )
{
tf_free ( connection - > debug_messages [ k_debug_close_message_count - 1 ] ) ;
}
for ( int i = k_debug_close_message_count - 1 ; i > 0 ; i - - )
{
connection - > debug_messages [ i ] = connection - > debug_messages [ i - 1 ] ;
}
tf_ssb_debug_message_t * message = tf_malloc ( sizeof ( tf_ssb_debug_message_t ) + size ) ;
* message = ( tf_ssb_debug_message_t )
{
. outgoing = outgoing ,
. flags = flags ,
. request_number = request_number ,
. size = size ,
} ;
memcpy ( message + 1 , data , size ) ;
connection - > debug_messages [ 0 ] = message ;
}
2021-01-02 13:10:00 -05:00
static void _tf_ssb_connection_send_close ( tf_ssb_connection_t * connection )
{
uint8_t message_enc [ 34 ] ;
uint8_t nonce1 [ crypto_secretbox_NONCEBYTES ] ;
memcpy ( nonce1 , connection - > send_nonce , sizeof ( nonce1 ) ) ;
_tf_ssb_nonce_inc ( connection - > send_nonce ) ;
uint8_t header [ 18 ] = { 0 } ;
2021-10-10 17:51:38 -04:00
if ( crypto_secretbox_easy ( message_enc , header , sizeof ( header ) , nonce1 , connection - > c_to_s_box_key ) = = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_write ( connection , message_enc , sizeof ( message_enc ) ) ;
2021-10-10 17:51:38 -04:00
}
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_close ( connection , " crypto_secretbox_easy close message " ) ;
2021-01-02 13:10:00 -05:00
}
static void _tf_ssb_connection_close ( tf_ssb_connection_t * connection , const char * reason )
{
2021-10-10 17:51:38 -04:00
if ( connection - > state = = k_tf_ssb_state_closing )
{
2021-01-02 13:10:00 -05:00
return ;
2021-10-10 17:51:38 -04:00
}
else if ( connection - > state = = k_tf_ssb_state_verified | |
connection - > state = = k_tf_ssb_state_server_verified )
{
2023-01-10 20:43:35 -05:00
printf ( " Connection %s %p is closing: %s. \n " , connection - > name , connection , reason ) ;
2023-01-22 15:37:19 -05:00
_tf_ssb_add_debug_close ( connection - > ssb , connection , reason ) ;
2021-01-02 13:10:00 -05:00
connection - > state = k_tf_ssb_state_closing ;
_tf_ssb_connection_send_close ( connection ) ;
2021-10-10 17:51:38 -04:00
}
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_destroy ( connection , reason ) ;
2021-01-02 13:10:00 -05:00
}
static void _tf_ssb_connection_on_tcp_alloc ( uv_handle_t * handle , size_t suggested_size , uv_buf_t * buf )
{
tf_ssb_connection_t * connection = handle - > data ;
size_t malloc_size = sizeof ( connection - > recv_buffer ) - connection - > recv_size ;
2022-06-04 13:04:51 -04:00
buf - > base = malloc_size ? tf_malloc ( malloc_size ) : NULL ;
2021-01-02 13:10:00 -05:00
buf - > len = malloc_size ;
}
static void _tf_ssb_connection_on_write ( uv_write_t * req , int status )
{
2022-02-27 14:38:48 -05:00
if ( status )
{
tf_ssb_connection_t * connection = req - > data ;
2022-11-13 17:30:09 -05:00
char buffer [ 256 ] ;
snprintf ( buffer , sizeof ( buffer ) , " write failed asynchronously: %s " , uv_strerror ( status ) ) ;
_tf_ssb_connection_close ( connection , buffer ) ;
2022-02-27 14:38:48 -05:00
}
2022-06-04 13:04:51 -04:00
tf_free ( req ) ;
2021-01-02 13:10:00 -05:00
}
static void _tf_ssb_write ( tf_ssb_connection_t * connection , void * data , size_t size )
{
2022-11-02 19:34:44 -04:00
if ( connection - > tcp . data )
2022-01-19 23:01:45 -05:00
{
2022-11-02 19:34:44 -04:00
uv_write_t * write = tf_malloc ( sizeof ( uv_write_t ) + size ) ;
* write = ( uv_write_t ) { . data = connection } ;
memcpy ( write + 1 , data , size ) ;
int result = uv_write ( write , ( uv_stream_t * ) & connection - > tcp , & ( uv_buf_t ) { . base = ( char * ) ( write + 1 ) , . len = size } , 1 , _tf_ssb_connection_on_write ) ;
if ( result )
{
_tf_ssb_connection_close ( connection , " write failed " ) ;
tf_free ( write ) ;
}
}
else if ( connection - > tunnel_connection )
{
tf_ssb_connection_rpc_send (
connection - > tunnel_connection ,
k_ssb_rpc_flag_binary | k_ssb_rpc_flag_stream ,
- connection - > tunnel_request_number ,
data ,
size ,
NULL ,
NULL ,
NULL ) ;
2022-01-19 23:01:45 -05:00
}
2021-01-02 13:10:00 -05:00
}
static void _tf_ssb_connection_send_identity ( tf_ssb_connection_t * connection , uint8_t * hmac , uint8_t * pubkey )
{
memcpy ( connection - > serverepub , pubkey , sizeof ( connection - > serverepub ) ) ;
2021-10-10 17:51:38 -04:00
if ( crypto_auth_hmacsha512256_verify ( hmac , connection - > serverepub , 32 , k_ssb_network ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " invalid server hello " ) ;
return ;
}
uint8_t shared_secret_ab [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_ab , connection - > epriv , connection - > serverepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_ab as client " ) ;
return ;
}
uint8_t servercurvepub [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_ed25519_pk_to_curve25519 ( servercurvepub , connection - > serverpub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute key to curve25519 as client " ) ;
return ;
}
uint8_t shared_secret_aB [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_aB , connection - > epriv , servercurvepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_aB as client " ) ;
return ;
}
uint8_t hash [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( hash , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
uint8_t msg [ sizeof ( k_ssb_network ) + sizeof ( connection - > serverpub ) + crypto_hash_sha256_BYTES ] ;
memcpy ( msg , k_ssb_network , sizeof ( k_ssb_network ) ) ;
memcpy ( msg + sizeof ( k_ssb_network ) , connection - > serverpub , sizeof ( connection - > serverpub ) ) ;
memcpy ( msg + sizeof ( k_ssb_network ) + sizeof ( connection - > serverpub ) , hash , sizeof ( hash ) ) ;
unsigned long long siglen ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_detached ( connection - > detached_signature_A , & siglen , msg , sizeof ( msg ) , connection - > ssb - > priv ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute detached_signature_A as client " ) ;
return ;
}
uint8_t tosend [ crypto_sign_BYTES + sizeof ( connection - > ssb - > pub ) ] ;
memcpy ( tosend , connection - > detached_signature_A , sizeof ( connection - > detached_signature_A ) ) ;
memcpy ( tosend + sizeof ( connection - > detached_signature_A ) , connection - > ssb - > pub , sizeof ( connection - > ssb - > pub ) ) ;
uint8_t nonce [ crypto_secretbox_NONCEBYTES ] = { 0 } ;
uint8_t tohash [ sizeof ( k_ssb_network ) + sizeof ( shared_secret_ab ) + sizeof ( shared_secret_aB ) ] ;
memcpy ( tohash , k_ssb_network , sizeof ( k_ssb_network ) ) ;
memcpy ( tohash + sizeof ( k_ssb_network ) , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
memcpy ( tohash + sizeof ( k_ssb_network ) + sizeof ( shared_secret_ab ) , shared_secret_aB , sizeof ( shared_secret_aB ) ) ;
uint8_t hash2 [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( hash2 , tohash , sizeof ( tohash ) ) ;
uint8_t c [ crypto_secretbox_MACBYTES + sizeof ( tosend ) ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_secretbox_easy ( c , tosend , sizeof ( tosend ) , nonce , hash2 ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to create initial secretbox as client " ) ;
return ;
}
static_assert ( sizeof ( c ) = = 112 , " client send size " ) ;
_tf_ssb_write ( connection , c , sizeof ( c ) ) ;
connection - > state = k_tf_ssb_state_sent_identity ;
}
static void _tf_ssb_nonce_inc ( uint8_t * nonce )
{
int i = 23 ;
2021-10-10 17:51:38 -04:00
while ( + + nonce [ i ] = = 0 & & i > 0 )
{
2021-01-02 13:10:00 -05:00
i - - ;
}
}
static void _tf_ssb_connection_box_stream_send ( tf_ssb_connection_t * connection , const uint8_t * message , size_t size )
{
2023-01-14 08:27:19 -05:00
const size_t k_send_max = 65535 ;
for ( size_t offset = 0 ; offset < size ; offset + = k_send_max )
{
size_t send_size = size - offset > k_send_max ? k_send_max : size - offset ;
uint8_t * message_enc = tf_malloc ( send_size + 34 ) ;
2021-01-02 13:10:00 -05:00
2023-01-14 08:27:19 -05:00
uint8_t nonce1 [ crypto_secretbox_NONCEBYTES ] ;
memcpy ( nonce1 , connection - > send_nonce , sizeof ( nonce1 ) ) ;
_tf_ssb_nonce_inc ( connection - > send_nonce ) ;
uint8_t nonce2 [ crypto_secretbox_NONCEBYTES ] ;
memcpy ( nonce2 , connection - > send_nonce , sizeof ( nonce2 ) ) ;
_tf_ssb_nonce_inc ( connection - > send_nonce ) ;
2021-01-02 13:10:00 -05:00
2023-01-14 08:27:19 -05:00
if ( crypto_secretbox_easy ( message_enc + 34 - 16 , message + offset , send_size , nonce2 , connection - > c_to_s_box_key ) ! = 0 )
{
_tf_ssb_connection_close ( connection , " unable to secretbox message " ) ;
tf_free ( message_enc ) ;
return ;
}
2021-01-02 13:10:00 -05:00
2023-01-14 08:27:19 -05:00
uint8_t header [ 18 ] ;
* ( uint16_t * ) header = htons ( ( uint16_t ) send_size ) ;
memcpy ( header + sizeof ( uint16_t ) , message_enc + 34 - 16 , 16 ) ;
if ( crypto_secretbox_easy ( message_enc , header , sizeof ( header ) , nonce1 , connection - > c_to_s_box_key ) ! = 0 )
{
_tf_ssb_connection_close ( connection , " unable to secretbox header " ) ;
tf_free ( message_enc ) ;
return ;
}
2023-01-13 19:55:51 -05:00
2023-01-14 08:27:19 -05:00
_tf_ssb_write ( connection , message_enc , send_size + 34 ) ;
2022-06-04 13:04:51 -04:00
tf_free ( message_enc ) ;
2021-01-02 13:10:00 -05:00
}
}
2023-01-16 21:17:29 -05:00
void tf_ssb_connection_schedule_idle ( tf_ssb_connection_t * connection , tf_ssb_scheduled_callback_t * callback , void * user_data )
{
connection - > scheduled = tf_resize_vec ( connection - > scheduled , sizeof ( tf_ssb_connection_scheduled_t ) * ( connection - > scheduled_count + 1 ) ) ;
connection - > scheduled [ connection - > scheduled_count + + ] = ( tf_ssb_connection_scheduled_t )
{
. callback = callback ,
. user_data = user_data ,
} ;
uv_async_send ( & connection - > async ) ;
}
2022-07-11 21:51:15 -04:00
static int _request_compare ( const void * a , const void * b )
{
int32_t ai = * ( const int32_t * ) a ;
const tf_ssb_request_t * br = ( const tf_ssb_request_t * ) b ;
return ai < br - > request_number ? - 1 : br - > request_number < ai ? 1 : 0 ;
}
2021-01-02 13:10:00 -05:00
static bool _tf_ssb_connection_get_request_callback ( tf_ssb_connection_t * connection , int32_t request_number , tf_ssb_rpc_callback_t * * out_callback , void * * out_user_data )
{
2022-07-11 21:51:15 -04:00
if ( ! connection - > requests )
{
return false ;
}
tf_ssb_request_t * request = bsearch ( & request_number , connection - > requests , connection - > requests_count , sizeof ( tf_ssb_request_t ) , _request_compare ) ;
if ( request )
2021-10-10 17:51:38 -04:00
{
2022-07-11 21:51:15 -04:00
if ( out_callback )
2021-10-10 17:51:38 -04:00
{
2022-07-11 21:51:15 -04:00
* out_callback = request - > callback ;
}
if ( out_user_data )
{
* out_user_data = request - > user_data ;
2021-01-02 13:10:00 -05:00
}
2022-07-11 21:51:15 -04:00
return true ;
2021-01-02 13:10:00 -05:00
}
2022-07-11 21:51:15 -04:00
return false ;
2021-01-02 13:10:00 -05:00
}
2022-11-06 21:57:29 -05:00
void tf_ssb_connection_add_request ( tf_ssb_connection_t * connection , int32_t request_number , tf_ssb_rpc_callback_t * callback , tf_ssb_callback_cleanup_t * cleanup , void * user_data , tf_ssb_connection_t * dependent_connection )
2021-01-02 13:10:00 -05:00
{
2023-01-18 18:43:49 -05:00
tf_ssb_connection_remove_request ( connection , request_number ) ;
2022-07-11 21:51:15 -04:00
tf_ssb_request_t request =
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
. request_number = request_number ,
. callback = callback ,
2022-11-02 19:34:44 -04:00
. cleanup = cleanup ,
2021-01-02 13:10:00 -05:00
. user_data = user_data ,
2022-11-06 21:57:29 -05:00
. dependent_connection = dependent_connection ,
2021-01-02 13:10:00 -05:00
} ;
2022-07-11 21:51:15 -04:00
int index = tf_util_insert_index ( & request_number , connection - > requests , connection - > requests_count , sizeof ( tf_ssb_request_t ) , _request_compare ) ;
connection - > requests = tf_resize_vec ( connection - > requests , sizeof ( tf_ssb_request_t ) * ( connection - > requests_count + 1 ) ) ;
if ( connection - > requests_count - index )
{
memmove ( connection - > requests + index + 1 , connection - > requests + index , sizeof ( tf_ssb_request_t ) * ( connection - > requests_count - index ) ) ;
}
connection - > requests [ index ] = request ;
connection - > requests_count + + ;
2022-07-09 18:00:33 -04:00
connection - > ssb - > request_count + + ;
2021-01-02 13:10:00 -05:00
}
2023-01-08 12:45:15 -05:00
static int _message_request_compare ( const void * a , const void * b )
{
const char * author = a ;
const tf_ssb_connection_message_request_t * rb = b ;
return strcmp ( author , rb - > author ) ;
}
void tf_ssb_connection_add_new_message_request ( tf_ssb_connection_t * connection , const char * author , int32_t request_number , bool keys )
{
int index = tf_util_insert_index ( author , connection - > message_requests , connection - > message_requests_count , sizeof ( tf_ssb_connection_message_request_t ) , _message_request_compare ) ;
if ( index < connection - > message_requests_count & & strcmp ( author , connection - > message_requests [ index ] . author ) = = 0 )
{
2023-01-08 15:01:35 -05:00
connection - > message_requests [ index ] . request_number = request_number ;
connection - > message_requests [ index ] . keys = keys ;
2023-01-08 12:45:15 -05:00
return ;
}
connection - > message_requests = tf_resize_vec ( connection - > message_requests , sizeof ( tf_ssb_connection_message_request_t ) * ( connection - > message_requests_count + 1 ) ) ;
if ( connection - > message_requests_count - index )
{
memmove ( connection - > message_requests + index + 1 , connection - > message_requests + index , sizeof ( tf_ssb_connection_message_request_t ) * ( connection - > message_requests_count - index ) ) ;
}
connection - > message_requests [ index ] = ( tf_ssb_connection_message_request_t )
{
. request_number = request_number ,
. keys = keys ,
} ;
snprintf ( connection - > message_requests [ index ] . author , sizeof ( connection - > message_requests [ index ] . author ) , " %s " , author ) ;
connection - > message_requests_count + + ;
}
2023-01-08 15:01:35 -05:00
void tf_ssb_connection_remove_new_message_request ( tf_ssb_connection_t * connection , const char * author )
{
int index = tf_util_insert_index ( author , connection - > message_requests , connection - > message_requests_count , sizeof ( tf_ssb_connection_message_request_t ) , _message_request_compare ) ;
if ( index < connection - > message_requests_count & & strcmp ( author , connection - > message_requests [ index ] . author ) = = 0 )
{
2023-01-24 12:38:45 -05:00
memmove ( connection - > message_requests + index , connection - > message_requests + index + 1 , sizeof ( tf_ssb_connection_message_request_t ) * ( connection - > message_requests_count - index - 1 ) ) ;
2023-01-08 15:01:35 -05:00
connection - > message_requests_count - - ;
}
}
2023-01-18 18:43:49 -05:00
void tf_ssb_connection_remove_request ( tf_ssb_connection_t * connection , int32_t request_number )
2021-01-02 13:10:00 -05:00
{
2022-07-11 21:51:15 -04:00
tf_ssb_request_t * request = bsearch ( & request_number , connection - > requests , connection - > requests_count , sizeof ( tf_ssb_request_t ) , _request_compare ) ;
if ( request )
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
if ( request - > cleanup )
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
request - > cleanup ( connection - > ssb , request - > user_data ) ;
2021-01-02 13:10:00 -05:00
}
2022-07-11 21:51:15 -04:00
int index = request - connection - > requests ;
memmove ( request , request + 1 , sizeof ( tf_ssb_request_t ) * ( connection - > requests_count - index - 1 ) ) ;
connection - > requests_count - - ;
connection - > requests = tf_resize_vec ( connection - > requests , sizeof ( tf_ssb_request_t ) * connection - > requests_count ) ;
connection - > ssb - > request_count - - ;
2021-01-02 13:10:00 -05:00
}
}
2022-11-02 19:34:44 -04:00
void tf_ssb_connection_rpc_send ( tf_ssb_connection_t * connection , uint8_t flags , int32_t request_number , const uint8_t * message , size_t size , tf_ssb_rpc_callback_t * callback , tf_ssb_callback_cleanup_t * cleanup , void * user_data )
2021-01-02 13:10:00 -05:00
{
2022-01-22 17:26:39 -05:00
if ( ! connection )
{
2023-02-14 21:34:46 -05:00
if ( cleanup )
{
cleanup ( NULL , user_data ) ;
}
2022-01-22 17:26:39 -05:00
return ;
}
2022-06-04 13:04:51 -04:00
uint8_t * combined = tf_malloc ( 9 + size ) ;
2021-01-02 13:10:00 -05:00
* combined = flags ;
uint32_t u32size = htonl ( ( uint32_t ) size ) ;
memcpy ( combined + 1 , & u32size , sizeof ( u32size ) ) ;
uint32_t rn = htonl ( ( uint32_t ) request_number ) ;
memcpy ( combined + 1 + sizeof ( uint32_t ) , & rn , sizeof ( rn ) ) ;
memcpy ( combined + 1 + 2 * sizeof ( uint32_t ) , message , size ) ;
2022-12-31 13:59:29 -05:00
if ( connection - > ssb - > verbose )
{
2023-01-01 17:42:31 -05:00
printf ( MAGENTA " %s RPC SEND " RESET " flags=%x RN=%d: [%zd B] %.*s \n " , connection - > name , flags , request_number , size , ( flags & k_ssb_rpc_mask_type ) = = k_ssb_rpc_flag_binary ? 0 : ( int ) size , message ) ;
2022-12-31 13:59:29 -05:00
}
2023-01-22 15:37:19 -05:00
_tf_ssb_connection_add_debug_message ( connection , true , flags , request_number , message , size ) ;
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_box_stream_send ( connection , combined , 1 + 2 * sizeof ( uint32_t ) + size ) ;
2022-06-04 13:04:51 -04:00
tf_free ( combined ) ;
2022-02-05 15:18:58 -05:00
connection - > ssb - > rpc_out + + ;
2023-02-14 21:34:46 -05:00
if ( request_number > 0 & & callback )
{
tf_ssb_connection_add_request ( connection , request_number , callback , cleanup , user_data , NULL ) ;
}
else if ( cleanup )
{
cleanup ( connection - > ssb , user_data ) ;
}
2021-01-02 13:10:00 -05:00
}
2023-01-07 19:25:38 -05:00
void tf_ssb_connection_rpc_send_json ( tf_ssb_connection_t * connection , uint8_t flags , int32_t request_number , JSValue message , tf_ssb_rpc_callback_t * callback , tf_ssb_callback_cleanup_t * cleanup , void * user_data )
{
JSContext * context = connection - > ssb - > context ;
JSValue json = JS_JSONStringify ( context , message , JS_NULL , JS_NULL ) ;
size_t size = 0 ;
const char * json_string = JS_ToCStringLen ( context , & size , json ) ;
tf_ssb_connection_rpc_send (
connection ,
2023-01-09 17:37:34 -05:00
k_ssb_rpc_flag_json | ( flags & k_ssb_rpc_flag_stream ) | ( flags & k_ssb_rpc_flag_end_error ) ,
2023-01-07 19:25:38 -05:00
request_number ,
( const uint8_t * ) json_string ,
size ,
callback ,
cleanup ,
user_data ) ;
JS_FreeCString ( context , json_string ) ;
JS_FreeValue ( context , json ) ;
}
2023-01-15 16:23:28 -05:00
static int _tf_ssb_backtrace_callback ( void * data , uintptr_t pc , const char * filename , int line_number , const char * function )
{
char * * stack = data ;
char line [ 256 ] ;
int length = snprintf ( line , sizeof ( line ) , " %p %s:%d %s \n " , ( void * ) pc , filename , line_number , function ) ;
int current = * stack ? strlen ( * stack ) : 0 ;
* stack = tf_resize_vec ( * stack , current + length + 1 ) ;
memcpy ( * stack + current , line , length + 1 ) ;
return 0 ;
}
static void _tf_ssb_backtrace_error ( void * data , const char * message , int error )
{
char * * stack = data ;
int length = strlen ( message ) ;
if ( message )
{
int current = * stack ? strlen ( * stack ) : 0 ;
* stack = tf_resize_vec ( * stack , current + length + 1 ) ;
memcpy ( * stack + current , message , length + 1 ) ;
}
}
static char * _tf_ssb_backtrace_string ( )
{
extern struct backtrace_state * g_backtrace_state ;
int count = 0 ;
void * buffer [ 32 ] ;
char * string = NULL ;
# ifdef _WIN32
count = CaptureStackBackTrace ( 0 , sizeof ( buffer ) / sizeof ( * buffer ) , buffer , NULL ) ;
# elif !defined(__ANDROID__)
count = backtrace ( buffer , sizeof ( buffer ) / sizeof ( * buffer ) ) ;
# endif
for ( int i = 0 ; i < count ; i + + )
{
backtrace_pcinfo (
g_backtrace_state ,
( uintptr_t ) buffer [ i ] ,
_tf_ssb_backtrace_callback ,
_tf_ssb_backtrace_error ,
& string ) ;
}
return string ;
}
2023-01-07 19:25:38 -05:00
void tf_ssb_connection_rpc_send_error ( tf_ssb_connection_t * connection , uint8_t flags , int32_t request_number , const char * error )
{
JSContext * context = connection - > ssb - > context ;
JSValue message = JS_NewObject ( context ) ;
2023-01-15 16:23:28 -05:00
char * stack = _tf_ssb_backtrace_string ( ) ;
2023-01-07 19:25:38 -05:00
JS_SetPropertyStr ( context , message , " name " , JS_NewString ( context , " Error " ) ) ;
2023-01-15 16:23:28 -05:00
JS_SetPropertyStr ( context , message , " stack " , JS_NewString ( context , stack ) ) ;
2023-01-07 19:25:38 -05:00
JS_SetPropertyStr ( context , message , " message " , JS_NewString ( context , error ) ) ;
2023-01-15 16:23:28 -05:00
tf_ssb_connection_rpc_send_json ( connection , ( ( flags & k_ssb_rpc_flag_stream ) ? ( k_ssb_rpc_flag_stream | k_ssb_rpc_flag_end_error ) : 0 ) , request_number , message , NULL , NULL , NULL ) ;
2023-01-07 19:25:38 -05:00
JS_FreeValue ( context , message ) ;
2023-01-15 16:23:28 -05:00
tf_free ( stack ) ;
2023-01-07 19:25:38 -05:00
}
void tf_ssb_connection_rpc_send_error_method_not_allowed ( tf_ssb_connection_t * connection , uint8_t flags , int32_t request_number )
{
2023-01-15 16:23:28 -05:00
tf_ssb_connection_rpc_send_error ( connection , flags , request_number , " method is not in list of allowed methods " ) ;
2023-01-07 19:25:38 -05:00
}
2022-02-09 22:58:33 -05:00
static int _utf8_len ( uint8_t ch )
{
static const uint8_t k_length [ ] =
{
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 2 , 2 , 3 , 4
} ;
return k_length [ ( ch & 0xf0 ) > > 4 ] ;
}
static uint32_t _utf8_decode ( uint32_t c )
{
if ( c > 0x7f )
{
uint32_t mask = ( c < = 0x00efbfbf ) ? 0x000f0000 : 0x003f0000 ;
c = ( ( c & 0x07000000 ) > > 6 ) |
( ( c & mask ) > > 4 ) |
( ( c & 0x00003f00 ) > > 2 ) |
( c & 0x0000003f ) ;
}
return c ;
}
static const uint8_t * _utf8_to_cp ( const uint8_t * ch , uint32_t * out_cp )
{
int len = _utf8_len ( * ch ) ;
int actual_len = 0 ;
uint32_t encoding = 0 ;
for ( int i = 0 ; i < len & & ch [ i ] ; i + + , actual_len + + )
{
encoding = ( encoding < < 8 ) | ch [ i ] ;
}
* out_cp = _utf8_decode ( encoding ) ;
return ch + actual_len ;
}
2022-02-10 21:44:27 -05:00
static uint32_t _cp_to_utf16 ( uint32_t cp , uint16_t * out_h , uint16_t * out_l )
{
if ( cp < 0x10000 )
{
* out_h = 0 ;
* out_l = cp & 0xffff ;
return cp ;
}
else
{
uint32_t t = cp - 0x10000 ;
uint32_t h = ( ( t < < 12 ) > > 22 ) + 0xd800 ;
uint32_t l = ( ( t < < 22 ) > > 22 ) + 0xdc00 ;
* out_h = h & 0xffff ;
* out_l = l & 0xffff ;
return ( h < < 16 ) | ( l & 0xffff ) ;
}
}
2021-01-02 13:10:00 -05:00
void tf_ssb_calculate_message_id ( JSContext * context , JSValue message , char * out_id , size_t out_id_size )
{
JSValue idval = JS_JSONStringify ( context , message , JS_NULL , JS_NewInt32 ( context , 2 ) ) ;
size_t len = 0 ;
const char * messagestr = JS_ToCStringLen ( context , & len , idval ) ;
2023-01-13 19:55:51 -05:00
if ( ! messagestr )
{
memset ( out_id , 0 , out_id_size ) ;
JS_FreeValue ( context , idval ) ;
return ;
}
2022-02-09 22:58:33 -05:00
2022-06-04 13:04:51 -04:00
char * latin1 = tf_strdup ( messagestr ) ;
2022-02-09 22:58:33 -05:00
uint8_t * write_pos = ( uint8_t * ) latin1 ;
const uint8_t * p = ( const uint8_t * ) messagestr ;
while ( p & & * p )
{
uint32_t cp = 0 ;
p = _utf8_to_cp ( p , & cp ) ;
2022-02-10 21:44:27 -05:00
uint16_t h = 0 ;
uint16_t l = 0 ;
_cp_to_utf16 ( cp , & h , & l ) ;
if ( h )
{
* write_pos + + = h & 0xff ;
}
if ( l )
{
* write_pos + + = l & 0xff ;
}
2022-02-09 22:58:33 -05:00
}
size_t latin1_len = write_pos - ( uint8_t * ) latin1 ;
* write_pos + + = ' \0 ' ;
2021-01-02 13:10:00 -05:00
uint8_t id [ crypto_hash_sha256_BYTES ] ;
2022-02-09 22:58:33 -05:00
crypto_hash_sha256 ( id , ( uint8_t * ) latin1 , latin1_len ) ;
2021-01-02 13:10:00 -05:00
char id_base64 [ k_id_base64_len ] ;
2023-02-13 22:15:24 -05:00
tf_base64_encode ( id , sizeof ( id ) , id_base64 , sizeof ( id_base64 ) ) ;
2021-01-02 13:10:00 -05:00
snprintf ( out_id , out_id_size , " %%%s.sha256 " , id_base64 ) ;
2022-06-04 13:04:51 -04:00
tf_free ( latin1 ) ;
2021-01-02 13:10:00 -05:00
JS_FreeCString ( context , messagestr ) ;
JS_FreeValue ( context , idval ) ;
}
2022-02-09 22:58:33 -05:00
static bool _tf_ssb_verify_and_strip_signature_internal ( JSContext * context , JSValue val , char * out_id , size_t out_id_size , char * out_signature , size_t out_signature_size )
2021-01-02 13:10:00 -05:00
{
JSValue signature = JS_GetPropertyStr ( context , val , " signature " ) ;
2023-01-13 19:55:51 -05:00
if ( JS_IsUndefined ( signature ) )
{
memset ( out_signature , 0 , out_signature_size ) ;
return false ;
}
2021-01-02 13:10:00 -05:00
const char * str = JS_ToCString ( context , signature ) ;
2023-01-13 19:55:51 -05:00
if ( ! str )
{
JS_FreeValue ( context , signature ) ;
memset ( out_signature , 0 , out_signature_size ) ;
return false ;
}
bool verified = false ;
tf_ssb_calculate_message_id ( context , val , out_id , out_id_size ) ;
2021-01-02 13:10:00 -05:00
JSAtom sigatom = JS_NewAtom ( context , " signature " ) ;
JS_DeleteProperty ( context , val , sigatom , 0 ) ;
JS_FreeAtom ( context , sigatom ) ;
2021-10-10 17:51:38 -04:00
if ( out_signature )
{
2021-01-02 13:10:00 -05:00
memset ( out_signature , 0 , out_signature_size ) ;
strncpy ( out_signature , str , out_signature_size - 1 ) ;
}
JSValue sigval = JS_JSONStringify ( context , val , JS_NULL , JS_NewInt32 ( context , 2 ) ) ;
const char * sigstr = JS_ToCString ( context , sigval ) ;
const char * sigkind = strstr ( str , " .sig.ed25519 " ) ;
JSValue authorval = JS_GetPropertyStr ( context , val , " author " ) ;
const char * author = JS_ToCString ( context , authorval ) ;
const char * author_id = author & & * author = = ' @ ' ? author + 1 : author ;
const char * type = strstr ( author_id , " .ed25519 " ) ;
uint8_t publickey [ crypto_box_PUBLICKEYBYTES ] ;
2023-02-13 22:15:24 -05:00
int r = tf_base64_decode ( author_id , type - author_id , publickey , sizeof ( publickey ) ) ;
2021-10-10 17:51:38 -04:00
if ( r ! = - 1 )
{
2021-01-02 13:10:00 -05:00
uint8_t binsig [ crypto_sign_BYTES ] ;
2023-02-13 22:15:24 -05:00
r = tf_base64_decode ( str , sigkind - str , binsig , sizeof ( binsig ) ) ;
2021-10-10 17:51:38 -04:00
if ( r ! = - 1 )
{
2021-01-02 13:10:00 -05:00
r = crypto_sign_verify_detached ( binsig , ( const uint8_t * ) sigstr , strlen ( sigstr ) , publickey ) ;
verified = r = = 0 ;
2021-10-10 17:51:38 -04:00
if ( ! verified )
{
2022-02-09 22:58:33 -05:00
//printf("crypto_sign_verify_detached fail (r=%d)\n", r);
2021-12-27 17:00:37 -05:00
if ( false )
{
printf ( " val=[%.*s] \n " , ( int ) strlen ( sigstr ) , sigstr ) ;
printf ( " sig=%.*s \n " , ( int ) ( sigkind - str ) , str ) ;
printf ( " public key=%.*s \n " , ( int ) ( type - author_id ) , author_id ) ;
}
2021-01-02 13:10:00 -05:00
}
2021-10-10 17:51:38 -04:00
}
else
{
2022-02-02 21:14:50 -05:00
printf ( " base64 decode sig fail [%.*s] \n " , ( int ) ( sigkind - str ) , str ) ;
2021-01-02 13:10:00 -05:00
}
2021-10-10 17:51:38 -04:00
}
else
{
2021-10-27 22:19:57 -04:00
printf ( " base64 decode author[%.*s] fail (%d) \n " , ( int ) ( type - author_id ) , author_id , r ) ;
2021-01-02 13:10:00 -05:00
}
JS_FreeCString ( context , author ) ;
JS_FreeCString ( context , sigstr ) ;
JS_FreeCString ( context , str ) ;
JS_FreeValue ( context , sigval ) ;
JS_FreeValue ( context , authorval ) ;
2022-02-02 21:38:05 -05:00
if ( verified )
{
JS_FreeValue ( context , signature ) ;
}
else
{
JS_SetPropertyStr ( context , val , " signature " , signature ) ;
}
2021-01-02 13:10:00 -05:00
return verified ;
}
2022-02-09 22:58:33 -05:00
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 )
2022-02-02 21:00:05 -05:00
{
2022-02-09 22:58:33 -05:00
if ( _tf_ssb_verify_and_strip_signature_internal ( context , val , out_id , out_id_size , out_signature , out_signature_size ) )
2022-02-02 21:00:05 -05:00
{
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 " ) ) ;
2022-02-09 22:58:33 -05:00
bool result = _tf_ssb_verify_and_strip_signature_internal ( context , reordered , out_id , out_id_size , out_signature , out_signature_size ) ;
2022-02-02 21:00:05 -05:00
JS_FreeValue ( context , reordered ) ;
if ( result )
{
* out_sequence_before_author = true ;
return true ;
}
}
return false ;
}
2023-01-07 19:44:36 -05:00
void tf_ssb_close_all ( tf_ssb_t * ssb )
{
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
_tf_ssb_connection_close ( connection , " tf_ssb_close_all " ) ;
}
}
2021-01-02 13:10:00 -05:00
void tf_ssb_send_close ( tf_ssb_t * ssb )
{
2021-10-10 17:51:38 -04:00
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_send_close ( connection ) ;
}
}
bool tf_ssb_id_bin_to_str ( char * str , size_t str_size , const uint8_t * bin )
{
char buffer [ k_id_base64_len - 9 ] ;
2023-02-13 22:15:24 -05:00
tf_base64_encode ( bin , crypto_sign_PUBLICKEYBYTES , buffer , sizeof ( buffer ) ) ;
2021-01-02 13:10:00 -05:00
return snprintf ( str , str_size , " @%s.ed25519 " , buffer ) < ( int ) str_size ;
}
bool tf_ssb_id_str_to_bin ( uint8_t * bin , const char * str )
{
const char * author_id = str & & * str = = ' @ ' ? str + 1 : str ;
const char * type = strstr ( str , " .ed25519 " ) ;
2023-02-13 22:15:24 -05:00
return tf_base64_decode ( author_id , type - author_id , bin , crypto_box_PUBLICKEYBYTES ) ! = 0 ;
2021-01-02 13:10:00 -05:00
}
2021-11-07 17:28:58 -05:00
static void _tf_ssb_notify_connections_changed ( tf_ssb_t * ssb , tf_ssb_change_t change , tf_ssb_connection_t * connection )
{
2021-12-27 17:28:27 -05:00
tf_ssb_connections_changed_callback_node_t * next = NULL ;
for ( tf_ssb_connections_changed_callback_node_t * node = ssb - > connections_changed ; node ; node = next )
2021-11-07 17:28:58 -05:00
{
2021-12-27 17:28:27 -05:00
next = node - > next ;
2023-02-03 10:06:18 -05:00
tf_trace_begin ( ssb - > trace , " connections_changed " ) ;
2021-11-07 17:28:58 -05:00
node - > callback ( ssb , change , connection , node - > user_data ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( ssb - > trace ) ;
2021-11-07 17:28:58 -05:00
}
}
2021-01-02 13:10:00 -05:00
static void _tf_ssb_connection_verify_identity ( tf_ssb_connection_t * connection , const uint8_t * message , size_t len )
{
uint8_t nonce [ crypto_secretbox_NONCEBYTES ] = { 0 } ;
uint8_t shared_secret_ab [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_ab , connection - > epriv , connection - > serverepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_ab " ) ;
return ;
}
uint8_t servercurvepub [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_ed25519_pk_to_curve25519 ( servercurvepub , connection - > serverpub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to convert key to curve25519 " ) ;
return ;
}
uint8_t shared_secret_aB [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_aB , connection - > epriv , servercurvepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_aB " ) ;
return ;
}
uint8_t clientcurvepriv [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_ed25519_sk_to_curve25519 ( clientcurvepriv , connection - > ssb - > priv ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to convert key to curve25519 " ) ;
return ;
}
uint8_t shared_secret_Ab [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_Ab , clientcurvepriv , connection - > serverepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_Ab " ) ;
return ;
}
uint8_t tohash [ sizeof ( k_ssb_network ) + sizeof ( shared_secret_ab ) + sizeof ( shared_secret_aB ) + sizeof ( shared_secret_Ab ) ] ;
memcpy ( tohash , k_ssb_network , sizeof ( k_ssb_network ) ) ;
memcpy ( tohash + sizeof ( k_ssb_network ) , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
memcpy ( tohash + sizeof ( k_ssb_network ) + sizeof ( shared_secret_ab ) , shared_secret_aB , sizeof ( shared_secret_aB ) ) ;
memcpy ( tohash + sizeof ( k_ssb_network ) + sizeof ( shared_secret_ab ) + sizeof ( shared_secret_aB ) , shared_secret_Ab , sizeof ( shared_secret_Ab ) ) ;
uint8_t hash2 [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( hash2 , tohash , sizeof ( tohash ) ) ;
uint8_t hash3a [ crypto_hash_sha256_BYTES + crypto_sign_PUBLICKEYBYTES ] ;
crypto_hash_sha256 ( hash3a , hash2 , sizeof ( hash2 ) ) ;
memcpy ( hash3a + crypto_hash_sha256_BYTES , connection - > ssb - > pub , sizeof ( connection - > ssb - > pub ) ) ;
crypto_hash_sha256 ( connection - > s_to_c_box_key , hash3a , sizeof ( hash3a ) ) ;
uint8_t hash3b [ crypto_hash_sha256_BYTES + crypto_sign_PUBLICKEYBYTES ] ;
crypto_hash_sha256 ( hash3b , hash2 , sizeof ( hash2 ) ) ;
memcpy ( hash3b + crypto_hash_sha256_BYTES , connection - > serverpub , sizeof ( connection - > serverpub ) ) ;
crypto_hash_sha256 ( connection - > c_to_s_box_key , hash3b , sizeof ( hash3b ) ) ;
uint8_t m [ 80 ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_secretbox_open_easy ( m , message , len , nonce , hash2 ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to open initial secret box as client " ) ;
return ;
}
uint8_t hash3 [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( hash3 , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
uint8_t msg [ sizeof ( k_ssb_network ) + sizeof ( connection - > detached_signature_A ) + sizeof ( connection - > ssb - > pub ) + sizeof ( hash3 ) ] ;
memcpy ( msg , k_ssb_network , sizeof ( k_ssb_network ) ) ;
memcpy ( msg + sizeof ( k_ssb_network ) , connection - > detached_signature_A , sizeof ( connection - > detached_signature_A ) ) ;
memcpy ( msg + sizeof ( k_ssb_network ) + sizeof ( connection - > detached_signature_A ) , connection - > ssb - > pub , sizeof ( connection - > ssb - > pub ) ) ;
memcpy ( msg + sizeof ( k_ssb_network ) + sizeof ( connection - > detached_signature_A ) + sizeof ( connection - > ssb - > pub ) , hash3 , sizeof ( hash3 ) ) ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_verify_detached ( m , msg , sizeof ( msg ) , connection - > serverpub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to verify server identity " ) ;
return ;
}
uint8_t nonce2 [ crypto_auth_hmacsha512256_BYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_auth_hmacsha512256 ( nonce2 , connection - > epub , sizeof ( connection - > epub ) , k_ssb_network ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute client recv nonce " ) ;
return ;
}
memcpy ( connection - > nonce , nonce2 , sizeof ( connection - > nonce ) ) ;
uint8_t nonce3 [ crypto_auth_hmacsha512256_BYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_auth_hmacsha512256 ( nonce3 , connection - > serverepub , sizeof ( connection - > serverepub ) , k_ssb_network ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute client send nonce " ) ;
return ;
}
memcpy ( connection - > send_nonce , nonce3 , sizeof ( connection - > send_nonce ) ) ;
char fullid [ k_id_base64_len ] ;
tf_ssb_id_bin_to_str ( fullid , sizeof ( fullid ) , connection - > serverpub ) ;
2021-09-06 17:21:51 -04:00
JSContext * context = connection - > ssb - > context ;
JS_SetPropertyStr ( context , connection - > object , " id " , JS_NewString ( context , fullid ) ) ;
2021-12-27 14:52:42 -05:00
JS_SetPropertyStr ( context , connection - > object , " is_client " , JS_TRUE ) ;
2021-09-06 17:21:51 -04:00
2021-01-02 13:10:00 -05:00
connection - > state = k_tf_ssb_state_verified ;
2021-11-07 17:28:58 -05:00
_tf_ssb_notify_connections_changed ( connection - > ssb , k_tf_ssb_change_connect , connection ) ;
2021-01-02 13:10:00 -05:00
}
2023-01-07 19:25:38 -05:00
bool tf_ssb_connection_is_client ( tf_ssb_connection_t * connection )
{
return connection - > state = = k_tf_ssb_state_verified ;
}
2023-01-16 21:17:29 -05:00
bool tf_ssb_connection_is_connected ( tf_ssb_connection_t * connection )
{
return
connection - > state = = k_tf_ssb_state_verified | |
connection - > state = = k_tf_ssb_state_server_verified ;
}
2021-01-02 13:10:00 -05:00
const char * tf_ssb_connection_get_host ( tf_ssb_connection_t * connection )
{
return connection - > host ;
}
int tf_ssb_connection_get_port ( tf_ssb_connection_t * connection )
{
return connection - > port ;
}
bool tf_ssb_connection_get_id ( tf_ssb_connection_t * connection , char * out_id , size_t out_id_size )
{
2023-01-10 20:43:35 -05:00
return
connection & &
memcmp ( connection - > serverpub , ( uint8_t [ k_id_bin_len ] ) { 0 } , k_id_bin_len ) ! = 0 & &
tf_ssb_id_bin_to_str ( out_id , out_id_size , connection - > serverpub ) ;
2021-01-02 13:10:00 -05:00
}
2022-11-02 19:34:44 -04:00
static bool _tf_ssb_is_already_connected ( tf_ssb_t * ssb , uint8_t * id , tf_ssb_connection_t * ignore_connection )
2021-01-19 21:01:14 -05:00
{
2021-10-10 17:51:38 -04:00
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
2022-11-02 19:34:44 -04:00
if ( ! ignore_connection | | connection ! = ignore_connection )
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
if ( memcmp ( connection - > serverpub , id , k_id_bin_len ) = = 0 )
{
return true ;
}
else if ( memcmp ( ssb - > pub , id , k_id_bin_len ) = = 0 )
{
return true ;
}
2021-01-19 21:01:14 -05:00
}
}
return false ;
}
2021-01-02 13:10:00 -05:00
static void _tf_ssb_connection_verify_client_identity ( tf_ssb_connection_t * connection , const uint8_t * message , size_t len )
{
uint8_t nonce [ crypto_secretbox_NONCEBYTES ] = { 0 } ;
/*
* * shared_secret_ab = nacl_scalarmult (
* * server_ephemeral_sk ,
* * client_ephemeral_pk
* * )
*/
uint8_t shared_secret_ab [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_ab , connection - > epriv , connection - > serverepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_ab " ) ;
return ;
}
/*
* * shared_secret_aB = nacl_scalarmult (
* * sk_to_curve25519 ( server_longterm_sk ) ,
* * client_ephemeral_pk
* * )
*/
uint8_t curvepriv [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_ed25519_sk_to_curve25519 ( curvepriv , connection - > ssb - > priv ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to convert key to curve25519 " ) ;
return ;
}
static_assert ( sizeof ( connection - > ssb - > priv ) = = crypto_sign_ed25519_SECRETKEYBYTES , " size " ) ;
uint8_t shared_secret_aB [ crypto_scalarmult_curve25519_SCALARBYTES ] = { 0 } ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult ( shared_secret_aB , curvepriv , connection - > serverepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_aB " ) ;
return ;
}
static_assert ( sizeof ( k_ssb_network ) = = crypto_auth_KEYBYTES , " network key size " ) ;
uint8_t tohash [ sizeof ( k_ssb_network ) + sizeof ( shared_secret_ab ) + sizeof ( shared_secret_aB ) ] ;
memcpy ( tohash , k_ssb_network , sizeof ( k_ssb_network ) ) ;
memcpy ( tohash + sizeof ( k_ssb_network ) , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
memcpy ( tohash + sizeof ( k_ssb_network ) + sizeof ( shared_secret_ab ) , shared_secret_aB , sizeof ( shared_secret_aB ) ) ;
uint8_t hash2 [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( hash2 , tohash , sizeof ( tohash ) ) ;
/*
* * msg3_plaintext = assert_nacl_secretbox_open (
* * ciphertext : msg3 ,
* * nonce : 24 _bytes_of_zeros ,
* * key : sha256 (
* * concat (
* * network_identifier ,
* * shared_secret_ab ,
* * shared_secret_aB
* * )
* * )
* * )
*/
uint8_t m [ 96 ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_secretbox_open_easy ( m , message , len , nonce , hash2 ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to open initial secret box as server " ) ;
return ;
}
uint8_t * detached_signature_A = m ;
2022-11-02 19:34:44 -04:00
if ( _tf_ssb_is_already_connected ( connection - > ssb , m + 64 , connection ) )
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
char id_base64 [ k_id_base64_len ] = { 0 } ;
tf_ssb_id_bin_to_str ( id_base64 , sizeof ( id_base64 ) , m + 64 ) ;
char reason [ 256 ] ;
snprintf ( reason , sizeof ( reason ) , " already connected: %s \n " , id_base64 ) ;
_tf_ssb_connection_close ( connection , reason ) ;
2021-01-19 21:01:14 -05:00
return ;
}
2021-01-02 13:10:00 -05:00
memcpy ( connection - > serverpub , m + 64 , sizeof ( connection - > serverpub ) ) ;
uint8_t hash3 [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( hash3 , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
uint8_t msg [ sizeof ( k_ssb_network ) + sizeof ( connection - > ssb - > pub ) + sizeof ( hash3 ) ] ;
memcpy ( msg , k_ssb_network , sizeof ( k_ssb_network ) ) ;
memcpy ( msg + sizeof ( k_ssb_network ) , connection - > ssb - > pub , sizeof ( connection - > ssb - > pub ) ) ;
memcpy ( msg + sizeof ( k_ssb_network ) + sizeof ( connection - > ssb - > pub ) , hash3 , sizeof ( hash3 ) ) ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_verify_detached ( detached_signature_A , msg , sizeof ( msg ) , connection - > serverpub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to verify client identity " ) ;
return ;
}
uint8_t nonce2 [ crypto_auth_hmacsha512256_BYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_auth_hmacsha512256 ( nonce2 , connection - > epub , sizeof ( connection - > epub ) , k_ssb_network ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute initial recv nonce as server " ) ;
return ;
}
memcpy ( connection - > nonce , nonce2 , sizeof ( connection - > nonce ) ) ;
uint8_t nonce3 [ crypto_auth_hmacsha512256_BYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_auth_hmacsha512256 ( nonce3 , connection - > serverepub , sizeof ( connection - > serverepub ) , k_ssb_network ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute initial send nonce as server " ) ;
return ;
}
memcpy ( connection - > send_nonce , nonce3 , sizeof ( connection - > send_nonce ) ) ;
int detached_signature_A_size = 64 ;
uint8_t sign_b [ sizeof ( k_ssb_network ) + detached_signature_A_size + sizeof ( connection - > serverpub ) + sizeof ( hash3 ) ] ;
memcpy ( sign_b , k_ssb_network , sizeof ( k_ssb_network ) ) ;
memcpy ( sign_b + sizeof ( k_ssb_network ) , detached_signature_A , detached_signature_A_size ) ;
memcpy ( sign_b + sizeof ( k_ssb_network ) + detached_signature_A_size , connection - > serverpub , sizeof ( connection - > serverpub ) ) ;
memcpy ( sign_b + sizeof ( k_ssb_network ) + detached_signature_A_size + sizeof ( connection - > serverpub ) , hash3 , sizeof ( hash3 ) ) ;
uint8_t detached_signature_B [ crypto_sign_BYTES ] ;
unsigned long long siglen ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_detached ( detached_signature_B , & siglen , sign_b , sizeof ( sign_b ) , connection - > ssb - > priv ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute detached_signature_B as server " ) ;
return ;
}
uint8_t clientcurvepub [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_sign_ed25519_pk_to_curve25519 ( clientcurvepub , connection - > serverpub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to convert key to curve25519 " ) ;
return ;
}
uint8_t shared_secret_Ab [ crypto_scalarmult_curve25519_SCALARBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_scalarmult_curve25519 ( shared_secret_Ab , connection - > epriv , clientcurvepub ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to compute shared_secret_Ab as server " ) ;
return ;
}
uint8_t key_buf [ sizeof ( k_ssb_network ) + sizeof ( shared_secret_ab ) + sizeof ( shared_secret_aB ) + sizeof ( shared_secret_Ab ) ] ;
memcpy ( key_buf , k_ssb_network , sizeof ( k_ssb_network ) ) ;
memcpy ( key_buf + sizeof ( k_ssb_network ) , shared_secret_ab , sizeof ( shared_secret_ab ) ) ;
memcpy ( key_buf + sizeof ( k_ssb_network ) + sizeof ( shared_secret_ab ) , shared_secret_aB , sizeof ( shared_secret_aB ) ) ;
memcpy ( key_buf + sizeof ( k_ssb_network ) + sizeof ( shared_secret_ab ) + sizeof ( shared_secret_aB ) , shared_secret_Ab , sizeof ( shared_secret_Ab ) ) ;
uint8_t key_hash [ crypto_hash_sha256_BYTES ] ;
crypto_hash_sha256 ( key_hash , key_buf , sizeof ( key_buf ) ) ;
uint8_t hash3a [ crypto_hash_sha256_BYTES + crypto_sign_PUBLICKEYBYTES ] ;
crypto_hash_sha256 ( hash3a , key_hash , sizeof ( key_hash ) ) ;
memcpy ( hash3a + crypto_hash_sha256_BYTES , connection - > ssb - > pub , sizeof ( connection - > ssb - > pub ) ) ;
crypto_hash_sha256 ( connection - > s_to_c_box_key , hash3a , sizeof ( hash3a ) ) ;
uint8_t hash3b [ crypto_hash_sha256_BYTES + crypto_sign_PUBLICKEYBYTES ] ;
crypto_hash_sha256 ( hash3b , key_hash , sizeof ( key_hash ) ) ;
memcpy ( hash3b + crypto_hash_sha256_BYTES , connection - > serverpub , sizeof ( connection - > serverpub ) ) ;
crypto_hash_sha256 ( connection - > c_to_s_box_key , hash3b , sizeof ( hash3b ) ) ;
uint8_t c [ crypto_secretbox_MACBYTES + sizeof ( detached_signature_B ) ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_secretbox_easy ( c , detached_signature_B , sizeof ( detached_signature_B ) , nonce , key_hash ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " unable to create initial secret box as server " ) ;
return ;
}
static_assert ( sizeof ( c ) = = 80 , " server send size " ) ;
_tf_ssb_write ( connection , c , sizeof ( c ) ) ;
2021-09-06 17:21:51 -04:00
char fullid [ k_id_base64_len ] ;
tf_ssb_id_bin_to_str ( fullid , sizeof ( fullid ) , connection - > serverpub ) ;
JSContext * context = connection - > ssb - > context ;
JS_SetPropertyStr ( context , connection - > object , " id " , JS_NewString ( context , fullid ) ) ;
2021-12-27 14:52:42 -05:00
JS_SetPropertyStr ( context , connection - > object , " is_client " , JS_FALSE ) ;
2021-09-06 17:21:51 -04:00
2021-01-02 13:10:00 -05:00
connection - > state = k_tf_ssb_state_server_verified ;
2021-11-07 17:28:58 -05:00
_tf_ssb_notify_connections_changed ( connection - > ssb , k_tf_ssb_change_connect , connection ) ;
2021-01-02 13:10:00 -05:00
}
static bool _tf_ssb_connection_recv_pop ( tf_ssb_connection_t * connection , uint8_t * buffer , size_t size )
{
2023-01-01 17:42:31 -05:00
if ( size > = sizeof ( connection - > recv_buffer ) )
{
char message [ 256 ] ;
snprintf ( message , sizeof ( message ) , " Trying to pop a message (%zd) larger than the connection's receive buffer (%zd). " , size , sizeof ( connection - > recv_buffer ) ) ;
_tf_ssb_connection_close ( connection , message ) ;
}
2021-10-10 17:51:38 -04:00
if ( connection - > recv_size < size )
{
2021-01-02 13:10:00 -05:00
return false ;
}
memcpy ( buffer , connection - > recv_buffer , size ) ;
2021-10-10 17:51:38 -04:00
if ( connection - > recv_size - size )
{
2021-01-02 13:10:00 -05:00
memmove ( connection - > recv_buffer , connection - > recv_buffer + size , connection - > recv_size - size ) ;
}
connection - > recv_size - = size ;
return true ;
}
static bool _tf_ssb_name_equals ( JSContext * context , JSValue object , const char * * match )
{
bool result = true ;
JSValue name = JS_GetPropertyStr ( context , object , " name " ) ;
2021-10-10 17:51:38 -04:00
if ( JS_IsArray ( context , name ) )
{
2022-07-09 11:13:35 -04:00
int length = tf_util_get_length ( context , name ) ;
for ( int i = 0 ; i < length ; i + + )
2021-10-10 17:51:38 -04:00
{
2022-07-09 11:13:35 -04:00
if ( ! match [ i ] )
2021-10-10 17:51:38 -04:00
{
2022-07-09 11:13:35 -04:00
result = false ;
break ;
2021-01-02 13:10:00 -05:00
}
2022-07-09 11:13:35 -04:00
JSValue element = JS_GetPropertyUint32 ( context , name , i ) ;
const char * str = JS_ToCString ( context , element ) ;
if ( ! str | | strcmp ( str , match [ i ] ) ! = 0 )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
result = false ;
}
2022-07-09 11:13:35 -04:00
JS_FreeCString ( context , str ) ;
JS_FreeValue ( context , element ) ;
}
if ( result & & match [ length ] )
{
result = false ;
2021-01-02 13:10:00 -05:00
}
2021-10-10 17:51:38 -04:00
}
2022-11-11 21:00:49 -05:00
else if ( JS_IsString ( name ) )
{
/* Manifest is traditionally sent as not an array for some reason. */
const char * str = JS_ToCString ( context , name ) ;
result = str & & match [ 0 ] & & strcmp ( str , match [ 0 ] ) = = 0 & & ! match [ 1 ] ;
JS_FreeCString ( context , str ) ;
}
2021-10-10 17:51:38 -04:00
else
{
2021-01-02 13:10:00 -05:00
result = false ;
}
JS_FreeValue ( context , name ) ;
return result ;
}
static void _tf_ssb_connection_rpc_recv ( tf_ssb_connection_t * connection , uint8_t flags , int32_t request_number , const uint8_t * message , size_t size )
{
2022-02-05 15:18:58 -05:00
connection - > ssb - > rpc_in + + ;
2023-01-22 15:37:19 -05:00
_tf_ssb_connection_add_debug_message ( connection , false , flags , request_number , message , size ) ;
2022-11-02 19:34:44 -04:00
if ( size = = 0 )
{
2023-01-10 20:43:35 -05:00
_tf_ssb_connection_close ( connection , " rpc recv zero " ) ;
2022-11-02 19:34:44 -04:00
return ;
}
else if ( flags & k_ssb_rpc_flag_json )
2021-10-10 17:51:38 -04:00
{
2022-02-05 22:28:29 -05:00
char id [ k_id_base64_len ] = " " ;
tf_ssb_id_bin_to_str ( id , sizeof ( id ) , connection - > serverpub ) ;
2022-12-31 13:59:29 -05:00
if ( connection - > ssb - > verbose )
{
2023-01-10 20:43:35 -05:00
printf ( CYAN " %s RPC RECV " RESET " from %s flags=%x RN=%d: [%zd B] %.*s \n " , connection - > name , id , flags , request_number , size , ( int ) size , message ) ;
2022-12-31 13:59:29 -05:00
}
2021-01-02 13:10:00 -05:00
JSContext * context = connection - > ssb - > context ;
JSValue val = JS_ParseJSON ( context , ( const char * ) message , size , NULL ) ;
2021-12-22 14:57:34 -05:00
if ( ! JS_IsUndefined ( val ) )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
bool found = false ;
2021-12-22 14:57:34 -05:00
if ( JS_IsObject ( val ) )
2021-10-10 17:51:38 -04:00
{
2021-12-22 14:57:34 -05:00
for ( tf_ssb_rpc_callback_node_t * it = connection - > ssb - > rpc ; it ; it = it - > next )
2021-10-10 17:51:38 -04:00
{
2021-12-22 14:57:34 -05:00
if ( _tf_ssb_name_equals ( context , val , it - > name ) )
{
2023-02-03 10:06:18 -05:00
tf_trace_begin ( connection - > ssb - > trace , it - > flattened_name ) ;
2023-01-22 18:34:32 -05:00
it - > callback ( connection , flags , request_number , val , message , size , it - > user_data ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( connection - > ssb - > trace ) ;
2021-12-22 14:57:34 -05:00
found = true ;
break ;
}
2021-01-02 13:10:00 -05:00
}
}
2021-10-10 17:51:38 -04:00
if ( ! found )
{
2021-01-02 13:10:00 -05:00
tf_ssb_rpc_callback_t * callback = NULL ;
void * user_data = NULL ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_connection_get_request_callback ( connection , - request_number , & callback , & user_data ) )
{
if ( callback )
{
2023-02-03 10:06:18 -05:00
char buffer [ 64 ] ;
snprintf ( buffer , sizeof ( buffer ) , " request %d " , request_number ) ;
tf_trace_begin ( connection - > ssb - > trace , buffer ) ;
2023-01-22 18:34:32 -05:00
callback ( connection , flags , request_number , val , message , size , user_data ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( connection - > ssb - > trace ) ;
2021-01-02 13:10:00 -05:00
}
2021-10-10 17:51:38 -04:00
}
2023-01-07 19:25:38 -05:00
else if ( ! _tf_ssb_name_equals ( context , val , ( const char * [ ] ) { " Error " , NULL } ) )
2021-10-10 17:51:38 -04:00
{
2023-01-07 19:25:38 -05:00
tf_ssb_connection_rpc_send_error_method_not_allowed ( connection , flags , - request_number ) ;
2021-01-02 13:10:00 -05:00
}
}
}
2021-12-22 14:57:34 -05:00
else
{
printf ( " Failed to parse %.*s \n " , ( int ) size , message ) ;
}
2021-01-02 13:10:00 -05:00
JS_FreeValue ( context , val ) ;
2021-10-10 17:51:38 -04:00
}
else if ( ( flags & k_ssb_rpc_mask_type ) = = k_ssb_rpc_flag_binary )
{
2022-12-31 13:59:29 -05:00
if ( connection - > ssb - > verbose )
{
printf ( CYAN " %s RPC RECV " RESET " flags=%x RN=%d: %zd bytes \n " , connection - > name , flags , request_number , size ) ;
}
2021-01-02 13:10:00 -05:00
tf_ssb_rpc_callback_t * callback = NULL ;
void * user_data = NULL ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_connection_get_request_callback ( connection , - request_number , & callback , & user_data ) )
{
if ( callback )
{
2023-02-03 10:06:18 -05:00
char buffer [ 64 ] ;
snprintf ( buffer , sizeof ( buffer ) , " request %d " , request_number ) ;
tf_trace_begin ( connection - > ssb - > trace , buffer ) ;
2021-01-02 13:10:00 -05:00
callback ( connection , flags , request_number , JS_UNDEFINED , message , size , user_data ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( connection - > ssb - > trace ) ;
2021-01-02 13:10:00 -05:00
}
}
2022-11-02 19:34:44 -04:00
else
{
printf ( " No request callback for %p %d \n " , connection , - request_number ) ;
}
2021-01-02 13:10:00 -05:00
}
2023-01-15 16:23:28 -05:00
if ( flags & k_ssb_rpc_flag_end_error )
2021-10-10 17:51:38 -04:00
{
2023-01-18 18:43:49 -05:00
tf_ssb_connection_remove_request ( connection , - request_number ) ;
2021-01-02 13:10:00 -05:00
}
}
static void _tf_ssb_connection_rpc_recv_push ( tf_ssb_connection_t * connection , const uint8_t * data , size_t size )
{
2023-01-13 19:55:51 -05:00
size_t size_left = size ;
size_t size_processed = 0 ;
while ( size_left > 0 )
2021-10-10 17:51:38 -04:00
{
2023-01-13 19:55:51 -05:00
size_t copy_size = ( connection - > rpc_recv_size + size_left > sizeof ( connection - > rpc_recv_buffer ) ) ? sizeof ( connection - > rpc_recv_buffer ) - connection - > rpc_recv_size : size_left ;
if ( copy_size = = 0 )
2021-10-10 17:51:38 -04:00
{
2023-01-13 19:55:51 -05:00
_tf_ssb_connection_close ( connection , " recv buffer overflow " ) ;
return ;
2021-10-10 17:51:38 -04:00
}
2023-01-13 19:55:51 -05:00
memcpy ( connection - > rpc_recv_buffer + connection - > rpc_recv_size , data + size_processed , copy_size ) ;
connection - > rpc_recv_size + = copy_size ;
size_processed + = copy_size ;
size_left - = copy_size ;
while ( connection - > rpc_recv_size > = 9 )
2021-10-10 17:51:38 -04:00
{
2023-01-13 19:55:51 -05:00
uint8_t flags = * connection - > rpc_recv_buffer ;
uint32_t body_len ;
int32_t request_number ;
memcpy ( & body_len , connection - > rpc_recv_buffer + 1 , sizeof ( body_len ) ) ;
body_len = htonl ( body_len ) ;
memcpy ( & request_number , connection - > rpc_recv_buffer + 1 + sizeof ( body_len ) , sizeof ( request_number ) ) ;
request_number = htonl ( request_number ) ;
size_t rpc_size = 9 + body_len ;
if ( connection - > rpc_recv_size > = rpc_size )
{
uint8_t * end = & connection - > rpc_recv_buffer [ 9 + body_len ] ;
uint8_t tmp = * end ;
* end = ' \0 ' ;
_tf_ssb_connection_rpc_recv ( connection , flags , request_number , connection - > rpc_recv_buffer + 9 , body_len ) ;
* end = tmp ;
memmove ( connection - > rpc_recv_buffer , connection - > rpc_recv_buffer + rpc_size , connection - > rpc_recv_size - rpc_size ) ;
connection - > rpc_recv_size - = rpc_size ;
}
else
{
/* Wait for more body. */
break ;
}
2021-01-02 13:10:00 -05:00
}
}
}
static bool _tf_ssb_connection_box_stream_recv ( tf_ssb_connection_t * connection )
{
2021-10-10 17:51:38 -04:00
if ( ! connection - > body_len )
{
2021-01-02 13:10:00 -05:00
uint8_t header_enc [ 34 ] ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_connection_recv_pop ( connection , header_enc , sizeof ( header_enc ) ) )
{
2021-01-02 13:10:00 -05:00
uint8_t header [ 18 ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_secretbox_open_easy ( header , header_enc , sizeof ( header_enc ) , connection - > nonce , connection - > s_to_c_box_key ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " failed to open header secret box " ) ;
return false ;
}
_tf_ssb_nonce_inc ( connection - > nonce ) ;
connection - > body_len = htons ( * ( uint16_t * ) header ) ;
memcpy ( connection - > body_auth_tag , header + sizeof ( uint16_t ) , sizeof ( connection - > body_auth_tag ) ) ;
2021-10-10 17:51:38 -04:00
if ( ! connection - > body_len )
{
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_close ( connection , " empty body, graceful close " ) ;
2021-01-02 13:10:00 -05:00
}
2021-10-10 17:51:38 -04:00
}
else
{
2021-01-02 13:10:00 -05:00
return false ;
}
}
2021-10-10 17:51:38 -04:00
if ( connection - > body_len )
{
2023-01-14 08:27:19 -05:00
memcpy ( connection - > box_stream_buf , connection - > body_auth_tag , sizeof ( connection - > body_auth_tag ) ) ;
if ( _tf_ssb_connection_recv_pop ( connection , connection - > box_stream_buf + 16 , connection - > body_len ) )
2021-10-10 17:51:38 -04:00
{
2023-01-14 08:27:19 -05:00
if ( crypto_secretbox_open_easy ( connection - > secretbox_buf , connection - > box_stream_buf , 16 + connection - > body_len , connection - > nonce , connection - > s_to_c_box_key ) ! = 0 )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " failed to open secret box " ) ;
return false ;
}
_tf_ssb_nonce_inc ( connection - > nonce ) ;
2023-01-14 08:27:19 -05:00
_tf_ssb_connection_rpc_recv_push ( connection , connection - > secretbox_buf , connection - > body_len ) ;
2021-01-02 13:10:00 -05:00
connection - > body_len = 0 ;
2021-10-10 17:51:38 -04:00
}
else
{
2021-01-02 13:10:00 -05:00
return false ;
}
}
return true ;
}
2022-07-13 21:01:14 -04:00
void tf_ssb_append_message_with_keys ( tf_ssb_t * ssb , const char * author , const uint8_t * private_key , JSValue message )
2021-01-02 13:10:00 -05:00
{
char previous_id [ crypto_hash_sha256_BYTES * 2 ] ;
int64_t previous_sequence = 0 ;
2021-08-22 15:41:27 -04:00
bool have_previous = tf_ssb_db_get_latest_message_by_author ( ssb , author , & previous_sequence , previous_id , sizeof ( previous_id ) ) ;
2021-01-02 13:10:00 -05:00
JSContext * context = ssb - > context ;
JSValue root = JS_NewObject ( context ) ;
2021-10-10 17:51:38 -04:00
if ( have_previous )
{
2021-09-06 16:54:44 -04:00
JS_SetPropertyStr ( context , root , " previous " , JS_NewString ( context , previous_id ) ) ;
2021-10-10 17:51:38 -04:00
}
else
{
2021-01-02 13:10:00 -05:00
JS_SetPropertyStr ( context , root , " previous " , JS_NULL ) ;
}
JSValue authorstr = JS_NewString ( context , author ) ;
JS_SetPropertyStr ( context , root , " author " , authorstr ) ;
JS_SetPropertyStr ( context , root , " sequence " , JS_NewInt64 ( context , previous_sequence + 1 ) ) ;
2022-01-10 22:18:15 -05:00
int64_t now = ( int64_t ) time ( NULL ) ;
JS_SetPropertyStr ( context , root , " timestamp " , JS_NewInt64 ( context , now * 1000LL ) ) ;
2021-01-02 13:10:00 -05:00
JSValue hashstr = JS_NewString ( context , " sha256 " ) ;
JS_SetPropertyStr ( context , root , " hash " , hashstr ) ;
JSValue content = JS_DupValue ( context , message ) ;
JS_SetPropertyStr ( context , root , " content " , content ) ;
JSValue jsonval = JS_JSONStringify ( context , root , JS_NULL , JS_NewInt32 ( context , 2 ) ) ;
size_t len = 0 ;
const char * json = JS_ToCStringLen ( context , & len , jsonval ) ;
uint8_t signature [ crypto_sign_BYTES ] ;
unsigned long long siglen ;
2022-07-13 21:01:14 -04:00
bool valid = crypto_sign_detached ( signature , & siglen , ( const uint8_t * ) json , len , private_key ) = = 0 ;
2021-01-02 13:10:00 -05:00
JS_FreeCString ( context , json ) ;
JS_FreeValue ( context , jsonval ) ;
char signature_base64 [ crypto_sign_BYTES * 2 ] ;
2023-02-13 22:15:24 -05:00
tf_base64_encode ( signature , sizeof ( signature ) , signature_base64 , sizeof ( signature_base64 ) ) ;
2021-01-02 13:10:00 -05:00
strcat ( signature_base64 , " .sig.ed25519 " ) ;
JSValue sigstr = JS_NewString ( context , signature_base64 ) ;
JS_SetPropertyStr ( context , root , " signature " , sigstr ) ;
jsonval = JS_JSONStringify ( context , root , JS_NULL , JS_NewInt32 ( context , 2 ) ) ;
len = 0 ;
json = JS_ToCStringLen ( context , & len , jsonval ) ;
JS_FreeCString ( context , json ) ;
JS_FreeValue ( context , jsonval ) ;
2021-11-05 22:10:13 -04:00
char id [ sodium_base64_ENCODED_LEN ( crypto_hash_sha256_BYTES , sodium_base64_VARIANT_ORIGINAL ) + 7 + 1 ] ;
2022-02-09 22:58:33 -05:00
if ( valid & & tf_ssb_verify_and_strip_signature ( ssb - > context , root , id , sizeof ( id ) , NULL , 0 , NULL ) )
2021-10-10 17:51:38 -04:00
{
2022-02-05 15:18:58 -05:00
if ( tf_ssb_db_store_message ( ssb , ssb - > context , id , root , signature_base64 , false ) )
{
tf_ssb_notify_message_added ( ssb , id ) ;
}
else
{
printf ( " message not stored. \n " ) ;
}
2021-01-02 13:10:00 -05:00
}
2022-02-09 22:58:33 -05:00
else
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
printf ( " Failed to verify message signature. \n " ) ;
}
JS_FreeValue ( context , root ) ;
}
2022-07-13 21:01:14 -04:00
void tf_ssb_append_message ( tf_ssb_t * ssb , JSValue message )
{
char author [ k_id_base64_len ] ;
tf_ssb_id_bin_to_str ( author , sizeof ( author ) , ssb - > pub ) ;
tf_ssb_append_message_with_keys ( ssb , author , ssb - > priv , message ) ;
}
2023-01-16 21:17:29 -05:00
static void _tf_ssb_connection_dispatch_scheduled ( tf_ssb_connection_t * connection )
{
if ( connection - > scheduled_count )
{
tf_ssb_connection_scheduled_t scheduled = connection - > scheduled [ 0 ] ;
memmove ( connection - > scheduled , connection - > scheduled + 1 , sizeof ( tf_ssb_connection_scheduled_t ) * ( connection - > scheduled_count - 1 ) ) ;
connection - > scheduled_count - - ;
2023-02-03 10:06:18 -05:00
tf_trace_begin ( connection - > ssb - > trace , " scheduled callback " ) ;
2023-01-16 21:17:29 -05:00
scheduled . callback ( connection , scheduled . user_data ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( connection - > ssb - > trace ) ;
2023-01-16 21:17:29 -05:00
}
}
2022-01-25 20:15:04 -05:00
void _tf_ssb_connection_destroy ( tf_ssb_connection_t * connection , const char * reason )
2021-01-02 13:10:00 -05:00
{
tf_ssb_t * ssb = connection - > ssb ;
2022-01-25 20:15:04 -05:00
if ( ! connection - > destroy_reason )
{
connection - > destroy_reason = reason ;
2022-11-02 19:34:44 -04:00
}
2023-01-16 21:17:29 -05:00
while ( connection - > scheduled_count )
{
_tf_ssb_connection_dispatch_scheduled ( connection ) ;
}
tf_free ( connection - > scheduled ) ;
connection - > scheduled = NULL ;
2022-11-02 19:34:44 -04:00
while ( connection - > requests )
{
2023-01-18 18:43:49 -05:00
tf_ssb_connection_remove_request ( connection , connection - > requests - > request_number ) ;
2022-01-25 20:15:04 -05:00
}
2022-11-08 20:31:18 -05:00
for ( tf_ssb_broadcast_t * node = ssb - > broadcasts ; node ; node = node - > next )
{
if ( node - > tunnel_connection = = connection )
{
node - > tunnel_connection = NULL ;
node - > mtime = 0 ;
}
}
2021-10-10 17:51:38 -04:00
for ( tf_ssb_connection_t * * it = & connection - > ssb - > connections ; * it ; it = & ( * it ) - > next )
{
2023-01-07 19:25:38 -05:00
for ( int i = ( * it ) - > requests_count - 1 ; i > = 0 ; i - - )
2022-11-06 21:57:29 -05:00
{
if ( ( * it ) - > requests [ i ] . dependent_connection = = connection )
{
2023-01-18 18:43:49 -05:00
tf_ssb_connection_remove_request ( * it , ( * it ) - > requests [ i ] . request_number ) ;
2022-11-06 21:57:29 -05:00
}
}
2021-10-10 17:51:38 -04:00
if ( * it = = connection )
{
2021-01-02 13:10:00 -05:00
* it = connection - > next ;
connection - > next = NULL ;
2022-01-12 20:08:17 -05:00
ssb - > connections_count - - ;
2022-01-22 15:13:14 -05:00
_tf_ssb_notify_connections_changed ( ssb , k_tf_ssb_change_remove , connection ) ;
2021-01-02 13:10:00 -05:00
break ;
}
}
2022-11-02 19:34:44 -04:00
bool again = true ;
while ( again )
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
again = false ;
for ( tf_ssb_connection_t * it = connection - > ssb - > connections ; it ; it = it - > next )
{
if ( it - > tunnel_connection = = connection )
{
it - > tunnel_connection = NULL ;
_tf_ssb_connection_close ( it , " tunnel closed " ) ;
again = true ;
break ;
}
2022-11-19 16:42:54 -05:00
else if ( it = = connection - > tunnel_connection )
2022-11-02 19:34:44 -04:00
{
2023-01-18 18:43:49 -05:00
tf_ssb_connection_remove_request ( it , connection - > tunnel_request_number ) ;
2022-11-02 19:34:44 -04:00
connection - > tunnel_connection = NULL ;
2022-11-19 16:42:54 -05:00
connection - > tunnel_request_number = 0 ;
2022-11-02 19:34:44 -04:00
}
}
2021-01-02 13:10:00 -05:00
}
2022-01-22 15:13:14 -05:00
if ( ! JS_IsUndefined ( connection - > object ) )
{
2022-01-23 07:52:55 -05:00
JSValue object = connection - > object ;
2022-01-22 15:13:14 -05:00
connection - > object = JS_UNDEFINED ;
2022-01-23 07:52:55 -05:00
JS_SetOpaque ( object , NULL ) ;
JS_FreeValue ( ssb - > context , object ) ;
2022-01-22 15:13:14 -05:00
}
if ( connection - > async . data & & ! uv_is_closing ( ( uv_handle_t * ) & connection - > async ) )
{
uv_close ( ( uv_handle_t * ) & connection - > async , _tf_ssb_connection_on_close ) ;
}
if ( connection - > tcp . data & & ! uv_is_closing ( ( uv_handle_t * ) & connection - > tcp ) )
{
uv_close ( ( uv_handle_t * ) & connection - > tcp , _tf_ssb_connection_on_close ) ;
}
if ( connection - > connect . data & & ! uv_is_closing ( ( uv_handle_t * ) & connection - > connect ) )
{
uv_close ( ( uv_handle_t * ) & connection - > connect , _tf_ssb_connection_on_close ) ;
}
if ( JS_IsUndefined ( connection - > object ) & &
! connection - > async . data & &
! connection - > tcp . data & &
! connection - > connect . data )
{
2023-01-08 15:01:35 -05:00
JS_FreeValue ( ssb - > context , connection - > ebt_send_clock ) ;
connection - > ebt_send_clock = JS_UNDEFINED ;
2023-01-08 12:45:15 -05:00
tf_free ( connection - > message_requests ) ;
connection - > message_requests = NULL ;
connection - > message_requests_count = 0 ;
2023-01-22 15:37:19 -05:00
for ( int i = 0 ; i < k_debug_close_message_count ; i + + )
{
tf_free ( connection - > debug_messages [ i ] ) ;
connection - > debug_messages [ i ] = NULL ;
}
2022-06-04 13:04:51 -04:00
tf_free ( connection ) ;
2022-01-22 15:13:14 -05:00
}
}
static void _tf_ssb_connection_on_close ( uv_handle_t * handle )
{
tf_ssb_connection_t * connection = handle - > data ;
handle - > data = NULL ;
2022-01-25 20:15:04 -05:00
if ( connection )
{
_tf_ssb_connection_destroy ( connection , " handle closed " ) ;
}
2021-01-02 13:10:00 -05:00
}
2022-11-02 19:34:44 -04:00
static void _tf_ssb_connection_on_tcp_recv_internal ( tf_ssb_connection_t * connection , const void * data , ssize_t nread )
2021-01-02 13:10:00 -05:00
{
2021-10-10 17:51:38 -04:00
if ( nread > = 0 )
{
if ( connection - > recv_size + nread > sizeof ( connection - > recv_buffer ) )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " recv buffer overflow " ) ;
return ;
}
2022-11-02 19:34:44 -04:00
memcpy ( connection - > recv_buffer + connection - > recv_size , data , nread ) ;
2021-01-02 13:10:00 -05:00
connection - > recv_size + = nread ;
2021-10-10 17:51:38 -04:00
switch ( connection - > state )
{
2021-01-02 13:10:00 -05:00
case k_tf_ssb_state_invalid :
_tf_ssb_connection_close ( connection , " received a message in invalid state " ) ;
break ;
case k_tf_ssb_state_connected :
_tf_ssb_connection_close ( connection , " received a message in connected state " ) ;
break ;
case k_tf_ssb_state_sent_hello :
{
uint8_t hello [ 64 ] ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_connection_recv_pop ( connection , hello , sizeof ( hello ) ) )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_send_identity ( connection , hello , hello + 32 ) ;
}
}
break ;
case k_tf_ssb_state_sent_identity :
{
uint8_t identity [ 80 ] ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_connection_recv_pop ( connection , identity , sizeof ( identity ) ) )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_verify_identity ( connection , identity , sizeof ( identity ) ) ;
}
}
break ;
case k_tf_ssb_state_verified :
2022-01-22 15:13:14 -05:00
uv_async_send ( & connection - > async ) ;
2021-01-02 13:10:00 -05:00
break ;
case k_tf_ssb_state_server_wait_hello :
{
uint8_t hello [ 64 ] ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_connection_recv_pop ( connection , hello , sizeof ( hello ) ) )
{
2021-01-02 13:10:00 -05:00
uint8_t * hmac = hello ;
memcpy ( connection - > serverepub , hello + crypto_box_PUBLICKEYBYTES , crypto_box_PUBLICKEYBYTES ) ;
static_assert ( sizeof ( connection - > serverepub ) = = crypto_box_PUBLICKEYBYTES , " serverepub size " ) ;
2021-10-10 17:51:38 -04:00
if ( crypto_auth_hmacsha512256_verify ( hmac , connection - > serverepub , 32 , k_ssb_network ) ! = 0 )
{
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_close ( connection , " crypto_auth_hmacsha512256_verify failed " ) ;
2021-10-10 17:51:38 -04:00
}
else
{
2022-11-02 19:34:44 -04:00
_tf_ssb_connection_client_send_hello ( connection ) ;
2021-01-02 13:10:00 -05:00
connection - > state = k_tf_ssb_state_server_wait_client_identity ;
}
}
}
break ;
case k_tf_ssb_state_server_wait_client_identity :
{
uint8_t identity [ 112 ] ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_connection_recv_pop ( connection , identity , sizeof ( identity ) ) )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_verify_client_identity ( connection , identity , sizeof ( identity ) ) ;
}
}
break ;
case k_tf_ssb_state_server_verified :
2022-01-22 15:13:14 -05:00
uv_async_send ( & connection - > async ) ;
2021-01-02 13:10:00 -05:00
break ;
case k_tf_ssb_state_closing :
break ;
}
2021-10-10 17:51:38 -04:00
}
2022-01-22 16:20:43 -05:00
else if ( nread = = UV_ENOBUFS )
{
/* Our read buffer is full. Try harder to process messages. */
uv_async_send ( & connection - > async ) ;
}
2021-10-10 17:51:38 -04:00
else
{
2023-01-10 20:43:35 -05:00
_tf_ssb_connection_close ( connection , uv_strerror ( nread ) ) ;
2021-01-02 13:10:00 -05:00
}
}
2022-11-02 19:34:44 -04:00
static void _tf_ssb_connection_on_tcp_recv ( uv_stream_t * stream , ssize_t nread , const uv_buf_t * buf )
2021-01-02 13:10:00 -05:00
{
tf_ssb_connection_t * connection = stream - > data ;
2022-11-02 19:34:44 -04:00
_tf_ssb_connection_on_tcp_recv_internal ( connection , buf - > base , nread ) ;
tf_free ( buf - > base ) ;
}
static void _tf_ssb_connection_client_send_hello ( tf_ssb_connection_t * connection )
{
2021-01-02 13:10:00 -05:00
char write [ crypto_auth_BYTES + crypto_box_PUBLICKEYBYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_box_keypair ( connection - > epub , connection - > epriv ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " failed to generate ephemeral keypair " ) ;
return ;
}
uint8_t a [ crypto_auth_hmacsha512256_BYTES ] ;
2021-10-10 17:51:38 -04:00
if ( crypto_auth_hmacsha512256 ( a , connection - > epub , sizeof ( connection - > epub ) , k_ssb_network ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_connection_close ( connection , " failed to create hello message " ) ;
return ;
}
char * b = write ;
memcpy ( b , a , crypto_auth_BYTES ) ;
memcpy ( b + crypto_auth_BYTES , connection - > epub , sizeof ( connection - > epub ) ) ;
_tf_ssb_write ( connection , b , crypto_auth_BYTES + sizeof ( connection - > epub ) ) ;
connection - > state = k_tf_ssb_state_sent_hello ;
}
static void _tf_ssb_connection_on_connect ( uv_connect_t * connect , int status )
{
tf_ssb_connection_t * connection = connect - > data ;
connect - > data = NULL ;
2021-10-10 17:51:38 -04:00
if ( status = = 0 )
{
2021-01-02 13:10:00 -05:00
connection - > state = k_tf_ssb_state_connected ;
2022-01-19 23:01:45 -05:00
int result = uv_read_start ( connect - > handle , _tf_ssb_connection_on_tcp_alloc , _tf_ssb_connection_on_tcp_recv ) ;
if ( result )
{
printf ( " uv_read_start => %s \n " , uv_strerror ( status ) ) ;
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_close ( connection , " uv_read_start failed " ) ;
2022-01-19 23:01:45 -05:00
}
else
{
2022-11-02 19:34:44 -04:00
_tf_ssb_connection_client_send_hello ( connection ) ;
2022-01-19 23:01:45 -05:00
}
2021-10-10 17:51:38 -04:00
}
else
{
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_close ( connection , " uv_tcp_connect failed " ) ;
2021-01-02 13:10:00 -05:00
}
}
2022-10-14 08:27:34 -04:00
static void _load_keys_callback ( const char * identity , void * user_data )
2021-01-02 13:10:00 -05:00
{
2022-10-14 08:27:34 -04:00
tf_ssb_t * ssb = user_data ;
if ( * ssb - > pub )
2021-10-10 17:51:38 -04:00
{
2022-10-14 08:27:34 -04:00
return ;
2021-01-02 13:10:00 -05:00
}
2022-10-14 08:27:34 -04:00
tf_ssb_id_str_to_bin ( ssb - > pub , identity ) ;
tf_ssb_db_identity_get_private_key ( ssb , " :admin " , identity , ssb - > priv , sizeof ( ssb - > priv ) ) ;
2021-01-02 13:10:00 -05:00
}
2022-10-14 08:27:34 -04:00
static bool _tf_ssb_load_keys ( tf_ssb_t * ssb )
2021-01-02 13:10:00 -05:00
{
2022-10-14 08:27:34 -04:00
tf_ssb_db_identity_visit ( ssb , " :admin " , _load_keys_callback , ssb ) ;
return * ssb - > pub ! = ' \0 ' & & * ssb - > priv ! = ' \0 ' ;
2021-01-02 13:10:00 -05:00
}
2021-12-21 14:06:44 -05:00
static void _tf_ssb_trace_timer ( uv_timer_t * timer )
{
tf_ssb_t * ssb = timer - > data ;
const char * names [ ] =
{
" connections " ,
" broadcasts " ,
" rpc " ,
" connections_changed " ,
" message_added " ,
" blob_want_added " ,
" broadcasts_changed " ,
} ;
int64_t values [ ] =
{
2022-01-12 20:08:17 -05:00
ssb - > connections_count ,
ssb - > broadcasts_count ,
ssb - > rpc_count ,
ssb - > connections_changed_count ,
ssb - > message_added_count ,
ssb - > blob_want_added_count ,
ssb - > broadcasts_changed_count ,
2021-12-21 14:06:44 -05:00
} ;
2022-01-15 12:40:24 -05:00
tf_trace_counter ( ssb - > trace , " ssb " , _countof ( values ) , names , values ) ;
2021-12-21 14:06:44 -05:00
}
2022-02-05 15:18:58 -05:00
void tf_ssb_get_stats ( tf_ssb_t * ssb , tf_ssb_stats_t * out_stats )
{
* out_stats = ( tf_ssb_stats_t )
{
. connections = ssb - > connections_count ,
. broadcasts = ssb - > broadcasts_count ,
. messages_stored = ssb - > messages_stored ,
2023-01-18 17:52:54 -05:00
. blobs_stored = ssb - > blobs_stored ,
2022-02-05 15:18:58 -05:00
. rpc_in = ssb - > rpc_in ,
. rpc_out = ssb - > rpc_out ,
2022-07-09 18:00:33 -04:00
. request_count = ssb - > request_count ,
2022-02-05 15:18:58 -05:00
. callbacks =
{
. rpc = ssb - > rpc_count ,
. connections_changed = ssb - > connections_changed_count ,
. message_added = ssb - > message_added_count ,
. blob_want_added = ssb - > blob_want_added_count ,
. broadcasts_changed = ssb - > broadcasts_changed_count ,
} ,
} ;
ssb - > messages_stored = 0 ;
2023-01-18 17:52:54 -05:00
ssb - > blobs_stored = 0 ;
2022-02-05 15:18:58 -05:00
ssb - > rpc_in = 0 ;
ssb - > rpc_out = 0 ;
}
2023-02-07 20:29:44 -05:00
tf_ssb_t * tf_ssb_create ( uv_loop_t * loop , JSContext * context , const char * db_path )
2021-01-02 13:10:00 -05:00
{
2022-06-04 13:04:51 -04:00
tf_ssb_t * ssb = tf_malloc ( sizeof ( tf_ssb_t ) ) ;
2021-01-02 13:10:00 -05:00
memset ( ssb , 0 , sizeof ( * ssb ) ) ;
2023-01-01 21:11:21 -05:00
ssb - > verbose = true ;
2021-10-10 17:51:38 -04:00
if ( context )
{
2021-01-02 13:10:00 -05:00
ssb - > context = context ;
2021-10-10 17:51:38 -04:00
}
else
{
2021-01-02 13:10:00 -05:00
ssb - > own_context = true ;
2022-06-20 13:57:07 -04:00
JSMallocFunctions funcs = { 0 } ;
tf_get_js_malloc_functions ( & funcs ) ;
ssb - > runtime = JS_NewRuntime2 ( & funcs , NULL ) ;
2021-01-02 13:10:00 -05:00
ssb - > context = JS_NewContext ( ssb - > runtime ) ;
}
2023-02-07 20:29:44 -05:00
uv_mutex_init ( & ssb - > db_readers_lock ) ;
2021-09-06 13:50:38 -04:00
JS_NewClassID ( & _connection_class_id ) ;
JSClassDef def =
{
. class_name = " connection " ,
. finalizer = _tf_ssb_connection_finalizer ,
} ;
JS_NewClass ( JS_GetRuntime ( ssb - > context ) , _connection_class_id , & def ) ;
2023-02-07 20:29:44 -05:00
ssb - > db_path = tf_strdup ( db_path ) ;
sqlite3_open ( db_path , & ssb - > db ) ;
2021-08-22 15:34:28 -04:00
tf_ssb_db_init ( ssb ) ;
2021-01-02 13:10:00 -05:00
2021-10-10 17:51:38 -04:00
if ( loop )
{
2021-01-02 13:10:00 -05:00
ssb - > loop = loop ;
2021-10-10 17:51:38 -04:00
}
else
{
2021-01-02 13:10:00 -05:00
uv_loop_init ( & ssb - > own_loop ) ;
ssb - > loop = & ssb - > own_loop ;
}
ssb - > broadcast_timer . data = ssb ;
uv_timer_init ( ssb - > loop , & ssb - > broadcast_timer ) ;
2021-10-10 17:51:38 -04:00
if ( ! _tf_ssb_load_keys ( ssb ) )
{
2021-01-02 13:10:00 -05:00
printf ( " Generating a new keypair. \n " ) ;
2022-10-14 08:27:34 -04:00
tf_ssb_db_identity_create ( ssb , " :admin " , ssb - > pub , ssb - > priv ) ;
2021-01-02 13:10:00 -05:00
}
ssb - > connections_tracker = tf_ssb_connections_create ( ssb ) ;
2022-11-16 20:36:24 -05:00
tf_ssb_rpc_register ( ssb ) ;
2021-01-02 13:10:00 -05:00
return ssb ;
}
sqlite3 * tf_ssb_get_db ( tf_ssb_t * ssb )
{
return ssb - > db ;
}
2023-02-07 20:29:44 -05:00
sqlite3 * tf_ssb_acquire_db_reader ( tf_ssb_t * ssb )
{
sqlite3 * db = NULL ;
uv_mutex_lock ( & ssb - > db_readers_lock ) ;
if ( ssb - > db_readers_count )
{
db = ssb - > db_readers [ - - ssb - > db_readers_count ] ;
}
else
{
sqlite3_open_v2 ( ssb - > db_path , & db , SQLITE_OPEN_READONLY , NULL ) ;
2023-02-17 17:43:19 -05:00
tf_ssb_db_init_reader ( db ) ;
2023-02-07 20:29:44 -05:00
}
uv_mutex_unlock ( & ssb - > db_readers_lock ) ;
return db ;
}
void tf_ssb_release_db_reader ( tf_ssb_t * ssb , sqlite3 * db )
{
uv_mutex_lock ( & ssb - > db_readers_lock ) ;
ssb - > db_readers = tf_resize_vec ( ssb - > db_readers , sizeof ( sqlite3 * ) * ( ssb - > db_readers_count + 1 ) ) ;
ssb - > db_readers [ ssb - > db_readers_count + + ] = db ;
uv_mutex_unlock ( & ssb - > db_readers_lock ) ;
}
2021-01-02 13:10:00 -05:00
uv_loop_t * tf_ssb_get_loop ( tf_ssb_t * ssb )
{
return ssb - > loop ;
}
void tf_ssb_generate_keys ( tf_ssb_t * ssb )
{
crypto_sign_ed25519_keypair ( ssb - > pub , ssb - > priv ) ;
}
2022-07-13 21:01:14 -04:00
void tf_ssb_generate_keys_buffer ( char * out_public , size_t public_size , char * out_private , size_t private_size )
{
uint8_t public [ crypto_sign_PUBLICKEYBYTES ] ;
uint8_t private [ crypto_sign_SECRETKEYBYTES ] ;
crypto_sign_ed25519_keypair ( public , private ) ;
2023-02-13 22:15:24 -05:00
char buffer [ 512 ] ;
tf_base64_encode ( public , sizeof ( public ) , buffer , sizeof ( buffer ) ) ;
2022-07-13 21:01:14 -04:00
snprintf ( out_public , public_size , " %s.ed25519 " , buffer ) ;
2023-02-13 22:15:24 -05:00
tf_base64_encode ( private , sizeof ( private ) , buffer , sizeof ( buffer ) ) ;
2022-07-13 21:01:14 -04:00
snprintf ( out_private , private_size , " %s.ed25519 " , buffer ) ;
}
2021-01-02 13:10:00 -05:00
void tf_ssb_set_trace ( tf_ssb_t * ssb , tf_trace_t * trace )
{
ssb - > trace = trace ;
2021-10-10 17:51:38 -04:00
if ( trace & & ssb - > db )
{
2021-01-02 13:10:00 -05:00
tf_trace_sqlite ( trace , ssb - > db ) ;
}
}
tf_trace_t * tf_ssb_get_trace ( tf_ssb_t * ssb )
{
return ssb - > trace ;
}
JSContext * tf_ssb_get_context ( tf_ssb_t * ssb )
{
return ssb - > context ;
}
static void _tf_ssb_on_handle_close ( uv_handle_t * handle )
{
handle - > data = NULL ;
}
void tf_ssb_destroy ( tf_ssb_t * ssb )
{
tf_ssb_connections_destroy ( ssb - > connections_tracker ) ;
ssb - > connections_tracker = NULL ;
2021-10-10 17:51:38 -04:00
if ( ssb - > broadcast_listener . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > broadcast_listener ) )
{
2021-01-02 13:10:00 -05:00
uv_close ( ( uv_handle_t * ) & ssb - > broadcast_listener , _tf_ssb_on_handle_close ) ;
}
2021-10-10 17:51:38 -04:00
if ( ssb - > broadcast_sender . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > broadcast_sender ) )
{
2021-01-02 13:10:00 -05:00
uv_close ( ( uv_handle_t * ) & ssb - > broadcast_sender , _tf_ssb_on_handle_close ) ;
}
2021-10-10 17:51:38 -04:00
if ( ssb - > broadcast_timer . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > broadcast_timer ) )
{
2021-01-02 13:10:00 -05:00
uv_close ( ( uv_handle_t * ) & ssb - > broadcast_timer , _tf_ssb_on_handle_close ) ;
}
2022-01-19 22:35:03 -05:00
if ( ssb - > broadcast_cleanup_timer . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > broadcast_cleanup_timer ) )
{
uv_close ( ( uv_handle_t * ) & ssb - > broadcast_cleanup_timer , _tf_ssb_on_handle_close ) ;
}
2021-12-21 14:06:44 -05:00
if ( ssb - > trace_timer . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > trace_timer ) )
{
uv_close ( ( uv_handle_t * ) & ssb - > trace_timer , _tf_ssb_on_handle_close ) ;
}
2021-10-10 17:51:38 -04:00
if ( ssb - > server . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > server ) )
{
2021-01-02 13:10:00 -05:00
uv_close ( ( uv_handle_t * ) & ssb - > server , _tf_ssb_on_handle_close ) ;
}
while ( ssb - > broadcast_listener . data | |
ssb - > broadcast_sender . data | |
ssb - > broadcast_timer . data | |
2022-01-19 22:35:03 -05:00
ssb - > broadcast_cleanup_timer . data | |
2021-12-21 14:06:44 -05:00
ssb - > trace_timer . data | |
2021-10-10 17:51:38 -04:00
ssb - > server . data )
{
2021-01-02 13:10:00 -05:00
uv_run ( ssb - > loop , UV_RUN_ONCE ) ;
}
2021-10-10 17:51:38 -04:00
while ( ssb - > rpc )
{
2021-09-06 13:50:38 -04:00
tf_ssb_rpc_callback_node_t * node = ssb - > rpc ;
ssb - > rpc = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > rpc_count - - ;
2021-10-10 17:51:38 -04:00
if ( node - > cleanup )
{
2021-09-06 13:50:38 -04:00
node - > cleanup ( ssb , node - > user_data ) ;
node - > cleanup = NULL ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-09-06 13:50:38 -04:00
}
2021-11-07 17:28:58 -05:00
while ( ssb - > connections_changed )
{
tf_ssb_connections_changed_callback_node_t * node = ssb - > connections_changed ;
ssb - > connections_changed = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > connections_changed_count - - ;
2021-11-07 17:28:58 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-07 17:28:58 -05:00
}
2021-11-10 19:05:07 -05:00
while ( ssb - > message_added )
{
tf_ssb_message_added_callback_node_t * node = ssb - > message_added ;
ssb - > message_added = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > message_added_count - - ;
2021-11-10 19:05:07 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-10 19:05:07 -05:00
}
2021-10-10 17:51:38 -04:00
while ( ssb - > blob_want_added )
{
2021-09-06 13:50:38 -04:00
tf_ssb_blob_want_added_callback_node_t * node = ssb - > blob_want_added ;
ssb - > blob_want_added = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > blob_want_added_count - - ;
2021-10-10 17:51:38 -04:00
if ( node - > cleanup )
{
2021-09-06 13:50:38 -04:00
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-09-06 13:50:38 -04:00
}
2021-11-07 17:28:58 -05:00
while ( ssb - > broadcasts_changed )
{
tf_ssb_broadcasts_changed_callback_node_t * node = ssb - > broadcasts_changed ;
ssb - > broadcasts_changed = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > broadcasts_changed_count - - ;
2021-11-07 17:28:58 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-07 17:28:58 -05:00
}
2022-11-02 19:34:44 -04:00
if ( ssb - > loop = = & ssb - > own_loop )
{
uv_loop_close ( ssb - > loop ) ;
}
2021-10-10 17:51:38 -04:00
if ( ssb - > own_context )
{
2021-01-02 13:10:00 -05:00
JS_FreeContext ( ssb - > context ) ;
JS_FreeRuntime ( ssb - > runtime ) ;
}
2023-02-07 20:29:44 -05:00
sqlite3_close ( ssb - > db ) ;
2021-10-10 17:51:38 -04:00
while ( ssb - > broadcasts )
{
2021-01-02 13:10:00 -05:00
tf_ssb_broadcast_t * broadcast = ssb - > broadcasts ;
ssb - > broadcasts = broadcast - > next ;
2022-01-12 20:08:17 -05:00
ssb - > broadcasts_count - - ;
2022-06-04 13:04:51 -04:00
tf_free ( broadcast ) ;
2021-01-02 13:10:00 -05:00
}
2023-01-22 15:37:19 -05:00
for ( int i = 0 ; i < k_debug_close_connection_count ; i + + )
{
for ( int j = 0 ; j < k_debug_close_message_count ; j + + )
{
tf_free ( ssb - > debug_close [ i ] . messages [ j ] ) ;
}
}
2023-02-07 20:29:44 -05:00
for ( int i = 0 ; i < ssb - > db_readers_count ; i + + )
{
sqlite3_close ( ssb - > db_readers [ i ] ) ;
}
2023-02-07 20:50:47 -05:00
tf_free ( ssb - > db_readers ) ;
2023-02-07 20:29:44 -05:00
uv_mutex_destroy ( & ssb - > db_readers_lock ) ;
tf_free ( ( void * ) ssb - > db_path ) ;
2022-06-04 13:04:51 -04:00
tf_free ( ssb ) ;
2021-01-02 13:10:00 -05:00
}
void tf_ssb_run ( tf_ssb_t * ssb )
{
uv_run ( ssb - > loop , UV_RUN_DEFAULT ) ;
}
2021-09-06 13:50:38 -04:00
static void _tf_ssb_connection_finalizer ( JSRuntime * runtime , JSValue value )
{
tf_ssb_connection_t * connection = JS_GetOpaque ( value , _connection_class_id ) ;
2022-01-22 15:13:14 -05:00
if ( connection )
{
connection - > object = JS_UNDEFINED ;
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_destroy ( connection , " object finalized " ) ;
2022-01-22 15:13:14 -05:00
}
2021-09-06 13:50:38 -04:00
}
2022-01-22 15:13:14 -05:00
static void _tf_ssb_connection_process_message_async ( uv_async_t * async )
{
tf_ssb_connection_t * connection = async - > data ;
if ( _tf_ssb_connection_box_stream_recv ( connection ) )
{
uv_async_send ( & connection - > async ) ;
}
2023-01-16 21:17:29 -05:00
_tf_ssb_connection_dispatch_scheduled ( connection ) ;
2022-01-22 15:13:14 -05:00
}
2021-01-02 13:10:00 -05:00
tf_ssb_connection_t * tf_ssb_connection_create ( tf_ssb_t * ssb , const char * host , const struct sockaddr_in * addr , const uint8_t * public_key )
{
2022-01-19 23:01:45 -05:00
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
2022-11-09 18:25:22 -05:00
if ( memcmp ( connection - > serverpub , public_key , k_id_bin_len ) = = 0 & & connection - > state ! = k_tf_ssb_state_invalid )
2022-01-19 23:01:45 -05:00
{
char id [ k_id_base64_len ] ;
tf_ssb_id_bin_to_str ( id , sizeof ( id ) , public_key ) ;
2022-11-09 18:25:22 -05:00
printf ( " Not connecting to %s:%d, because we are already connected to %s (state = %d). \n " , host , ntohs ( addr - > sin_port ) , id , connection - > state ) ;
2022-01-19 23:01:45 -05:00
return NULL ;
}
else if ( memcmp ( ssb - > pub , public_key , k_id_bin_len ) = = 0 )
{
char id [ k_id_base64_len ] ;
tf_ssb_id_bin_to_str ( id , sizeof ( id ) , public_key ) ;
printf ( " Not connecting to %s:%d, because they appear to be ourselves %s. \n " , host , ntohs ( addr - > sin_port ) , id ) ;
return NULL ;
}
}
2021-09-06 13:50:38 -04:00
JSContext * context = ssb - > context ;
2022-06-04 13:04:51 -04:00
tf_ssb_connection_t * connection = tf_malloc ( sizeof ( tf_ssb_connection_t ) ) ;
2021-01-02 13:10:00 -05:00
memset ( connection , 0 , sizeof ( * connection ) ) ;
2022-11-02 19:34:44 -04:00
snprintf ( connection - > name , sizeof ( connection - > name ) , " cli%d " , s_connection_index + + ) ;
2021-01-02 13:10:00 -05:00
connection - > ssb = ssb ;
connection - > tcp . data = connection ;
connection - > connect . data = connection ;
connection - > send_request_number = 1 ;
snprintf ( connection - > host , sizeof ( connection - > host ) , " %s " , host ) ;
connection - > port = ntohs ( addr - > sin_port ) ;
2022-01-22 15:13:14 -05:00
connection - > async . data = connection ;
uv_async_init ( ssb - > loop , & connection - > async , _tf_ssb_connection_process_message_async ) ;
2021-01-02 13:10:00 -05:00
2021-09-06 13:50:38 -04:00
connection - > object = JS_NewObjectClass ( ssb - > context , _connection_class_id ) ;
2022-01-22 15:47:10 -05:00
JS_SetOpaque ( connection - > object , connection ) ;
2021-09-06 13:50:38 -04:00
char public_key_str [ k_id_base64_len ] = { 0 } ;
if ( tf_ssb_id_bin_to_str ( public_key_str , sizeof ( public_key_str ) , public_key ) )
{
JS_SetPropertyStr ( context , connection - > object , " id " , JS_NewString ( context , public_key_str ) ) ;
2021-12-27 14:52:42 -05:00
JS_SetPropertyStr ( context , connection - > object , " is_client " , JS_TRUE ) ;
2021-09-06 13:50:38 -04:00
}
2021-01-02 13:10:00 -05:00
memcpy ( connection - > serverpub , public_key , sizeof ( connection - > serverpub ) ) ;
uv_tcp_init ( ssb - > loop , & connection - > tcp ) ;
2022-01-19 23:01:45 -05:00
int result = uv_tcp_connect ( & connection - > connect , & connection - > tcp , ( const struct sockaddr * ) addr , _tf_ssb_connection_on_connect ) ;
if ( result )
{
printf ( " uv_tcp_connect(%s): %s \n " , host , uv_strerror ( result ) ) ;
2022-05-20 21:38:13 -04:00
connection - > connect . data = NULL ;
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_destroy ( connection , " connect failed " ) ;
2022-01-19 23:01:45 -05:00
}
else
{
connection - > next = ssb - > connections ;
ssb - > connections = connection ;
ssb - > connections_count + + ;
_tf_ssb_notify_connections_changed ( ssb , k_tf_ssb_change_create , connection ) ;
}
2021-01-02 13:10:00 -05:00
return connection ;
}
2022-11-02 19:34:44 -04:00
static void _tf_ssb_connection_tunnel_callback (
tf_ssb_connection_t * connection ,
uint8_t flags ,
int32_t request_number ,
JSValue args ,
const uint8_t * message ,
size_t size ,
void * user_data )
{
tf_ssb_connection_t * tunnel = user_data ;
_tf_ssb_connection_on_tcp_recv_internal ( tunnel , message , size ) ;
}
2022-11-12 22:24:30 -05:00
tf_ssb_connection_t * tf_ssb_connection_tunnel_create ( tf_ssb_t * ssb , const char * portal_id , int32_t request_number , const char * target_id )
2022-11-02 19:34:44 -04:00
{
2023-01-18 19:02:31 -05:00
if ( tf_ssb_connection_get ( ssb , target_id ) )
{
/* Already have a possibly more direct connection to target. */
return NULL ;
}
2022-11-12 22:24:30 -05:00
tf_ssb_connection_t * connection = tf_ssb_connection_get ( ssb , portal_id ) ;
2022-11-02 19:34:44 -04:00
JSContext * context = ssb - > context ;
tf_ssb_connection_t * tunnel = tf_malloc ( sizeof ( tf_ssb_connection_t ) ) ;
memset ( tunnel , 0 , sizeof ( * tunnel ) ) ;
snprintf ( tunnel - > name , sizeof ( tunnel - > name ) , " tun%d " , s_tunnel_index + + ) ;
tunnel - > ssb = ssb ;
tunnel - > tunnel_connection = connection ;
tunnel - > tunnel_request_number = - request_number ;
tunnel - > send_request_number = 1 ;
tunnel - > async . data = tunnel ;
uv_async_init ( ssb - > loop , & tunnel - > async , _tf_ssb_connection_process_message_async ) ;
tunnel - > object = JS_NewObjectClass ( ssb - > context , _connection_class_id ) ;
JS_SetOpaque ( tunnel - > object , tunnel ) ;
JS_SetPropertyStr ( context , tunnel - > object , " id " , JS_NewString ( context , target_id ) ) ;
JS_SetPropertyStr ( context , tunnel - > object , " is_client " , JS_TRUE ) ;
tf_ssb_id_str_to_bin ( tunnel - > serverpub , target_id ) ;
tunnel - > next = ssb - > connections ;
ssb - > connections = tunnel ;
ssb - > connections_count + + ;
_tf_ssb_notify_connections_changed ( ssb , k_tf_ssb_change_create , tunnel ) ;
tf_ssb_connection_add_request (
connection ,
request_number ,
_tf_ssb_connection_tunnel_callback ,
NULL ,
2022-11-06 21:57:29 -05:00
tunnel ,
2022-11-02 19:34:44 -04:00
tunnel ) ;
2022-11-13 17:30:09 -05:00
if ( request_number > 0 )
2022-11-02 19:34:44 -04:00
{
tunnel - > state = k_tf_ssb_state_connected ;
_tf_ssb_connection_client_send_hello ( tunnel ) ;
}
else
{
tunnel - > state = k_tf_ssb_state_server_wait_hello ;
}
return tunnel ;
}
2021-01-02 13:10:00 -05:00
typedef struct _connect_t {
tf_ssb_t * ssb ;
uv_getaddrinfo_t req ;
char host [ 256 ] ;
int port ;
uint8_t key [ k_id_bin_len ] ;
} connect_t ;
static void _tf_on_connect_getaddrinfo ( uv_getaddrinfo_t * addrinfo , int result , struct addrinfo * info )
{
connect_t * connect = addrinfo - > data ;
2021-10-10 17:51:38 -04:00
if ( result = = 0 & & info )
{
2021-01-02 13:10:00 -05:00
struct sockaddr_in addr = * ( struct sockaddr_in * ) info - > ai_addr ;
addr . sin_port = htons ( connect - > port ) ;
tf_ssb_connection_create ( connect - > ssb , connect - > host , & addr , connect - > key ) ;
}
2022-01-19 23:01:45 -05:00
else
{
printf ( " getaddrinfo => %s \n " , uv_strerror ( result ) ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( connect ) ;
2021-01-02 13:10:00 -05:00
uv_freeaddrinfo ( info ) ;
}
void tf_ssb_connect ( tf_ssb_t * ssb , const char * host , int port , const uint8_t * key )
{
2022-06-04 13:04:51 -04:00
connect_t * connect = tf_malloc ( sizeof ( connect_t ) ) ;
2021-10-10 17:51:38 -04:00
* connect = ( connect_t )
{
2021-01-02 13:10:00 -05:00
. ssb = ssb ,
. port = port ,
. req . data = connect ,
} ;
2023-01-17 19:37:45 -05:00
char id [ k_id_base64_len ] = { 0 } ;
tf_ssb_id_bin_to_str ( id , sizeof ( id ) , key ) ;
tf_ssb_connections_store ( ssb - > connections_tracker , host , port , id ) ;
2021-01-02 13:10:00 -05:00
snprintf ( connect - > host , sizeof ( connect - > host ) , " %s " , host ) ;
memcpy ( connect - > key , key , k_id_bin_len ) ;
int r = uv_getaddrinfo ( ssb - > loop , & connect - > req , _tf_on_connect_getaddrinfo , host , NULL , & ( struct addrinfo ) { . ai_family = AF_INET } ) ;
2021-10-10 17:51:38 -04:00
if ( r < 0 )
{
2021-01-02 13:10:00 -05:00
printf ( " uv_getaddrinfo: %s \n " , uv_strerror ( r ) ) ;
2022-06-04 13:04:51 -04:00
tf_free ( connect ) ;
2021-01-02 13:10:00 -05:00
}
}
2022-11-08 20:31:18 -05:00
void tf_ssb_connection_close ( tf_ssb_connection_t * connection )
{
_tf_ssb_connection_close ( connection , " tf_ssb_connection_close " ) ;
}
2021-10-10 17:51:38 -04:00
static void _tf_ssb_on_connection ( uv_stream_t * stream , int status )
{
2021-01-02 13:10:00 -05:00
tf_ssb_t * ssb = stream - > data ;
2021-10-10 17:51:38 -04:00
if ( status < 0 )
{
2021-01-02 13:10:00 -05:00
printf ( " uv_listen failed: %s \n " , uv_strerror ( status ) ) ;
return ;
}
2022-06-04 13:04:51 -04:00
tf_ssb_connection_t * connection = tf_malloc ( sizeof ( tf_ssb_connection_t ) ) ;
2021-01-02 13:10:00 -05:00
memset ( connection , 0 , sizeof ( * connection ) ) ;
2022-11-02 19:34:44 -04:00
snprintf ( connection - > name , sizeof ( connection - > name ) , " srv%d " , s_connection_index + + ) ;
2021-01-02 13:10:00 -05:00
connection - > ssb = ssb ;
connection - > tcp . data = connection ;
connection - > send_request_number = 1 ;
2022-01-22 15:13:14 -05:00
connection - > async . data = connection ;
uv_async_init ( ssb - > loop , & connection - > async , _tf_ssb_connection_process_message_async ) ;
2021-01-02 13:10:00 -05:00
2021-09-06 13:50:38 -04:00
connection - > object = JS_NewObjectClass ( ssb - > context , _connection_class_id ) ;
JS_SetOpaque ( connection - > object , connection ) ;
2021-10-10 17:51:38 -04:00
if ( uv_tcp_init ( ssb - > loop , & connection - > tcp ) ! = 0 )
{
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_destroy ( connection , " init failed " ) ;
2021-01-02 13:10:00 -05:00
return ;
}
2021-10-10 17:51:38 -04:00
if ( uv_accept ( stream , ( uv_stream_t * ) & connection - > tcp ) ! = 0 )
{
2022-01-25 20:15:04 -05:00
_tf_ssb_connection_destroy ( connection , " accept failed " ) ;
2021-01-02 13:10:00 -05:00
return ;
}
connection - > next = ssb - > connections ;
ssb - > connections = connection ;
2022-01-12 20:08:17 -05:00
ssb - > connections_count + + ;
2021-11-07 17:28:58 -05:00
_tf_ssb_notify_connections_changed ( ssb , k_tf_ssb_change_create , connection ) ;
2021-01-02 13:10:00 -05:00
connection - > state = k_tf_ssb_state_server_wait_hello ;
uv_read_start ( ( uv_stream_t * ) & connection - > tcp , _tf_ssb_connection_on_tcp_alloc , _tf_ssb_connection_on_tcp_recv ) ;
}
static void _tf_ssb_send_broadcast ( tf_ssb_t * ssb , struct sockaddr_in * address )
{
struct sockaddr server_addr ;
int len = ( int ) sizeof ( server_addr ) ;
if ( uv_tcp_getsockname ( & ssb - > server , & server_addr , & len ) ! = 0 | |
2021-10-10 17:51:38 -04:00
server_addr . sa_family ! = AF_INET )
{
2021-01-02 13:10:00 -05:00
printf ( " Unable to get server's address. \n " ) ;
}
char address_str [ 256 ] ;
2021-10-10 17:51:38 -04:00
if ( uv_ip4_name ( address , address_str , sizeof ( address_str ) ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
printf ( " Unable to convert address to string. \n " ) ;
}
char fullid [ k_id_base64_len ] ;
2023-02-13 22:15:24 -05:00
tf_base64_encode ( ssb - > pub , sizeof ( ssb - > pub ) , fullid , sizeof ( fullid ) ) ;
2021-01-02 13:10:00 -05:00
char message [ 512 ] ;
snprintf ( message , sizeof ( message ) , " net:%s:%d~shs:%s " , address_str , ntohs ( ( ( struct sockaddr_in * ) & server_addr ) - > sin_port ) , fullid ) ;
uv_buf_t buf = { . base = message , . len = strlen ( message ) } ;
struct sockaddr_in broadcast_addr = { 0 } ;
broadcast_addr . sin_family = AF_INET ;
broadcast_addr . sin_port = htons ( 8008 ) ;
broadcast_addr . sin_addr . s_addr = INADDR_BROADCAST ;
int r = uv_udp_try_send ( & ssb - > broadcast_sender , & buf , 1 , ( struct sockaddr * ) & broadcast_addr ) ;
2021-10-10 17:51:38 -04:00
if ( r < 0 )
{
2021-01-02 13:10:00 -05:00
printf ( " failed to send broadcast %d: %s \n " , r , uv_strerror ( r ) ) ;
}
}
static void _tf_ssb_broadcast_timer ( uv_timer_t * timer )
{
tf_ssb_t * ssb = timer - > data ;
uv_interface_address_t * info = NULL ;
int count = 0 ;
2021-10-10 17:51:38 -04:00
if ( uv_interface_addresses ( & info , & count ) = = 0 )
{
for ( int i = 0 ; i < count ; i + + )
{
2021-01-02 13:10:00 -05:00
if ( ! info [ i ] . is_internal & &
2021-10-10 17:51:38 -04:00
info [ i ] . address . address4 . sin_family = = AF_INET )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_send_broadcast ( ssb , & info [ i ] . address . address4 ) ;
}
}
uv_free_interface_addresses ( info , count ) ;
}
}
void tf_ssb_server_open ( tf_ssb_t * ssb , int port )
{
2021-10-10 17:51:38 -04:00
if ( ssb - > server . data )
{
2021-01-02 13:10:00 -05:00
printf ( " Already listening. \n " ) ;
return ;
}
ssb - > server . data = ssb ;
2021-10-10 17:51:38 -04:00
if ( uv_tcp_init ( ssb - > loop , & ssb - > server ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
printf ( " uv_tcp_init failed \n " ) ;
return ;
}
struct sockaddr_in addr = { 0 } ;
addr . sin_family = AF_INET ;
addr . sin_port = htons ( port ) ;
addr . sin_addr . s_addr = INADDR_ANY ;
2021-10-10 17:51:38 -04:00
if ( uv_tcp_bind ( & ssb - > server , ( struct sockaddr * ) & addr , 0 ) ! = 0 )
{
2021-01-02 13:10:00 -05:00
printf ( " uv_tcp_bind failed \n " ) ;
return ;
}
int status = uv_listen ( ( uv_stream_t * ) & ssb - > server , SOMAXCONN , _tf_ssb_on_connection ) ;
2021-10-10 17:51:38 -04:00
if ( status ! = 0 )
{
2021-01-02 13:10:00 -05:00
printf ( " uv_listen failed: %s \n " , uv_strerror ( status ) ) ;
/* TODO: cleanup */
return ;
}
2021-12-20 12:00:25 -05:00
printf ( " Starting broadcasts. \n " ) ;
2021-01-02 13:10:00 -05:00
uv_timer_start ( & ssb - > broadcast_timer , _tf_ssb_broadcast_timer , 2000 , 2000 ) ;
}
void tf_ssb_server_close ( tf_ssb_t * ssb )
{
2021-10-10 17:51:38 -04:00
if ( ssb - > server . data & & ! uv_is_closing ( ( uv_handle_t * ) & ssb - > server ) )
{
2021-01-02 13:10:00 -05:00
uv_close ( ( uv_handle_t * ) & ssb - > server , _tf_ssb_on_handle_close ) ;
}
uv_timer_stop ( & ssb - > broadcast_timer ) ;
2021-12-20 12:00:25 -05:00
printf ( " Stopped broadcasts. \n " ) ;
2021-01-02 13:10:00 -05:00
}
bool tf_ssb_whoami ( tf_ssb_t * ssb , char * out_id , size_t out_id_size )
{
return tf_ssb_id_bin_to_str ( out_id , out_id_size , ssb - > pub ) ;
}
static bool _tf_ssb_parse_broadcast ( const char * in_broadcast , tf_ssb_broadcast_t * out_broadcast )
{
char public_key_str [ 45 ] = { 0 } ;
int port = 0 ;
static_assert ( sizeof ( out_broadcast - > host ) = = 256 , " host field size " ) ;
2022-11-08 21:15:07 -05:00
if ( sscanf ( in_broadcast , " net:%255[0-9A-Za-z.-]:%d~shs:%44s " , out_broadcast - > host , & port , public_key_str ) = = 3 )
2021-10-10 17:51:38 -04:00
{
2022-11-08 21:15:07 -05:00
out_broadcast - > addr . sin_family = AF_INET ;
out_broadcast - > addr . sin_port = htons ( ( uint16_t ) port ) ;
2023-02-13 22:15:24 -05:00
int r = tf_base64_decode ( public_key_str , strlen ( public_key_str ) , out_broadcast - > pub , crypto_sign_PUBLICKEYBYTES ) ;
2022-11-08 21:15:07 -05:00
return r ! = - 1 ;
2021-10-10 17:51:38 -04:00
}
2022-11-02 19:34:44 -04:00
else if ( strncmp ( in_broadcast , " ws: " , 3 ) = = 0 )
2021-10-10 17:51:38 -04:00
{
2021-01-02 13:10:00 -05:00
printf ( " Unsupported broadcast: %s \n " , in_broadcast ) ;
}
return false ;
}
void tf_ssb_connect_str ( tf_ssb_t * ssb , const char * address )
{
tf_ssb_broadcast_t broadcast = { 0 } ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_parse_broadcast ( address , & broadcast ) )
{
2022-11-08 21:15:07 -05:00
tf_ssb_connect ( ssb , broadcast . host , ntohs ( broadcast . addr . sin_port ) , broadcast . pub ) ;
2021-10-10 17:51:38 -04:00
}
else
{
2021-01-02 13:10:00 -05:00
printf ( " Unable to parse: %s \n " , address ) ;
}
}
static void _tf_ssb_on_broadcast_listener_alloc ( uv_handle_t * handle , size_t suggested_size , uv_buf_t * buf )
{
2022-06-04 13:04:51 -04:00
buf - > base = tf_malloc ( suggested_size ) ;
2022-02-05 14:58:22 -05:00
buf - > len = suggested_size ;
2021-01-02 13:10:00 -05:00
}
2021-11-07 17:28:58 -05:00
static void _tf_ssb_notify_broadcasts_changed ( tf_ssb_t * ssb )
{
2021-12-27 17:28:27 -05:00
tf_ssb_broadcasts_changed_callback_node_t * next = NULL ;
for ( tf_ssb_broadcasts_changed_callback_node_t * node = ssb - > broadcasts_changed ; node ; node = next )
2021-11-07 17:28:58 -05:00
{
2021-12-27 17:28:27 -05:00
next = node - > next ;
2021-11-07 17:28:58 -05:00
if ( node - > callback )
{
2023-02-03 10:06:18 -05:00
tf_trace_begin ( ssb - > trace , " broadcasts changed " ) ;
2021-11-07 17:28:58 -05:00
node - > callback ( ssb , node - > user_data ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( ssb - > trace ) ;
2021-11-07 17:28:58 -05:00
}
}
}
2021-01-02 13:10:00 -05:00
static void _tf_ssb_add_broadcast ( tf_ssb_t * ssb , const tf_ssb_broadcast_t * broadcast )
{
2021-10-10 17:51:38 -04:00
if ( memcmp ( broadcast - > pub , ssb - > pub , sizeof ( ssb - > pub ) ) = = 0 )
{
2021-01-02 13:10:00 -05:00
return ;
}
2022-11-02 19:34:44 -04:00
if ( broadcast - > tunnel_connection )
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
for ( tf_ssb_broadcast_t * node = ssb - > broadcasts ; node ; node = node - > next )
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
if ( node - > tunnel_connection = = broadcast - > tunnel_connection & &
memcmp ( node - > pub , broadcast - > pub , sizeof ( node - > pub ) ) = = 0 )
{
node - > mtime = time ( NULL ) ;
return ;
}
2021-01-02 13:10:00 -05:00
}
}
2022-11-02 19:34:44 -04:00
else
2021-10-10 17:51:38 -04:00
{
2022-11-02 19:34:44 -04:00
for ( tf_ssb_broadcast_t * node = ssb - > broadcasts ; node ; node = node - > next )
{
if ( node - > addr . sin_family = = broadcast - > addr . sin_family & &
node - > addr . sin_port = = broadcast - > addr . sin_port & &
node - > addr . sin_addr . s_addr = = broadcast - > addr . sin_addr . s_addr & &
memcmp ( node - > pub , broadcast - > pub , sizeof ( node - > pub ) ) = = 0 )
{
node - > mtime = time ( NULL ) ;
return ;
}
}
char key [ k_id_base64_len ] ;
if ( tf_ssb_id_bin_to_str ( key , sizeof ( key ) , broadcast - > pub ) )
{
2023-01-17 19:37:45 -05:00
printf ( " Received new broadcast: host=%s, pub=%s. \n " , broadcast - > host , key ) ;
2022-11-02 19:34:44 -04:00
}
2021-01-02 13:10:00 -05:00
}
2022-06-04 13:04:51 -04:00
tf_ssb_broadcast_t * node = tf_malloc ( sizeof ( tf_ssb_broadcast_t ) ) ;
2021-01-02 13:10:00 -05:00
* node = * broadcast ;
node - > next = ssb - > broadcasts ;
node - > ctime = time ( NULL ) ;
node - > mtime = node - > ctime ;
ssb - > broadcasts = node ;
2022-01-12 20:08:17 -05:00
ssb - > broadcasts_count + + ;
2021-01-02 13:10:00 -05:00
2021-11-07 17:28:58 -05:00
_tf_ssb_notify_broadcasts_changed ( ssb ) ;
2021-01-02 13:10:00 -05:00
}
static void _tf_ssb_on_broadcast_listener_recv ( uv_udp_t * handle , ssize_t nread , const uv_buf_t * buf , const struct sockaddr * addr , unsigned flags )
{
2021-10-10 17:51:38 -04:00
if ( nread < = 0 )
{
2022-06-04 13:04:51 -04:00
tf_free ( buf - > base ) ;
2021-01-02 13:10:00 -05:00
return ;
}
tf_ssb_t * ssb = handle - > data ;
( ( char * ) buf - > base ) [ nread ] = ' \0 ' ;
const char * k_delim = " ; " ;
char * state = NULL ;
char * entry = strtok_r ( buf - > base , k_delim , & state ) ;
2021-10-10 17:51:38 -04:00
while ( entry )
{
2021-01-02 13:10:00 -05:00
tf_ssb_broadcast_t broadcast = { 0 } ;
2021-10-10 17:51:38 -04:00
if ( _tf_ssb_parse_broadcast ( entry , & broadcast ) )
{
2021-01-02 13:10:00 -05:00
_tf_ssb_add_broadcast ( ssb , & broadcast ) ;
}
entry = strtok_r ( NULL , k_delim , & state ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( buf - > base ) ;
2021-01-02 13:10:00 -05:00
}
2022-11-08 22:51:31 -05:00
void tf_ssb_visit_broadcasts ( tf_ssb_t * ssb , void ( * callback ) ( const char * host , const struct sockaddr_in * addr , tf_ssb_connection_t * tunnel , const uint8_t * pub , void * user_data ) , void * user_data )
2021-01-02 13:10:00 -05:00
{
time_t now = time ( NULL ) ;
2021-12-27 17:28:27 -05:00
tf_ssb_broadcast_t * next = NULL ;
for ( tf_ssb_broadcast_t * node = ssb - > broadcasts ; node ; node = next )
2021-10-10 17:51:38 -04:00
{
2021-12-27 17:28:27 -05:00
next = node - > next ;
2021-10-10 17:51:38 -04:00
if ( node - > mtime - now < 60 )
{
2023-02-03 10:06:18 -05:00
tf_trace_begin ( ssb - > trace , " broadcast " ) ;
2022-11-08 22:51:31 -05:00
callback ( node - > host , & node - > addr , node - > tunnel_connection , node - > pub , user_data ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( ssb - > trace ) ;
2021-01-02 13:10:00 -05:00
}
}
}
2022-01-19 22:35:03 -05:00
static void _tf_ssb_broadcast_cleanup_timer ( uv_timer_t * timer )
{
tf_ssb_t * ssb = timer - > data ;
int modified = 0 ;
time_t now = time ( NULL ) ;
for ( tf_ssb_broadcast_t * * it = & ssb - > broadcasts ; * it ; )
{
2022-11-08 19:37:51 -05:00
if ( ! ( * it ) - > tunnel_connection & & ( * it ) - > mtime < now - 10 )
2022-01-19 22:35:03 -05:00
{
tf_ssb_broadcast_t * node = * it ;
* it = node - > next ;
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2022-01-19 22:35:03 -05:00
ssb - > broadcasts_count - - ;
modified + + ;
}
else
{
it = & ( * it ) - > next ;
}
}
if ( modified )
{
_tf_ssb_notify_broadcasts_changed ( ssb ) ;
}
}
2021-01-02 13:10:00 -05:00
void tf_ssb_broadcast_listener_start ( tf_ssb_t * ssb , bool linger )
{
2021-10-10 17:51:38 -04:00
if ( ssb - > broadcast_listener . data )
{
2021-01-02 13:10:00 -05:00
return ;
}
ssb - > broadcast_listener . data = ssb ;
uv_udp_init ( ssb - > loop , & ssb - > broadcast_listener ) ;
struct sockaddr_in addr = { 0 } ;
addr . sin_family = AF_INET ;
addr . sin_port = htons ( 8008 ) ;
addr . sin_addr . s_addr = INADDR_ANY ;
int result = uv_udp_bind ( & ssb - > broadcast_listener , ( const struct sockaddr * ) & addr , UV_UDP_REUSEADDR ) ;
2021-10-10 17:51:38 -04:00
if ( result ! = 0 )
{
2021-01-02 13:10:00 -05:00
printf ( " bind: %s \n " , uv_strerror ( result ) ) ;
}
result = uv_udp_recv_start ( & ssb - > broadcast_listener , _tf_ssb_on_broadcast_listener_alloc , _tf_ssb_on_broadcast_listener_recv ) ;
2021-10-10 17:51:38 -04:00
if ( result ! = 0 )
{
2021-01-02 13:10:00 -05:00
printf ( " uv_udp_recv_start: %s \n " , uv_strerror ( result ) ) ;
}
2021-10-10 17:51:38 -04:00
if ( ! linger )
{
2021-01-02 13:10:00 -05:00
uv_unref ( ( uv_handle_t * ) & ssb - > broadcast_listener ) ;
}
2022-01-19 22:35:03 -05:00
ssb - > broadcast_cleanup_timer . data = ssb ;
uv_timer_init ( ssb - > loop , & ssb - > broadcast_cleanup_timer ) ;
uv_timer_start ( & ssb - > broadcast_cleanup_timer , _tf_ssb_broadcast_cleanup_timer , 2000 , 2000 ) ;
2021-01-02 13:10:00 -05:00
}
2023-01-08 08:48:28 -05:00
void tf_ssb_broadcast_sender_start ( tf_ssb_t * ssb )
{
if ( ssb - > broadcast_sender . data )
{
return ;
}
ssb - > broadcast_sender . data = ssb ;
uv_udp_init ( ssb - > loop , & ssb - > broadcast_sender ) ;
struct sockaddr_in broadcast_from = {
. sin_family = AF_INET ,
. sin_addr . s_addr = INADDR_ANY ,
} ;
uv_udp_bind ( & ssb - > broadcast_sender , ( struct sockaddr * ) & broadcast_from , 0 ) ;
uv_udp_set_broadcast ( & ssb - > broadcast_sender , 1 ) ;
ssb - > trace_timer . data = ssb ;
uv_timer_init ( ssb - > loop , & ssb - > trace_timer ) ;
uv_timer_start ( & ssb - > trace_timer , _tf_ssb_trace_timer , 100 , 100 ) ;
uv_unref ( ( uv_handle_t * ) & ssb - > trace_timer ) ;
}
2021-01-02 13:10:00 -05:00
void tf_ssb_append_post ( tf_ssb_t * ssb , const char * text )
{
JSValue obj = JS_NewObject ( ssb - > context ) ;
JS_SetPropertyStr ( ssb - > context , obj , " type " , JS_NewString ( ssb - > context , " post " ) ) ;
JS_SetPropertyStr ( ssb - > context , obj , " text " , JS_NewString ( ssb - > context , text ) ) ;
tf_ssb_append_message ( ssb , obj ) ;
JS_FreeValue ( ssb - > context , obj ) ;
}
2022-11-02 19:34:44 -04:00
tf_ssb_connection_t * tf_ssb_connection_get ( tf_ssb_t * ssb , const char * id )
{
uint8_t pub [ k_id_bin_len ] = { 0 } ;
tf_ssb_id_str_to_bin ( pub , id ) ;
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
if ( memcmp ( connection - > serverpub , pub , k_id_bin_len ) = = 0 )
{
return connection ;
}
else if ( memcmp ( ssb - > pub , pub , k_id_bin_len ) = = 0 )
{
return connection ;
}
}
return NULL ;
}
2021-01-02 13:10:00 -05:00
const char * * tf_ssb_get_connection_ids ( tf_ssb_t * ssb )
{
int count = 0 ;
2021-10-10 17:51:38 -04:00
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
if ( connection - > state = = k_tf_ssb_state_verified | | connection - > state = = k_tf_ssb_state_server_verified )
{
2021-01-02 13:10:00 -05:00
count + + ;
}
}
2022-06-04 13:04:51 -04:00
char * buffer = tf_malloc ( sizeof ( char * ) * ( count + 1 ) + k_id_base64_len * count ) ;
2021-01-02 13:10:00 -05:00
char * * array = ( char * * ) buffer ;
char * strings = buffer + sizeof ( char * ) * ( count + 1 ) ;
int i = 0 ;
2021-10-10 17:51:38 -04:00
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
if ( connection - > state = = k_tf_ssb_state_verified | | connection - > state = = k_tf_ssb_state_server_verified )
{
2021-01-02 13:10:00 -05:00
char * write_pos = strings + k_id_base64_len * i ;
tf_ssb_id_bin_to_str ( write_pos , k_id_base64_len , connection - > serverpub ) ;
array [ i + + ] = write_pos ;
}
}
array [ i ] = NULL ;
return ( const char * * ) array ;
}
int tf_ssb_get_connections ( tf_ssb_t * ssb , tf_ssb_connection_t * * out_connections , int out_connections_count )
{
int i = 0 ;
for ( tf_ssb_connection_t * connection = ssb - > connections ;
connection & & i < out_connections_count ;
2021-10-10 17:51:38 -04:00
connection = connection - > next )
{
2021-01-02 13:10:00 -05:00
out_connections [ i + + ] = connection ;
}
return i ;
}
2021-11-07 17:28:58 -05:00
void tf_ssb_add_broadcasts_changed_callback ( tf_ssb_t * ssb , tf_ssb_broadcasts_changed_callback_t * callback , tf_ssb_callback_cleanup_t * cleanup , void * user_data )
{
2022-06-04 13:04:51 -04:00
tf_ssb_broadcasts_changed_callback_node_t * node = tf_malloc ( sizeof ( tf_ssb_broadcasts_changed_callback_node_t ) ) ;
2021-11-07 17:28:58 -05:00
* node = ( tf_ssb_broadcasts_changed_callback_node_t )
{
. callback = callback ,
. cleanup = cleanup ,
. user_data = user_data ,
. next = ssb - > broadcasts_changed ,
} ;
ssb - > broadcasts_changed = node ;
2022-01-12 20:08:17 -05:00
ssb - > broadcasts_changed_count + + ;
2021-11-07 17:28:58 -05:00
}
void tf_ssb_remove_broadcasts_changed_callback ( tf_ssb_t * ssb , tf_ssb_broadcasts_changed_callback_t * callback , void * user_data )
2021-01-02 13:10:00 -05:00
{
2021-11-07 17:28:58 -05:00
tf_ssb_broadcasts_changed_callback_node_t * * it = & ssb - > broadcasts_changed ;
while ( * it )
{
if ( ( * it ) - > callback = = callback & &
( * it ) - > user_data = = user_data )
{
tf_ssb_broadcasts_changed_callback_node_t * node = * it ;
* it = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > broadcasts_changed_count - - ;
2021-11-07 17:28:58 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-07 17:28:58 -05:00
}
else
{
2021-11-17 18:47:55 -05:00
it = & ( * it ) - > next ;
2021-11-07 17:28:58 -05:00
}
}
2021-01-02 13:10:00 -05:00
}
2021-11-07 17:28:58 -05:00
void tf_ssb_add_connections_changed_callback ( tf_ssb_t * ssb , tf_ssb_connections_changed_callback_t * callback , tf_ssb_callback_cleanup_t * cleanup , void * user_data )
2021-01-02 13:10:00 -05:00
{
2022-06-04 13:04:51 -04:00
tf_ssb_connections_changed_callback_node_t * node = tf_malloc ( sizeof ( tf_ssb_connections_changed_callback_node_t ) ) ;
2021-11-07 17:28:58 -05:00
* node = ( tf_ssb_connections_changed_callback_node_t )
{
. callback = callback ,
. cleanup = cleanup ,
. user_data = user_data ,
. next = ssb - > connections_changed ,
} ;
ssb - > connections_changed = node ;
2022-01-12 20:08:17 -05:00
ssb - > connections_changed_count + + ;
2021-01-02 13:10:00 -05:00
}
2021-11-07 17:28:58 -05:00
void tf_ssb_remove_connections_changed_callback ( tf_ssb_t * ssb , tf_ssb_connections_changed_callback_t * callback , void * user_data )
{
tf_ssb_connections_changed_callback_node_t * * it = & ssb - > connections_changed ;
while ( * it )
{
if ( ( * it ) - > callback = = callback & &
( * it ) - > user_data = = user_data )
{
tf_ssb_connections_changed_callback_node_t * node = * it ;
* it = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > connections_changed_count - - ;
2021-11-07 17:28:58 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-07 17:28:58 -05:00
}
else
{
2021-11-17 18:47:55 -05:00
it = & ( * it ) - > next ;
2021-11-07 17:28:58 -05:00
}
}
}
void tf_ssb_add_rpc_callback ( tf_ssb_t * ssb , const char * * name , tf_ssb_rpc_callback_t * callback , tf_ssb_callback_cleanup_t * cleanup , void * user_data )
2021-01-02 13:10:00 -05:00
{
size_t name_len = 0 ;
int name_count = 0 ;
2021-10-10 17:51:38 -04:00
for ( int i = 0 ; name [ i ] ; i + + )
{
2021-01-02 13:10:00 -05:00
name_count + + ;
name_len + = strlen ( name [ i ] ) + 1 ;
}
2023-02-03 10:06:18 -05:00
tf_ssb_rpc_callback_node_t * node = tf_malloc (
sizeof ( tf_ssb_rpc_callback_node_t ) +
( name_count + 1 ) * sizeof ( const char * ) +
name_len +
name_len + 3 ) ;
2021-10-10 17:51:38 -04:00
* node = ( tf_ssb_rpc_callback_node_t )
{
2021-01-02 13:10:00 -05:00
. name = ( const char * * ) ( node + 1 ) ,
2023-02-03 10:06:18 -05:00
. flattened_name = ( const char * ) ( node + 1 ) + ( name_count + 1 ) * sizeof ( const char * ) + name_len ,
2021-01-02 13:10:00 -05:00
. callback = callback ,
2021-09-06 13:50:38 -04:00
. cleanup = cleanup ,
2021-01-02 13:10:00 -05:00
. user_data = user_data ,
. next = ssb - > rpc ,
} ;
char * p = ( char * ) ( node + 1 ) + ( name_count + 1 ) * sizeof ( const char * ) ;
2021-10-10 17:51:38 -04:00
for ( int i = 0 ; i < name_count ; i + + )
{
2021-01-02 13:10:00 -05:00
size_t len = strlen ( name [ i ] ) ;
memcpy ( p , name [ i ] , len + 1 ) ;
node - > name [ i ] = p ;
p + = len + 1 ;
}
2023-02-03 10:06:18 -05:00
char * flattened_name = ( char * ) node - > flattened_name ;
for ( int i = 0 ; i < name_count ; i + + )
{
size_t length = strlen ( name [ i ] ) ;
memcpy ( flattened_name , name [ i ] , length ) ;
flattened_name + = length ;
if ( i ! = name_count - 1 )
{
* flattened_name + + = ' . ' ;
}
}
* flattened_name + + = ' ( ' ;
* flattened_name + + = ' ) ' ;
* flattened_name + + = ' \0 ' ;
2021-01-02 13:10:00 -05:00
node - > name [ name_count ] = NULL ;
ssb - > rpc = node ;
2022-01-12 20:08:17 -05:00
ssb - > rpc_count + + ;
2021-01-02 13:10:00 -05:00
}
JSContext * tf_ssb_connection_get_context ( tf_ssb_connection_t * connection )
{
return connection - > ssb - > context ;
}
tf_ssb_t * tf_ssb_connection_get_ssb ( tf_ssb_connection_t * connection )
{
return connection - > ssb ;
}
int32_t tf_ssb_connection_next_request_number ( tf_ssb_connection_t * connection )
{
return connection - > send_request_number + + ;
}
2021-09-06 13:50:38 -04:00
JSClassID tf_ssb_get_connection_class_id ( )
{
return _connection_class_id ;
}
JSValue tf_ssb_connection_get_object ( tf_ssb_connection_t * connection )
{
return connection ? connection - > object : JS_UNDEFINED ;
}
2021-11-10 19:05:07 -05:00
void tf_ssb_add_message_added_callback ( tf_ssb_t * ssb , void ( * callback ) ( tf_ssb_t * ssb , const char * id , void * user_data ) , void ( * cleanup ) ( tf_ssb_t * ssb , void * user_data ) , void * user_data )
{
2022-06-04 13:04:51 -04:00
tf_ssb_message_added_callback_node_t * node = tf_malloc ( sizeof ( tf_ssb_message_added_callback_node_t ) ) ;
2021-11-10 19:05:07 -05:00
* node = ( tf_ssb_message_added_callback_node_t )
{
. callback = callback ,
. cleanup = cleanup ,
. user_data = user_data ,
. next = ssb - > message_added ,
} ;
ssb - > message_added = node ;
2022-01-12 20:08:17 -05:00
ssb - > message_added_count + + ;
2021-11-10 19:05:07 -05:00
}
void tf_ssb_remove_message_added_callback ( tf_ssb_t * ssb , tf_ssb_message_added_callback_t * callback , void * user_data )
{
tf_ssb_message_added_callback_node_t * * it = & ssb - > message_added ;
while ( * it )
{
if ( ( * it ) - > callback = = callback & &
( * it ) - > user_data = = user_data )
{
tf_ssb_message_added_callback_node_t * node = * it ;
* it = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > message_added_count - - ;
2021-11-10 19:05:07 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-10 19:05:07 -05:00
}
else
{
2021-11-17 18:47:55 -05:00
it = & ( * it ) - > next ;
2021-11-10 19:05:07 -05:00
}
}
}
2023-01-18 17:52:54 -05:00
void tf_ssb_notify_blob_stored ( tf_ssb_t * ssb , const char * id )
{
ssb - > blobs_stored + + ;
}
2021-11-10 19:05:07 -05:00
void tf_ssb_notify_message_added ( tf_ssb_t * ssb , const char * id )
{
2021-12-27 17:28:27 -05:00
tf_ssb_message_added_callback_node_t * next = NULL ;
2022-02-05 15:18:58 -05:00
ssb - > messages_stored + + ;
2021-12-27 17:28:27 -05:00
for ( tf_ssb_message_added_callback_node_t * node = ssb - > message_added ; node ; node = next )
2021-11-10 19:05:07 -05:00
{
2021-12-27 17:28:27 -05:00
next = node - > next ;
2023-02-03 10:06:18 -05:00
tf_trace_begin ( ssb - > trace , " message added callback " ) ;
2021-11-10 19:05:07 -05:00
node - > callback ( ssb , id , node - > user_data ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( ssb - > trace ) ;
2021-11-10 19:05:07 -05:00
}
2023-01-08 12:45:15 -05:00
JSContext * context = ssb - > context ;
JSValue message_keys = tf_ssb_db_get_message_by_id ( ssb , id , true ) ;
JSValue message = JS_GetPropertyStr ( context , message_keys , " value " ) ;
if ( ! JS_IsUndefined ( message ) )
{
JSValue author = JS_GetPropertyStr ( context , message , " author " ) ;
const char * author_string = JS_ToCString ( context , author ) ;
for ( tf_ssb_connection_t * connection = ssb - > connections ; connection ; connection = connection - > next )
{
tf_ssb_connection_message_request_t * message_request =
bsearch (
author_string ,
connection - > message_requests ,
connection - > message_requests_count ,
sizeof ( tf_ssb_connection_message_request_t ) ,
_message_request_compare ) ;
if ( message_request )
{
tf_ssb_connection_rpc_send_json (
connection ,
k_ssb_rpc_flag_stream ,
message_request - > request_number ,
message_request - > keys ? message_keys : message ,
NULL ,
NULL ,
NULL ) ;
}
}
JS_FreeCString ( context , author_string ) ;
JS_FreeValue ( context , author ) ;
}
JS_FreeValue ( context , message ) ;
JS_FreeValue ( context , message_keys ) ;
2021-11-10 19:05:07 -05:00
}
2021-11-07 17:28:58 -05:00
void tf_ssb_add_blob_want_added_callback ( tf_ssb_t * ssb , void ( * callback ) ( tf_ssb_t * ssb , const char * id , void * user_data ) , void ( * cleanup ) ( tf_ssb_t * ssb , void * user_data ) , void * user_data )
2021-09-06 13:50:38 -04:00
{
2022-06-04 13:04:51 -04:00
tf_ssb_blob_want_added_callback_node_t * node = tf_malloc ( sizeof ( tf_ssb_blob_want_added_callback_node_t ) ) ;
2021-09-06 13:50:38 -04:00
* node = ( tf_ssb_blob_want_added_callback_node_t )
{
. callback = callback ,
. cleanup = cleanup ,
. user_data = user_data ,
. next = ssb - > blob_want_added ,
} ;
ssb - > blob_want_added = node ;
2022-01-12 20:08:17 -05:00
ssb - > blob_want_added_count + + ;
2021-09-06 13:50:38 -04:00
}
2021-11-07 17:28:58 -05:00
void tf_ssb_remove_blob_want_added_callback ( tf_ssb_t * ssb , tf_ssb_blob_want_added_callback_t * callback , void * user_data )
{
tf_ssb_blob_want_added_callback_node_t * * it = & ssb - > blob_want_added ;
while ( * it )
{
if ( ( * it ) - > callback = = callback & &
( * it ) - > user_data = = user_data )
{
tf_ssb_blob_want_added_callback_node_t * node = * it ;
* it = node - > next ;
2022-01-12 20:08:17 -05:00
ssb - > blob_want_added_count - - ;
2021-11-07 17:28:58 -05:00
if ( node - > cleanup )
{
node - > cleanup ( ssb , node - > user_data ) ;
}
2022-06-04 13:04:51 -04:00
tf_free ( node ) ;
2021-11-07 17:28:58 -05:00
}
else
{
2021-11-17 18:47:55 -05:00
it = & ( * it ) - > next ;
2021-11-07 17:28:58 -05:00
}
}
}
2021-09-06 13:50:38 -04:00
void tf_ssb_notify_blob_want_added ( tf_ssb_t * ssb , const char * id )
{
2021-12-27 17:28:27 -05:00
tf_ssb_blob_want_added_callback_node_t * next = NULL ;
for ( tf_ssb_blob_want_added_callback_node_t * node = ssb - > blob_want_added ; node ; node = next )
2021-09-06 13:50:38 -04:00
{
2021-12-27 17:28:27 -05:00
next = node - > next ;
2023-02-03 10:06:18 -05:00
tf_trace_begin ( ssb - > trace , " blob want added callback " ) ;
2021-09-06 13:50:38 -04:00
node - > callback ( ssb , id , node - > user_data ) ;
2023-02-03 10:06:18 -05:00
tf_trace_end ( ssb - > trace ) ;
2021-09-06 13:50:38 -04:00
}
}
2022-11-02 19:34:44 -04:00
void tf_ssb_connection_add_room_attendant ( tf_ssb_connection_t * connection , const char * id )
{
tf_ssb_broadcast_t broadcast =
{
. tunnel_connection = connection ,
} ;
tf_ssb_id_str_to_bin ( broadcast . pub , id ) ;
_tf_ssb_add_broadcast ( connection - > ssb , & broadcast ) ;
}
void tf_ssb_connection_remove_room_attendant ( tf_ssb_connection_t * connection , const char * id )
{
uint8_t pub [ k_id_bin_len ] = { 0 } ;
tf_ssb_id_str_to_bin ( pub , id ) ;
int modified = 0 ;
for ( tf_ssb_broadcast_t * * it = & connection - > ssb - > broadcasts ; * it ; )
{
if ( ( * it ) - > tunnel_connection = = connection & &
memcmp ( ( * it ) - > pub , pub , k_id_bin_len ) = = 0 )
{
tf_ssb_broadcast_t * node = * it ;
* it = node - > next ;
tf_free ( node ) ;
connection - > ssb - > broadcasts_count - - ;
modified + + ;
}
else
{
it = & ( * it ) - > next ;
}
}
if ( modified )
{
_tf_ssb_notify_broadcasts_changed ( connection - > ssb ) ;
}
}
2023-01-04 19:52:23 -05:00
2023-01-07 19:25:38 -05:00
bool tf_ssb_connection_is_attendant ( tf_ssb_connection_t * connection )
{
return connection - > is_attendant ;
}
int32_t tf_ssb_connection_get_attendant_request_number ( tf_ssb_connection_t * connection )
{
return connection - > attendant_request_number ;
}
void tf_ssb_connection_set_attendant ( tf_ssb_connection_t * connection , bool attendant , int request_number )
{
connection - > is_attendant = attendant ;
connection - > attendant_request_number = request_number ;
_tf_ssb_notify_broadcasts_changed ( connection - > ssb ) ;
}
void tf_ssb_connection_clear_room_attendants ( tf_ssb_connection_t * connection )
{
int modified = 0 ;
for ( tf_ssb_broadcast_t * * it = & connection - > ssb - > broadcasts ; * it ; )
{
if ( ( * it ) - > tunnel_connection = = connection )
{
tf_ssb_broadcast_t * node = * it ;
* it = node - > next ;
tf_free ( node ) ;
connection - > ssb - > broadcasts_count - - ;
modified + + ;
}
else
{
it = & ( * it ) - > next ;
}
}
if ( modified )
{
_tf_ssb_notify_broadcasts_changed ( connection - > ssb ) ;
}
}
2023-01-04 19:52:23 -05:00
tf_ssb_blob_wants_t * tf_ssb_connection_get_blob_wants_state ( tf_ssb_connection_t * connection )
{
return connection ? & connection - > blob_wants : NULL ;
}
2023-01-08 15:01:35 -05:00
bool tf_ssb_verify_strip_and_store_message ( tf_ssb_t * ssb , JSValue value )
{
JSContext * context = tf_ssb_get_context ( ssb ) ;
2023-01-13 19:55:51 -05:00
char signature [ crypto_sign_BYTES + 128 ] = { 0 } ;
char id [ crypto_hash_sha256_BYTES * 2 + 1 ] = { 0 } ;
2023-01-08 15:01:35 -05:00
bool sequence_before_author = false ;
if ( tf_ssb_verify_and_strip_signature ( context , value , id , sizeof ( id ) , signature , sizeof ( signature ) , & sequence_before_author ) )
{
if ( tf_ssb_db_store_message ( ssb , context , id , value , signature , sequence_before_author ) )
{
tf_ssb_notify_message_added ( ssb , id ) ;
return true ;
}
}
else
{
printf ( " failed to verify message \n " ) ;
}
return false ;
}
bool tf_ssb_connection_get_sent_clock ( tf_ssb_connection_t * connection )
{
return connection - > sent_clock ;
}
void tf_ssb_connection_set_sent_clock ( tf_ssb_connection_t * connection , bool sent_clock )
{
connection - > sent_clock = sent_clock ;
}
int32_t tf_ssb_connection_get_ebt_request_number ( tf_ssb_connection_t * connection )
{
return connection - > ebt_request_number ;
}
void tf_ssb_connection_set_ebt_request_number ( tf_ssb_connection_t * connection , int32_t request_number )
{
connection - > ebt_request_number = request_number ;
}
JSValue tf_ssb_connection_get_ebt_send_clock ( tf_ssb_connection_t * connection )
{
JSContext * context = connection - > ssb - > context ;
return JS_DupValue ( context , connection - > ebt_send_clock ) ;
}
void tf_ssb_connection_set_ebt_send_clock ( tf_ssb_connection_t * connection , JSValue send_clock )
{
JSContext * context = connection - > ssb - > context ;
JS_FreeValue ( context , connection - > ebt_send_clock ) ;
connection - > ebt_send_clock = JS_DupValue ( context , send_clock ) ;
}
2023-01-22 15:37:19 -05:00
JSValue tf_ssb_get_disconnection_debug ( tf_ssb_t * ssb , JSContext * context )
{
JSValue result = JS_NewObject ( context ) ;
JSValue disconnections = JS_NewArray ( context ) ;
for ( int i = 0 ; i < k_debug_close_connection_count ; i + + )
{
JSValue disconnection = JS_NewObject ( context ) ;
if ( * ssb - > debug_close [ i ] . id )
{
JS_SetPropertyStr ( context , disconnection , " id " , JS_NewString ( context , ssb - > debug_close [ i ] . id ) ) ;
if ( * ssb - > debug_close [ i ] . tunnel )
{
JS_SetPropertyStr ( context , disconnection , " tunnel " , JS_NewString ( context , ssb - > debug_close [ i ] . tunnel ) ) ;
}
JS_SetPropertyStr ( context , disconnection , " reason " , JS_NewString ( context , ssb - > debug_close [ i ] . reason ) ) ;
JSValue messages = JS_NewArray ( context ) ;
for ( int j = 0 ; j < k_debug_close_message_count ; j + + )
{
if ( ssb - > debug_close [ i ] . messages [ j ] )
{
JSValue message = JS_NewObject ( context ) ;
JS_SetPropertyStr ( context , message , " direction " , JS_NewString ( context , ssb - > debug_close [ i ] . messages [ j ] - > outgoing ? " out " : " in " ) ) ;
JS_SetPropertyStr ( context , message , " flags " , JS_NewInt32 ( context , ssb - > debug_close [ i ] . messages [ j ] - > flags ) ) ;
JS_SetPropertyStr ( context , message , " request_number " , JS_NewInt32 ( context , ssb - > debug_close [ i ] . messages [ j ] - > request_number ) ) ;
JS_SetPropertyStr ( context , message , " payload " , JS_NewStringLen ( context , ( const char * ) ssb - > debug_close [ i ] . messages [ j ] - > data , ssb - > debug_close [ i ] . messages [ j ] - > size ) ) ;
JS_SetPropertyUint32 ( context , messages , j , message ) ;
}
}
JS_SetPropertyStr ( context , disconnection , " messages " , messages ) ;
}
JS_SetPropertyUint32 ( context , disconnections , i , disconnection ) ;
}
JS_SetPropertyStr ( context , result , " disconnections " , disconnections ) ;
return result ;
}