upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/main/tollgate_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/tollgate_api.c')
-rw-r--r--main/tollgate_api.c156
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));