damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

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:
Mnostrdb/nostrdb.c | 158+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Mnostrdb/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);