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, ¬e->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