diff --git a/dap_chain_net_srv_vpn_cdb.c b/dap_chain_net_srv_vpn_cdb.c index 16b1651fe66198ab06f419f4830421af1ac9dcfe..3179ed38a24be261aaff5d12d1980fd0b72ae7df 100644 --- a/dap_chain_net_srv_vpn_cdb.c +++ b/dap_chain_net_srv_vpn_cdb.c @@ -76,12 +76,10 @@ typedef struct tx_cond_template{ dap_chain_net_t * net; dap_ledger_t * ledger; time_t min_time; // Minimum time between transactions - - struct tx_cond_template * prev; - struct tx_cond_template * next; + struct tx_cond_template *prev, *next; } tx_cond_template_t; -static tx_cond_template_t * s_tx_cond_templates = NULL; +static tx_cond_template_t *s_tx_cond_templates = NULL; const char *c_wallets_path = NULL; static void s_auth_callback(enc_http_delegate_t* a_delegate, void * a_arg); @@ -124,108 +122,93 @@ int dap_chain_net_srv_vpn_cdb_init(dap_http_t * a_http) false)) { dap_chain_net_srv_vpn_cdb_server_list_add_proc ( a_http, SLIST_URL); } - if( dap_config_get_item_bool_default( g_config,"cdb_auth","enabled",false) ){ + if (dap_config_get_item_bool_default( g_config,"cdb_auth","enabled",false) ){ db_auth_init( dap_config_get_item_str_default(g_config,"cdb_auth","collection_name","cdb") ); // Produce transaction for authorized users if (dap_config_get_item_bool_default( g_config, "cdb_auth", "tx_cond_create", false)) { - + log_it (L_DEBUG, "2791: tx_cond_create is true"); // Parse tx cond templates - size_t l_tx_cond_tpls_count=0; - char ** l_tx_cond_tpls =dap_config_get_array_str( g_config,"cdb_auth", "tx_cond_templates",&l_tx_cond_tpls_count); - for ( size_t i = 0 ; i< l_tx_cond_tpls_count; i++){ - char * l_wallet_name = NULL; - long double l_value = 0.0L; - char * l_token_ticker = NULL; - char * l_net_name = NULL; - int l_step = 0; - time_t l_min_time = 0; - char * l_tpl_parse_old = l_tx_cond_tpls[i]; + size_t l_tx_cond_tpls_count = 0; + char **l_tx_cond_tpls = dap_config_get_array_str(g_config, "cdb_auth", "tx_cond_templates", &l_tx_cond_tpls_count); + log_it (L_DEBUG, "2791: tx_cond_templates: %d", l_tx_cond_tpls_count); + if (l_tx_cond_tpls_count == 0) { + log_it( L_ERROR, "No condition tpl, can't setup auth callback"); + return -5; + } + db_auth_set_callbacks(s_auth_callback); + + for (size_t i = 0 ; i < l_tx_cond_tpls_count; i++) { + char *l_wallet_name = NULL; + long double l_value = 0.0L; + char *l_token_ticker = NULL; + char *l_net_name = NULL; + int l_step = 0; + time_t l_min_time = 0; + log_it (L_DEBUG, "2791: tx_cond: %s", l_tx_cond_tpls[i]); + // Parse template entries - for(char * l_tpl_parse = index(l_tx_cond_tpls[i],':'); l_tpl_parse ;l_tpl_parse = index(l_tpl_parse,':') ){ - size_t l_tpl_entry_size = l_tpl_parse - l_tpl_parse_old; - if (l_tpl_entry_size){ // if not empty entry - char *l_tpl_entry = DAP_NEW_Z_SIZE(char,l_tpl_entry_size); - strncpy(l_tpl_entry,l_tpl_parse_old,l_tpl_entry_size-1); - switch ( l_step) { // Parse entries by order - case 0: l_wallet_name = l_tpl_entry; break; - case 1: l_value = strtold( l_tpl_entry, NULL); DAP_DELETE( l_tpl_entry); break; - case 2: l_min_time =(time_t) atoll(l_tpl_entry); DAP_DELETE( l_tpl_entry); break; - case 3: l_token_ticker = l_tpl_entry; break; - case 4: l_net_name = l_tpl_entry; break; - default: log_it( L_WARNING, "Too many ':' (%d) characters in condition template", l_step); - } - l_step++; - if( l_step > 4) - break; + char *ctx; + for (char *l_tpl_token = strtok_r(l_tx_cond_tpls[i], ":", &ctx); l_tpl_token && l_step <= 4; l_tpl_token = strtok_r(NULL, ":", &ctx), ++l_step) { + log_it (L_DEBUG, "2791: tx_cond_token: %s", l_tpl_token); + switch (l_step) { + case 0: l_wallet_name = l_tpl_token; break; + case 1: l_value = strtold( l_tpl_token, NULL); break; + case 2: l_min_time =(time_t) atoll(l_tpl_token); break; + case 3: l_token_ticker = l_tpl_token; break; + case 4: l_net_name = l_tpl_token; break; + default: log_it(L_WARNING, "Too many ':' (%d) characters in condition template", l_step); break; } - l_tpl_parse_old = l_tpl_parse; } + // If all what we need is present - if ( l_step >4 ) { - if ( l_wallet_name && l_value > 0.0L && l_token_ticker && l_net_name && l_min_time){ - // we create condition template - tx_cond_template_t * l_tx_cond_template = DAP_NEW_Z(tx_cond_template_t); - - l_tx_cond_template->wallet = dap_chain_wallet_open( l_wallet_name,c_wallets_path ); - if( l_tx_cond_template->wallet){ - l_tx_cond_template->wallet_name = l_wallet_name; - - l_tx_cond_template->net = dap_chain_net_by_name( l_net_name ); - if ( l_tx_cond_template->net){ - l_tx_cond_template->net_name = l_net_name; - l_tx_cond_template->ledger = dap_chain_ledger_by_net_name( l_net_name ); - if ( l_tx_cond_template->ledger ){ - l_tx_cond_template->min_time = l_min_time; - l_tx_cond_template->value_coins = l_value; - l_tx_cond_template->value_datoshi = dap_chain_coins_to_balance ( l_value ); - l_tx_cond_template->token_ticker = l_token_ticker; - // and put it in list - l_tx_cond_template->prev = s_tx_cond_templates; - if ( s_tx_cond_templates) - s_tx_cond_templates->next = l_tx_cond_template; - s_tx_cond_templates = l_tx_cond_template; - }else{ - log_it(L_ERROR, "Can't open ledger in network \"%s\" for condition transaction template \"%s\"", l_net_name, l_tx_cond_tpls[i]); - DAP_DELETE( l_wallet_name ); - DAP_DELETE( l_net_name); - DAP_DELETE( l_token_ticker); - DAP_DELETE( l_tx_cond_template); - l_tx_cond_template = NULL; - ret = -4; - } - }else{ - log_it(L_ERROR, "Can't open network \"%s\" for condition transaction template \"%s\"", l_net_name, l_tx_cond_tpls[i]); - DAP_DELETE( l_wallet_name ); - DAP_DELETE( l_net_name); - DAP_DELETE( l_token_ticker); - DAP_DELETE( l_tx_cond_template); - l_tx_cond_template = NULL; - ret = -2; - } - }else{ - log_it(L_ERROR, "Can't open wallet \"%s\" for condition transaction template \"%s\"", l_wallet_name, l_tx_cond_tpls[i]); - DAP_DELETE( l_wallet_name ); - DAP_DELETE( l_net_name); - DAP_DELETE( l_token_ticker); - DAP_DELETE( l_tx_cond_template); - l_tx_cond_template = NULL; - ret = -3; - } + if (l_step <= 4) { + log_it(L_ERROR, "Not enough elements in condition template: 5 needed, %d present", l_step); + //assert(l_wallet_name && l_value > 0.0L && l_token_ticker && l_net_name && l_min_time); + if (!l_wallet_name || l_value <= 0.0L || !l_token_ticker || !l_net_name || !l_min_time) { + log_it(L_ERROR, "Condition template inconsistent"); } + continue; } - } - if ( l_tx_cond_tpls_count ) - db_auth_set_callbacks( s_auth_callback ); - else{ - log_it( L_ERROR, "No condition tpl, can't setup auth callback"); - ret=-1; + + // we create condition template + tx_cond_template_t *l_tx_cond_template = DAP_NEW_Z(tx_cond_template_t); + + if(!(l_tx_cond_template->wallet = dap_chain_wallet_open(l_wallet_name, c_wallets_path))) { + log_it(L_ERROR, "Can't open wallet \"%s\" for condition transaction template \"%s\"", l_wallet_name, l_tx_cond_tpls[i]); + DAP_DELETE(l_tx_cond_template); + continue; + } + + if (!(l_tx_cond_template->net = dap_chain_net_by_name(l_net_name))) { + log_it(L_ERROR, "Can't open network \"%s\" for condition transaction template \"%s\"", l_net_name, l_tx_cond_tpls[i]); + DAP_DELETE(l_tx_cond_template->wallet); + DAP_DELETE(l_tx_cond_template); + continue; + } + + if (!(l_tx_cond_template->ledger = dap_chain_ledger_by_net_name(l_net_name))) { + log_it(L_ERROR, "Can't open ledger in network \"%s\" for condition transaction template \"%s\"", l_net_name, l_tx_cond_tpls[i]); + DAP_DELETE(l_tx_cond_template->wallet); + DAP_DELETE(l_tx_cond_template); + continue; + } + + l_tx_cond_template->wallet_name = l_wallet_name; + l_tx_cond_template->net_name = l_net_name; + l_tx_cond_template->min_time = l_min_time; + l_tx_cond_template->value_coins = l_value; + l_tx_cond_template->value_datoshi = dap_chain_coins_to_balance (l_value); + l_tx_cond_template->token_ticker = l_token_ticker; + DL_APPEND(s_tx_cond_templates, l_tx_cond_template); } } } + if (!s_tx_cond_templates) + ret = -1; return ret; } @@ -248,68 +231,78 @@ static void s_auth_callback(enc_http_delegate_t* a_delegate, void * a_arg) { #ifndef __ANDROID__ db_auth_info_t *l_auth_info = (db_auth_info_t *) a_arg; + dap_enc_key_t *l_client_key; log_it( L_DEBUG, "Authorized, now need to create conditioned transaction if not present"); + { + size_t l_pkey_b64_length = strlen(l_auth_info->pkey); + byte_t l_pkey_raw[l_pkey_b64_length]; + memset(l_pkey_raw, 0, l_pkey_b64_length); + size_t l_pkey_raw_size = + dap_enc_base64_decode(l_auth_info->pkey, l_pkey_b64_length, l_pkey_raw, DAP_ENC_DATA_TYPE_B64_URLSAFE); + char l_pkey_gdb_group[sizeof(DAP_CHAIN_NET_SRV_VPN_CDB_GDB_PREFIX) + 8] = { '\0' }; + dap_snprintf(l_pkey_gdb_group, "%s.pkey", DAP_CHAIN_NET_SRV_VPN_CDB_GDB_PREFIX); + log_it(L_DEBUG, "2791: pkey group %s", l_pkey_gdb_group); + dap_chain_global_db_gr_set(l_auth_info->user, l_pkey_raw, l_pkey_raw_size, l_pkey_gdb_group); + l_client_key = dap_enc_key_deserealize(l_pkey_raw, l_pkey_raw_size); + } - size_t l_pkey_b64_length = strlen(l_auth_info->pkey); - byte_t * l_pkey_raw = DAP_NEW_Z_SIZE(byte_t,l_pkey_b64_length ); - size_t l_pkey_raw_size = dap_enc_base64_decode(l_auth_info->pkey,l_pkey_b64_length,l_pkey_raw, DAP_ENC_DATA_TYPE_B64_URLSAFE ); - char * l_pkey_gdb_group = dap_strdup_printf("%s.pkey", DAP_CHAIN_NET_SRV_VPN_CDB_GDB_PREFIX ); - dap_chain_global_db_gr_set( l_auth_info->user , l_pkey_raw, l_pkey_raw_size,l_pkey_gdb_group); - - dap_enc_key_t *l_client_key = dap_enc_key_deserealize(l_pkey_raw, l_pkey_raw_size); - - for ( tx_cond_template_t * l_tpl = s_tx_cond_templates; l_tpl; l_tpl=l_tpl->next) { - - size_t l_gdb_group_size=0; + tx_cond_template_t *l_tpl, *l_tmp; + DL_FOREACH_SAFE(s_tx_cond_templates, l_tpl, l_tmp) { + size_t l_gdb_group_size = 0; // Try to load from gdb - char * l_tx_cond_gdb_group = dap_strdup_printf("%s.%s.tx_cond", l_tpl->net->pub.name, DAP_CHAIN_NET_SRV_VPN_CDB_GDB_PREFIX ); - dap_chain_hash_fast_t * l_tx_cond_hash = (dap_hash_type_t*) dap_chain_global_db_gr_get( - l_auth_info->user,&l_gdb_group_size, l_tx_cond_gdb_group ); + char l_tx_cond_gdb_group[128] = {'\0'}; + dap_snprintf(l_tx_cond_gdb_group, "%s.%s.tx_cond", l_tpl->net->pub.name, DAP_CHAIN_NET_SRV_VPN_CDB_GDB_PREFIX); + log_it(L_DEBUG, "2791: Checkout group %s", l_tx_cond_gdb_group); + dap_chain_hash_fast_t *l_tx_cond_hash = + (dap_hash_type_t*)dap_chain_global_db_gr_get(l_auth_info->user, &l_gdb_group_size, l_tx_cond_gdb_group); // Check for entry size - if (l_gdb_group_size && l_gdb_group_size != sizeof (dap_chain_hash_fast_t) ){ - log_it(L_ERROR, "Wrong size of tx condition on database (%zd but expected %zd), may be old entry", - l_gdb_group_size, sizeof (dap_chain_hash_fast_t)); + if (l_gdb_group_size && l_gdb_group_size != sizeof(dap_chain_hash_fast_t)) { + log_it(L_ERROR, "Wrong size of tx condition on database (%zd but expected %zd), may be old entry", + l_gdb_group_size, sizeof(dap_chain_hash_fast_t)); } time_t l_tx_cond_ts = 0; // If loaded lets check is it spent or not if ( l_tx_cond_hash ){ - dap_chain_datum_tx_t * l_tx = dap_chain_net_get_tx_by_hash( l_tpl->net, l_tx_cond_hash, TX_SEARCH_TYPE_NET_UNSPENT ); - if ( ! l_tx ){ // If not found - all outs are used. Create new one + log_it(L_DEBUG, "2791: Search for unspent tx, net %s", l_tpl->net_name); + dap_chain_datum_tx_t *l_tx = dap_chain_net_get_tx_by_hash(l_tpl->net, l_tx_cond_hash, TX_SEARCH_TYPE_NET_UNSPENT); + if ( !l_tx ){ // If not found - all outs are used. Create new one // pass all chains - l_tx = dap_chain_net_get_tx_by_hash( l_tpl->net, l_tx_cond_hash, TX_SEARCH_TYPE_NET ); + l_tx = dap_chain_net_get_tx_by_hash(l_tpl->net, l_tx_cond_hash, TX_SEARCH_TYPE_NET); DAP_DELETE(l_tx_cond_hash); l_tx_cond_hash = NULL; if ( l_tx ){ l_tx_cond_ts =(time_t) l_tx->header.ts_created; + log_it(L_DEBUG, "2791: got some tx, created %d", l_tx->header.ts_created); } } - } + // Try to create condition if (! l_tx_cond_hash ) { // test + log_it(L_DEBUG, "2791: Create a tx"); dap_chain_wallet_t *l_wallet_from = l_tpl->wallet; + log_it(L_DEBUG, "2791: From wallet %s", l_wallet_from->name); dap_enc_key_t *l_key_from = dap_chain_wallet_get_key(l_wallet_from, 0); // where to take coins for service - dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet_from, l_tpl->net->pub.id ); + dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet_from, l_tpl->net->pub.id); dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = SERV_UNIT_SEC }; dap_chain_net_srv_uid_t l_srv_uid = { .uint64 = DAP_CHAIN_NET_SRV_VPN_ID }; - l_tx_cond_hash= dap_chain_mempool_tx_create_cond( l_tpl->net, l_key_from,l_client_key, l_addr_from,l_tpl->token_ticker, - (uint64_t) l_tpl->value_datoshi , 0,l_price_unit,l_srv_uid, 0,NULL, 0); - char * l_addr_from_str =dap_chain_addr_to_str( l_addr_from ); + l_tx_cond_hash = dap_chain_mempool_tx_create_cond(l_tpl->net, l_key_from, l_client_key, l_addr_from, l_tpl->token_ticker, + (uint64_t) l_tpl->value_datoshi, 0, l_price_unit, l_srv_uid, 0, NULL, 0); + char *l_addr_from_str = dap_chain_addr_to_str( l_addr_from ); DAP_DELETE( l_addr_from); - if ( l_tx_cond_hash == NULL ){ - log_it( L_ERROR, "Can't create condiftion for user"); - }else - log_it( L_NOTICE, "User \"%s\": created conditioned transaction from %s(%s) on " - , l_auth_info->user, l_tpl->wallet_name, l_addr_from_str - ); + if (!l_tx_cond_hash) { + log_it(L_ERROR, "Can't create condiftion for user"); + } else { + log_it(L_NOTICE, "User \"%s\": created conditioned transaction from %s(%s) on " + , l_auth_info->user, l_tpl->wallet_name, l_addr_from_str); + } DAP_DELETE( l_addr_from_str ); - } // If we loaded or created hash @@ -323,9 +316,9 @@ static void s_auth_callback(enc_http_delegate_t* a_delegate, void * a_arg) DAP_DELETE(l_tx_cond_hash_str); } enc_http_reply_f(a_delegate,"\t</tx_cond_tpl>\n"); - } + } if (l_client_key) - DAP_DELETE( l_client_key); + DAP_DELETE(l_client_key); #endif }