damus

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

nostr_bech32.c (7653B)


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