commando: make rune alternatives a JSON array.

This avoids having to escape | or &, though we still allow that for
the deprecation period.

To detect deprecated usage, we insist that alternatives are *always*
an array (which could be loosened later), but that also means that
restrictions must *always* be an array for now.

Before:

```
# invoice, description either A or B
lightning-cli commando-rune '["method=invoice","pnamedescription=A|pnamedescription=B"]'
# invoice, description literally 'A|B'
lightning-cli commando-rune '["method=invoice","pnamedescription=A\\|B"]'
```

After:

```
# invoice, description either A or B
lightning-cli commando-rune '[["method=invoice"],["pnamedescription=A", "pnamedescription=B"]]'
# invoice, description literally 'A|B'
lightning-cli commando-rune '[["method=invoice"],["pnamedescription=A|B"]]'
```

Changelog-Deprecated: JSON-RPC: `commando-rune` restrictions is always an array, each element an array of alternatives.  Replaces a string with `|`-separators, so no escaping necessary except for `\\`.
This commit is contained in:
Rusty Russell
2022-09-14 15:00:26 +09:30
committed by Christian Decker
parent d57d87ea3a
commit a6d4756d08
4 changed files with 87 additions and 35 deletions

View File

@@ -762,11 +762,14 @@ static struct rune_restr **readonly_restrictions(const tal_t *ctx)
return restrs;
}
/* \| is not valid JSON, so they use \\|: undo it! */
static struct rune_restr *rune_restr_from_json(const tal_t *ctx,
const char *buffer,
const jsmntok_t *tok)
static struct rune_altern *rune_altern_from_json(const tal_t *ctx,
const char *buffer,
const jsmntok_t *tok)
{
struct rune_altern *alt;
size_t condoff;
/* We still need to unescape here, for \\ -> \. JSON doesn't
* allow unnecessary \ */
const char *unescape;
struct json_escape *e = json_escape_string_(tmpctx,
buffer + tok->start,
@@ -774,7 +777,51 @@ static struct rune_restr *rune_restr_from_json(const tal_t *ctx,
unescape = json_escape_unescape(tmpctx, e);
if (!unescape)
return NULL;
return rune_restr_from_string(ctx, unescape, strlen(unescape));
condoff = rune_altern_fieldname_len(unescape, strlen(unescape));
if (!rune_condition_is_valid(unescape[condoff]))
return NULL;
alt = tal(ctx, struct rune_altern);
alt->fieldname = tal_strndup(alt, unescape, condoff);
alt->condition = unescape[condoff];
alt->value = tal_strdup(alt, unescape + condoff + 1);
return alt;
}
static struct rune_restr *rune_restr_from_json(const tal_t *ctx,
const char *buffer,
const jsmntok_t *tok)
{
const jsmntok_t *t;
size_t i;
struct rune_restr *restr;
/* \| is not valid JSON, so they use \\|: undo it! */
if (deprecated_apis && tok->type == JSMN_STRING) {
const char *unescape;
struct json_escape *e = json_escape_string_(tmpctx,
buffer + tok->start,
tok->end - tok->start);
unescape = json_escape_unescape(tmpctx, e);
if (!unescape)
return NULL;
return rune_restr_from_string(ctx, unescape, strlen(unescape));
}
restr = tal(ctx, struct rune_restr);
/* FIXME: after deprecation removed, allow singletons again! */
if (tok->type != JSMN_ARRAY)
return NULL;
restr->alterns = tal_arr(restr, struct rune_altern *, tok->size);
json_for_each_arr(i, t, tok) {
restr->alterns[i] = rune_altern_from_json(restr->alterns,
buffer, t);
if (!restr->alterns[i])
return tal_free(restr);
}
return restr;
}
static struct command_result *param_restrictions(struct command *cmd,
@@ -794,7 +841,7 @@ static struct command_result *param_restrictions(struct command *cmd,
(*restrs)[i] = rune_restr_from_json(*restrs, buffer, t);
if (!(*restrs)[i]) {
return command_fail_badparam(cmd, name, buffer, t,
"not a valid restriction");
"not a valid restriction (should be array)");
}
}
} else {
@@ -802,7 +849,7 @@ static struct command_result *param_restrictions(struct command *cmd,
(*restrs)[0] = rune_restr_from_json(*restrs, buffer, tok);
if (!(*restrs)[0])
return command_fail_badparam(cmd, name, buffer, tok,
"not a valid restriction");
"not a valid restriction (should be array)");
}
return NULL;
}