mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-21 14:24:09 +01:00
ccan: upgrade to get ccan/runes.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
3e672b784d
commit
f65d3bb1fc
12 changed files with 1755 additions and 2 deletions
11
Makefile
11
Makefile
|
@ -92,6 +92,7 @@ FEATURES :=
|
|||
|
||||
CCAN_OBJS := \
|
||||
ccan-asort.o \
|
||||
ccan-base64.o \
|
||||
ccan-bitmap.o \
|
||||
ccan-bitops.o \
|
||||
ccan-breakpoint.o \
|
||||
|
@ -127,6 +128,8 @@ CCAN_OBJS := \
|
|||
ccan-ptr_valid.o \
|
||||
ccan-rbuf.o \
|
||||
ccan-read_write_all.o \
|
||||
ccan-rune-coding.o \
|
||||
ccan-rune-rune.o \
|
||||
ccan-str-base32.o \
|
||||
ccan-str-hex.o \
|
||||
ccan-str.o \
|
||||
|
@ -195,6 +198,8 @@ CCAN_HEADERS := \
|
|||
$(CCANDIR)/ccan/ptrint/ptrint.h \
|
||||
$(CCANDIR)/ccan/rbuf/rbuf.h \
|
||||
$(CCANDIR)/ccan/read_write_all/read_write_all.h \
|
||||
$(CCANDIR)/ccan/rune/internal.h \
|
||||
$(CCANDIR)/ccan/rune/rune.h \
|
||||
$(CCANDIR)/ccan/short_types/short_types.h \
|
||||
$(CCANDIR)/ccan/str/base32/base32.h \
|
||||
$(CCANDIR)/ccan/str/hex/hex.h \
|
||||
|
@ -840,6 +845,8 @@ endif
|
|||
|
||||
ccan-breakpoint.o: $(CCANDIR)/ccan/breakpoint/breakpoint.c
|
||||
@$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<)
|
||||
ccan-base64.o: $(CCANDIR)/ccan/base64/base64.c
|
||||
@$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<)
|
||||
ccan-tal.o: $(CCANDIR)/ccan/tal/tal.c
|
||||
@$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<)
|
||||
ccan-tal-str.o: $(CCANDIR)/ccan/tal/str/str.c
|
||||
|
@ -940,3 +947,7 @@ ccan-json_out.o: $(CCANDIR)/ccan/json_out/json_out.c
|
|||
@$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<)
|
||||
ccan-closefrom.o: $(CCANDIR)/ccan/closefrom/closefrom.c
|
||||
@$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<)
|
||||
ccan-rune-rune.o: $(CCANDIR)/ccan/rune/rune.c
|
||||
@$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<)
|
||||
ccan-rune-coding.o: $(CCANDIR)/ccan/rune/coding.c
|
||||
@$(call VERBOSE, "cc $<", $(CC) $(CFLAGS) -c -o $@ $<)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
CCAN imported from http://ccodearchive.net.
|
||||
|
||||
CCAN version: init-2540-g8448fd28
|
||||
CCAN version: init-2541-g52b86922
|
||||
|
|
|
@ -116,7 +116,7 @@ ssize_t base64_decode_quartet_using_maps(const base64_maps_t *maps,
|
|||
* @note sets errno = EDOM if src contains invalid characters
|
||||
* @note sets errno = EINVAL if src is an invalid base64 tail
|
||||
*/
|
||||
ssize_t base64_decode_tail_using_maps(const base64_maps_t *maps, char *dest,
|
||||
ssize_t base64_decode_tail_using_maps(const base64_maps_t *maps, char dest[3],
|
||||
const char *src, size_t srclen);
|
||||
|
||||
|
||||
|
|
1
ccan/ccan/rune/LICENSE
Symbolic link
1
ccan/ccan/rune/LICENSE
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../licenses/BSD-MIT
|
130
ccan/ccan/rune/_info
Normal file
130
ccan/ccan/rune/_info
Normal file
|
@ -0,0 +1,130 @@
|
|||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* rune - Simple cookies you can extend (a-la Python runes class).
|
||||
*
|
||||
* This code is a form of cookies, but they are user-extensible, and
|
||||
* contain a simple language to define what the cookie allows.
|
||||
*
|
||||
* A "rune" contains the hash of a secret (so the server can
|
||||
* validate), such that you can add, but not subtract, conditions.
|
||||
* This is a simplified form of Macaroons, See
|
||||
* https://research.google/pubs/pub41892/ "Macaroons: Cookies with
|
||||
* Contextual Caveats for Decentralized Authorization in the Cloud".
|
||||
* It has one good idea, some extended ideas nobody implements, and
|
||||
* lots and lots of words.
|
||||
*
|
||||
* License: BSD-MIT
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
* Example:
|
||||
* // Given "generate secret 1" outputs kr7AW-eJ2Munhv5ftu4rHqAnhxUpPQM8aOyWOmqiytk9MQ==
|
||||
* // Given "add kr7AW-eJ2Munhv5ftu4rHqAnhxUpPQM8aOyWOmqiytk9MQ== uid=rusty" outputs Xyt5S6FKUnA2ppGB62c6HTPGojt2S7k2n7Cf7Tjj6zM9MSZ1aWQ9cnVzdHk=
|
||||
* // Given "test secret Xyt5S6FKUnA2ppGB62c6HTPGojt2S7k2n7Cf7Tjj6zM9MSZ1aWQ9cnVzdHk= rusty" outputs PASSED
|
||||
* // Given "test secret Xyt5S6FKUnA2ppGB62c6HTPGojt2S7k2n7Cf7Tjj6zM9MSZ1aWQ9cnVzdHk= notrusty" outputs FAILED: uid is not equal to rusty
|
||||
* // Given "add Xyt5S6FKUnA2ppGB62c6HTPGojt2S7k2n7Cf7Tjj6zM9MSZ1aWQ9cnVzdHk= t\<1655958616" outputs _YBFmeAedqlLigWHAmvyyGGHRrnI40BRQGh2hWdSZ9E9MSZ1aWQ9cnVzdHkmdDwxNjU1OTU4NjE2
|
||||
* // Given "test secret _YBFmeAedqlLigWHAmvyyGGHRrnI40BRQGh2hWdSZ9E9MSZ1aWQ9cnVzdHkmdDwxNjU1OTU4NjE2 rusty" outputs FAILED: t is greater or equal to 1655958616
|
||||
* #include <ccan/err/err.h>
|
||||
* #include <ccan/rune/rune.h>
|
||||
* #include <ccan/str/str.h>
|
||||
* #include <stdio.h>
|
||||
* #include <sys/time.h>
|
||||
*
|
||||
* // We support two values: current time (t), and user id (uid).
|
||||
* static const char *check(const tal_t *ctx,
|
||||
* const struct rune *rune,
|
||||
* const struct rune_altern *alt,
|
||||
* char *uid)
|
||||
* {
|
||||
* // t= means current time, in seconds, as integer
|
||||
* if (streq(alt->fieldname, "t")) {
|
||||
* struct timeval now;
|
||||
* gettimeofday(&now, NULL);
|
||||
* return rune_alt_single_int(ctx, alt, now.tv_sec);
|
||||
* }
|
||||
* if (streq(alt->fieldname, "uid")) {
|
||||
* return rune_alt_single_str(ctx, alt, uid, strlen(uid));
|
||||
* }
|
||||
* // Otherwise, field is missing
|
||||
* return rune_alt_single_missing(ctx, alt);
|
||||
* }
|
||||
*
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* struct rune *master, *rune;
|
||||
*
|
||||
* if (argc < 3)
|
||||
* goto usage;
|
||||
*
|
||||
* if (streq(argv[1], "generate")) {
|
||||
* // Make master, derive a unique_id'd rune.
|
||||
* if (argc != 3 && argc != 4)
|
||||
* goto usage;
|
||||
* master = rune_new(NULL, (u8 *)argv[2], strlen(argv[2]), NULL);
|
||||
* rune = rune_derive_start(NULL, master, argv[3]);
|
||||
* } else if (streq(argv[1], "add")) {
|
||||
* // Add a restriction
|
||||
* struct rune_restr *restr;
|
||||
* if (argc != 4)
|
||||
* goto usage;
|
||||
* rune = rune_from_base64(NULL, argv[2]);
|
||||
* if (!rune)
|
||||
* errx(1, "Bad rune");
|
||||
* restr = rune_restr_from_string(NULL, argv[3], strlen(argv[3]));
|
||||
* if (!restr)
|
||||
* errx(1, "Bad restriction string");
|
||||
* rune_add_restr(rune, restr);
|
||||
* } else if (streq(argv[1], "test")) {
|
||||
* const char *err;
|
||||
* if (argc != 5)
|
||||
* goto usage;
|
||||
* master = rune_new(NULL, (u8 *)argv[2], strlen(argv[2]), NULL);
|
||||
* if (!master)
|
||||
* errx(1, "Bad master rune");
|
||||
* rune = rune_from_base64(NULL, argv[3]);
|
||||
* if (!rune)
|
||||
* errx(1, "Bad rune");
|
||||
* err = rune_test(NULL, master, rune, check, argv[4]);
|
||||
* if (err)
|
||||
* printf("FAILED: %s\n", err);
|
||||
* else
|
||||
* printf("PASSED\n");
|
||||
* return 0;
|
||||
* } else
|
||||
* goto usage;
|
||||
*
|
||||
* printf("%s\n", rune_to_base64(NULL, rune));
|
||||
* return 0;
|
||||
*
|
||||
* usage:
|
||||
* errx(1, "Usage: %s generate <secret> <uniqueid> OR\n"
|
||||
* "%s add <rune> <restriction> OR\n"
|
||||
* "%s test <secret> <rune> <uid>", argv[0], argv[0], argv[0]);
|
||||
* }
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* Expect exactly one argument */
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
printf("ccan/base64\n");
|
||||
printf("ccan/crypto/sha256\n");
|
||||
printf("ccan/endian\n");
|
||||
printf("ccan/mem\n");
|
||||
printf("ccan/short_types\n");
|
||||
printf("ccan/str/hex\n");
|
||||
printf("ccan/tal/str\n");
|
||||
printf("ccan/tal\n");
|
||||
printf("ccan/typesafe_cb\n");
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[1], "testdepends") == 0) {
|
||||
printf("ccan/tal/grab_file\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
422
ccan/ccan/rune/coding.c
Normal file
422
ccan/ccan/rune/coding.c
Normal file
|
@ -0,0 +1,422 @@
|
|||
/* MIT (BSD) license - see LICENSE file for details */
|
||||
/* Routines to encode / decode a rune */
|
||||
#include <ccan/rune/rune.h>
|
||||
#include <ccan/rune/internal.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <ccan/base64/base64.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* From Python base64.urlsafe_b64encode:
|
||||
*
|
||||
* The alphabet uses '-' instead of '+' and '_' instead of '/'.
|
||||
*/
|
||||
static const base64_maps_t base64_maps_urlsafe = {
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
|
||||
|
||||
"\xff\xff\xff\xff\xff" /* 0 */
|
||||
"\xff\xff\xff\xff\xff" /* 5 */
|
||||
"\xff\xff\xff\xff\xff" /* 10 */
|
||||
"\xff\xff\xff\xff\xff" /* 15 */
|
||||
"\xff\xff\xff\xff\xff" /* 20 */
|
||||
"\xff\xff\xff\xff\xff" /* 25 */
|
||||
"\xff\xff\xff\xff\xff" /* 30 */
|
||||
"\xff\xff\xff\xff\xff" /* 35 */
|
||||
"\xff\xff\xff\xff\xff" /* 40 */
|
||||
"\x3e\xff\xff\x34\x35" /* 45 */
|
||||
"\x36\x37\x38\x39\x3a" /* 50 */
|
||||
"\x3b\x3c\x3d\xff\xff" /* 55 */
|
||||
"\xff\xff\xff\xff\xff" /* 60 */
|
||||
"\x00\x01\x02\x03\x04" /* 65 A */
|
||||
"\x05\x06\x07\x08\x09" /* 70 */
|
||||
"\x0a\x0b\x0c\x0d\x0e" /* 75 */
|
||||
"\x0f\x10\x11\x12\x13" /* 80 */
|
||||
"\x14\x15\x16\x17\x18" /* 85 */
|
||||
"\x19\xff\xff\xff\xff" /* 90 */
|
||||
"\x3f\xff\x1a\x1b\x1c" /* 95 */
|
||||
"\x1d\x1e\x1f\x20\x21" /* 100 */
|
||||
"\x22\x23\x24\x25\x26" /* 105 */
|
||||
"\x27\x28\x29\x2a\x2b" /* 110 */
|
||||
"\x2c\x2d\x2e\x2f\x30" /* 115 */
|
||||
"\x31\x32\x33\xff\xff" /* 120 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 125 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 135 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 145 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 155 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 165 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 175 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 185 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 195 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 205 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 215 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 225 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 235 */
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 245 */
|
||||
};
|
||||
|
||||
/* For encoding as a string */
|
||||
struct wbuf {
|
||||
size_t off, len;
|
||||
char *buf;
|
||||
};
|
||||
|
||||
static void to_wbuf(const char *s, size_t len, void *vwbuf)
|
||||
{
|
||||
struct wbuf *wbuf = vwbuf;
|
||||
|
||||
while (wbuf->off + len > wbuf->len)
|
||||
tal_resize(&wbuf->buf, wbuf->len *= 2);
|
||||
memcpy(wbuf->buf + wbuf->off, s, len);
|
||||
wbuf->off += len;
|
||||
}
|
||||
|
||||
/* For adding to sha256 */
|
||||
static void to_sha256(const char *s, size_t len, void *vshactx)
|
||||
{
|
||||
struct sha256_ctx *shactx = vshactx;
|
||||
sha256_update(shactx, s, len);
|
||||
}
|
||||
|
||||
static void rune_altern_encode(const struct rune_altern *altern,
|
||||
void (*cb)(const char *s, size_t len,
|
||||
void *arg),
|
||||
void *arg)
|
||||
{
|
||||
char cond = altern->condition;
|
||||
const char *p;
|
||||
|
||||
cb(altern->fieldname, strlen(altern->fieldname), arg);
|
||||
cb(&cond, 1, arg);
|
||||
|
||||
p = altern->value;
|
||||
for (;;) {
|
||||
char esc[2] = { '\\' };
|
||||
size_t len = strcspn(p, "\\|&");
|
||||
cb(p, len, arg);
|
||||
if (!p[len])
|
||||
break;
|
||||
esc[1] = p[len];
|
||||
cb(esc, 2, arg);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
static void rune_restr_encode(const struct rune_restr *restr,
|
||||
void (*cb)(const char *s, size_t len,
|
||||
void *arg),
|
||||
void *arg)
|
||||
{
|
||||
for (size_t i = 0; i < tal_count(restr->alterns); i++) {
|
||||
if (i != 0)
|
||||
cb("|", 1, arg);
|
||||
rune_altern_encode(restr->alterns[i], cb, arg);
|
||||
}
|
||||
}
|
||||
|
||||
void rune_sha256_add_restr(struct sha256_ctx *shactx,
|
||||
struct rune_restr *restr)
|
||||
{
|
||||
rune_restr_encode(restr, to_sha256, shactx);
|
||||
rune_sha256_endmarker(shactx);
|
||||
}
|
||||
|
||||
const char *rune_is_derived(const struct rune *source, const struct rune *rune)
|
||||
{
|
||||
if (!runestr_eq(source->version, rune->version))
|
||||
return "Version mismatch";
|
||||
|
||||
return rune_is_derived_anyversion(source, rune);
|
||||
}
|
||||
|
||||
const char *rune_is_derived_anyversion(const struct rune *source,
|
||||
const struct rune *rune)
|
||||
{
|
||||
struct sha256_ctx shactx;
|
||||
size_t i;
|
||||
|
||||
if (tal_count(rune->restrs) < tal_count(source->restrs))
|
||||
return "Fewer restrictions than master";
|
||||
|
||||
/* If we add the same restrictions to source rune, do we match? */
|
||||
shactx = source->shactx;
|
||||
for (i = 0; i < tal_count(rune->restrs); i++) {
|
||||
/* First restrictions must be identical */
|
||||
if (i < tal_count(source->restrs)) {
|
||||
if (!rune_restr_eq(source->restrs[i], rune->restrs[i]))
|
||||
return "Does not match master restrictions";
|
||||
} else
|
||||
rune_sha256_add_restr(&shactx, rune->restrs[i]);
|
||||
}
|
||||
|
||||
if (memcmp(shactx.s, rune->shactx.s, sizeof(shactx.s)) != 0)
|
||||
return "Not derived from master";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool peek_char(const char *data, size_t len, char *c)
|
||||
{
|
||||
if (len == 0)
|
||||
return false;
|
||||
*c = *data;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void drop_char(const char **data, size_t *len)
|
||||
{
|
||||
(*data)++;
|
||||
(*len)--;
|
||||
}
|
||||
|
||||
static void pull_invalid(const char **data, size_t *len)
|
||||
{
|
||||
*data = NULL;
|
||||
*len = 0;
|
||||
}
|
||||
|
||||
static bool pull_char(const char **data, size_t *len, char *c)
|
||||
{
|
||||
if (!peek_char(*data, *len, c)) {
|
||||
pull_invalid(data, len);
|
||||
return false;
|
||||
}
|
||||
drop_char(data, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_valid_cond(enum rune_condition cond)
|
||||
{
|
||||
switch (cond) {
|
||||
case RUNE_COND_IF_MISSING:
|
||||
case RUNE_COND_EQUAL:
|
||||
case RUNE_COND_NOT_EQUAL:
|
||||
case RUNE_COND_BEGINS:
|
||||
case RUNE_COND_ENDS:
|
||||
case RUNE_COND_CONTAINS:
|
||||
case RUNE_COND_INT_LESS:
|
||||
case RUNE_COND_INT_GREATER:
|
||||
case RUNE_COND_LEXO_BEFORE:
|
||||
case RUNE_COND_LEXO_AFTER:
|
||||
case RUNE_COND_COMMENT:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Sets *more on success: true if another altern follows */
|
||||
static struct rune_altern *rune_altern_decode(const tal_t *ctx,
|
||||
const char **data, size_t *len,
|
||||
bool *more)
|
||||
{
|
||||
struct rune_altern *alt = tal(ctx, struct rune_altern);
|
||||
const char *strstart = *data;
|
||||
char *value;
|
||||
size_t strlen = 0;
|
||||
char c;
|
||||
|
||||
/* Swallow field up to conditional */
|
||||
for (;;) {
|
||||
if (!pull_char(data, len, &c))
|
||||
return tal_free(alt);
|
||||
if (cispunct(c))
|
||||
break;
|
||||
strlen++;
|
||||
}
|
||||
|
||||
alt->fieldname = tal_strndup(alt, strstart, strlen);
|
||||
if (!is_valid_cond(c)) {
|
||||
pull_invalid(data, len);
|
||||
return tal_free(alt);
|
||||
}
|
||||
alt->condition = c;
|
||||
|
||||
/* Assign worst case. */
|
||||
value = tal_arr(alt, char, *len + 1);
|
||||
strlen = 0;
|
||||
*more = false;
|
||||
while (*len && pull_char(data, len, &c)) {
|
||||
if (c == '|') {
|
||||
*more = true;
|
||||
break;
|
||||
}
|
||||
if (c == '&')
|
||||
break;
|
||||
|
||||
if (c == '\\' && !pull_char(data, len, &c))
|
||||
return tal_free(alt);
|
||||
value[strlen++] = c;
|
||||
}
|
||||
value[strlen] = '\0';
|
||||
tal_resize(&value, strlen + 1);
|
||||
alt->value = value;
|
||||
return alt;
|
||||
}
|
||||
|
||||
static struct rune_restr *rune_restr_decode(const tal_t *ctx,
|
||||
const char **data, size_t *len)
|
||||
{
|
||||
struct rune_restr *restr = tal(ctx, struct rune_restr);
|
||||
size_t num_alts = 0;
|
||||
bool more;
|
||||
|
||||
/* Must have at least one! */
|
||||
restr->alterns = tal_arr(restr, struct rune_altern *, 0);
|
||||
do {
|
||||
struct rune_altern *alt;
|
||||
|
||||
alt = rune_altern_decode(restr, data, len, &more);
|
||||
if (!alt)
|
||||
return tal_free(restr);
|
||||
tal_resize(&restr->alterns, num_alts+1);
|
||||
restr->alterns[num_alts++] = alt;
|
||||
} while (more);
|
||||
return restr;
|
||||
}
|
||||
|
||||
static struct rune *from_string(const tal_t *ctx,
|
||||
const char *str,
|
||||
const u8 *hash32)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
struct rune *rune = tal(ctx, struct rune);
|
||||
|
||||
/* Now count up how many bytes we should have hashed: secret uses
|
||||
* first block. */
|
||||
rune->shactx.bytes = 64;
|
||||
|
||||
rune->restrs = tal_arr(rune, struct rune_restr *, 0);
|
||||
rune->unique_id = NULL;
|
||||
rune->version = NULL;
|
||||
|
||||
while (len) {
|
||||
struct rune_restr *restr;
|
||||
restr = rune_restr_decode(rune, &str, &len);
|
||||
if (!restr)
|
||||
return tal_free(rune);
|
||||
if (!rune_add_restr(rune, restr))
|
||||
return tal_free(rune);
|
||||
}
|
||||
|
||||
/* Now we replace with canned hash state */
|
||||
memcpy(rune->shactx.s, hash32, 32);
|
||||
for (size_t i = 0; i < 8; i++)
|
||||
rune->shactx.s[i] = be32_to_cpu(rune->shactx.s[i]);
|
||||
|
||||
return rune;
|
||||
}
|
||||
|
||||
struct rune_restr *rune_restr_from_string(const tal_t *ctx,
|
||||
const char *str,
|
||||
size_t len)
|
||||
{
|
||||
struct rune_restr *restr;
|
||||
|
||||
restr = rune_restr_decode(NULL, &str, &len);
|
||||
/* Don't allow trailing chars */
|
||||
if (restr && len != 0)
|
||||
restr = tal_free(restr);
|
||||
return tal_steal(ctx, restr);
|
||||
}
|
||||
|
||||
static void to_string(struct wbuf *wbuf, const struct rune *rune, u8 *hash32)
|
||||
{
|
||||
/* Copy hash in big-endian */
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
be32 v = cpu_to_be32(rune->shactx.s[i]);
|
||||
memcpy(hash32 + i*4, &v, sizeof(v));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < tal_count(rune->restrs); i++) {
|
||||
if (i != 0)
|
||||
to_wbuf("&", 1, wbuf);
|
||||
rune_restr_encode(rune->restrs[i], to_wbuf, wbuf);
|
||||
}
|
||||
to_wbuf("", 1, wbuf);
|
||||
}
|
||||
|
||||
struct rune *rune_from_base64n(const tal_t *ctx, const char *str, size_t len)
|
||||
{
|
||||
size_t blen;
|
||||
u8 *data;
|
||||
struct rune *rune;
|
||||
|
||||
data = tal_arr(NULL, u8, base64_decoded_length(len) + 1);
|
||||
|
||||
blen = base64_decode_using_maps(&base64_maps_urlsafe,
|
||||
(char *)data, tal_bytelen(data),
|
||||
str, len);
|
||||
if (blen == -1)
|
||||
goto fail;
|
||||
|
||||
if (blen < 32)
|
||||
goto fail;
|
||||
|
||||
data[blen] = '\0';
|
||||
/* Sanity check that it's a valid string! */
|
||||
if (strlen((char *)data + 32) != blen - 32)
|
||||
goto fail;
|
||||
|
||||
rune = from_string(ctx, (const char *)data + 32, data);
|
||||
tal_free(data);
|
||||
return rune;
|
||||
|
||||
fail:
|
||||
tal_free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct rune *rune_from_base64(const tal_t *ctx, const char *str)
|
||||
{
|
||||
return rune_from_base64n(ctx, str, strlen(str));
|
||||
}
|
||||
|
||||
char *rune_to_base64(const tal_t *ctx, const struct rune *rune)
|
||||
{
|
||||
u8 hash32[32];
|
||||
char *ret;
|
||||
size_t ret_len;
|
||||
struct wbuf wbuf;
|
||||
|
||||
/* We're going to prepend hash */
|
||||
wbuf.off = sizeof(hash32);
|
||||
wbuf.len = 64;
|
||||
wbuf.buf = tal_arr(NULL, char, wbuf.len);
|
||||
|
||||
to_string(&wbuf, rune, hash32);
|
||||
/* Prepend hash */
|
||||
memcpy(wbuf.buf, hash32, sizeof(hash32));
|
||||
|
||||
ret = tal_arr(ctx, char, base64_encoded_length(wbuf.off) + 1);
|
||||
ret_len = base64_encode_using_maps(&base64_maps_urlsafe,
|
||||
ret, tal_bytelen(ret),
|
||||
wbuf.buf, wbuf.off - 1);
|
||||
ret[ret_len] = '\0';
|
||||
tal_free(wbuf.buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct rune *rune_from_string(const tal_t *ctx, const char *str)
|
||||
{
|
||||
u8 hash[32];
|
||||
if (!hex_decode(str, 64, hash, sizeof(hash)))
|
||||
return NULL;
|
||||
if (str[64] != ':')
|
||||
return NULL;
|
||||
return from_string(ctx, str + 65, hash);
|
||||
}
|
||||
|
||||
char *rune_to_string(const tal_t *ctx, const struct rune *rune)
|
||||
{
|
||||
u8 hash32[32];
|
||||
struct wbuf wbuf;
|
||||
|
||||
/* We're going to prepend hash (in hex), plus colon */
|
||||
wbuf.off = sizeof(hash32) * 2 + 1;
|
||||
wbuf.len = 128;
|
||||
wbuf.buf = tal_arr(ctx, char, wbuf.len);
|
||||
|
||||
to_string(&wbuf, rune, hash32);
|
||||
hex_encode(hash32, sizeof(hash32), wbuf.buf, sizeof(hash32) * 2 + 1);
|
||||
wbuf.buf[sizeof(hash32) * 2] = ':';
|
||||
return wbuf.buf;
|
||||
}
|
8
ccan/ccan/rune/internal.h
Normal file
8
ccan/ccan/rune/internal.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef CCAN_RUNE_INTERNAL_H
|
||||
#define CCAN_RUNE_INTERNAL_H
|
||||
/* MIT (BSD) license - see LICENSE file for details */
|
||||
void rune_sha256_endmarker(struct sha256_ctx *shactx);
|
||||
void rune_sha256_add_restr(struct sha256_ctx *shactx,
|
||||
struct rune_restr *restr);
|
||||
bool runestr_eq(const char *a, const char *b);
|
||||
#endif /* CCAN_RUNE_INTERNAL_H */
|
491
ccan/ccan/rune/rune.c
Normal file
491
ccan/ccan/rune/rune.c
Normal file
|
@ -0,0 +1,491 @@
|
|||
/* MIT (BSD) license - see LICENSE file for details */
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <ccan/rune/rune.h>
|
||||
#include <ccan/rune/internal.h>
|
||||
|
||||
/* Helper to produce an id field */
|
||||
static struct rune_restr *unique_id_restr(const tal_t *ctx,
|
||||
const char *unique_id,
|
||||
const char *version)
|
||||
{
|
||||
const char *id;
|
||||
struct rune_restr *restr;
|
||||
|
||||
assert(!strchr(unique_id, '-'));
|
||||
if (version)
|
||||
id = tal_fmt(NULL, "%s-%s", unique_id, version);
|
||||
else
|
||||
id = tal_strdup(NULL, unique_id);
|
||||
|
||||
restr = rune_restr_new(ctx);
|
||||
/* We use the empty field for this, since it's always present. */
|
||||
rune_restr_add_altern(restr,
|
||||
take(rune_altern_new(NULL, "", '=', take(id))));
|
||||
return restr;
|
||||
}
|
||||
|
||||
/* We pad between fields with something identical to the SHA end marker */
|
||||
void rune_sha256_endmarker(struct sha256_ctx *shactx)
|
||||
{
|
||||
static const unsigned char pad[64] = {0x80};
|
||||
be64 sizedesc;
|
||||
|
||||
sizedesc = cpu_to_be64((uint64_t)shactx->bytes << 3);
|
||||
/* Add '1' bit to terminate, then all 0 bits, up to next block - 8. */
|
||||
sha256_update(shactx, pad, 1 + ((128 - 8 - (shactx->bytes % 64) - 1) % 64));
|
||||
/* Add number of bits of data (big endian) */
|
||||
sha256_update(shactx, &sizedesc, 8);
|
||||
}
|
||||
|
||||
struct rune *rune_new(const tal_t *ctx, const u8 *secret, size_t secret_len,
|
||||
const char *version)
|
||||
{
|
||||
struct rune *rune = tal(ctx, struct rune);
|
||||
assert(secret_len + 1 + 8 <= 64);
|
||||
|
||||
if (version)
|
||||
rune->version = tal_strdup(rune, version);
|
||||
else
|
||||
rune->version = NULL;
|
||||
rune->unique_id = NULL;
|
||||
sha256_init(&rune->shactx);
|
||||
sha256_update(&rune->shactx, secret, secret_len);
|
||||
rune_sha256_endmarker(&rune->shactx);
|
||||
rune->restrs = tal_arr(rune, struct rune_restr *, 0);
|
||||
return rune;
|
||||
}
|
||||
|
||||
struct rune *rune_dup(const tal_t *ctx, const struct rune *rune TAKES)
|
||||
{
|
||||
struct rune *dup;
|
||||
|
||||
if (taken(rune))
|
||||
return tal_steal(ctx, (struct rune *)rune);
|
||||
|
||||
dup = tal_dup(ctx, struct rune, rune);
|
||||
dup->restrs = tal_arr(dup, struct rune_restr *, tal_count(rune->restrs));
|
||||
for (size_t i = 0; i < tal_count(rune->restrs); i++) {
|
||||
dup->restrs[i] = rune_restr_dup(dup->restrs,
|
||||
rune->restrs[i]);
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
|
||||
struct rune *rune_derive_start(const tal_t *ctx,
|
||||
const struct rune *master,
|
||||
const char *unique_id TAKES)
|
||||
{
|
||||
struct rune *rune = rune_dup(ctx, master);
|
||||
|
||||
/* If they provide a unique_id, it goes first. */
|
||||
if (unique_id) {
|
||||
if (taken(unique_id))
|
||||
rune->unique_id = tal_steal(rune, unique_id);
|
||||
else
|
||||
rune->unique_id = tal_strdup(rune, unique_id);
|
||||
|
||||
rune_add_restr(rune, take(unique_id_restr(NULL,
|
||||
rune->unique_id,
|
||||
rune->version)));
|
||||
} else {
|
||||
assert(!rune->version);
|
||||
}
|
||||
return rune;
|
||||
}
|
||||
|
||||
struct rune_altern *rune_altern_new(const tal_t *ctx,
|
||||
const char *fieldname TAKES,
|
||||
enum rune_condition condition,
|
||||
const char *value TAKES)
|
||||
{
|
||||
struct rune_altern *altern = tal(ctx, struct rune_altern);
|
||||
altern->condition = condition;
|
||||
altern->fieldname = tal_strdup(altern, fieldname);
|
||||
altern->value = tal_strdup(altern, value);
|
||||
return altern;
|
||||
}
|
||||
|
||||
struct rune_altern *rune_altern_dup(const tal_t *ctx,
|
||||
const struct rune_altern *altern TAKES)
|
||||
{
|
||||
struct rune_altern *dup;
|
||||
|
||||
if (taken(altern))
|
||||
return tal_steal(ctx, (struct rune_altern *)altern);
|
||||
dup = tal(ctx, struct rune_altern);
|
||||
dup->condition = altern->condition;
|
||||
dup->fieldname = tal_strdup(dup, altern->fieldname);
|
||||
dup->value = tal_strdup(dup, altern->value);
|
||||
return dup;
|
||||
}
|
||||
|
||||
struct rune_restr *rune_restr_dup(const tal_t *ctx,
|
||||
const struct rune_restr *restr TAKES)
|
||||
{
|
||||
struct rune_restr *dup;
|
||||
size_t num_altern;
|
||||
|
||||
if (taken(restr))
|
||||
return tal_steal(ctx, (struct rune_restr *)restr);
|
||||
|
||||
num_altern = tal_count(restr->alterns);
|
||||
dup = tal(ctx, struct rune_restr);
|
||||
dup->alterns = tal_arr(dup, struct rune_altern *, num_altern);
|
||||
for (size_t i = 0; i < num_altern; i++) {
|
||||
dup->alterns[i] = rune_altern_dup(dup->alterns,
|
||||
restr->alterns[i]);
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
|
||||
struct rune_restr *rune_restr_new(const tal_t *ctx)
|
||||
{
|
||||
struct rune_restr *restr = tal(ctx, struct rune_restr);
|
||||
restr->alterns = tal_arr(restr, struct rune_altern *, 0);
|
||||
return restr;
|
||||
}
|
||||
|
||||
void rune_restr_add_altern(struct rune_restr *restr,
|
||||
const struct rune_altern *alt TAKES)
|
||||
{
|
||||
size_t num = tal_count(restr->alterns);
|
||||
|
||||
tal_resize(&restr->alterns, num+1);
|
||||
restr->alterns[num] = rune_altern_dup(restr->alterns, alt);
|
||||
}
|
||||
|
||||
static bool is_unique_id(const struct rune_altern *alt)
|
||||
{
|
||||
return streq(alt->fieldname, "");
|
||||
}
|
||||
|
||||
/* Return unique_id if valid, and sets *version */
|
||||
static const char *extract_unique_id(const tal_t *ctx,
|
||||
const struct rune_altern *alt,
|
||||
const char **version)
|
||||
{
|
||||
size_t len;
|
||||
/* Condition must be '='! */
|
||||
if (alt->condition != '=')
|
||||
return NULL;
|
||||
|
||||
len = strcspn(alt->value, "-");
|
||||
if (alt->value[len])
|
||||
*version = tal_strdup(ctx, alt->value + len + 1);
|
||||
else
|
||||
*version = NULL;
|
||||
return tal_strndup(ctx, alt->value, len);
|
||||
}
|
||||
|
||||
bool rune_add_restr(struct rune *rune,
|
||||
const struct rune_restr *restr TAKES)
|
||||
{
|
||||
size_t num = tal_count(rune->restrs);
|
||||
|
||||
/* An empty fieldname is additional correctness checks */
|
||||
for (size_t i = 0; i < tal_count(restr->alterns); i++) {
|
||||
if (!is_unique_id(restr->alterns[i]))
|
||||
continue;
|
||||
|
||||
/* Must be the only alternative */
|
||||
if (tal_count(restr->alterns) != 1)
|
||||
goto fail;
|
||||
/* Must be the first restriction */
|
||||
if (num != 0)
|
||||
goto fail;
|
||||
|
||||
rune->unique_id = extract_unique_id(rune,
|
||||
restr->alterns[i],
|
||||
&rune->version);
|
||||
if (!rune->unique_id)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
tal_resize(&rune->restrs, num+1);
|
||||
rune->restrs[num] = rune_restr_dup(rune->restrs, restr);
|
||||
|
||||
rune_sha256_add_restr(&rune->shactx, rune->restrs[num]);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
if (taken(restr))
|
||||
tal_free(restr);
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char *rune_restr_test(const tal_t *ctx,
|
||||
const struct rune *rune,
|
||||
const struct rune_restr *restr,
|
||||
const char *(*check)(const tal_t *ctx,
|
||||
const struct rune *rune,
|
||||
const struct rune_altern *alt,
|
||||
void *arg),
|
||||
void *arg)
|
||||
{
|
||||
size_t num = tal_count(restr->alterns);
|
||||
const char **errs = tal_arr(NULL, const char *, num);
|
||||
char *err;
|
||||
|
||||
/* Only one alternative has to pass! */
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
errs[i] = check(errs, rune, restr->alterns[i], arg);
|
||||
if (!errs[i]) {
|
||||
tal_free(errs);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
err = tal_fmt(ctx, "%s", errs[0]);
|
||||
for (size_t i = 1; i < num; i++)
|
||||
tal_append_fmt(&err, " AND %s", errs[i]);
|
||||
tal_free(errs);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char *cond_test(const tal_t *ctx,
|
||||
const struct rune_altern *alt,
|
||||
const char *complaint,
|
||||
bool cond)
|
||||
{
|
||||
if (cond)
|
||||
return NULL;
|
||||
|
||||
return tal_fmt(ctx, "%s %s %s", alt->fieldname, complaint, alt->value);
|
||||
}
|
||||
|
||||
static const char *integer_compare_valid(const tal_t *ctx,
|
||||
const s64 *fieldval_int,
|
||||
const struct rune_altern *alt,
|
||||
s64 *runeval_int)
|
||||
{
|
||||
long l;
|
||||
char *p;
|
||||
|
||||
if (!fieldval_int)
|
||||
return tal_fmt(ctx, "%s is not an integer field",
|
||||
alt->fieldname);
|
||||
|
||||
errno = 0;
|
||||
l = strtol(alt->value, &p, 10);
|
||||
if (p == alt->value
|
||||
|| *p
|
||||
|| ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE))
|
||||
return tal_fmt(ctx, "%s is not a valid integer", alt->value);
|
||||
|
||||
*runeval_int = l;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int lexo_order(const char *fieldval_str,
|
||||
size_t fieldval_strlen,
|
||||
const char *alt)
|
||||
{
|
||||
int ret = strncmp(fieldval_str, alt, fieldval_strlen);
|
||||
|
||||
/* If alt is same but longer, fieldval is < */
|
||||
if (ret == 0 && strlen(alt) > fieldval_strlen)
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *rune_alt_single(const tal_t *ctx,
|
||||
const struct rune_altern *alt,
|
||||
const char *fieldval_str,
|
||||
size_t fieldval_strlen,
|
||||
const s64 *fieldval_int)
|
||||
{
|
||||
char strfield[STR_MAX_CHARS(s64) + 1];
|
||||
s64 runeval_int = 0 /* gcc v9.4.0 gets upset with uninitiaized var at -O3 */;
|
||||
const char *err;
|
||||
|
||||
/* Caller can't set both! */
|
||||
if (fieldval_int) {
|
||||
assert(!fieldval_str);
|
||||
sprintf(strfield, "%"PRIi64, *fieldval_int);
|
||||
fieldval_str = strfield;
|
||||
fieldval_strlen = strlen(strfield);
|
||||
}
|
||||
|
||||
switch (alt->condition) {
|
||||
case RUNE_COND_IF_MISSING:
|
||||
if (!fieldval_str)
|
||||
return NULL;
|
||||
return tal_fmt(ctx, "%s is present", alt->fieldname);
|
||||
case RUNE_COND_EQUAL:
|
||||
if (!fieldval_str)
|
||||
return tal_fmt(ctx, "%s not present", alt->fieldname);
|
||||
return cond_test(ctx, alt, "is not equal to",
|
||||
memeqstr(fieldval_str, fieldval_strlen, alt->value));
|
||||
case RUNE_COND_NOT_EQUAL:
|
||||
if (!fieldval_str)
|
||||
return tal_fmt(ctx, "%s not present", alt->fieldname);
|
||||
return cond_test(ctx, alt, "is equal to",
|
||||
!memeqstr(fieldval_str, fieldval_strlen, alt->value));
|
||||
case RUNE_COND_BEGINS:
|
||||
if (!fieldval_str)
|
||||
return tal_fmt(ctx, "%s not present", alt->fieldname);
|
||||
return cond_test(ctx, alt, "does not start with",
|
||||
memstarts_str(fieldval_str, fieldval_strlen, alt->value));
|
||||
case RUNE_COND_ENDS:
|
||||
if (!fieldval_str)
|
||||
return tal_fmt(ctx, "%s not present", alt->fieldname);
|
||||
return cond_test(ctx, alt, "does not end with",
|
||||
memends_str(fieldval_str, fieldval_strlen, alt->value));
|
||||
case RUNE_COND_CONTAINS:
|
||||
if (!fieldval_str)
|
||||
return tal_fmt(ctx, "%s not present", alt->fieldname);
|
||||
return cond_test(ctx, alt, "does not contain",
|
||||
memmem(fieldval_str, fieldval_strlen,
|
||||
alt->value, strlen(alt->value)));
|
||||
case RUNE_COND_INT_LESS:
|
||||
err = integer_compare_valid(ctx, fieldval_int,
|
||||
alt, &runeval_int);
|
||||
if (err)
|
||||
return err;
|
||||
return cond_test(ctx, alt, "is greater or equal to",
|
||||
*fieldval_int < runeval_int);
|
||||
case RUNE_COND_INT_GREATER:
|
||||
err = integer_compare_valid(ctx, fieldval_int,
|
||||
alt, &runeval_int);
|
||||
if (err)
|
||||
return err;
|
||||
return cond_test(ctx, alt, "is less or equal to",
|
||||
*fieldval_int > runeval_int);
|
||||
case RUNE_COND_LEXO_BEFORE:
|
||||
if (!fieldval_str)
|
||||
return tal_fmt(ctx, "%s not present", alt->fieldname);
|
||||
return cond_test(ctx, alt, "is equal to or ordered after",
|
||||
lexo_order(fieldval_str, fieldval_strlen, alt->value) < 0);
|
||||
case RUNE_COND_LEXO_AFTER:
|
||||
if (!fieldval_str)
|
||||
return tal_fmt(ctx, "%s not present", alt->fieldname);
|
||||
return cond_test(ctx, alt, "is equal to or ordered before",
|
||||
lexo_order(fieldval_str, fieldval_strlen, alt->value) > 0);
|
||||
case RUNE_COND_COMMENT:
|
||||
return NULL;
|
||||
}
|
||||
/* We should never create any other values! */
|
||||
abort();
|
||||
}
|
||||
|
||||
const char *rune_alt_single_str(const tal_t *ctx,
|
||||
const struct rune_altern *alt,
|
||||
const char *fieldval_str,
|
||||
size_t fieldval_strlen)
|
||||
{
|
||||
return rune_alt_single(ctx, alt, fieldval_str, fieldval_strlen, NULL);
|
||||
}
|
||||
|
||||
const char *rune_alt_single_int(const tal_t *ctx,
|
||||
const struct rune_altern *alt,
|
||||
s64 fieldval_int)
|
||||
{
|
||||
return rune_alt_single(ctx, alt, NULL, 0, &fieldval_int);
|
||||
}
|
||||
|
||||
const char *rune_alt_single_missing(const tal_t *ctx,
|
||||
const struct rune_altern *alt)
|
||||
{
|
||||
return rune_alt_single(ctx, alt, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
const char *rune_meets_criteria_(const tal_t *ctx,
|
||||
const struct rune *rune,
|
||||
const char *(*check)(const tal_t *ctx,
|
||||
const struct rune *rune,
|
||||
const struct rune_altern *alt,
|
||||
void *arg),
|
||||
void *arg)
|
||||
{
|
||||
for (size_t i = 0; i < tal_count(rune->restrs); i++) {
|
||||
const char *err;
|
||||
|
||||
/* Don't "check" unique id */
|
||||
if (i == 0 && is_unique_id(rune->restrs[i]->alterns[0]))
|
||||
continue;
|
||||
|
||||
err = rune_restr_test(ctx, rune, rune->restrs[i], check, arg);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *rune_test_(const tal_t *ctx,
|
||||
const struct rune *master,
|
||||
const struct rune *rune,
|
||||
const char *(*check)(const tal_t *ctx,
|
||||
const struct rune *rune,
|
||||
const struct rune_altern *alt,
|
||||
void *arg),
|
||||
void *arg)
|
||||
{
|
||||
const char *err;
|
||||
|
||||
err = rune_is_derived(master, rune);
|
||||
if (err)
|
||||
return err;
|
||||
return rune_meets_criteria_(ctx, rune, check, arg);
|
||||
}
|
||||
|
||||
bool rune_altern_eq(const struct rune_altern *alt1,
|
||||
const struct rune_altern *alt2)
|
||||
{
|
||||
return alt1->condition == alt2->condition
|
||||
&& streq(alt1->fieldname, alt2->fieldname)
|
||||
&& streq(alt1->value, alt2->value);
|
||||
}
|
||||
|
||||
bool rune_restr_eq(const struct rune_restr *rest1,
|
||||
const struct rune_restr *rest2)
|
||||
{
|
||||
if (tal_count(rest1->alterns) != tal_count(rest2->alterns))
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < tal_count(rest1->alterns); i++)
|
||||
if (!rune_altern_eq(rest1->alterns[i], rest2->alterns[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Equal, as in both NULL, or both non-NULL and matching */
|
||||
bool runestr_eq(const char *a, const char *b)
|
||||
{
|
||||
if (a) {
|
||||
if (!b)
|
||||
return false;
|
||||
return streq(a, b);
|
||||
} else
|
||||
return b == NULL;
|
||||
}
|
||||
|
||||
bool rune_eq(const struct rune *rune1, const struct rune *rune2)
|
||||
{
|
||||
if (!runestr_eq(rune1->unique_id, rune2->unique_id))
|
||||
return false;
|
||||
if (!runestr_eq(rune1->version, rune2->version))
|
||||
return false;
|
||||
|
||||
if (memcmp(rune1->shactx.s, rune2->shactx.s, sizeof(rune1->shactx.s)))
|
||||
return false;
|
||||
if (rune1->shactx.bytes != rune2->shactx.bytes)
|
||||
return false;
|
||||
if (memcmp(rune1->shactx.buf.u8, rune2->shactx.buf.u8,
|
||||
rune1->shactx.bytes % 64))
|
||||
return false;
|
||||
|
||||
if (tal_count(rune1->restrs) != tal_count(rune2->restrs))
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < tal_count(rune1->restrs); i++)
|
||||
if (!rune_restr_eq(rune1->restrs[i], rune2->restrs[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
379
ccan/ccan/rune/rune.h
Normal file
379
ccan/ccan/rune/rune.h
Normal file
|
@ -0,0 +1,379 @@
|
|||
/* MIT (BSD) license - see LICENSE file for details */
|
||||
#ifndef CCAN_RUNE_RUNE_H
|
||||
#define CCAN_RUNE_RUNE_H
|
||||
#include <ccan/crypto/sha256/sha256.h>
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
|
||||
/* A rune is a series of restrictions. */
|
||||
struct rune {
|
||||
/* unique_id (if any) */
|
||||
const char *unique_id;
|
||||
/* Version (if any) */
|
||||
const char *version;
|
||||
|
||||
/* SHA-2 256 of restrictions so far. */
|
||||
struct sha256_ctx shactx;
|
||||
/* Length given by tal_count() */
|
||||
struct rune_restr **restrs;
|
||||
};
|
||||
|
||||
/* A restriction is one or more alternatives (altern) */
|
||||
struct rune_restr {
|
||||
/* Length given by tal_count() */
|
||||
struct rune_altern **alterns;
|
||||
};
|
||||
|
||||
enum rune_condition {
|
||||
RUNE_COND_IF_MISSING = '!',
|
||||
RUNE_COND_EQUAL = '=',
|
||||
RUNE_COND_NOT_EQUAL = '/',
|
||||
RUNE_COND_BEGINS = '^',
|
||||
RUNE_COND_ENDS = '$',
|
||||
RUNE_COND_CONTAINS = '~',
|
||||
RUNE_COND_INT_LESS = '<',
|
||||
RUNE_COND_INT_GREATER = '>',
|
||||
RUNE_COND_LEXO_BEFORE = '{',
|
||||
RUNE_COND_LEXO_AFTER = '}',
|
||||
RUNE_COND_COMMENT = '#',
|
||||
};
|
||||
|
||||
/* An alternative is a utf-8 fieldname, a condition, and a value */
|
||||
struct rune_altern {
|
||||
enum rune_condition condition;
|
||||
/* Strings. */
|
||||
const char *fieldname, *value;
|
||||
};
|
||||
|
||||
/**
|
||||
* rune_new - Create an unrestricted rune from this secret.
|
||||
* @ctx: tal context, or NULL. Freeing @ctx will free the returned rune.
|
||||
* @secret: secret bytes.
|
||||
* @secret_len: number of @secret bytes (must be 55 bytes or less)
|
||||
* @version: if non-NULL, sets a version for this rune.
|
||||
*
|
||||
* This allocates a new, unrestricted rune (sometimes called a master rune).
|
||||
*
|
||||
* Setting a version allows for different interpretations of a rune if
|
||||
* things change in future, at cost of some space when it's used.
|
||||
*
|
||||
* Example:
|
||||
* u8 secret[16];
|
||||
* struct rune *master;
|
||||
*
|
||||
* // A secret determined with a fair die roll!
|
||||
* memset(secret, 5, sizeof(secret));
|
||||
* master = rune_new(NULL, secret, sizeof(secret), NULL);
|
||||
* assert(master);
|
||||
*/
|
||||
struct rune *rune_new(const tal_t *ctx, const u8 *secret, size_t secret_len,
|
||||
const char *version);
|
||||
|
||||
/**
|
||||
* rune_derive_start - Copy master rune, add a unique id.
|
||||
* @ctx: context to allocate rune off
|
||||
* @master: master rune.
|
||||
* @unique_id: unique id; can be NULL, but that's not recommended.
|
||||
*
|
||||
* It's usually recommended to assign each rune a unique_id, so that
|
||||
* specific runes can be blacklisted later (otherwise you need to disable
|
||||
* all runes). This enlarges the rune string by '=<unique_id>' however.
|
||||
*
|
||||
* The rune version will be the same as the master: if that's non-zero,
|
||||
* you *must* set unique_id.
|
||||
*
|
||||
* @unique_id cannot contain '-'.
|
||||
*
|
||||
* Example:
|
||||
* struct rune *rune;
|
||||
* // In reality, some global incrementing variable.
|
||||
* const char *id = "1";
|
||||
* rune = rune_derive_start(NULL, master, id);
|
||||
* assert(rune);
|
||||
*/
|
||||
struct rune *rune_derive_start(const tal_t *ctx,
|
||||
const struct rune *master,
|
||||
const char *unique_id);
|
||||
|
||||
/**
|
||||
* rune_dup - Copy a rune.
|
||||
* @ctx: tal context, or NULL.
|
||||
* @altern: the altern to copy.
|
||||
*
|
||||
* If @altern is take(), then simply returns it, otherwise copies.
|
||||
*/
|
||||
struct rune *rune_dup(const tal_t *ctx, const struct rune *rune TAKES);
|
||||
|
||||
/**
|
||||
* rune_altern_new - Create a new alternative.
|
||||
* @ctx: tal context, or NULL. Freeing @ctx will free the returned altern.
|
||||
* @fieldname: the UTF-8 field for the altern. You can only have
|
||||
* alphanumerics, '.', '-' and '_' here.
|
||||
* @condition: the condition, defined above.
|
||||
* @value: the value for comparison; use "" if you don't care. Any UTF-8 value
|
||||
* is allowed.
|
||||
*
|
||||
* An altern is the basis of rune restrictions (technically, a restriction
|
||||
* is one or more alterns, but it's often just one).
|
||||
*
|
||||
* Example:
|
||||
* struct rune_altern *a1, *a2;
|
||||
* a1 = rune_altern_new(NULL, "val", RUNE_COND_EQUAL, "7");
|
||||
* a2 = rune_altern_new(NULL, "val2", '>', "-1");
|
||||
* assert(a1 && a2);
|
||||
*/
|
||||
struct rune_altern *rune_altern_new(const tal_t *ctx,
|
||||
const char *fieldname TAKES,
|
||||
enum rune_condition condition,
|
||||
const char *value TAKES);
|
||||
|
||||
/**
|
||||
* rune_altern_dup - copy an alternative.
|
||||
* @ctx: tal context, or NULL.
|
||||
* @altern: the altern to copy.
|
||||
*
|
||||
* If @altern is take(), then simply returns it, otherwise copies.
|
||||
*/
|
||||
struct rune_altern *rune_altern_dup(const tal_t *ctx,
|
||||
const struct rune_altern *altern TAKES);
|
||||
|
||||
/**
|
||||
* rune_restr_new - Create a new (empty) restriction.
|
||||
* @ctx: tal context, or NULL. Freeing @ctx will free the returned restriction.
|
||||
*
|
||||
* Example:
|
||||
* struct rune_restr *restr = rune_restr_new(NULL);
|
||||
* assert(restr);
|
||||
*/
|
||||
struct rune_restr *rune_restr_new(const tal_t *ctx);
|
||||
|
||||
/**
|
||||
* rune_restr_dup - copy a restr.
|
||||
* @ctx: tal context, or NULL.
|
||||
* @restr: the restr to copy.
|
||||
*
|
||||
* If @resttr is take(), then simply returns it, otherwise copies.
|
||||
*/
|
||||
struct rune_restr *rune_restr_dup(const tal_t *ctx,
|
||||
const struct rune_restr *restr TAKES);
|
||||
|
||||
/**
|
||||
* rune_restr_add_altern - add an altern to this restriction
|
||||
* @restr: the restriction to add to
|
||||
* @alt: the altern.
|
||||
*
|
||||
* If the alt is take(alt) then the alt will be owned by the restriction,
|
||||
* otherwise it's copied.
|
||||
*
|
||||
* Example:
|
||||
* rune_restr_add_altern(restr, take(a1));
|
||||
* rune_restr_add_altern(restr, take(a2));
|
||||
*/
|
||||
void rune_restr_add_altern(struct rune_restr *restr,
|
||||
const struct rune_altern *alt TAKES);
|
||||
|
||||
/**
|
||||
* rune_add_restr - add a restriction to this rune
|
||||
* @rune: the rune to add to.
|
||||
* @restr: the (non-empty) restriction.
|
||||
*
|
||||
* If the alt is take(alt) then the alt will be owned by the restr,
|
||||
* otherwise it's copied (and all its children are copied!).
|
||||
*
|
||||
* This fails (and returns false) if restr tries to set unique_id/version
|
||||
* and is not the first restriction, or has more than one alternative,
|
||||
* or uses a non '=' condition.
|
||||
*
|
||||
* Example:
|
||||
* rune_add_restr(rune, take(restr));
|
||||
*/
|
||||
bool rune_add_restr(struct rune *rune,
|
||||
const struct rune_restr *restr TAKES);
|
||||
|
||||
/**
|
||||
* rune_altern_eq - are two rune_altern equivalent?
|
||||
* @alt1: the first
|
||||
* @alt2: the second
|
||||
*/
|
||||
bool rune_altern_eq(const struct rune_altern *alt1,
|
||||
const struct rune_altern *alt2);
|
||||
|
||||
/**
|
||||
* rune_restr_eq - are two rune_restr equivalent?
|
||||
* @rest1: the first
|
||||
* @rest2: the second
|
||||
*/
|
||||
bool rune_restr_eq(const struct rune_restr *rest1,
|
||||
const struct rune_restr *rest2);
|
||||
|
||||
/**
|
||||
* rune_eq - are two runes equivalent?
|
||||
* @rest1: the first
|
||||
* @rest2: the second
|
||||
*/
|
||||
bool rune_eq(const struct rune *rune1, const struct rune *rune2);
|
||||
|
||||
/**
|
||||
* rune_alt_single_str - helper to implement check().
|
||||
* @ctx: context to allocate any error return from.
|
||||
* @alt: alternative to test.
|
||||
* @fieldval_str: field value as a string.
|
||||
* @fieldval_strlen: length of @fieldval_str
|
||||
*/
|
||||
const char *rune_alt_single_str(const tal_t *ctx,
|
||||
const struct rune_altern *alt,
|
||||
const char *fieldval_str,
|
||||
size_t fieldval_strlen);
|
||||
|
||||
/**
|
||||
* rune_alt_single_int - helper to implement check().
|
||||
* @ctx: context to allocate any error return from.
|
||||
* @alt: alternative to test.
|
||||
* @fieldval_int: field value as an integer.
|
||||
*/
|
||||
const char *rune_alt_single_int(const tal_t *ctx,
|
||||
const struct rune_altern *alt,
|
||||
s64 fieldval_int);
|
||||
|
||||
/**
|
||||
* rune_alt_single_missing - helper to implement check().
|
||||
* @ctx: context to allocate any error return from.
|
||||
* @alt: alternative to test.
|
||||
*
|
||||
* Use this if alt->fieldname is unknown (it could still pass, if
|
||||
* the test is that the fieldname is missing).
|
||||
*/
|
||||
const char *rune_alt_single_missing(const tal_t *ctx,
|
||||
const struct rune_altern *alt);
|
||||
|
||||
|
||||
/**
|
||||
* rune_is_derived - is a rune derived from this other rune?
|
||||
* @source: the base rune (usually the master rune)
|
||||
* @rune: the rune to check.
|
||||
*
|
||||
* This is the first part of "is this rune valid?": does the cryptography
|
||||
* check out, such that they validly made the rune from this source rune?
|
||||
*
|
||||
* It also checks that the versions match: if you want to allow more than
|
||||
* one version, see rune_is_derived_anyversion.
|
||||
*/
|
||||
const char *rune_is_derived(const struct rune *source, const struct rune *rune);
|
||||
|
||||
/**
|
||||
* rune_is_derived_anyversion - is a rune derived from this other rune?
|
||||
* @source: the base rune (usually the master rune)
|
||||
* @rune: the rune to check.
|
||||
*
|
||||
* This does not check source->version against rune->version: if you issue
|
||||
* different rune versions you will need to check that yourself.
|
||||
*/
|
||||
const char *rune_is_derived_anyversion(const struct rune *source,
|
||||
const struct rune *rune);
|
||||
|
||||
/**
|
||||
* rune_meets_criteria - do we meet the criteria specified by the rune?
|
||||
* @ctx: the tal context to allocate the returned error off.
|
||||
* @rune: the rune to check.
|
||||
* @check: the callback to check values
|
||||
* @arg: data to hand to @check
|
||||
*
|
||||
* This is the second part of "is this rune valid?".
|
||||
*/
|
||||
const char *rune_meets_criteria_(const tal_t *ctx,
|
||||
const struct rune *rune,
|
||||
const char *(*check)(const tal_t *ctx,
|
||||
const struct rune *rune,
|
||||
const struct rune_altern *alt,
|
||||
void *arg),
|
||||
void *arg);
|
||||
|
||||
/* Typesafe wrapper */
|
||||
#define rune_meets_criteria(ctx, rune, check, arg) \
|
||||
rune_meets_criteria_(typesafe_cb_preargs(const char *, void *, \
|
||||
(ctx), (rune), \
|
||||
(check), (arg), \
|
||||
const tal_t *, \
|
||||
const struct rune *, \
|
||||
const struct rune_altern *), \
|
||||
(arg))
|
||||
|
||||
/**
|
||||
* rune_test - is a rune authorized?
|
||||
* @ctx: the tal context to allocate @errstr off.
|
||||
* @master: the master rune created from secret.
|
||||
* @rune: the rune to check.
|
||||
* @errstr: if non-NULL, descriptive string of failure.
|
||||
* @get: the callback to get values
|
||||
* @arg: data to hand to callback
|
||||
*
|
||||
* Simple call for rune_is_derived() and rune_meets_criteria(). If
|
||||
* it's not OK, returns non-NULL.
|
||||
*/
|
||||
const char *rune_test_(const tal_t *ctx,
|
||||
const struct rune *master,
|
||||
const struct rune *rune,
|
||||
const char *(*check)(const tal_t *ctx,
|
||||
const struct rune *rune,
|
||||
const struct rune_altern *alt,
|
||||
void *arg),
|
||||
void *arg);
|
||||
|
||||
/* Typesafe wrapper */
|
||||
#define rune_test(ctx_, master_, rune_, check_, arg_) \
|
||||
rune_test_((ctx_), (master_), (rune_), \
|
||||
typesafe_cb_preargs(const char *, void *, \
|
||||
(check_), (arg_), \
|
||||
const tal_t *, \
|
||||
const struct rune *, \
|
||||
const struct rune_altern *), \
|
||||
(arg_))
|
||||
|
||||
|
||||
/**
|
||||
* rune_from_base64 - convert base64 string to rune.
|
||||
* @ctx: context to allocate rune off.
|
||||
* @str: base64 string.
|
||||
*
|
||||
* Returns NULL if it's malformed.
|
||||
*/
|
||||
struct rune *rune_from_base64(const tal_t *ctx, const char *str);
|
||||
|
||||
/**
|
||||
* rune_from_base64n - convert base64 string to rune.
|
||||
* @ctx: context to allocate rune off.
|
||||
* @str: base64 string.
|
||||
* @len: length of @str.
|
||||
*
|
||||
* Returns NULL if it's malformed.
|
||||
*/
|
||||
struct rune *rune_from_base64n(const tal_t *ctx, const char *str, size_t len);
|
||||
|
||||
/**
|
||||
* rune_to_base64 - convert run to base64 string.
|
||||
* @ctx: context to allocate rune off.
|
||||
* @rune: the rune.
|
||||
*
|
||||
* Only returns NULL if you've allowed tal allocations to return NULL.
|
||||
*/
|
||||
char *rune_to_base64(const tal_t *ctx, const struct rune *rune);
|
||||
|
||||
/**
|
||||
* This is a much more convenient working form.
|
||||
*/
|
||||
struct rune *rune_from_string(const tal_t *ctx, const char *str);
|
||||
char *rune_to_string(const tal_t *ctx, const struct rune *rune);
|
||||
|
||||
/**
|
||||
* rune_restr_from_string - convenience routine to parse a single restriction.
|
||||
* @ctx: context to allocate rune off.
|
||||
* @str: the string of form "<field><cond><val>[|<field><cond><val>]*"
|
||||
* @len: the length of @str.
|
||||
*
|
||||
* This is useful for writing simple tests and making simple runes.
|
||||
*/
|
||||
struct rune_restr *rune_restr_from_string(const tal_t *ctx,
|
||||
const char *str,
|
||||
size_t len);
|
||||
#endif /* CCAN_RUNE_RUNE_H */
|
33
ccan/ccan/rune/test/run-alt-lexicographic-order.c
Normal file
33
ccan/ccan/rune/test/run-alt-lexicographic-order.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include <ccan/rune/rune.c>
|
||||
#include <ccan/rune/coding.c>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <ccan/tap/tap.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const char *str = "test string";
|
||||
plan_tests(strlen(str) * strlen(str));
|
||||
|
||||
for (size_t i = 0; str[i]; i++) {
|
||||
char *stra = strdup(str);
|
||||
stra[i] = '\0';
|
||||
for (size_t j = 0; str[j]; j++) {
|
||||
char *strb = strdup(str);
|
||||
strb[j] = '\0';
|
||||
int lexo, strc;
|
||||
|
||||
lexo = lexo_order(str, i, strb);
|
||||
strc = strcmp(stra, strb);
|
||||
if (strc > 0)
|
||||
ok1(lexo > 0);
|
||||
else if (strc < 0)
|
||||
ok1(lexo < 0);
|
||||
else
|
||||
ok1(lexo == 0);
|
||||
free(strb);
|
||||
}
|
||||
free(stra);
|
||||
}
|
||||
/* This exits depending on whether all tests passed */
|
||||
return exit_status();
|
||||
}
|
127
ccan/ccan/rune/test/run.c
Normal file
127
ccan/ccan/rune/test/run.c
Normal file
|
@ -0,0 +1,127 @@
|
|||
#include <ccan/rune/rune.c>
|
||||
#include <ccan/rune/coding.c>
|
||||
#include <ccan/tal/grab_file/grab_file.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <ccan/tap/tap.h>
|
||||
|
||||
static const char *check(const tal_t *ctx,
|
||||
const struct rune *rune,
|
||||
const struct rune_altern *alt,
|
||||
char **parts)
|
||||
{
|
||||
const char *val = NULL;
|
||||
|
||||
for (size_t i = 1; parts[i]; i++) {
|
||||
if (strstarts(parts[i], alt->fieldname)
|
||||
&& parts[i][strlen(alt->fieldname)] == '=')
|
||||
val = parts[i] + strlen(alt->fieldname) + 1;
|
||||
}
|
||||
|
||||
/* If it's an integer, hand it like that */
|
||||
if (val) {
|
||||
char *endp;
|
||||
s64 v = strtol(val, &endp, 10);
|
||||
if (*endp == '\0' && endp != val)
|
||||
return rune_alt_single_int(ctx, alt, v);
|
||||
return rune_alt_single_str(ctx, alt, val, strlen(val));
|
||||
}
|
||||
return rune_alt_single_missing(ctx, alt);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char *vecs;
|
||||
char **lines;
|
||||
static const u8 secret_zero[16];
|
||||
struct rune *mr;
|
||||
|
||||
/* Test vector rune uses all-zero secret */
|
||||
mr = rune_new(NULL, secret_zero, sizeof(secret_zero), NULL);
|
||||
|
||||
/* Python runes library generates test vectors */
|
||||
vecs = grab_file(mr, "test/test_vectors.csv");
|
||||
assert(vecs);
|
||||
lines = tal_strsplit(mr, take(vecs), "\n", STR_NO_EMPTY);
|
||||
|
||||
plan_tests(343);
|
||||
|
||||
for (size_t i = 0; lines[i]; i++) {
|
||||
struct rune *rune1, *rune2;
|
||||
char **parts;
|
||||
|
||||
parts = tal_strsplit(lines, lines[i], ",", STR_EMPTY_OK);
|
||||
if (streq(parts[0], "VALID")) {
|
||||
diag("test %s %s", parts[0], parts[1]);
|
||||
rune1 = rune_from_string(parts, parts[2]);
|
||||
ok1(rune1);
|
||||
rune2 = rune_from_base64(parts, parts[3]);
|
||||
ok1(rune2);
|
||||
ok1(rune_eq(rune1, rune2));
|
||||
ok1(streq(rune_to_string(parts, rune2), parts[2]));
|
||||
ok1(streq(rune_to_base64(parts, rune1), parts[3]));
|
||||
ok1(rune_is_derived_anyversion(mr, rune1) == NULL);
|
||||
ok1(rune_is_derived_anyversion(mr, rune2) == NULL);
|
||||
|
||||
if (parts[4]) {
|
||||
if (parts[5])
|
||||
ok1(streq(rune1->version, parts[5]));
|
||||
ok1(streq(rune1->unique_id, parts[4]));
|
||||
} else {
|
||||
ok1(!rune1->version);
|
||||
ok1(!rune1->unique_id);
|
||||
}
|
||||
mr->version = NULL;
|
||||
} else if (streq(parts[0], "DERIVE")) {
|
||||
struct rune_restr *restr;
|
||||
diag("test %s %s", parts[0], parts[1]);
|
||||
rune1 = rune_from_base64(parts, parts[2]);
|
||||
ok1(rune1);
|
||||
rune2 = rune_from_base64(parts, parts[3]);
|
||||
ok1(rune2);
|
||||
ok1(rune_is_derived_anyversion(mr, rune1) == NULL);
|
||||
ok1(rune_is_derived_anyversion(mr, rune2) == NULL);
|
||||
ok1(rune_is_derived_anyversion(rune1, rune2) == NULL);
|
||||
|
||||
restr = rune_restr_new(NULL);
|
||||
for (size_t i = 4; parts[i]; i+=3) {
|
||||
struct rune_altern *alt;
|
||||
alt = rune_altern_new(NULL,
|
||||
parts[i],
|
||||
parts[i+1][0],
|
||||
parts[i+2]);
|
||||
rune_restr_add_altern(restr, take(alt));
|
||||
}
|
||||
rune_add_restr(rune1, take(restr));
|
||||
ok1(rune_eq(rune1, rune2));
|
||||
} else if (streq(parts[0], "MALFORMED")) {
|
||||
diag("test %s %s", parts[0], parts[1]);
|
||||
rune1 = rune_from_string(parts, parts[2]);
|
||||
ok1(!rune1);
|
||||
rune2 = rune_from_base64(parts, parts[3]);
|
||||
ok1(!rune2);
|
||||
} else if (streq(parts[0], "BAD DERIVATION")) {
|
||||
diag("test %s %s", parts[0], parts[1]);
|
||||
rune1 = rune_from_string(parts, parts[2]);
|
||||
ok1(rune1);
|
||||
rune2 = rune_from_base64(parts, parts[3]);
|
||||
ok1(rune2);
|
||||
ok1(rune_eq(rune1, rune2));
|
||||
ok1(rune_is_derived(mr, rune1) != NULL);
|
||||
ok1(rune_is_derived(mr, rune2) != NULL);
|
||||
} else {
|
||||
const char *err;
|
||||
diag("test %s", parts[0]);
|
||||
err = rune_test(parts, mr, rune1, check, parts);
|
||||
if (streq(parts[0], "PASS")) {
|
||||
ok1(!err);
|
||||
} else {
|
||||
assert(streq(parts[0], "FAIL"));
|
||||
ok1(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tal_free(mr);
|
||||
/* This exits depending on whether all tests passed */
|
||||
return exit_status();
|
||||
}
|
151
ccan/ccan/rune/test/test_vectors.csv
Normal file
151
ccan/ccan/rune/test/test_vectors.csv
Normal file
|
@ -0,0 +1,151 @@
|
|||
VALID,empty rune (secret = [0]*16),374708fff7719dd5979ec875d56cd2286f6d3cf7ec317a3b25632aab28ec37bb:,N0cI__dxndWXnsh11WzSKG9tPPfsMXo7JWMqqyjsN7s=
|
||||
PASS
|
||||
PASS,f1=1
|
||||
PASS,f1=var
|
||||
PASS,f1=\|\&\\
|
||||
VALID,unique id 1,6035731a2cbb022cbeb67645aa0f8a26653d8cc454e0e087d4d19d282b8da4bd:=1,YDVzGiy7Aiy-tnZFqg-KJmU9jMRU4OCH1NGdKCuNpL09MQ==,1
|
||||
VALID,unique id 2 version 1,4520773407c9658646326fdffe685ffbc3c8639a080dae4310b371830a205cf1:=2-1,RSB3NAfJZYZGMm_f_mhf-8PIY5oIDa5DELNxgwogXPE9Mi0x,2,1
|
||||
VALID,f1 is missing,64a926b7185d7cf98e10a07dfc4e83d2a826896ebdb112ac964566fa2d50b464:f1!,ZKkmtxhdfPmOEKB9_E6D0qgmiW69sRKslkVm-i1QtGRmMSE=
|
||||
PASS
|
||||
PASS,f2=f1
|
||||
FAIL,f1=1
|
||||
FAIL,f1=var
|
||||
VALID,f1 equals v1,745c6e39cd41ee9f8388af8ad882bae4ee4e8f6b373f7682cc64d8574551fa5f:f1=v1,dFxuOc1B7p-DiK-K2IK65O5Oj2s3P3aCzGTYV0VR-l9mMT12MQ==
|
||||
PASS,f1=v1
|
||||
FAIL,f1=v
|
||||
FAIL,f1=v1a
|
||||
FAIL
|
||||
FAIL,f2=f1
|
||||
VALID,f1 not equal v1,c9236a6532bfa8e24bec9a66e96af3fb355f817770e79c5a81f6dd0b5ed20e47:f1/v1,ySNqZTK_qOJL7Jpm6Wrz-zVfgXdw55xagfbdC17SDkdmMS92MQ==
|
||||
PASS,f1=v2
|
||||
PASS,f1=v
|
||||
PASS,f1=v1a
|
||||
FAIL
|
||||
FAIL,f2=v1
|
||||
VALID,f1 ends with v1,71f2a1ec9631efc75b01db15fe1f025327ab467f8a83e6bfa7506da222adc5a2:f1$v1,cfKh7JYx78dbAdsV_h8CUyerRn-Kg-a_p1BtoiKtxaJmMSR2MQ==
|
||||
PASS,f1=v1
|
||||
PASS,f1=2v1
|
||||
FAIL,f1=v1a
|
||||
FAIL
|
||||
VALID,f1 starts with v1,5b13dffbbd9f7b191b0557595d10b22c0acec0c567f8efeba1d7d047927d7bce:f1^v1,WxPf-72fexkbBVdZXRCyLArOwMVn-O_rodfQR5J9e85mMV52MQ==
|
||||
PASS,f1=v1
|
||||
PASS,f1=v1a
|
||||
FAIL,f1=2v1
|
||||
FAIL
|
||||
VALID,f1 contains v1,ccbe593b72e0ab29446e46796ccd0c775ecd7a327fcc9ddc00fd3910cdacca00:f1~v1,zL5ZO3LgqylEbkZ5bM0Md17NejJ_zJ3cAP05EM2sygBmMX52MQ==
|
||||
PASS,f1=v1
|
||||
PASS,f1=v1a
|
||||
PASS,f1=2v1
|
||||
PASS,f1=2v12
|
||||
FAIL,f1=1v2
|
||||
FAIL
|
||||
VALID,f1 less than v1,caff52cedb9241dc00aea7cefc2b89b0a7445b1a4e34c48a5a2b91d2fe76d31f:f1<v1,yv9SztuSQdwArqfO_CuJsKdEWxpONMSKWiuR0v520x9mMTx2MQ==
|
||||
FAIL,f1=1
|
||||
FAIL,f1=2
|
||||
FAIL,f1=v1
|
||||
FAIL
|
||||
VALID,f1 less than 1,f9776db54fb54c8dd6af20a65a0f210a752a0ee4d1b0a0e7fd9d7ef65af76f84:f1<1,-XdttU-1TI3WryCmWg8hCnUqDuTRsKDn_Z1-9lr3b4RmMTwx
|
||||
PASS,f1=0
|
||||
PASS,f1=-10000
|
||||
FAIL,f1=1
|
||||
FAIL,f1=10000
|
||||
FAIL,f1=v1
|
||||
FAIL
|
||||
VALID,f1 greater than v1,2135748f1956d9dfa3c5b09ab6af9d6bb06a41c5bcf93d3f8105cb278af5ac56:f1>v1,ITV0jxlW2d-jxbCatq-da7BqQcW8-T0_gQXLJ4r1rFZmMT52MQ==
|
||||
FAIL,f1=1
|
||||
FAIL,f1=2
|
||||
FAIL,f1=v1
|
||||
FAIL
|
||||
VALID,f1 greater than 1,84e9991dd941bac97cc681eefec5dd7ac3668a4490ca6b0f19f0e79d2bb9c746:f1>1,hOmZHdlBusl8xoHu_sXdesNmikSQymsPGfDnnSu5x0ZmMT4x
|
||||
PASS,f1=2
|
||||
PASS,f1=10000
|
||||
FAIL,f1=1
|
||||
FAIL,f1=-10000
|
||||
FAIL,f1=0
|
||||
FAIL,f1=v1
|
||||
FAIL
|
||||
VALID,f1 sorts before 11,b9653ad0dcad7e5ed183f98cdd7e616acd07a98cc66a107a67626290bf000236:f1{11,uWU60Nytfl7Rg_mM3X5has0HqYzGahB6Z2JikL8AAjZmMXsxMQ==
|
||||
PASS,f1=0
|
||||
PASS,f1=1
|
||||
PASS,f1=
|
||||
PASS,f1=/
|
||||
FAIL,f1=11
|
||||
FAIL,f1=111
|
||||
FAIL,f1=v1
|
||||
FAIL,f1=:
|
||||
FAIL
|
||||
VALID,f1 sorts after 11,8c1f6c7c39badc5dea850192a0a4c6e9dd96bf33d410adc5a08fc375b22a1a52:f1}11,jB9sfDm63F3qhQGSoKTG6d2WvzPUEK3FoI_DdbIqGlJmMX0xMQ==
|
||||
PASS,f1=111
|
||||
PASS,f1=v1
|
||||
PASS,f1=:
|
||||
FAIL,f1=0
|
||||
FAIL,f1=1
|
||||
FAIL,f1=
|
||||
FAIL,f1=/
|
||||
FAIL,f1=11
|
||||
FAIL
|
||||
VALID,f1 comment 11,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1#11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMSMxMQ==
|
||||
PASS,f1=111
|
||||
PASS,f1=v1
|
||||
PASS,f1=:
|
||||
PASS,f1=0
|
||||
PASS,f1=1
|
||||
PASS,f1=
|
||||
PASS,f1=/
|
||||
PASS,f1=11
|
||||
PASS
|
||||
VALID,f1=1 or f2=3,85c3643dc102f0a0d6f20eeb8c294092151688fae41ef7c8ec7272ab23918376:f1=1|f2=3,hcNkPcEC8KDW8g7rjClAkhUWiPrkHvfI7HJyqyORg3ZmMT0xfGYyPTM=
|
||||
PASS,f1=1
|
||||
PASS,f1=1,f2=2
|
||||
PASS,f2=3
|
||||
PASS,f1=var,f2=3
|
||||
PASS,f1=1,f2=3
|
||||
FAIL
|
||||
FAIL,f1=2
|
||||
FAIL,f1=f1
|
||||
FAIL,f2=1
|
||||
FAIL,f2=f1
|
||||
DERIVE,unique_id 1 derivation,N0cI__dxndWXnsh11WzSKG9tPPfsMXo7JWMqqyjsN7s=,YDVzGiy7Aiy-tnZFqg-KJmU9jMRU4OCH1NGdKCuNpL09MQ==,,=,1
|
||||
DERIVE,unique_id 2 version 1 derivation,N0cI__dxndWXnsh11WzSKG9tPPfsMXo7JWMqqyjsN7s=,RSB3NAfJZYZGMm_f_mhf-8PIY5oIDa5DELNxgwogXPE9Mi0x,,=,2-1
|
||||
DERIVE,f1=1 or f2=3,N0cI__dxndWXnsh11WzSKG9tPPfsMXo7JWMqqyjsN7s=,hcNkPcEC8KDW8g7rjClAkhUWiPrkHvfI7HJyqyORg3ZmMT0xfGYyPTM=,f1,=,1,f2,=,3
|
||||
DERIVE,AND f3 contains &|\,hcNkPcEC8KDW8g7rjClAkhUWiPrkHvfI7HJyqyORg3ZmMT0xfGYyPTM=,S253BW1Lragb1CpCSLXYGt9AdrE4iFMlXmnO0alV5vlmMT0xfGYyPTMmZjN-XCZcfFxc,f3,~,&|\
|
||||
PASS,f1=1,f3=&|\
|
||||
PASS,f2=3,f3=&|\x
|
||||
FAIL
|
||||
FAIL,f1=1
|
||||
FAIL,f2=3
|
||||
FAIL,f1=1,f2=3
|
||||
FAIL,f1=2,f3=&|\
|
||||
FAIL,f2=2,f3=&|\
|
||||
FAIL,f3=&|\
|
||||
MALFORMED,unique id must use = not !,6035731a2cbb022cbeb67645aa0f8a26653d8cc454e0e087d4d19d282b8da4bd:!1,YDVzGiy7Aiy-tnZFqg-KJmU9jMRU4OCH1NGdKCuNpL0hMQ==
|
||||
MALFORMED,unique id must use = not /,6035731a2cbb022cbeb67645aa0f8a26653d8cc454e0e087d4d19d282b8da4bd:/1,YDVzGiy7Aiy-tnZFqg-KJmU9jMRU4OCH1NGdKCuNpL0vMQ==
|
||||
MALFORMED,unique id must use = not ^,6035731a2cbb022cbeb67645aa0f8a26653d8cc454e0e087d4d19d282b8da4bd:^1,YDVzGiy7Aiy-tnZFqg-KJmU9jMRU4OCH1NGdKCuNpL1eMQ==
|
||||
MALFORMED,unique id must use = not $,6035731a2cbb022cbeb67645aa0f8a26653d8cc454e0e087d4d19d282b8da4bd:$1,YDVzGiy7Aiy-tnZFqg-KJmU9jMRU4OCH1NGdKCuNpL0kMQ==
|
||||
MALFORMED,unique id must use = not ~,6035731a2cbb022cbeb67645aa0f8a26653d8cc454e0e087d4d19d282b8da4bd:~1,YDVzGiy7Aiy-tnZFqg-KJmU9jMRU4OCH1NGdKCuNpL1-MQ==
|
||||
MALFORMED,unique id must use = not <,6035731a2cbb022cbeb67645aa0f8a26653d8cc454e0e087d4d19d282b8da4bd:<1,YDVzGiy7Aiy-tnZFqg-KJmU9jMRU4OCH1NGdKCuNpL08MQ==
|
||||
MALFORMED,unique id must use = not >,6035731a2cbb022cbeb67645aa0f8a26653d8cc454e0e087d4d19d282b8da4bd:>1,YDVzGiy7Aiy-tnZFqg-KJmU9jMRU4OCH1NGdKCuNpL0-MQ==
|
||||
MALFORMED,unique id must use = not },6035731a2cbb022cbeb67645aa0f8a26653d8cc454e0e087d4d19d282b8da4bd:}1,YDVzGiy7Aiy-tnZFqg-KJmU9jMRU4OCH1NGdKCuNpL19MQ==
|
||||
MALFORMED,unique id must use = not {,6035731a2cbb022cbeb67645aa0f8a26653d8cc454e0e087d4d19d282b8da4bd:{1,YDVzGiy7Aiy-tnZFqg-KJmU9jMRU4OCH1NGdKCuNpL17MQ==
|
||||
MALFORMED,unique id cannot be overridden,7a63a2966d38e6fed89256d4a6e983a6813bf084d4fc6c20b9cdaef24b23fa7e:=1-2&=3,emOilm045v7YklbUpumDpoE78ITU_Gwguc2u8ksj-n49MS0yJj0z
|
||||
MALFORMED,version cannot be overridden,db823224f960976b3ee142ce8899fc7ea461b42617e7d16167b1886c5988c628:=1-2&=1-3,24IyJPlgl2s-4ULOiJn8fqRhtCYX59FhZ7GIbFmIxig9MS0yJj0xLTM=
|
||||
MALFORMED,Bad condition ",76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1"11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMSIxMQ==
|
||||
MALFORMED,Bad condition &,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1&11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMSYxMQ==
|
||||
MALFORMED,Bad condition ',76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1'11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMScxMQ==
|
||||
MALFORMED,Bad condition (,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1(11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMSgxMQ==
|
||||
MALFORMED,Bad condition ),76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1)11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMSkxMQ==
|
||||
MALFORMED,Bad condition *,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1*11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMSoxMQ==
|
||||
MALFORMED,Bad condition +,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1+11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMSsxMQ==
|
||||
MALFORMED,Bad condition -,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1-11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMS0xMQ==
|
||||
MALFORMED,Bad condition .,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1.11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMS4xMQ==
|
||||
MALFORMED,Bad condition :,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1:11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMToxMQ==
|
||||
MALFORMED,Bad condition ;,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1;11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMTsxMQ==
|
||||
MALFORMED,Bad condition ?,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1?11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMT8xMQ==
|
||||
MALFORMED,Bad condition [,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1[11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMVsxMQ==
|
||||
MALFORMED,Bad condition \,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1\11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMVwxMQ==
|
||||
MALFORMED,Bad condition ],76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1]11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMV0xMQ==
|
||||
MALFORMED,Bad condition _,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1_11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMV8xMQ==
|
||||
MALFORMED,Bad condition `,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1`11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMWAxMQ==
|
||||
MALFORMED,Bad condition |,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1|11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMXwxMQ==
|
||||
BAD DERIVATION,Incremented sha,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0e:f1#11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw5mMSMxMQ==
|
||||
BAD DERIVATION,Unchanged sha,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1#11&a=1,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMSMxMSZhPTE=
|
Can't render this file because it has a wrong number of fields in line 70.
|
Loading…
Add table
Reference in a new issue