From f0731d2ca11ee647566bd6fc11809c9519252cf8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 9 Nov 2022 14:10:54 +1030 Subject: [PATCH] common/json_stream: support filtering don't print fields not allowed. Signed-off-by: Rusty Russell --- common/json_stream.c | 85 +++++++++++++++++++++++++------- common/json_stream.h | 12 +++++ common/test/run-json.c | 3 ++ common/test/run-param.c | 4 ++ lightningd/Makefile | 1 + plugins/bkpr/test/run-bkpr_db.c | 1 + plugins/bkpr/test/run-recorder.c | 1 + 7 files changed, 88 insertions(+), 19 deletions(-) diff --git a/common/json_stream.c b/common/json_stream.c index 7263c5e3c..59a21d280 100644 --- a/common/json_stream.c +++ b/common/json_stream.c @@ -12,13 +12,15 @@ #include #include #include +#include +#include #include #include +#include #include #include #include #include -#include #include #include #include @@ -46,9 +48,29 @@ struct json_stream *new_json_stream(const tal_t *ctx, js->writer = writer; js->reader = NULL; js->log = log; + js->filter = NULL; return js; } +void json_stream_attach_filter(struct json_stream *js, + struct json_filter *filter STEALS) +{ + assert(!js->filter); + js->filter = tal_steal(js, filter); +} + +const char *json_stream_detach_filter(const tal_t *ctx, struct json_stream *js) +{ + const char *err; + assert(js->filter); + /* Should be well-formed at this point! */ + assert(json_filter_finished(js->filter)); + + err = json_filter_misused(ctx, js->filter); + js->filter = tal_free(js->filter); + return err; +} + struct json_stream *json_stream_dup(const tal_t *ctx, struct json_stream *original, struct log *log) @@ -57,6 +79,8 @@ struct json_stream *json_stream_dup(const tal_t *ctx, js->jout = json_out_dup(js, original->jout); js->log = log; + /* You can't dup things with filters! */ + assert(!js->filter); return js; } @@ -83,6 +107,8 @@ void json_stream_append(struct json_stream *js, { char *dest; + /* Only on low-level streams! */ + assert(!js->filter); dest = json_out_direct(js->jout, len); memcpy(dest, str, len); } @@ -115,7 +141,7 @@ void json_stream_close(struct json_stream *js, struct command *writer) * I used to assert(writer); here. */ assert(js->writer == writer); - /* Should be well-formed at this point! */ + assert(!js->filter); json_stream_double_cr(js); json_stream_flush(js); js->writer = NULL; @@ -130,22 +156,26 @@ void json_stream_flush(struct json_stream *js) void json_array_start(struct json_stream *js, const char *fieldname) { - json_out_start(js->jout, fieldname, '['); + if (json_filter_down(&js->filter, fieldname)) + json_out_start(js->jout, fieldname, '['); } void json_array_end(struct json_stream *js) { - json_out_end(js->jout, ']'); + if (json_filter_up(&js->filter)) + json_out_end(js->jout, ']'); } void json_object_start(struct json_stream *js, const char *fieldname) { - json_out_start(js->jout, fieldname, '{'); + if (json_filter_down(&js->filter, fieldname)) + json_out_start(js->jout, fieldname, '{'); } void json_object_end(struct json_stream *js) { - json_out_end(js->jout, '}'); + if (json_filter_up(&js->filter)) + json_out_end(js->jout, '}'); } void json_add_primitive_fmt(struct json_stream *js, @@ -154,9 +184,11 @@ void json_add_primitive_fmt(struct json_stream *js, { va_list ap; - va_start(ap, fmt); - json_out_addv(js->jout, fieldname, false, fmt, ap); - va_end(ap); + if (json_filter_ok(js->filter, fieldname)) { + va_start(ap, fmt); + json_out_addv(js->jout, fieldname, false, fmt, ap); + va_end(ap); + } } void json_add_str_fmt(struct json_stream *js, @@ -165,9 +197,11 @@ void json_add_str_fmt(struct json_stream *js, { va_list ap; - va_start(ap, fmt); - json_out_addv(js->jout, fieldname, true, fmt, ap); - va_end(ap); + if (json_filter_ok(js->filter, fieldname)) { + va_start(ap, fmt); + json_out_addv(js->jout, fieldname, true, fmt, ap); + va_end(ap); + } } void json_add_primitive(struct json_stream *js, @@ -183,7 +217,8 @@ void json_add_string(struct json_stream *js, const char *fieldname, const char *str TAKES) { - json_out_addstr(js->jout, fieldname, str); + if (json_filter_ok(js->filter, fieldname)) + json_out_addstr(js->jout, fieldname, str); if (taken(str)) tal_free(str); } @@ -204,6 +239,13 @@ void json_add_jsonstr(struct json_stream *js, { char *p; + if (!json_filter_ok(js->filter, fieldname)) + return; + + /* NOTE: Filtering doesn't really work here! */ + if (!json_filter_ok(js->filter, fieldname)) + return; + p = json_member_direct(js, fieldname, jsonstrlen); memcpy(p, jsonstr, jsonstrlen); } @@ -321,13 +363,15 @@ void json_add_hex_talarr(struct json_stream *result, void json_add_escaped_string(struct json_stream *result, const char *fieldname, const struct json_escape *esc TAKES) { - /* Already escaped, don't re-escape! */ - char *dest = json_member_direct(result, fieldname, - 1 + strlen(esc->s) + 1); + if (json_filter_ok(result->filter, fieldname)) { + /* Already escaped, don't re-escape! */ + char *dest = json_member_direct(result, fieldname, + 1 + strlen(esc->s) + 1); - dest[0] = '"'; - memcpy(dest + 1, esc->s, strlen(esc->s)); - dest[1+strlen(esc->s)] = '"'; + dest[0] = '"'; + memcpy(dest + 1, esc->s, strlen(esc->s)); + dest[1+strlen(esc->s)] = '"'; + } if (taken(esc)) tal_free(esc); } @@ -373,6 +417,9 @@ void json_add_tok(struct json_stream *result, const char *fieldname, char *space; assert(tok->type != JSMN_UNDEFINED); + if (!json_filter_ok(result->filter, fieldname)) + return; + space = json_member_direct(result, fieldname, json_tok_full_len(tok)); memcpy(space, json_tok_full(buffer, tok), json_tok_full_len(tok)); } diff --git a/common/json_stream.h b/common/json_stream.h index 22786ce26..afcd29a57 100644 --- a/common/json_stream.h +++ b/common/json_stream.h @@ -13,6 +13,7 @@ #include #include #include +#include struct command; struct io_conn; @@ -48,6 +49,9 @@ struct json_stream { void *reader_arg; size_t len_read; + /* If non-NULL, reflects the current filter position */ + struct json_filter *filter; + /* Where to log I/O */ struct log *log; }; @@ -78,6 +82,14 @@ struct json_stream *json_stream_dup(const tal_t *ctx, struct json_stream *original, struct log *log); +/* Attach a filter. Usually this works at the result level: you don't + * want to filter out id, etc! */ +void json_stream_attach_filter(struct json_stream *js, + struct json_filter *filter STEALS); + +/* Detach the filter: returns non-NULL string if it was misused. */ +const char *json_stream_detach_filter(const tal_t *ctx, struct json_stream *js); + /** * json_stream_close - finished writing to a JSON stream. * @js: the json_stream. diff --git a/common/test/run-json.c b/common/test/run-json.c index 84e672d2a..a9dc6daa9 100644 --- a/common/test/run-json.c +++ b/common/test/run-json.c @@ -24,6 +24,9 @@ bool json_filter_down(struct json_filter **filter UNNEEDED, const char *member U /* Generated stub for json_filter_finished */ bool json_filter_finished(const struct json_filter *filter UNNEEDED) { fprintf(stderr, "json_filter_finished called!\n"); abort(); } +/* Generated stub for json_filter_misused */ +const char *json_filter_misused(const tal_t *ctx UNNEEDED, const struct json_filter *f UNNEEDED) +{ fprintf(stderr, "json_filter_misused called!\n"); abort(); } /* Generated stub for json_filter_ok */ bool json_filter_ok(const struct json_filter *filter UNNEEDED, const char *member UNNEEDED) { fprintf(stderr, "json_filter_ok called!\n"); abort(); } diff --git a/common/test/run-param.c b/common/test/run-param.c index bd450aef3..6609247db 100644 --- a/common/test/run-param.c +++ b/common/test/run-param.c @@ -1,4 +1,5 @@ #include "config.h" +#include "../json_filter.c" #include "../json_parse.c" #include "../json_parse_simple.c" #include "../json_param.c" @@ -35,6 +36,9 @@ struct command_result *command_fail(struct command *cmd, } /* AUTOGENERATED MOCKS START */ +/* Generated stub for command_filter_ptr */ +struct json_filter **command_filter_ptr(struct command *cmd UNNEEDED) +{ fprintf(stderr, "command_filter_ptr called!\n"); abort(); } /* Generated stub for deprecated_apis */ bool deprecated_apis; /* Generated stub for fromwire_tlv */ diff --git a/lightningd/Makefile b/lightningd/Makefile index 661f01faa..adc8a1f80 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -101,6 +101,7 @@ LIGHTNINGD_COMMON_OBJS := \ common/htlc_wire.o \ common/key_derive.o \ common/keyset.o \ + common/json_filter.o \ common/json_param.o \ common/json_parse.o \ common/json_parse_simple.o \ diff --git a/plugins/bkpr/test/run-bkpr_db.c b/plugins/bkpr/test/run-bkpr_db.c index a27cb93ec..e71d7c1d4 100644 --- a/plugins/bkpr/test/run-bkpr_db.c +++ b/plugins/bkpr/test/run-bkpr_db.c @@ -19,6 +19,7 @@ void db_fatal(const char *fmt, ...) } #endif /* DB_FATAL */ +#include "common/json_filter.c" #include "plugins/bkpr/db.c" #include "plugins/libplugin.c" diff --git a/plugins/bkpr/test/run-recorder.c b/plugins/bkpr/test/run-recorder.c index c3e449426..7872800be 100644 --- a/plugins/bkpr/test/run-recorder.c +++ b/plugins/bkpr/test/run-recorder.c @@ -1,4 +1,5 @@ #include "config.h" +#include "common/json_filter.c" #include "test_utils.h" #include "plugins/libplugin.c"