@ -102,48 +102,7 @@ static int fb_key(uint64_t channel, const struct chat_feedback_record* r, merkle
return 0 ;
}
/* Полный мембер, доверенный ключ узла, join_sig и подпись дерева приглашений обязательны. */
static int fb_author_key ( struct UTUN_INSTANCE * inst , const char * channel , uint64_t author , uint8_t key [ 32 ] ) {
char sql [ 384 ] ;
snprintf ( sql , sizeof ( sql ) , " SELECT x25519_pubkey,ed25519_pubkey,signed_by,signature,join_sig,join_ts "
" FROM peers_%s WHERE node_id=? AND source=0 " , channel ) ;
sqlite3_stmt * st = NULL ; sqlite3 * db = inst - > topo_sqlite_db ;
if ( sqlite3_prepare_v2 ( db , sql , - 1 , & st , NULL ) ! = SQLITE_OK ) return fb_db_error ( inst , channel , " author lookup " ) ;
sqlite3_bind_int64 ( st , 1 , ( sqlite3_int64 ) author ) ;
int rc = sqlite3_step ( st ) , ok = 0 ;
int x_bytes = rc = = SQLITE_ROW ? sqlite3_column_bytes ( st , 0 ) : 0 , ed_bytes = rc = = SQLITE_ROW ? sqlite3_column_bytes ( st , 1 ) : 0 ;
int tree_bytes = rc = = SQLITE_ROW ? sqlite3_column_bytes ( st , 3 ) : 0 , join_bytes = rc = = SQLITE_ROW ? sqlite3_column_bytes ( st , 4 ) : 0 ;
const char * reason = " member absent " ;
if ( rc ! = SQLITE_ROW ) goto done ;
reason = " invalid member fields " ;
if ( x_bytes ! = 32 | | ed_bytes ! = 32 | | tree_bytes ! = 64
| | join_bytes ! = 64 | | sqlite3_column_int64 ( st , 5 ) < = 0 ) goto done ;
struct ms_member_rec member = { . node_id = author , . x25519 = sqlite3_column_blob ( st , 0 ) ,
. ed25519 = sqlite3_column_blob ( st , 1 ) , . signed_by = ( uint64_t ) sqlite3_column_int64 ( st , 2 ) ,
. signature = sqlite3_column_blob ( st , 3 ) , . join_sig = sqlite3_column_blob ( st , 4 ) ,
. join_ts = ( uint64_t ) sqlite3_column_int64 ( st , 5 ) } ;
reason = " node_id/X25519 mismatch " ;
if ( sc_derive_node_id_from_pubkey ( member . x25519 ) ! = author ) goto done ;
uint8_t trusted [ 32 ] , x [ 32 ] , ed [ 32 ] , body [ 112 ] ;
reason = " trusted Ed25519 key unavailable " ;
if ( topo_node_sqlite_get_ed25519_pubkey ( db , author , trusted ) ! = 0 ) goto done ;
reason = " trusted Ed25519 key mismatch " ;
if ( memcmp ( trusted , member . ed25519 , 32 ) ) goto done ;
reason = " channel keys unavailable " ;
if ( topo_node_sqlite_channel_get ( db , channel , NULL , 0 , NULL , x , ed , NULL ) ! = 0 ) goto done ;
reason = " invalid join signature " ;
int bytes = member_sync_build_join_msg ( x , ed , author , member . x25519 , member . join_ts , body , sizeof ( body ) ) ;
if ( bytes ! = 112 | | sc_ed25519_verify ( member . ed25519 , body , bytes , member . join_sig ) ! = SC_OK ) goto done ;
reason = " invalid or unresolved invitation signature " ;
if ( member_sync_verify_signature ( db , channel , & member ) ! = 1 ) goto done ;
memcpy ( key , member . ed25519 , 32 ) ; ok = 1 ;
done :
sqlite3_finalize ( st ) ;
if ( ok ) return 0 ;
DEBUG_WARN ( DEBUG_CATEGORY_CHAT_SYNC ,
" feedback: author not verified ch=%s node=%016llx reason=%s rc=%d x_bytes=%d ed_bytes=%d tree_bytes=%d join_bytes=%d " ,
channel , ( unsigned long long ) author , reason , rc , x_bytes , ed_bytes , tree_bytes , join_bytes ) ; return - 1 ;
}
/* Создаёт одну таблицу подписанных состояний и индекс обхода листьев. */
int chat_feedback_ensure_channel ( struct UTUN_INSTANCE * inst , const char * channel ) {
@ -197,7 +156,7 @@ static int fb_apply_row(struct UTUN_INSTANCE* inst, const char* channel, const s
char table [ 40 ] , sql [ 512 ] ; uint64_t id ; uint8_t body [ FB_WIRE_MAX + 32 ] , key [ 32 ] ;
if ( fb_table ( inst , channel , table , & id ) < 0 ) return - 1 ;
int bytes = fb_signed_bytes ( id , r , body ) ;
if ( bytes < 0 | | fb_author_key ( inst , channel , r - > node_id , key ) < 0 ) return - 1 ;
if ( bytes < 0 | | member_sync_verified_ed25519 ( inst , channel , r - > node_id , key ) < 0 ) return - 1 ;
if ( sc_ed25519_verify ( key , body , bytes , r - > signature ) ! = SC_OK ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CHAT_SYNC , " feedback: invalid signature ch=%s node=%016llx kind=%u ver=%llu " ,
channel , ( unsigned long long ) r - > node_id , r - > kind , ( unsigned long long ) r - > ver ) ; return - 1 ;
@ -395,7 +354,7 @@ static int fb_apply_page(void* ctx, const char* channel, uint64_t peer, const ui
static int fb_peer ( void * ctx , const char * channel , uint64_t peer ) {
struct UTUN_INSTANCE * inst = ctx ; uint8_t key [ 32 ] ;
return fb_author_key ( inst , channel , peer , key ) = = 0 ;
return member_sync_verified_ed25519 ( inst , channel , peer , key ) = = 0 ;
}
static const struct merkle_sync_data_ops fb_ops = {
@ -422,7 +381,7 @@ int chat_feedback_init(struct UTUN_INSTANCE* inst) {
while ( ( rc = sqlite3_step ( st ) ) = = SQLITE_ROW ) {
struct chat_feedback_record r ; uint64_t id ; uint8_t body [ FB_WIRE_MAX + 32 ] , key [ 32 ] ; merkle_key_t record_key ;
if ( fb_read_row ( st , & r ) < 0 | | fb_table ( inst , channel , table , & id ) < 0
| | fb_author_key ( inst , channel , r . node_id , key ) < 0 ) { result = - 1 ; break ; }
| | member_sync_verified_ed25519 ( inst , channel , r . node_id , key ) < 0 ) { result = - 1 ; break ; }
int bytes = fb_signed_bytes ( id , & r , body ) ;
if ( bytes < 0 | | sc_ed25519_verify ( key , body , bytes , r . signature ) ! = SC_OK | | fb_key ( id , & r , & record_key ) < 0
| | merkle_sync_recompute_path ( inst , MT_DATA_FEEDBACK , channel , fb_read64 ( record_key . bytes ) ) < 0 ) {