damus

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

nostr_bech32.c (8011B)


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