commit 07dfa3b1fbc19457a86a1e60fea920f41031897c
parent 88306d00a3edfea2523210bb50c33bc7435b6da6
Author: William Casarin <jb55@jb55.com>
Date: Tue, 1 Aug 2023 16:35:40 -0700
ndb: update nostrdb
This include various fixes for parsing and key decoding
Diffstat:
M | nostrdb/nostrdb.c | | | 158 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- |
M | nostrdb/nostrdb.h | | | 46 | +++++++++++++++++++++++++++++++++++++++++++--- |
2 files changed, 169 insertions(+), 35 deletions(-)
diff --git a/nostrdb/nostrdb.c b/nostrdb/nostrdb.c
@@ -18,6 +18,7 @@ struct ndb_json_parser {
struct ndb_builder builder;
jsmn_parser json_parser;
jsmntok_t *toks, *toks_end;
+ int i;
int num_tokens;
};
@@ -102,6 +103,8 @@ static inline int ndb_json_parser_parse(struct ndb_json_parser *p)
p->num_tokens =
jsmn_parse(&p->json_parser, p->json, p->json_len, p->toks, cap);
+ p->i = 0;
+
return p->num_tokens;
}
@@ -242,7 +245,7 @@ static int ndb_event_commitment(struct ndb_note *ev, unsigned char *buf, int buf
struct cursor cur;
int ok;
- if (!hex_encode(ev->pubkey, sizeof(ev->pubkey), pubkey, 32))
+ if (!hex_encode(ev->pubkey, sizeof(ev->pubkey), pubkey, sizeof(pubkey)))
return 0;
make_cursor(buf, buf + buflen, &cur);
@@ -351,7 +354,9 @@ int ndb_builder_finalize(struct ndb_builder *builder, struct ndb_note **note,
unsigned char *end = builder->mem.end;
unsigned char *start = (unsigned char*)(*note) + total_size;
- if (!ndb_calculate_id(*note, start, end - start))
+ ndb_builder_set_pubkey(builder, keypair->pubkey);
+
+ if (!ndb_calculate_id(builder->note, start, end - start))
return 0;
if (!ndb_sign_id(keypair, (*note)->id, (*note)->sig))
@@ -645,92 +650,181 @@ static int parse_unsigned_int(const char *start, int len, unsigned int *num)
return 1;
}
-
-int ndb_note_from_json(const char *json, int len, struct ndb_note **note,
- unsigned char *buf, int bufsize)
+int ndb_ws_event_from_json(const char *json, int len, struct ndb_tce *tce,
+ unsigned char *buf, int bufsize)
{
jsmntok_t *tok = NULL;
- unsigned char hexbuf[64];
-
- int i, tok_len, res;
- const char *start;
+ int tok_len, res;
struct ndb_json_parser parser;
+ tce->subid_len = 0;
+ tce->subid = "";
+
ndb_json_parser_init(&parser, json, len, buf, bufsize);
- res = ndb_json_parser_parse(&parser);
- if (res < 0)
+ if ((res = ndb_json_parser_parse(&parser)) < 0)
return res;
- if (parser.num_tokens < 1 || parser.toks[0].type != JSMN_OBJECT)
+ if (parser.num_tokens < 3 || parser.toks[0].type != JSMN_ARRAY)
+ return 0;
+
+ parser.i = 1;
+ tok = &parser.toks[parser.i++];
+ tok_len = toksize(tok);
+ if (tok->type != JSMN_STRING)
return 0;
- for (i = 1; i < parser.num_tokens; i++) {
- tok = &parser.toks[i];
+ if (tok_len == 5 && !memcmp("EVENT", json + tok->start, 5)) {
+ tce->evtype = NDB_TCE_EVENT;
+ struct ndb_event *ev = &tce->event;
+
+ tok = &parser.toks[parser.i++];
+ if (tok->type != JSMN_STRING)
+ return 0;
+
+ tce->subid = json + tok->start;
+ tce->subid_len = toksize(tok);
+
+ return ndb_parse_json_note(&parser, &ev->note);
+ } else if (tok_len == 4 && !memcmp("EOSE", json + tok->start, 4)) {
+ tce->evtype = NDB_TCE_EOSE;
+
+ tok = &parser.toks[parser.i++];
+ if (tok->type != JSMN_STRING)
+ return 0;
+
+ tce->subid = json + tok->start;
+ tce->subid_len = toksize(tok);
+ return 1;
+ } else if (tok_len == 2 && !memcmp("OK", json + tok->start, 2)) {
+ if (parser.num_tokens != 5)
+ return 0;
+
+ struct ndb_command_result *cr = &tce->command_result;
+
+ tce->evtype = NDB_TCE_OK;
+
+ tok = &parser.toks[parser.i++];
+ if (tok->type != JSMN_STRING)
+ return 0;
+
+ tce->subid = json + tok->start;
+ tce->subid_len = toksize(tok);
+
+ tok = &parser.toks[parser.i++];
+ if (tok->type != JSMN_PRIMITIVE || toksize(tok) == 0)
+ return 0;
+
+ cr->ok = (json + tok->start)[0] == 't';
+
+ tok = &parser.toks[parser.i++];
+ if (tok->type != JSMN_STRING)
+ return 0;
+
+ tce->command_result.msg = json + tok->start;
+ tce->command_result.msglen = toksize(tok);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int ndb_parse_json_note(struct ndb_json_parser *parser, struct ndb_note **note)
+{
+ jsmntok_t *tok = NULL;
+ unsigned char hexbuf[64];
+ const char *json = parser->json;
+ const char *start;
+ int i, tok_len;
+
+ if (parser->toks[parser->i].type != JSMN_OBJECT)
+ return 0;
+
+ // TODO: build id buffer and verify at end
+
+ for (i = parser->i + 1; i < parser->num_tokens; i++) {
+ tok = &parser->toks[i];
start = json + tok->start;
tok_len = toksize(tok);
//printf("toplevel %.*s %d\n", tok_len, json + tok->start, tok->type);
- if (tok_len == 0 || i + 1 >= parser.num_tokens)
+ if (tok_len == 0 || i + 1 >= parser->num_tokens)
continue;
if (start[0] == 'p' && jsoneq(json, tok, tok_len, "pubkey")) {
// pubkey
- tok = &parser.toks[i+1];
+ tok = &parser->toks[i+1];
hex_decode(json + tok->start, toksize(tok), hexbuf, sizeof(hexbuf));
- ndb_builder_set_pubkey(&parser.builder, hexbuf);
+ ndb_builder_set_pubkey(&parser->builder, hexbuf);
} else if (tok_len == 2 && start[0] == 'i' && start[1] == 'd') {
// id
- tok = &parser.toks[i+1];
+ tok = &parser->toks[i+1];
hex_decode(json + tok->start, toksize(tok), hexbuf, sizeof(hexbuf));
// TODO: validate id
- ndb_builder_set_id(&parser.builder, hexbuf);
+ ndb_builder_set_id(&parser->builder, hexbuf);
} else if (tok_len == 3 && start[0] == 's' && start[1] == 'i' && start[2] == 'g') {
// sig
- tok = &parser.toks[i+1];
+ tok = &parser->toks[i+1];
hex_decode(json + tok->start, toksize(tok), hexbuf, sizeof(hexbuf));
- ndb_builder_set_sig(&parser.builder, hexbuf);
+ ndb_builder_set_sig(&parser->builder, hexbuf);
} else if (start[0] == 'k' && jsoneq(json, tok, tok_len, "kind")) {
// kind
- tok = &parser.toks[i+1];
+ tok = &parser->toks[i+1];
start = json + tok->start;
if (tok->type != JSMN_PRIMITIVE || tok_len <= 0)
return 0;
if (!parse_unsigned_int(start, toksize(tok),
- &parser.builder.note->kind))
+ &parser->builder.note->kind))
return 0;
} else if (start[0] == 'c') {
if (jsoneq(json, tok, tok_len, "created_at")) {
// created_at
- tok = &parser.toks[i+1];
+ tok = &parser->toks[i+1];
start = json + tok->start;
if (tok->type != JSMN_PRIMITIVE || tok_len <= 0)
return 0;
if (!parse_unsigned_int(start, toksize(tok),
- &parser.builder.note->created_at))
+ &parser->builder.note->created_at))
return 0;
} else if (jsoneq(json, tok, tok_len, "content")) {
// content
- tok = &parser.toks[i+1];
+ tok = &parser->toks[i+1];
union ndb_packed_str pstr;
tok_len = toksize(tok);
int written, pack_ids = 0;
- if (!ndb_builder_make_json_str(&parser.builder,
+ if (!ndb_builder_make_json_str(&parser->builder,
json + tok->start,
tok_len, &pstr,
&written, pack_ids)) {
return 0;
}
- parser.builder.note->content_length = written;
- parser.builder.note->content = pstr;
+ parser->builder.note->content_length = written;
+ parser->builder.note->content = pstr;
}
} else if (start[0] == 't' && jsoneq(json, tok, tok_len, "tags")) {
- tok = &parser.toks[i+1];
- ndb_builder_process_json_tags(&parser, tok);
+ tok = &parser->toks[i+1];
+ ndb_builder_process_json_tags(parser, tok);
i += tok->size;
}
}
- return ndb_builder_finalize(&parser.builder, note, NULL);
+ return ndb_builder_finalize(&parser->builder, note, NULL);
+}
+
+int ndb_note_from_json(const char *json, int len, struct ndb_note **note,
+ unsigned char *buf, int bufsize)
+{
+ struct ndb_json_parser parser;
+ int res;
+
+ ndb_json_parser_init(&parser, json, len, buf, bufsize);
+ if ((res = ndb_json_parser_parse(&parser)) < 0)
+ return res;
+
+ if (parser.num_tokens < 1)
+ return 0;
+
+ return ndb_parse_json_note(&parser, note);
}
void ndb_builder_set_pubkey(struct ndb_builder *builder, unsigned char *pubkey)
diff --git a/nostrdb/nostrdb.h b/nostrdb/nostrdb.h
@@ -4,6 +4,19 @@
#include <inttypes.h>
#include "cursor.h"
+#define NDB_PACKED_STR 0x1
+#define NDB_PACKED_ID 0x2
+
+struct ndb_json_parser;
+
+// To-client event types
+enum tce_type {
+ NDB_TCE_EVENT = 0x1,
+ NDB_TCE_OK = 0x2,
+ NDB_TCE_NOTICE = 0x3,
+ NDB_TCE_EOSE = 0x4,
+};
+
struct ndb_str {
unsigned char flag;
union {
@@ -12,9 +25,36 @@ struct ndb_str {
};
};
+struct ndb_event {
+ struct ndb_note *note;
+};
+
+struct ndb_command_result {
+ int ok;
+ const char *msg;
+ int msglen;
+};
+
+
+// To-client event
+struct ndb_tce {
+ enum tce_type evtype;
+ const char *subid;
+ int subid_len;
+
+ union {
+ struct ndb_event event;
+ struct ndb_command_result command_result;
+ };
+};
+
struct ndb_keypair {
unsigned char pubkey[32];
unsigned char secret[32];
+
+ // this corresponds to secp256k1's keypair type. it's guaranteed to
+ // be 96 bytes according to their docs. I don't want to depend on
+ // the secp256k1 header here so we just use raw bytes.
unsigned char pair[96];
};
@@ -22,9 +62,6 @@ struct ndb_keypair {
// representation
#pragma pack(push, 1)
-/// We can store byte data in the string table, so
-#define NDB_PACKED_STR 0x1
-#define NDB_PACKED_ID 0x2
union ndb_packed_str {
struct {
@@ -91,6 +128,9 @@ int ndb_create_keypair(struct ndb_keypair *key);
int ndb_decode_key(const char *secstr, struct ndb_keypair *keypair);
// BUILDER
+
+int ndb_parse_json_note(struct ndb_json_parser *, struct ndb_note **);
+int ndb_ws_event_from_json(const char *json, int len, struct ndb_tce *tce, unsigned char *buf, int bufsize);
int ndb_note_from_json(const char *json, int len, struct ndb_note **, unsigned char *buf, int buflen);
int ndb_builder_init(struct ndb_builder *builder, unsigned char *buf, int bufsize);
int ndb_builder_finalize(struct ndb_builder *builder, struct ndb_note **note, struct ndb_keypair *privkey);