nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

nostr_bech32.c (7098B)


      1 //
      2 //	nostr_bech32.c
      3 //	damus
      4 //
      5 //	Created by William Casarin on 2023-04-09.
      6 //
      7 
      8 #include "nostr_bech32.h"
      9 #include <stdlib.h>
     10 #include "cursor.h"
     11 #include "str_block.h"
     12 #include "nostrdb.h"
     13 #include "bolt11/bech32.h"
     14 
     15 #define MAX_TLVS 32
     16 
     17 #define TLV_SPECIAL 0
     18 #define TLV_RELAY 1
     19 #define TLV_AUTHOR 2
     20 #define TLV_KIND 3
     21 #define TLV_KNOWN_TLVS 4
     22 
     23 struct nostr_tlv {
     24 	unsigned char type;
     25 	unsigned char len;
     26 	const unsigned char *value;
     27 };
     28 
     29 static int parse_nostr_tlv(struct cursor *cur, struct nostr_tlv *tlv) {
     30 	// get the tlv tag
     31 	if (!cursor_pull_byte(cur, &tlv->type))
     32 		return 0;
     33 
     34 	if (tlv->type >= TLV_KNOWN_TLVS)
     35 		return 0;
     36 	
     37 	// get the length
     38 	if (!cursor_pull_byte(cur, &tlv->len))
     39 		return 0;
     40 	
     41 	// is the reported length greater then our buffer? if so fail
     42 	if (cur->p + tlv->len > cur->end)
     43 		return 0;
     44 	
     45 	tlv->value = cur->p;
     46 	cur->p += tlv->len;
     47 	
     48 	return 1;
     49 }
     50 
     51 int parse_nostr_bech32_type(const char *prefix, enum nostr_bech32_type *type) {
     52 	// Parse type
     53 	if (strncmp(prefix, "note", 4) == 0) {
     54 		*type = NOSTR_BECH32_NOTE;
     55 		return 4;
     56 	} else if (strncmp(prefix, "npub", 4) == 0) {
     57 		*type = NOSTR_BECH32_NPUB;
     58 		return 4;
     59 	} else if (strncmp(prefix, "nsec", 4) == 0) {
     60 		*type = NOSTR_BECH32_NSEC;
     61 		return 4;
     62 	} else if (strncmp(prefix, "nprofile", 8) == 0) {
     63 		*type = NOSTR_BECH32_NPROFILE;
     64 		return 8;
     65 	} else if (strncmp(prefix, "nevent", 6) == 0) {
     66 		*type = NOSTR_BECH32_NEVENT;
     67 		return 6;
     68 	} else if (strncmp(prefix, "nrelay", 6) == 0) {
     69 		*type = NOSTR_BECH32_NRELAY;
     70 		return 6;
     71 	} else if (strncmp(prefix, "naddr", 5) == 0) {
     72 		*type = NOSTR_BECH32_NADDR;
     73 		return 5;
     74 	}
     75 	
     76 	return 0;
     77 }
     78 
     79 static int parse_nostr_bech32_note(struct cursor *cur, struct bech32_note *note) {
     80 	return pull_bytes(cur, 32, &note->event_id);
     81 }
     82 
     83 static int parse_nostr_bech32_npub(struct cursor *cur, struct bech32_npub *npub) {
     84 	return pull_bytes(cur, 32, &npub->pubkey);
     85 }
     86 
     87 static int parse_nostr_bech32_nsec(struct cursor *cur, struct bech32_nsec *nsec) {
     88 	return pull_bytes(cur, 32, &nsec->nsec);
     89 }
     90 
     91 static int add_relay(struct ndb_relays *relays, struct nostr_tlv *tlv)
     92 {
     93 	struct ndb_str_block *str;
     94 
     95 	if (relays->num_relays + 1 > NDB_MAX_RELAYS)
     96 		return 0;
     97 	
     98 	str = &relays->relays[relays->num_relays++];
     99 	str->str = (const char*)tlv->value;
    100 	str->len = tlv->len;
    101 	
    102 	return 1;
    103 }
    104 
    105 static int parse_nostr_bech32_nevent(struct cursor *cur, struct bech32_nevent *nevent) {
    106 	struct nostr_tlv tlv;
    107 	int i;
    108 
    109 	nevent->event_id = NULL;
    110 	nevent->pubkey = NULL;
    111 	nevent->relays.num_relays = 0;
    112 
    113 	for (i = 0; i < MAX_TLVS; i++) {
    114 		if (!parse_nostr_tlv(cur, &tlv))
    115 			break;
    116 
    117 		switch (tlv.type) {
    118 		case TLV_SPECIAL:
    119 			if (tlv.len != 32)
    120 				return 0;
    121 			nevent->event_id = tlv.value;
    122 			break;
    123 		case TLV_AUTHOR:
    124 			if (tlv.len != 32)
    125 				return 0;
    126 			nevent->pubkey = tlv.value;
    127 			break;
    128 		case TLV_RELAY:
    129 			add_relay(&nevent->relays, &tlv);
    130 			break;
    131 		}
    132 	}
    133 
    134 	return nevent->event_id != NULL;
    135 }
    136 
    137 static int parse_nostr_bech32_naddr(struct cursor *cur, struct bech32_naddr *naddr) {
    138 	struct nostr_tlv tlv;
    139 	int i;
    140 
    141 	naddr->identifier.str = NULL;
    142 	naddr->identifier.len = 0;
    143 	naddr->pubkey = NULL;
    144 	naddr->relays.num_relays = 0;
    145 
    146 	for (i = 0; i < MAX_TLVS; i++) {
    147 		if (!parse_nostr_tlv(cur, &tlv))
    148 			break;
    149 
    150 		switch (tlv.type) {
    151 		case TLV_SPECIAL:
    152 			naddr->identifier.str = (const char*)tlv.value;
    153 			naddr->identifier.len = tlv.len;
    154 			break;
    155 		case TLV_AUTHOR:
    156 			if (tlv.len != 32) return 0;
    157 			naddr->pubkey = tlv.value;
    158 			break;
    159 		case TLV_RELAY:
    160 			add_relay(&naddr->relays, &tlv);
    161 			break;
    162 		}
    163 	}
    164 
    165 	return naddr->identifier.str != NULL;
    166 }
    167 
    168 static int parse_nostr_bech32_nprofile(struct cursor *cur, struct bech32_nprofile *nprofile) {
    169 	struct nostr_tlv tlv;
    170 	int i;
    171 
    172 	nprofile->pubkey = NULL;
    173 	nprofile->relays.num_relays = 0;
    174 
    175 	for (i = 0; i < MAX_TLVS; i++) {
    176 		if (!parse_nostr_tlv(cur, &tlv))
    177 			break;
    178 
    179 		switch (tlv.type) {
    180 		case TLV_SPECIAL:
    181 			if (tlv.len != 32) return 0;
    182 			nprofile->pubkey = tlv.value;
    183 			break;
    184 		case TLV_RELAY:
    185 			add_relay(&nprofile->relays, &tlv);
    186 			break;
    187 		}
    188 	}
    189 
    190 	return nprofile->pubkey != NULL;
    191 }
    192 
    193 static int parse_nostr_bech32_nrelay(struct cursor *cur, struct bech32_nrelay *nrelay) {
    194 	struct nostr_tlv tlv;
    195 	int i;
    196 
    197 	nrelay->relay.str = NULL;
    198 	nrelay->relay.len = 0;
    199 
    200 	for (i = 0; i < MAX_TLVS; i++) {
    201 		if (!parse_nostr_tlv(cur, &tlv))
    202 			break;
    203 
    204 		switch (tlv.type) {
    205 		case TLV_SPECIAL:
    206 			nrelay->relay.str = (const char*)tlv.value;
    207 			nrelay->relay.len = tlv.len;
    208 			break;
    209 		}
    210 	}
    211 	
    212 	return nrelay->relay.str != NULL;
    213 }
    214 
    215 int parse_nostr_bech32_buffer(struct cursor *cur,
    216 			      enum nostr_bech32_type type,
    217 			      struct nostr_bech32 *obj)
    218 {
    219 	obj->type = type;
    220 	
    221 	switch (obj->type) {
    222 		case NOSTR_BECH32_NOTE:
    223 			if (!parse_nostr_bech32_note(cur, &obj->note))
    224 				return 0;
    225 			break;
    226 		case NOSTR_BECH32_NPUB:
    227 			if (!parse_nostr_bech32_npub(cur, &obj->npub))
    228 				return 0;
    229 			break;
    230 		case NOSTR_BECH32_NSEC:
    231 			if (!parse_nostr_bech32_nsec(cur, &obj->nsec))
    232 				return 0;
    233 			break;
    234 		case NOSTR_BECH32_NEVENT:
    235 			if (!parse_nostr_bech32_nevent(cur, &obj->nevent))
    236 				return 0;
    237 			break;
    238 		case NOSTR_BECH32_NADDR:
    239 			if (!parse_nostr_bech32_naddr(cur, &obj->naddr))
    240 				return 0;
    241 			break;
    242 		case NOSTR_BECH32_NPROFILE:
    243 			if (!parse_nostr_bech32_nprofile(cur, &obj->nprofile))
    244 				return 0;
    245 			break;
    246 		case NOSTR_BECH32_NRELAY:
    247 			if (!parse_nostr_bech32_nrelay(cur, &obj->nrelay))
    248 				return 0;
    249 			break;
    250 	}
    251 
    252 	return 1;
    253 }
    254 
    255 
    256 int parse_nostr_bech32_str(struct cursor *bech32, enum nostr_bech32_type *type) {
    257 	unsigned char *start = bech32->p;
    258 	unsigned char *data_start;
    259 	int n;
    260 
    261 	if (!(n = parse_nostr_bech32_type((const char *)bech32->p, type))) {
    262 		bech32->p = start;
    263 		return 0;
    264 	}
    265 	
    266 	data_start = start + n;
    267 	if (!consume_until_non_alphanumeric(bech32, 1)) {
    268 		bech32->p = start;
    269 		return 0;
    270 	}
    271 
    272 	// must be at least 59 chars for the data part
    273 	//ndb_debug("bech32_data_size %ld '%c' '%c' '%.*s'\n", bech32->p - data_start, *(bech32->p-1), *data_start, (int)(bech32->p - data_start), data_start);
    274 	if (bech32->p - data_start < 59) {
    275 		bech32->p = start;
    276 		return 0;
    277 	}
    278 
    279 	return 1;
    280 }
    281 
    282 
    283 int parse_nostr_bech32(unsigned char *buf, int buflen,
    284 		       const char *bech32_str, size_t bech32_len,
    285 		       struct nostr_bech32 *obj) {
    286 	unsigned char *start;
    287 	size_t parsed_len, u5_out_len, u8_out_len;
    288 	enum nostr_bech32_type type;
    289 	static const int MAX_PREFIX = 8;
    290 	struct cursor cur, bech32, u8;
    291 
    292 	make_cursor(buf, buf + buflen, &cur);
    293 	make_cursor((unsigned char*)bech32_str, (unsigned char*)bech32_str + bech32_len, &bech32);
    294 	
    295 	start = bech32.p;
    296 	if (!parse_nostr_bech32_str(&bech32, &type))
    297 		return 0;
    298 
    299 	parsed_len = bech32.p - start;
    300 
    301 	// some random sanity checking
    302 	if (parsed_len < 10 || parsed_len > 10000)
    303 		return 0;
    304 
    305 	unsigned char u5[parsed_len];
    306 	char prefix[MAX_PREFIX];
    307 	
    308 	if (bech32_decode_len(prefix, u5, &u5_out_len, (const char*)start,
    309 			      parsed_len, MAX_PREFIX) == BECH32_ENCODING_NONE)
    310 	{
    311 		return 0;
    312 	}
    313 
    314 	if (!bech32_convert_bits(cur.p, &u8_out_len, 8, u5, u5_out_len, 5, 0))
    315 		return 0;
    316 
    317 	make_cursor(cur.p, cur.p + u8_out_len, &u8);
    318 
    319 	return parse_nostr_bech32_buffer(&u8, type, obj);
    320 }
    321