upleb.uk

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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile41
-rw-r--r--main/cashu.c31
-rw-r--r--main/tollgate_api.c1
3 files changed, 56 insertions, 17 deletions
diff --git a/Makefile b/Makefile
index 7de799e..2ed8e07 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ PYTHON ?= python3
20.PHONY: help setup detect-ports detect-chip detect-all 20.PHONY: help setup detect-ports detect-chip detect-all
21.PHONY: flash flash-a flash-b monitor monitor-a monitor-b 21.PHONY: flash flash-a flash-b monitor monitor-a monitor-b
22.PHONY: test smoke test-api test-portal test-network test-full 22.PHONY: test smoke test-api test-portal test-network test-full
23.PHONY: tokens test-payment 23.PHONY: tokens test-payment wallet-setup wallet-info wallet-balance mint-token send-token
24.PHONY: clean erase-nvs reset serial-log 24.PHONY: clean erase-nvs reset serial-log
25.PHONY: bootstrap-config 25.PHONY: bootstrap-config
26 26
@@ -47,7 +47,12 @@ help:
47 @echo " test-full All 14 Phase 1 tests" 47 @echo " test-full All 14 Phase 1 tests"
48 @echo "" 48 @echo ""
49 @echo "Test (Phase 2):" 49 @echo "Test (Phase 2):"
50 @echo " tokens Mint test Cashu tokens (AMOUNT=21)" 50 @echo " wallet-setup Initialize nutshell wallet for test mint"
51 @echo " wallet-info Show mint info"
52 @echo " wallet-balance Show wallet balance"
53 @echo " mint-token Invoice + send test token (AMOUNT=21)"
54 @echo " send-token Send cashuA token (AMOUNT=21)"
55 @echo " tokens Alias for send-token"
51 @echo " test-payment Payment flow tests" 56 @echo " test-payment Payment flow tests"
52 @echo "" 57 @echo ""
53 @echo "Utilities:" 58 @echo "Utilities:"
@@ -165,17 +170,39 @@ test-full: test-api test-portal test-network
165 @echo "=== Full test suite passed ===" 170 @echo "=== Full test suite passed ==="
166 171
167# ────────────────────────────────────────────── 172# ──────────────────────────────────────────────
168# Phase 2: Payment Testing 173# Phase 2: Payment Testing (Nutshell wallet)
169# ────────────────────────────────────────────── 174# ──────────────────────────────────────────────
170 175
171tokens: 176wallet-setup:
172 @echo "=== Minting test tokens from $(TEST_MINT) ===" 177 @echo "=== Setting up Nutshell wallet for $(TEST_MINT) ==="
178 cashu --env-mint $(TEST_MINT) info 2>/dev/null || \
179 cashu --env-mint $(TEST_MINT) restore
180
181wallet-info:
182 @echo "=== Mint info ==="
183 cashu --env-mint $(TEST_MINT) info
184
185wallet-balance:
186 @echo "=== Wallet balance ==="
187 cashu --env-mint $(TEST_MINT) balance
188
189mint-token:
190 @echo "=== Minting test token (AMOUNT=$(or $(AMOUNT),21)) ==="
173 @AMOUNT=$${AMOUNT:-21}; \ 191 @AMOUNT=$${AMOUNT:-21}; \
174 cd scripts/mint-token && go run main.go -mint https://$(TEST_MINT) -amount $$AMOUNT 192 cashu --env-mint $(TEST_MINT) invoice $$AMOUNT && \
193 echo "--- Token (cashuA legacy) ---" && \
194 cashu --env-mint $(TEST_MINT) send --legacy $$AMOUNT
195
196send-token:
197 @AMOUNT=$${AMOUNT:-21}; \
198 echo "=== Sending $$AMOUNT sats as cashuA token ===" && \
199 cashu --env-mint $(TEST_MINT) send --legacy $$AMOUNT
200
201tokens: send-token
175 202
176test-payment: 203test-payment:
177 @echo "=== Running payment tests ===" 204 @echo "=== Running payment tests ==="
178 $(NODE) tests/payment.mjs 205 $(NODE) tests/phase2.mjs
179 206
180# ────────────────────────────────────────────── 207# ──────────────────────────────────────────────
181# Utilities 208# Utilities
diff --git a/main/cashu.c b/main/cashu.c
index bafd000..8dffacc 100644
--- a/main/cashu.c
+++ b/main/cashu.c
@@ -14,9 +14,9 @@ static const size_t V3_PREFIX_LEN = 6;
14 14
15static int b64url_decode(const char *input, size_t input_len, char *out, size_t out_size, size_t *out_len) 15static int b64url_decode(const char *input, size_t input_len, char *out, size_t out_size, size_t *out_len)
16{ 16{
17 char b64[1024]; 17 char *b64 = malloc(input_len + 4);
18 if (!b64) return -1;
18 size_t b64_len = input_len; 19 size_t b64_len = input_len;
19 if (b64_len >= sizeof(b64)) return -1;
20 memcpy(b64, input, b64_len); 20 memcpy(b64, input, b64_len);
21 b64[b64_len] = '\0'; 21 b64[b64_len] = '\0';
22 22
@@ -24,7 +24,7 @@ static int b64url_decode(const char *input, size_t input_len, char *out, size_t
24 if (b64[i] == '-') b64[i] = '+'; 24 if (b64[i] == '-') b64[i] = '+';
25 else if (b64[i] == '_') b64[i] = '/'; 25 else if (b64[i] == '_') b64[i] = '/';
26 } 26 }
27 while (b64_len % 4 != 0 && b64_len < sizeof(b64) - 1) { 27 while (b64_len % 4 != 0) {
28 b64[b64_len++] = '='; 28 b64[b64_len++] = '=';
29 } 29 }
30 b64[b64_len] = '\0'; 30 b64[b64_len] = '\0';
@@ -32,6 +32,7 @@ static int b64url_decode(const char *input, size_t input_len, char *out, size_t
32 size_t olen = 0; 32 size_t olen = 0;
33 int ret = mbedtls_base64_decode((unsigned char *)out, out_size, &olen, 33 int ret = mbedtls_base64_decode((unsigned char *)out, out_size, &olen,
34 (const unsigned char *)b64, b64_len); 34 (const unsigned char *)b64, b64_len);
35 free(b64);
35 if (ret != 0) return -1; 36 if (ret != 0) return -1;
36 *out_len = olen; 37 *out_len = olen;
37 return 0; 38 return 0;
@@ -86,16 +87,19 @@ esp_err_t cashu_decode_token(const char *token_str, cashu_token_t *out)
86 return ESP_FAIL; 87 return ESP_FAIL;
87 } 88 }
88 89
89 char json_buf[2048]; 90 char *json_buf = malloc(2048);
91 if (!json_buf) return ESP_FAIL;
90 size_t json_len = 0; 92 size_t json_len = 0;
91 if (b64url_decode(token_str + V3_PREFIX_LEN, len - V3_PREFIX_LEN, 93 if (b64url_decode(token_str + V3_PREFIX_LEN, len - V3_PREFIX_LEN,
92 json_buf, sizeof(json_buf) - 1, &json_len) != 0) { 94 json_buf, 2047, &json_len) != 0) {
93 ESP_LOGE(TAG, "Base64url decode failed"); 95 ESP_LOGE(TAG, "Base64url decode failed");
96 free(json_buf);
94 return ESP_FAIL; 97 return ESP_FAIL;
95 } 98 }
96 json_buf[json_len] = '\0'; 99 json_buf[json_len] = '\0';
97 100
98 cJSON *root = cJSON_Parse(json_buf); 101 cJSON *root = cJSON_Parse(json_buf);
102 free(json_buf);
99 if (!root) { 103 if (!root) {
100 ESP_LOGE(TAG, "JSON parse failed"); 104 ESP_LOGE(TAG, "JSON parse failed");
101 return ESP_FAIL; 105 return ESP_FAIL;
@@ -167,14 +171,16 @@ esp_err_t cashu_check_proof_states(const char *mint_url, const cashu_token_t *to
167 char *ys_json = cJSON_PrintUnformatted(ys_arr); 171 char *ys_json = cJSON_PrintUnformatted(ys_arr);
168 cJSON_Delete(ys_arr); 172 cJSON_Delete(ys_arr);
169 173
170 char post_body[2048]; 174 char *post_body = malloc(4096);
171 snprintf(post_body, sizeof(post_body), "{\"Ys\":%s}", ys_json); 175 if (!post_body) { cJSON_free(ys_json); return ESP_FAIL; }
176 snprintf(post_body, 4096, "{\"Ys\":%s}", ys_json);
172 cJSON_free(ys_json); 177 cJSON_free(ys_json);
173 178
174 char url[512]; 179 char url[512];
175 snprintf(url, sizeof(url), "%s/v1/checkstate", mint_url); 180 snprintf(url, sizeof(url), "%s/v1/checkstate", mint_url);
176 181
177 char resp_buf[4096]; 182 char *resp_buf = malloc(8192);
183 if (!resp_buf) { free(post_body); return ESP_FAIL; }
178 int resp_len = 0; 184 int resp_len = 0;
179 185
180 esp_http_client_config_t config = { 186 esp_http_client_config_t config = {
@@ -183,27 +189,32 @@ esp_err_t cashu_check_proof_states(const char *mint_url, const cashu_token_t *to
183 .timeout_ms = 10000, 189 .timeout_ms = 10000,
184 }; 190 };
185 esp_http_client_handle_t client = esp_http_client_init(&config); 191 esp_http_client_handle_t client = esp_http_client_init(&config);
186 if (!client) return ESP_FAIL; 192 if (!client) { free(post_body); free(resp_buf); return ESP_FAIL; }
187 193
188 esp_http_client_set_header(client, "Content-Type", "application/json"); 194 esp_http_client_set_header(client, "Content-Type", "application/json");
189 esp_err_t err = esp_http_client_open(client, strlen(post_body)); 195 esp_err_t err = esp_http_client_open(client, strlen(post_body));
190 if (err != ESP_OK) { 196 if (err != ESP_OK) {
191 esp_http_client_cleanup(client); 197 esp_http_client_cleanup(client);
198 free(post_body);
199 free(resp_buf);
192 return err; 200 return err;
193 } 201 }
194 esp_http_client_write(client, post_body, strlen(post_body)); 202 esp_http_client_write(client, post_body, strlen(post_body));
203 free(post_body);
195 204
196 resp_len = esp_http_client_read(client, resp_buf, sizeof(resp_buf) - 1); 205 resp_len = esp_http_client_read(client, resp_buf, 8191);
197 int status = esp_http_client_get_status_code(client); 206 int status = esp_http_client_get_status_code(client);
198 esp_http_client_cleanup(client); 207 esp_http_client_cleanup(client);
199 208
200 if (status != 200 || resp_len <= 0) { 209 if (status != 200 || resp_len <= 0) {
201 ESP_LOGE(TAG, "checkstate returned %d", status); 210 ESP_LOGE(TAG, "checkstate returned %d", status);
211 free(resp_buf);
202 return ESP_FAIL; 212 return ESP_FAIL;
203 } 213 }
204 resp_buf[resp_len] = '\0'; 214 resp_buf[resp_len] = '\0';
205 215
206 cJSON *root = cJSON_Parse(resp_buf); 216 cJSON *root = cJSON_Parse(resp_buf);
217 free(resp_buf);
207 if (!root) return ESP_FAIL; 218 if (!root) return ESP_FAIL;
208 219
209 cJSON *states_arr = cJSON_GetObjectItemCaseSensitive(root, "states"); 220 cJSON *states_arr = cJSON_GetObjectItemCaseSensitive(root, "states");
diff --git a/main/tollgate_api.c b/main/tollgate_api.c
index 5ada3c7..b2ad647 100644
--- a/main/tollgate_api.c
+++ b/main/tollgate_api.c
@@ -330,6 +330,7 @@ esp_err_t tollgate_api_start(void)
330 config.server_port = 2121; 330 config.server_port = 2121;
331 config.ctrl_port = 32769; 331 config.ctrl_port = 32769;
332 config.max_uri_handlers = 10; 332 config.max_uri_handlers = 10;
333 config.stack_size = 16384;
333 334
334 esp_err_t ret = httpd_start(&s_api_server, &config); 335 esp_err_t ret = httpd_start(&s_api_server, &config);
335 if (ret != ESP_OK) { 336 if (ret != ESP_OK) {