@ -813,6 +813,9 @@ static void cs_handle_channel_info_req(struct chat_sync* cs, uint64_t peer,
memcpy ( buf + boff , ed_pub , 32 ) ; boff + = 32 ;
memcpy ( buf + boff , ch_sig , 64 ) ; boff + = 64 ;
memcpy ( buf + boff , my_join_sig , 64 ) ; boff + = 64 ;
{ const char * iname = cs - > inst - > name [ 0 ] ? cs - > inst - > name : " " ;
uint8_t il = ( uint8_t ) strlen ( iname ) ;
buf [ boff + + ] = il ; memcpy ( buf + boff , iname , il ) ; boff + = il ; }
cs_send ( cs , ch_id , peer , buf , boff ) ;
}
@ -822,7 +825,8 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
const char * ch_id , const uint8_t * pl , size_t len ) {
if ( cs - > info_req_timer ) { uasync_cancel_timeout ( cs - > inst - > ua , cs - > info_req_timer ) ; cs - > info_req_timer = NULL ; }
if ( len < 1 ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP too short len=%zu peer=%016llx " , CS_ID , len , ( unsigned long long ) peer ) ; return ; }
uint8_t nl = pl [ 0 ] ; if ( 1 + nl + 8 + 1 + 32 + 32 + 64 + 64 > len ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP truncated len=%zu need=%d " , CS_ID , len , 1 + nl + 8 + 1 + 32 + 32 + 64 + 64 ) ; return ; }
uint8_t nl = pl [ 0 ] ;
if ( 1 + nl + 8 + 1 + 32 + 32 + 64 + 64 + 1 > len ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP truncated len=%zu min=%d " , CS_ID , len , 1 + nl + 8 + 1 + 32 + 32 + 64 + 64 + 1 ) ; return ; }
const uint8_t * p = pl + 1 ;
char name [ 128 ] ; memcpy ( name , p , nl ) ; name [ nl ] = ' \0 ' ; p + = nl ;
uint64_t owner ; memcpy ( & owner , p , 8 ) ; p + = 8 ;
@ -830,7 +834,10 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
const uint8_t * x25519 = p ; p + = 32 ;
const uint8_t * ed_pub = p ; p + = 32 ;
const uint8_t * ch_sig = p ; p + = 64 ;
const uint8_t * inviter_join_sig = p ;
const uint8_t * inviter_join_sig = p ; p + = 64 ;
uint8_t inv_name_len = * p + + ;
char inv_name [ 128 ] = " " ;
if ( p + inv_name_len < = pl + len ) { memcpy ( inv_name , p , inv_name_len ) ; inv_name [ inv_name_len ] = ' \0 ' ; }
DEBUG_DEBUG ( DEBUG_CATEGORY_DEBUG , " %s: CHANNEL_INFO_RESP from peer=%016llx owner=%016llx ch_x25519=%016llx ch_ed=%016llx name=%s " ,
CS_ID , ( unsigned long long ) peer , ( unsigned long long ) owner ,
@ -853,7 +860,7 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
ch_id , name , ( int ) is_dm , owner , x25519 , NULL , ed_pub , NULL , ch_sig ) ;
chat_core_ensure_channel_ready ( ch_id ) ;
/* verify inviter's join_sig using ETCP-authenticated keys */
/* verify inviter's join_sig AND save node info using ETCP-authenticated keys */
{ struct ETCP_CONN * inv_conn = cs_find_conn_for_node ( cs - > inst , peer ) ;
if ( ! inv_conn ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP no ETCP conn for inviter peer=%016llx " , CS_ID , ( unsigned long long ) peer ) ;
@ -865,13 +872,24 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
ilen + = snprintf ( ( char * ) ivmsg + ilen , sizeof ( ivmsg ) - ilen , " %s " , ch_id ) + 1 ;
memcpy ( ivmsg + ilen , & peer , 8 ) ; ilen + = 8 ;
memcpy ( ivmsg + ilen , inv_x25519 , 32 ) ; ilen + = 32 ;
{ char nnm [ 64 ] = " " ; _get_node_name ( cs - > inst - > topo_groups - > topo_sqlite_db , peer , nnm , sizeof ( nnm ) ) ;
size_t nl = strlen ( n nm) ; memcpy ( ivmsg + ilen , n nm, nl ) ; ilen + = nl ; ivmsg [ ilen + + ] = ' \0 ' ;
{ const char * nm = inv_name [ 0 ] ? inv_name : " " ;
size_t nl2 = strlen ( nm ) ; memcpy ( ivmsg + ilen , nm , nl2 ) ; ilen + = nl2 ; ivmsg [ ilen + + ] = ' \0 ' ;
if ( cs_ed25519_verify ( inv_ed , ivmsg , ilen , inviter_join_sig ) ! = 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP invalid inviter_join_sig peer=%016llx x25519=%016llx inv_ed=%016llx name=%s " ,
CS_ID , ( unsigned long long ) peer , * ( const uint64_t * ) inv_x25519 , * ( const uint64_t * ) inv_ed , nn m ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP invalid inviter_join_sig peer=%016llx x25519=%016llx inv_ed=%016llx inv_ name=%s " ,
CS_ID , ( unsigned long long ) peer , * ( const uint64_t * ) inv_x25519 , * ( const uint64_t * ) inv_ed , nm ) ;
}
}
/* save inviter node_info to local DB */
sqlite3 * vdb = cs - > inst - > topo_groups - > topo_sqlite_db ;
if ( vdb & & inv_name [ 0 ] ) {
sqlite3_stmt * ns = NULL ;
sqlite3_prepare_v2 ( vdb , " INSERT OR REPLACE INTO nodes(node_id,name,x25519_pubkey,ed25519_pubkey) VALUES(?,?,?,?) " , - 1 , & ns , NULL ) ;
if ( ns ) { sqlite3_bind_int64 ( ns , 1 , ( sqlite3_int64 ) peer ) ;
sqlite3_bind_text ( ns , 2 , inv_name , - 1 , SQLITE_STATIC ) ;
sqlite3_bind_blob ( ns , 3 , inv_x25519 , 32 , SQLITE_STATIC ) ;
sqlite3_bind_blob ( ns , 4 , inv_ed , 32 , SQLITE_STATIC ) ;
sqlite3_step ( ns ) ; sqlite3_finalize ( ns ) ; }
}
}
/* save inviter as node and member */
@ -900,6 +918,9 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
memcpy ( jbuf + joff , my_x25519 , 32 ) ; joff + = 32 ;
memcpy ( jbuf + joff , cs - > inst - > my_ed25519_pubkey , 32 ) ; joff + = 32 ;
memcpy ( jbuf + joff , join_sig , 64 ) ; joff + = 64 ;
{ const char * nm = cs - > inst - > name [ 0 ] ? cs - > inst - > name : " " ;
uint8_t nml = ( uint8_t ) strlen ( nm ) ;
jbuf [ joff + + ] = nml ; memcpy ( jbuf + joff , nm , nml ) ; joff + = nml ; }
/* add local addresses */
uint8_t addr_cnt = 0 ; size_t ac_pos = joff ;
jbuf [ joff + + ] = 0 ;
@ -942,12 +963,15 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
static void cs_handle_channel_join ( struct chat_sync * cs , uint64_t peer ,
const char * ch_id , const uint8_t * pl , size_t len ) {
if ( len < 8 + 32 + 32 + 64 + 1 ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_JOIN too short len=%zu peer=%016llx " , CS_ID , len , ( unsigned long long ) peer ) ; return ; }
if ( len < 8 + 32 + 32 + 64 + 1 + 1 ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_JOIN too short len=%zu peer=%016llx " , CS_ID , len , ( unsigned long long ) peer ) ; return ; }
const uint8_t * p = pl ;
uint64_t node_id ; memcpy ( & node_id , p , 8 ) ; p + = 8 ;
const uint8_t * x25519 = p ; p + = 32 ;
const uint8_t * ed_pub = p ; p + = 32 ;
const uint8_t * join_sig = p ; p + = 64 ;
uint8_t name_len = * p + + ;
char joiner_name [ 128 ] = " " ;
if ( p + name_len < = pl + len ) { memcpy ( joiner_name , p , name_len ) ; joiner_name [ name_len ] = ' \0 ' ; p + = name_len ; }
uint8_t addr_cnt = * p + + ;
/* verify join_sig */
@ -955,17 +979,27 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
vlen + = snprintf ( ( char * ) vmsg + vlen , sizeof ( vmsg ) - vlen , " %s " , ch_id ) + 1 ;
memcpy ( vmsg + vlen , & node_id , 8 ) ; vlen + = 8 ;
memcpy ( vmsg + vlen , x25519 , 32 ) ; vlen + = 32 ;
{ sqlite3 * tdb = cs - > inst - > topo_groups - > topo_sqlite_db ; char nnm [ 64 ] = " " ; _get_node_name ( tdb , node_id , nnm , sizeof ( nnm ) ) ;
size_t nl = strlen ( nn m ) ; memcpy ( vmsg + vlen , n nm, nl ) ; vlen + = nl ; vmsg [ vlen + + ] = ' \0 ' ; }
{ const char * nm = joiner_name [ 0 ] ? joiner_name : " " ;
size_t nl = strlen ( nm ) ; memcpy ( vmsg + vlen , nm , nl ) ; vlen + = nl ; vmsg [ vlen + + ] = ' \0 ' ; }
if ( cs_ed25519_verify ( ed_pub , vmsg , vlen , join_sig ) ! = 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTIVITY , " %s: JOIN invalid sig node=0x%016llx ch=%s — signed(node=%016llx x25519=%016llx ed=%016llx) " , CS_ID ,
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTIVITY , " %s: JOIN invalid sig node=0x%016llx ch=%s — signed(node=%016llx x25519=%016llx ed=%016llx name=%s ) " , CS_ID ,
( unsigned long long ) node_id , ch_id ,
( unsigned long long ) node_id , * ( const uint64_t * ) x25519 , * ( const uint64_t * ) ed_pub ) ;
( unsigned long long ) node_id , * ( const uint64_t * ) x25519 , * ( const uint64_t * ) ed_pub , joiner_name ) ;
return ;
}
sqlite3 * db = cs - > inst - > topo_groups - > topo_sqlite_db ;
topo_node_sqlite_member_put ( db , ch_id , node_id , join_sig , NULL ) ;
/* save joiner node_info to local DB */
if ( db & & joiner_name [ 0 ] ) {
sqlite3_stmt * ns = NULL ;
sqlite3_prepare_v2 ( db , " INSERT OR REPLACE INTO nodes(node_id,name,x25519_pubkey,ed25519_pubkey) VALUES(?,?,?,?) " , - 1 , & ns , NULL ) ;
if ( ns ) { sqlite3_bind_int64 ( ns , 1 , ( sqlite3_int64 ) node_id ) ;
sqlite3_bind_text ( ns , 2 , joiner_name , - 1 , SQLITE_STATIC ) ;
sqlite3_bind_blob ( ns , 3 , x25519 , 32 , SQLITE_STATIC ) ;
sqlite3_bind_blob ( ns , 4 , ed_pub , 32 , SQLITE_STATIC ) ;
sqlite3_step ( ns ) ; sqlite3_finalize ( ns ) ; }
}
/* save/update node addresses */
for ( uint8_t i = 0 ; i < addr_cnt & & p + 1 < = pl + len ; i + + ) {
@ -1010,10 +1044,12 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
memcpy ( ubuf + uoff , x25519 , 32 ) ; uoff + = 32 ;
memcpy ( ubuf + uoff , ed_pub , 32 ) ; uoff + = 32 ;
memcpy ( ubuf + uoff , join_sig , 64 ) ; uoff + = 64 ;
ubuf [ uoff + + ] = name_len ;
memcpy ( ubuf + uoff , joiner_name , name_len ) ; uoff + = name_len ;
ubuf [ uoff + + ] = addr_cnt ;
size_t addr_data_sz = ( size_t ) ( p - ( pl + 8 + 32 + 32 + 64 + 1 ) ) ;
size_t addr_data_sz = ( size_t ) ( p - ( pl + 8 + 32 + 32 + 64 + 1 + name_len + 1 ) ) ;
if ( uoff + addr_data_sz < = sizeof ( ubuf ) ) {
memcpy ( ubuf + uoff , pl + 8 + 32 + 32 + 64 + 1 , addr_data_sz ) ;
memcpy ( ubuf + uoff , pl + 8 + 32 + 32 + 64 + 1 + name_len + 1 , addr_data_sz ) ;
uoff + = addr_data_sz ;
}
cs_propagate ( cs , ch_id , peer , ubuf , uoff ) ;
@ -1100,12 +1136,15 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
static void cs_handle_peer_upsert ( struct chat_sync * cs , uint64_t peer ,
const char * ch_id , const uint8_t * pl , size_t len ) {
if ( len < 8 + 32 + 32 + 64 + 1 ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: PEER_UPSERT too short len=%zu " , CS_ID , len ) ; return ; }
if ( len < 8 + 32 + 32 + 64 + 1 + 1 + 1 ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: PEER_UPSERT too short len=%zu " , CS_ID , len ) ; return ; }
const uint8_t * p = pl ;
uint64_t node_id ; memcpy ( & node_id , p , 8 ) ; p + = 8 ;
const uint8_t * x25519 = p ; p + = 32 ;
const uint8_t * ed_pub = p ; p + = 32 ;
const uint8_t * join_sig = p ; p + = 64 ;
uint8_t name_len = * p + + ;
char peer_name [ 128 ] = " " ;
if ( p + name_len < = pl + len ) { memcpy ( peer_name , p , name_len ) ; peer_name [ name_len ] = ' \0 ' ; p + = name_len ; }
uint8_t ac = * p + + ;
/* verify join_sig */
@ -1113,8 +1152,8 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
vlen + = snprintf ( ( char * ) vmsg + vlen , sizeof ( vmsg ) - vlen , " %s " , ch_id ) + 1 ;
memcpy ( vmsg + vlen , & node_id , 8 ) ; vlen + = 8 ;
memcpy ( vmsg + vlen , x25519 , 32 ) ; vlen + = 32 ;
{ sqlite3 * tdb = cs - > inst - > topo_groups - > topo_sqlite_db ; char nnm [ 64 ] = " " ; _get_node_name ( tdb , node_id , nnm , sizeof ( nnm ) ) ;
size_t nl = strlen ( nn m ) ; memcpy ( vmsg + vlen , n nm, nl ) ; vlen + = nl ; vmsg [ vlen + + ] = ' \0 ' ; }
{ const char * nm = peer_name [ 0 ] ? peer_name : " " ;
size_t nl = strlen ( nm ) ; memcpy ( vmsg + vlen , nm , nl ) ; vlen + = nl ; vmsg [ vlen + + ] = ' \0 ' ; }
if ( cs_ed25519_verify ( ed_pub , vmsg , vlen , join_sig ) ! = 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTIVITY , " %s: PEER_UPSERT invalid sig node=0x%016llx " , CS_ID ,
( unsigned long long ) node_id ) ;
@ -1124,6 +1163,15 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
sqlite3 * db = cs - > inst - > topo_groups - > topo_sqlite_db ;
topo_node_sqlite_member_put ( db , ch_id , node_id , join_sig , NULL ) ;
if ( db & & peer_name [ 0 ] ) {
sqlite3_stmt * ns = NULL ;
sqlite3_prepare_v2 ( db , " INSERT OR REPLACE INTO nodes(node_id,name,x25519_pubkey,ed25519_pubkey) VALUES(?,?,?,?) " , - 1 , & ns , NULL ) ;
if ( ns ) { sqlite3_bind_int64 ( ns , 1 , ( sqlite3_int64 ) node_id ) ;
sqlite3_bind_text ( ns , 2 , peer_name , - 1 , SQLITE_STATIC ) ;
sqlite3_bind_blob ( ns , 3 , x25519 , 32 , SQLITE_STATIC ) ;
sqlite3_bind_blob ( ns , 4 , ed_pub , 32 , SQLITE_STATIC ) ;
sqlite3_step ( ns ) ; sqlite3_finalize ( ns ) ; }
}
for ( uint8_t i = 0 ; i < ac ; i + + ) {
if ( p + 1 > pl + len ) break ;