Skip to content

Commit

Permalink
config: add the ability for plugins to specify that config values sho…
Browse files Browse the repository at this point in the history
…uld be concealed.

And use it for `exposesecret-passphrase`.  This is probably overly
cautious, but it makes me feel a little better that we won't leak it
to someone with read-only access.

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Nov 12, 2024
1 parent 101aeea commit 8293352
Show file tree
Hide file tree
Showing 8 changed files with 24 additions and 8 deletions.
2 changes: 2 additions & 0 deletions common/configvar.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ struct configvar {
#define OPT_DYNAMIC (1 << (OPT_USER_START+6))
/* Keep whitespace at the end of the option argument */
#define OPT_KEEP_WHITESPACE (1 << (OPT_USER_START+7))
/* Don't show value in listconfigs */
#define OPT_CONCEAL (1 << (OPT_USER_START+8))

/* Use this instead of opt_register_*_arg if you want OPT_* from above */
#define clnopt_witharg(names, type, cb, show, arg, desc) \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,11 @@ Plugins are free to register any `name` for their `rpcmethod` as long as the nam

There are currently four supported option 'types':

- string: a string
- bool: a boolean
- int: parsed as a signed integer (64-bit)
- flag: no-arg flag option. Presented as `true` if config specifies it.
- `string`: a string
- `string-conceal`: a string which will appear as "..." in `listconfigs`.
- `bool`: a boolean
- `int`: parsed as a signed integer (64-bit)
- `flag`: no-arg flag option. Presented as `true` if config specifies it.

In addition, string and int types can specify `"multi": true` to indicate they can be specified multiple times. These will always be represented in `init` as a (possibly empty) JSON array. "multi" flag types do not make
sense.
Expand Down
3 changes: 3 additions & 0 deletions lightningd/configs.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ static const char *get_opt_val(const struct opt_table *ot,
char buf[],
const struct configvar *cv)
{
if (ot->type & OPT_CONCEAL)
return "...";

if (ot->show == (void *)opt_show_charp) {
/* Don't truncate or quote! */
return *(char **)ot->u.carg;
Expand Down
6 changes: 4 additions & 2 deletions lightningd/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -2095,8 +2095,10 @@ void add_config_deprecated(struct lightningd *ld,
if (!opt->show(buf, sizeof(buf) - sizeof("..."), opt->u.carg))
buf[0] = '\0';

if ((opt->type & OPT_SHOWINT)
|| (opt->type & OPT_SHOWMSATS)) {
if (opt->type & OPT_CONCEAL) {
strcpy(buf, "...");
} else if ((opt->type & OPT_SHOWINT)
|| (opt->type & OPT_SHOWMSATS)) {
if (streq(buf, "")
|| strspn(buf, "-0123456789.") != strlen(buf))
errx(1, "Bad literal for %s: %s", name0, buf);
Expand Down
5 changes: 4 additions & 1 deletion lightningd/plugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -1168,7 +1168,10 @@ static const char *plugin_opt_add(struct plugin *plugin, const char *buffer,
/* These all take an arg. */
char *(*cb_arg)(const char *optarg, void *arg);

if (json_tok_streq(buffer, typetok, "string")) {
if (json_tok_streq(buffer, typetok, "string-conceal")) {
optflags |= OPT_CONCEAL;
cb_arg = (void *)plugin_opt_string_check;
} else if (json_tok_streq(buffer, typetok, "string")) {
cb_arg = (void *)plugin_opt_string_check;
} else if (json_tok_streq(buffer, typetok, "int")) {
cb_arg = (void *)plugin_opt_long_check;
Expand Down
1 change: 1 addition & 0 deletions plugins/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ cln-renepay
recover
cln-askrene
recklessrpc
exposesecret
2 changes: 1 addition & 1 deletion plugins/exposesecret.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ int main(int argc, char *argv[])
plugin_main(argv, init, take(exposesecret),
PLUGIN_RESTARTABLE, true, NULL, commands, ARRAY_SIZE(commands),
NULL, 0, NULL, 0, NULL, 0,
plugin_option("exposesecret-passphrase", "string",
plugin_option("exposesecret-passphrase", "string-conceal",
"Enable exposesecret command to allow HSM Secret backup, with this passphrase",
charp_option, NULL, &exposesecret->exposure_passphrase),
NULL);
Expand Down
4 changes: 4 additions & 0 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4453,6 +4453,10 @@ def test_listchannels_broken_message(node_factory):
def test_exposesecret(node_factory):
l1, l2 = node_factory.get_nodes(2, opts=[{'exposesecret-passphrase': "test_exposesecret"}, {}])

# listconfigs will conceal the value for us, even if we ask directly.
l1.rpc.listconfigs()['configs']['exposesecret-passphrase']['value_str'] == '...'
l1.rpc.listconfigs('exposesecret-passphrase')['configs']['exposesecret-passphrase']['value_str'] == '...'

# l2 won't expose the secret!
with pytest.raises(RpcError, match="exposesecrets-passphrase is not set"):
l2.rpc.exposesecret(passphrase='test_exposesecret')
Expand Down

0 comments on commit 8293352

Please sign in to comment.