diff options
Diffstat (limited to 'main/tollgate_api.c')
| -rw-r--r-- | main/tollgate_api.c | 156 |
1 files changed, 13 insertions, 143 deletions
diff --git a/main/tollgate_api.c b/main/tollgate_api.c index 650b0f3..62f75ee 100644 --- a/main/tollgate_api.c +++ b/main/tollgate_api.c | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | #include "tollgate_api.h" | 1 | #include "tollgate_api.h" |
| 2 | #include "cashu.h" | 2 | #include "tollgate_core.h" |
| 3 | #include "config.h" | 3 | #include "config.h" |
| 4 | #include "session.h" | ||
| 5 | #include "firewall.h" | ||
| 6 | #include "nucula_wallet.h" | 4 | #include "nucula_wallet.h" |
| 7 | #include "esp_log.h" | 5 | #include "esp_log.h" |
| 8 | #include "cJSON.h" | 6 | #include "cJSON.h" |
| @@ -184,37 +182,11 @@ static esp_err_t api_post_payment(httpd_req_t *req) | |||
| 184 | 182 | ||
| 185 | ESP_LOGI(TAG, "Payment received: %d bytes", total); | 183 | ESP_LOGI(TAG, "Payment received: %d bytes", total); |
| 186 | 184 | ||
| 187 | cashu_token_t *token = malloc(sizeof(cashu_token_t)); | 185 | esp_err_t err = tollgate_core_process_payment(client_ip, body); |
| 188 | if (!token) { | ||
| 189 | cJSON *notice = create_notice("error", "session-error", "Out of memory"); | ||
| 190 | char *json = cJSON_PrintUnformatted(notice); | ||
| 191 | httpd_resp_set_status(req, "503 Service Unavailable"); | ||
| 192 | httpd_resp_set_type(req, "application/json"); | ||
| 193 | httpd_resp_send(req, json, strlen(json)); | ||
| 194 | cJSON_free(json); | ||
| 195 | cJSON_Delete(notice); | ||
| 196 | return ESP_OK; | ||
| 197 | } | ||
| 198 | esp_err_t err = cashu_decode_token(body, token); | ||
| 199 | char *body_copy = strdup(body); | ||
| 200 | free(body); | 186 | free(body); |
| 201 | 187 | ||
| 202 | if (err != ESP_OK) { | 188 | if (err != ESP_OK) { |
| 203 | free(token); | 189 | cJSON *notice = create_notice("error", "payment-error", "Payment processing failed"); |
| 204 | cJSON *notice = create_notice("error", "payment-error-invalid", "Failed to decode Cashu token"); | ||
| 205 | char *json = cJSON_PrintUnformatted(notice); | ||
| 206 | httpd_resp_set_status(req, "400 Bad Request"); | ||
| 207 | httpd_resp_set_type(req, "application/json"); | ||
| 208 | httpd_resp_send(req, json, strlen(json)); | ||
| 209 | cJSON_free(json); | ||
| 210 | cJSON_Delete(notice); | ||
| 211 | return ESP_OK; | ||
| 212 | } | ||
| 213 | |||
| 214 | const char *mint_url = token->mint_url[0] ? token->mint_url : tollgate_config_get()->mint_url; | ||
| 215 | if (!cashu_is_mint_accepted(mint_url)) { | ||
| 216 | free(token); | ||
| 217 | cJSON *notice = create_notice("error", "payment-error-mint-not-accepted", "Mint not accepted"); | ||
| 218 | char *json = cJSON_PrintUnformatted(notice); | 190 | char *json = cJSON_PrintUnformatted(notice); |
| 219 | httpd_resp_set_status(req, "402 Payment Required"); | 191 | httpd_resp_set_status(req, "402 Payment Required"); |
| 220 | httpd_resp_set_type(req, "application/json"); | 192 | httpd_resp_set_type(req, "application/json"); |
| @@ -224,97 +196,14 @@ static esp_err_t api_post_payment(httpd_req_t *req) | |||
| 224 | return ESP_OK; | 196 | return ESP_OK; |
| 225 | } | 197 | } |
| 226 | 198 | ||
| 227 | cashu_proof_state_t *states = malloc(CASHU_MAX_PROOFS * sizeof(cashu_proof_state_t)); | ||
| 228 | if (!states) { | ||
| 229 | free(token); | ||
| 230 | cJSON *notice = create_notice("error", "session-error", "Out of memory"); | ||
| 231 | char *json = cJSON_PrintUnformatted(notice); | ||
| 232 | httpd_resp_set_status(req, "503 Service Unavailable"); | ||
| 233 | httpd_resp_set_type(req, "application/json"); | ||
| 234 | httpd_resp_send(req, json, strlen(json)); | ||
| 235 | cJSON_free(json); | ||
| 236 | cJSON_Delete(notice); | ||
| 237 | return ESP_OK; | ||
| 238 | } | ||
| 239 | int state_count = 0; | ||
| 240 | err = cashu_check_proof_states(mint_url, token, states, &state_count); | ||
| 241 | ESP_LOGI(TAG, "Stack HWM after checkstate: %u", uxTaskGetStackHighWaterMark(NULL)); | ||
| 242 | if (err != ESP_OK) { | ||
| 243 | free(states); | ||
| 244 | free(token); | ||
| 245 | cJSON *notice = create_notice("error", "payment-error-verification", "Failed to verify token with mint"); | ||
| 246 | char *json = cJSON_PrintUnformatted(notice); | ||
| 247 | httpd_resp_set_status(req, "502 Bad Gateway"); | ||
| 248 | httpd_resp_set_type(req, "application/json"); | ||
| 249 | httpd_resp_send(req, json, strlen(json)); | ||
| 250 | cJSON_free(json); | ||
| 251 | cJSON_Delete(notice); | ||
| 252 | return ESP_OK; | ||
| 253 | } | ||
| 254 | |||
| 255 | for (int i = 0; i < state_count; i++) { | ||
| 256 | if (states[i].spent) { | ||
| 257 | free(states); | ||
| 258 | free(token); | ||
| 259 | cJSON *notice = create_notice("error", "payment-error-token-spent", "Token already spent"); | ||
| 260 | char *json = cJSON_PrintUnformatted(notice); | ||
| 261 | httpd_resp_set_status(req, "402 Payment Required"); | ||
| 262 | httpd_resp_set_type(req, "application/json"); | ||
| 263 | httpd_resp_send(req, json, strlen(json)); | ||
| 264 | cJSON_free(json); | ||
| 265 | cJSON_Delete(notice); | ||
| 266 | return ESP_OK; | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | const tollgate_config_t *cfg = tollgate_config_get(); | 199 | const tollgate_config_t *cfg = tollgate_config_get(); |
| 271 | bool is_bytes = (strcmp(cfg->metric, "bytes") == 0); | 200 | uint64_t allotment = 0; |
| 272 | uint64_t step_size = is_bytes ? (uint64_t)cfg->step_size_bytes : (uint64_t)cfg->step_size_ms; | ||
| 273 | uint64_t allotment = cashu_calculate_allotment(token->total_amount, cfg->price_per_step, | ||
| 274 | cfg->metric, step_size); | ||
| 275 | if (allotment == 0) { | ||
| 276 | free(states); | ||
| 277 | free(token); | ||
| 278 | cJSON *notice = create_notice("error", "payment-error-insufficient", "Token value too low"); | ||
| 279 | char *json = cJSON_PrintUnformatted(notice); | ||
| 280 | httpd_resp_set_status(req, "402 Payment Required"); | ||
| 281 | httpd_resp_set_type(req, "application/json"); | ||
| 282 | httpd_resp_send(req, json, strlen(json)); | ||
| 283 | cJSON_free(json); | ||
| 284 | cJSON_Delete(notice); | ||
| 285 | return ESP_OK; | ||
| 286 | } | ||
| 287 | |||
| 288 | session_t *session; | ||
| 289 | if (is_bytes) { | ||
| 290 | session = session_create_bytes(client_ip, allotment); | ||
| 291 | } else { | ||
| 292 | session = session_create(client_ip, allotment); | ||
| 293 | } | ||
| 294 | if (!session) { | ||
| 295 | free(states); | ||
| 296 | free(token); | ||
| 297 | cJSON *notice = create_notice("error", "session-error", "Failed to create session"); | ||
| 298 | char *json = cJSON_PrintUnformatted(notice); | ||
| 299 | httpd_resp_set_status(req, "503 Service Unavailable"); | ||
| 300 | httpd_resp_set_type(req, "application/json"); | ||
| 301 | httpd_resp_send(req, json, strlen(json)); | ||
| 302 | cJSON_free(json); | ||
| 303 | cJSON_Delete(notice); | ||
| 304 | return ESP_OK; | ||
| 305 | } | ||
| 306 | |||
| 307 | cJSON *session_event = create_session_event(client_ip, allotment); | 201 | cJSON *session_event = create_session_event(client_ip, allotment); |
| 308 | char *json = cJSON_PrintUnformatted(session_event); | 202 | char *json = cJSON_PrintUnformatted(session_event); |
| 309 | httpd_resp_set_type(req, "application/json"); | 203 | httpd_resp_set_type(req, "application/json"); |
| 310 | httpd_resp_send(req, json, strlen(json)); | 204 | httpd_resp_send(req, json, strlen(json)); |
| 311 | cJSON_free(json); | 205 | cJSON_free(json); |
| 312 | cJSON_Delete(session_event); | 206 | cJSON_Delete(session_event); |
| 313 | |||
| 314 | nucula_wallet_receive(body_copy); | ||
| 315 | |||
| 316 | free(states); | ||
| 317 | free(token); | ||
| 318 | return ESP_OK; | 207 | return ESP_OK; |
| 319 | } | 208 | } |
| 320 | 209 | ||
| @@ -323,29 +212,15 @@ static esp_err_t api_get_usage(httpd_req_t *req) | |||
| 323 | uint32_t client_ip = 0; | 212 | uint32_t client_ip = 0; |
| 324 | get_client_ip(req, &client_ip); | 213 | get_client_ip(req, &client_ip); |
| 325 | 214 | ||
| 326 | session_t *session = session_find_by_ip(client_ip); | 215 | char *status_json = tollgate_core_get_status_json(); |
| 327 | if (!session || !session->active) { | 216 | if (status_json) { |
| 328 | httpd_resp_set_type(req, "text/plain"); | 217 | httpd_resp_set_type(req, "application/json"); |
| 329 | httpd_resp_send(req, "-1/-1", 5); | 218 | httpd_resp_send(req, status_json, strlen(status_json)); |
| 330 | return ESP_OK; | 219 | cJSON_free(status_json); |
| 331 | } | ||
| 332 | |||
| 333 | const tollgate_config_t *cfg = tollgate_config_get(); | ||
| 334 | bool is_bytes = (strcmp(cfg->metric, "bytes") == 0); | ||
| 335 | |||
| 336 | char resp[64]; | ||
| 337 | if (is_bytes) { | ||
| 338 | int64_t remaining = (int64_t)session->allotment_bytes - (int64_t)session->bytes_consumed; | ||
| 339 | if (remaining < 0) remaining = 0; | ||
| 340 | snprintf(resp, sizeof(resp), "%lld/%llu", (long long)remaining, (unsigned long long)session->allotment_bytes); | ||
| 341 | } else { | 220 | } else { |
| 342 | int64_t elapsed = (int64_t)xTaskGetTickCount() * portTICK_PERIOD_MS - session->start_time_ms; | 221 | httpd_resp_set_type(req, "text/plain"); |
| 343 | int64_t remaining = session->allotment_ms - elapsed; | 222 | httpd_resp_send(req, "{}", 2); |
| 344 | if (remaining < 0) remaining = 0; | ||
| 345 | snprintf(resp, sizeof(resp), "%lld/%llu", (long long)remaining, (unsigned long long)session->allotment_ms); | ||
| 346 | } | 223 | } |
| 347 | httpd_resp_set_type(req, "text/plain"); | ||
| 348 | httpd_resp_send(req, resp, strlen(resp)); | ||
| 349 | return ESP_OK; | 224 | return ESP_OK; |
| 350 | } | 225 | } |
| 351 | 226 | ||
| @@ -354,15 +229,10 @@ static esp_err_t api_get_whoami(httpd_req_t *req) | |||
| 354 | uint32_t client_ip = 0; | 229 | uint32_t client_ip = 0; |
| 355 | char resp[96]; | 230 | char resp[96]; |
| 356 | if (get_client_ip(req, &client_ip) == ESP_OK) { | 231 | if (get_client_ip(req, &client_ip) == ESP_OK) { |
| 357 | char mac[18] = {0}; | ||
| 358 | esp_ip4_addr_t ip = { .addr = client_ip }; | 232 | esp_ip4_addr_t ip = { .addr = client_ip }; |
| 359 | if (firewall_get_mac_for_ip(client_ip, mac, sizeof(mac)) == ESP_OK) { | 233 | snprintf(resp, sizeof(resp), "ip=" IPSTR, IP2STR(&ip)); |
| 360 | snprintf(resp, sizeof(resp), "ip=" IPSTR " mac=%s", IP2STR(&ip), mac); | ||
| 361 | } else { | ||
| 362 | snprintf(resp, sizeof(resp), "ip=" IPSTR " mac=unknown", IP2STR(&ip)); | ||
| 363 | } | ||
| 364 | } else { | 234 | } else { |
| 365 | snprintf(resp, sizeof(resp), "ip=unknown mac=unknown"); | 235 | snprintf(resp, sizeof(resp), "ip=unknown"); |
| 366 | } | 236 | } |
| 367 | httpd_resp_set_type(req, "text/plain"); | 237 | httpd_resp_set_type(req, "text/plain"); |
| 368 | httpd_resp_send(req, resp, strlen(resp)); | 238 | httpd_resp_send(req, resp, strlen(resp)); |