diff --git a/lightningd/invoice.c b/lightningd/invoice.c index 2ba723a1e..a4f8417eb 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -35,7 +35,7 @@ static void json_add_invoice(struct json_result *response, bool modern) { json_object_start(response, NULL); - json_add_string(response, "label", inv->label); + json_add_escaped_string(response, "label", inv->label); json_add_string(response, "bolt11", inv->bolt11); json_add_hex(response, "payment_hash", &inv->rhash, sizeof(inv->rhash)); if (inv->msatoshi) @@ -154,7 +154,7 @@ static void json_invoice(struct command *cmd, label->end - label->start, buffer + label->start); return; } - if (wallet_invoice_find_by_label(wallet, &invoice, label_val->s)) { + if (wallet_invoice_find_by_label(wallet, &invoice, label_val)) { command_fail(cmd, "Duplicate label '%s'", label_val->s); return; } @@ -226,7 +226,7 @@ static void json_invoice(struct command *cmd, result = wallet_invoice_create(cmd->ld->wallet, &invoice, take(msatoshi_val), - take((char *)label_val->s), + take(label_val), expiry, b11enc, &r, @@ -261,19 +261,16 @@ AUTODATA(json_command, &invoice_command); static void json_add_invoices(struct json_result *response, struct wallet *wallet, - const char *buffer, const jsmntok_t *label, + const struct json_escaped *label, bool modern) { struct invoice_iterator it; struct invoice_details details; - char *lbl = NULL; - if (label) - lbl = tal_strndup(response, &buffer[label->start], label->end - label->start); memset(&it, 0, sizeof(it)); while (wallet_invoice_iterate(wallet, &it)) { wallet_invoice_iterator_deref(response, wallet, &it, &details); - if (lbl && !streq(details.label, lbl)) + if (label && !json_escaped_eq(details.label, label)) continue; json_add_invoice(response, &details, modern); } @@ -284,22 +281,34 @@ static void json_listinvoice_internal(struct command *cmd, const jsmntok_t *params, bool modern) { - jsmntok_t *label = NULL; + jsmntok_t *labeltok = NULL; + struct json_escaped *label; struct json_result *response = new_json_result(cmd); struct wallet *wallet = cmd->ld->wallet; if (!json_get_params(cmd, buffer, params, - "?label", &label, + "?label", &labeltok, NULL)) { return; } + if (labeltok) { + label = json_tok_escaped_string(cmd, buffer, labeltok); + if (!label) { + command_fail(cmd, "label '%.*s' is not a string", + labeltok->end - labeltok->start, + buffer + labeltok->start); + return; + } + } else + label = NULL; + if (modern) { json_object_start(response, NULL); json_array_start(response, "invoices"); } else json_array_start(response, NULL); - json_add_invoices(response, wallet, buffer, label, modern); + json_add_invoices(response, wallet, label, modern); json_array_end(response); if (modern) json_object_end(response); @@ -341,7 +350,8 @@ static void json_delinvoice(struct command *cmd, struct invoice_details details; jsmntok_t *labeltok, *statustok; struct json_result *response = new_json_result(cmd); - const char *label, *status, *actual_status; + const char *status, *actual_status; + struct json_escaped *label; struct wallet *wallet = cmd->ld->wallet; if (!json_get_params(cmd, buffer, params, @@ -351,8 +361,13 @@ static void json_delinvoice(struct command *cmd, return; } - label = tal_strndup(cmd, buffer + labeltok->start, - labeltok->end - labeltok->start); + label = json_tok_escaped_string(cmd, buffer, labeltok); + if (!label) { + command_fail(cmd, "label '%.*s' not a string", + labeltok->end - labeltok->start, + buffer + labeltok->start); + return; + } if (!wallet_invoice_find_by_label(wallet, &i, label)) { command_fail(cmd, "Unknown invoice"); return; @@ -532,14 +547,21 @@ static void json_waitinvoice(struct command *cmd, struct invoice_details details; struct wallet *wallet = cmd->ld->wallet; jsmntok_t *labeltok; - const char *label = NULL; + struct json_escaped *label; if (!json_get_params(cmd, buffer, params, "label", &labeltok, NULL)) { return; } /* Search for invoice */ - label = tal_strndup(cmd, buffer + labeltok->start, labeltok->end - labeltok->start); + label = json_tok_escaped_string(cmd, buffer, labeltok); + if (!label) { + command_fail(cmd, "label '%.*s' is not a string", + labeltok->end - labeltok->start, + buffer + labeltok->start); + return; + } + if (!wallet_invoice_find_by_label(wallet, &i, label)) { command_fail(cmd, "Label not found"); return; diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 2cea4f153..6b5bebc7f 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -299,9 +300,9 @@ static void handle_localpay(struct htlc_in *hin, } log_info(ld->log, "Resolving invoice '%s' with HTLC %"PRIu64, - details.label, hin->key.id); + details.label->s, hin->key.id); log_debug(ld->log, "%s: Actual amount %"PRIu64"msat, HTLC expiry %u", - details.label, hin->msatoshi, cltv_expiry); + details.label->s, hin->msatoshi, cltv_expiry); fulfill_htlc(hin, &details.r); wallet_invoice_resolve(ld->wallet, invoice, hin->msatoshi); diff --git a/wallet/db.c b/wallet/db.c index f8879b137..c45e68edf 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -1,6 +1,7 @@ #include "db.h" #include +#include #include #include #include @@ -759,3 +760,18 @@ bool sqlite3_bind_sha256_double(sqlite3_stmt *stmt, int col, const struct sha256 sqlite3_bind_blob(stmt, col, p, sizeof(struct sha256_double), SQLITE_TRANSIENT); return true; } + +struct json_escaped *sqlite3_column_json_escaped(const tal_t *ctx, + sqlite3_stmt *stmt, int col) +{ + return json_escaped_string_(ctx, + sqlite3_column_blob(stmt, col), + sqlite3_column_bytes(stmt, col)); +} + +bool sqlite3_bind_json_escaped(sqlite3_stmt *stmt, int col, + const struct json_escaped *esc) +{ + sqlite3_bind_text(stmt, col, esc->s, strlen(esc->s), SQLITE_TRANSIENT); + return true; +} diff --git a/wallet/db.h b/wallet/db.h index 935945286..5ce3c5a22 100644 --- a/wallet/db.h +++ b/wallet/db.h @@ -156,4 +156,9 @@ bool sqlite3_column_sha256_double(sqlite3_stmt *stmt, int col, struct sha256_do bool sqlite3_bind_sha256_double(sqlite3_stmt *stmt, int col, const struct sha256_double *p); struct secret *sqlite3_column_secrets(const tal_t *ctx, sqlite3_stmt *stmt, int col); + +struct json_escaped *sqlite3_column_json_escaped(const tal_t *ctx, + sqlite3_stmt *stmt, int col); +bool sqlite3_bind_json_escaped(sqlite3_stmt *stmt, int col, + const struct json_escaped *esc); #endif /* LIGHTNING_WALLET_DB_H */ diff --git a/wallet/invoices.c b/wallet/invoices.c index de631bd88..b4ae1a5a4 100644 --- a/wallet/invoices.c +++ b/wallet/invoices.c @@ -98,7 +98,7 @@ static void wallet_stmt2invoice_details(const tal_t *ctx, sqlite3_column_sha256(stmt, 2, &dtl->rhash); - dtl->label = tal_strndup(ctx, sqlite3_column_blob(stmt, 3), sqlite3_column_bytes(stmt, 3)); + dtl->label = sqlite3_column_json_escaped(ctx, stmt, 3); if (sqlite3_column_type(stmt, 4) != SQLITE_NULL) { dtl->msatoshi = tal(ctx, u64); @@ -258,7 +258,7 @@ bool invoices_load(struct invoices *invoices) bool invoices_create(struct invoices *invoices, struct invoice *pinvoice, u64 *msatoshi TAKES, - const char *label TAKES, + const struct json_escaped *label TAKES, u64 expiry, const char *b11enc, const struct preimage *r, @@ -302,7 +302,7 @@ bool invoices_create(struct invoices *invoices, sqlite3_bind_int64(stmt, 4, *msatoshi); else sqlite3_bind_null(stmt, 4); - sqlite3_bind_text(stmt, 5, label, strlen(label), SQLITE_TRANSIENT); + sqlite3_bind_json_escaped(stmt, 5, label); sqlite3_bind_int64(stmt, 6, expiry_time); sqlite3_bind_text(stmt, 7, b11enc, strlen(b11enc), SQLITE_TRANSIENT); @@ -328,7 +328,7 @@ bool invoices_create(struct invoices *invoices, bool invoices_find_by_label(struct invoices *invoices, struct invoice *pinvoice, - const char *label) + const struct json_escaped *label) { sqlite3_stmt *stmt; @@ -336,7 +336,7 @@ bool invoices_find_by_label(struct invoices *invoices, "SELECT id" " FROM invoices" " WHERE label = ?;"); - sqlite3_bind_text(stmt, 1, label, strlen(label), SQLITE_TRANSIENT); + sqlite3_bind_json_escaped(stmt, 1, label); if (sqlite3_step(stmt) == SQLITE_ROW) { pinvoice->id = sqlite3_column_int64(stmt, 0); sqlite3_finalize(stmt); diff --git a/wallet/invoices.h b/wallet/invoices.h index 68fd3b6f5..5c4bbac47 100644 --- a/wallet/invoices.h +++ b/wallet/invoices.h @@ -7,6 +7,7 @@ #include struct db; +struct json_escaped; struct invoice; struct invoice_details; struct invoice_iterator; @@ -44,7 +45,7 @@ bool invoices_load(struct invoices *invoices); * @msatoshi - the amount the invoice should have, or * NULL for any-amount invoices. * @label - the unique label for this invoice. Must be - * non-NULL. Must be null-terminated. + * non-NULL. * @expiry - the number of seconds before the invoice * expires * @@ -55,7 +56,7 @@ bool invoices_load(struct invoices *invoices); bool invoices_create(struct invoices *invoices, struct invoice *pinvoice, u64 *msatoshi TAKES, - const char *label TAKES, + const struct json_escaped *label TAKES, u64 expiry, const char *b11enc, const struct preimage *r, @@ -66,14 +67,14 @@ bool invoices_create(struct invoices *invoices, * * @invoices - the invoice handler. * @pinvoice - pointer to location to load found invoice in. - * @label - the label to search for. Must be null-terminated. + * @label - the label to search for. * * Returns false if no invoice with that label exists. * Returns true if found. */ bool invoices_find_by_label(struct invoices *invoices, struct invoice *pinvoice, - const char *label); + const struct json_escaped *label); /** * invoices_find_unpaid - Search for an unpaid, unexpired invoice by diff --git a/wallet/test/run-db.c b/wallet/test/run-db.c index ce027aa9a..86d54292d 100644 --- a/wallet/test/run-db.c +++ b/wallet/test/run-db.c @@ -17,6 +17,10 @@ static void db_log_(struct log *log UNUSED, enum log_level level UNUSED, const c #include /* AUTOGENERATED MOCKS START */ +/* Generated stub for json_escaped_string_ */ +struct json_escaped *json_escaped_string_(const tal_t *ctx UNNEEDED, + const void *bytes UNNEEDED, size_t len UNNEEDED) +{ fprintf(stderr, "json_escaped_string_ called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ static char *db_err; diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index b829bf628..6345b50bd 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -108,7 +108,7 @@ void invoices_autoclean_set(struct invoices *invoices UNNEEDED, bool invoices_create(struct invoices *invoices UNNEEDED, struct invoice *pinvoice UNNEEDED, u64 *msatoshi TAKES UNNEEDED, - const char *label TAKES UNNEEDED, + const struct json_escaped *label TAKES UNNEEDED, u64 expiry UNNEEDED, const char *b11enc UNNEEDED, const struct preimage *r UNNEEDED, @@ -125,7 +125,7 @@ void invoices_delete_expired(struct invoices *invoices UNNEEDED, /* Generated stub for invoices_find_by_label */ bool invoices_find_by_label(struct invoices *invoices UNNEEDED, struct invoice *pinvoice UNNEEDED, - const char *label UNNEEDED) + const struct json_escaped *label UNNEEDED) { fprintf(stderr, "invoices_find_by_label called!\n"); abort(); } /* Generated stub for invoices_find_unpaid */ bool invoices_find_unpaid(struct invoices *invoices UNNEEDED, @@ -181,7 +181,8 @@ void json_add_bool(struct json_result *result UNNEEDED, const char *fieldname UN bool value UNNEEDED) { fprintf(stderr, "json_add_bool called!\n"); abort(); } /* Generated stub for json_add_escaped_string */ -void json_add_escaped_string(struct json_result *result UNNEEDED, const char *fieldname UNNEEDED, +void json_add_escaped_string(struct json_result *result UNNEEDED, + const char *fieldname UNNEEDED, const struct json_escaped *esc TAKES UNNEEDED) { fprintf(stderr, "json_add_escaped_string called!\n"); abort(); } /* Generated stub for json_add_hex */ @@ -230,6 +231,10 @@ void json_array_start(struct json_result *ptr UNNEEDED, const char *fieldname UN /* Generated stub for json_escape */ struct json_escaped *json_escape(const tal_t *ctx UNNEEDED, const char *str TAKES UNNEEDED) { fprintf(stderr, "json_escape called!\n"); abort(); } +/* Generated stub for json_escaped_string_ */ +struct json_escaped *json_escaped_string_(const tal_t *ctx UNNEEDED, + const void *bytes UNNEEDED, size_t len UNNEEDED) +{ fprintf(stderr, "json_escaped_string_ called!\n"); abort(); } /* Generated stub for json_get_params */ bool json_get_params(struct command *cmd UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t param[] UNNEEDED, ...) diff --git a/wallet/wallet.c b/wallet/wallet.c index a2489aab4..d3d516cc5 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1369,7 +1369,7 @@ bool wallet_invoice_load(struct wallet *wallet) bool wallet_invoice_create(struct wallet *wallet, struct invoice *pinvoice, u64 *msatoshi TAKES, - const char *label TAKES, + const struct json_escaped *label TAKES, u64 expiry, const char *b11enc, const struct preimage *r, @@ -1379,7 +1379,7 @@ bool wallet_invoice_create(struct wallet *wallet, } bool wallet_invoice_find_by_label(struct wallet *wallet, struct invoice *pinvoice, - const char *label) + const struct json_escaped *label) { return invoices_find_by_label(wallet->invoices, pinvoice, label); } diff --git a/wallet/wallet.h b/wallet/wallet.h index 780b1b2de..3ae4cdc18 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -397,7 +397,7 @@ struct invoice_details { /* Hash of preimage r */ struct sha256 rhash; /* Label assigned by user */ - const char *label; + const struct json_escaped *label; /* NULL if they specified "any" */ u64 *msatoshi; /* Absolute UNIX epoch time this will expire */ @@ -449,7 +449,7 @@ bool wallet_invoice_load(struct wallet *wallet); * @msatoshi - the amount the invoice should have, or * NULL for any-amount invoices. * @label - the unique label for this invoice. Must be - * non-NULL. Must be null-terminated. + * non-NULL. * @expiry - the number of seconds before the invoice * expires * @@ -460,7 +460,7 @@ bool wallet_invoice_load(struct wallet *wallet); bool wallet_invoice_create(struct wallet *wallet, struct invoice *pinvoice, u64 *msatoshi TAKES, - const char *label TAKES, + const struct json_escaped *label TAKES, u64 expiry, const char *b11enc, const struct preimage *r, @@ -471,14 +471,14 @@ bool wallet_invoice_create(struct wallet *wallet, * * @wallet - the wallet to search. * @pinvoice - pointer to location to load found invoice in. - * @label - the label to search for. Must be null-terminated. + * @label - the label to search for. * * Returns false if no invoice with that label exists. * Returns true if found. */ bool wallet_invoice_find_by_label(struct wallet *wallet, struct invoice *pinvoice, - const char *label); + const struct json_escaped *label); /** * wallet_invoice_find_unpaid - Search for an unpaid, unexpired invoice by