jb55 on Nostr: #[0] are there any issues with this code? static int parse_mention_bech32(struct ...
dave (npub1tsg…htk4) are there any issues with this code?
static int parse_mention_bech32(struct cursor *cur, struct block *block) {
const u8 *start, *start_entity, *end;
start = cur->p;
if (!parse_str(cur, "nostr:"))
return 0;
start_entity = cur->p;
if (!consume_until_whitespace(cur, 1)) {
cur->p = start;
return 0;
}
end = cur->p;
char str[end - start_entity + 1];
str[end - start_entity] = 0;
memcpy(str, start_entity, end - start_entity);
char prefix[end - start_entity];
u8 data[end - start_entity];
size_t data_len;
size_t max_input_len = end - start_entity + 2;
if (bech32_decode(prefix, data, &data_len, str, max_input_len) == BECH32_ENCODING_NONE) {
cur->p = start;
return 0;
}
struct mention_bech32_block mention = { 0 };
mention.kind = -1;
mention.buffer = (u8*)malloc(data_len);
mention.str.start = (const char*)start;
mention.str.end = (const char*)end;
size_t len = 0;
if (!bech32_convert_bits(mention.buffer, &len, 8, data, data_len, 5, 0)) {
goto fail;
}
// Parse type
if (strcmp(prefix, "note") == 0) {
mention.type = NOSTR_BECH32_NOTE;
} else if (strcmp(prefix, "npub") == 0) {
mention.type = NOSTR_BECH32_NPUB;
} else if (strcmp(prefix, "nprofile") == 0) {
mention.type = NOSTR_BECH32_NPROFILE;
} else if (strcmp(prefix, "nevent") == 0) {
mention.type = NOSTR_BECH32_NEVENT;
} else if (strcmp(prefix, "nrelay") == 0) {
mention.type = NOSTR_BECH32_NRELAY;
} else if (strcmp(prefix, "naddr") == 0) {
mention.type = NOSTR_BECH32_NADDR;
} else {
goto fail;
}
// Parse notes and npubs (non-TLV)
if (mention.type == NOSTR_BECH32_NOTE || mention.type == NOSTR_BECH32_NPUB) {
if (len != 32) goto fail;
if (mention.type == NOSTR_BECH32_NOTE) {
mention.event_id = mention.buffer;
} else {
mention.pubkey = mention.buffer;
}
goto ok;
}
// Parse TLV entities
const int MAX_VALUES = 16;
int values_count = 0;
u8 Ts[MAX_VALUES];
u8 Ls[MAX_VALUES];
u8* Vs[MAX_VALUES];
for (int i = 0; i < len - 1;) {
if (values_count == MAX_VALUES) goto fail;
Ts[values_count] = mention.buffer[i++];
Ls[values_count] = mention.buffer[i++];
if (Ls[values_count] > len - i) goto fail;
Vs[values_count] = &mention.buffer[i];
i += Ls[values_count];
++values_count;
}
// Decode and validate all TLV-type entities
if (mention.type == NOSTR_BECH32_NPROFILE) {
for (int i = 0; i < values_count; ++i) {
if (Ts[i] == TLV_SPECIAL) {
if (Ls[i] != 32 || mention.pubkey) goto fail;
mention.pubkey = Vs[i];
} else if (Ts[i] == TLV_RELAY) {
if (mention.relays_count == MAX_RELAYS) goto fail;
Vs[i][Ls[i]] = 0;
mention.relays[mention.relays_count++] = (char*)Vs[i];
} else {
goto fail;
}
}
if (!mention.pubkey) goto fail;
} else if (mention.type == NOSTR_BECH32_NEVENT) {
for (int i = 0; i < values_count; ++i) {
if (Ts[i] == TLV_SPECIAL) {
if (Ls[i] != 32 || mention.event_id) goto fail;
mention.event_id = Vs[i];
} else if (Ts[i] == TLV_RELAY) {
if (mention.relays_count == MAX_RELAYS) goto fail;
Vs[i][Ls[i]] = 0;
mention.relays[mention.relays_count++] = (char*)Vs[i];
} else if (Ts[i] == TLV_AUTHOR) {
if (Ls[i] != 32 || mention.pubkey) goto fail;
mention.pubkey = Vs[i];
} else {
goto fail;
}
}
if (!mention.event_id) goto fail;
} else if (mention.type == NOSTR_BECH32_NRELAY) {
if (values_count != 1 || Ts[0] != TLV_SPECIAL) goto fail;
Vs[0][Ls[0]] = 0;
mention.relays[mention.relays_count++] = (char*)Vs[0];
} else { // entity.type == NOSTR_BECH32_NADDR
for (int i = 0; i < values_count; ++i) {
if (Ts[i] == TLV_SPECIAL) {
Vs[i][Ls[i]] = 0;
mention.identifier = (char*)Vs[i];
} else if (Ts[i] == TLV_RELAY) {
if (mention.relays_count == MAX_RELAYS) goto fail;
Vs[i][Ls[i]] = 0;
mention.relays[mention.relays_count++] = (char*)Vs[i];
} else if (Ts[i] == TLV_AUTHOR) {
if (Ls[i] != 32 || mention.pubkey) goto fail;
mention.pubkey = Vs[i];
} else if (Ts[i] == TLV_KIND) {
if (Ls[i] != sizeof(int) || mention.kind != -1) goto fail;
mention.kind = *(int*)Vs[i];
} else {
goto fail;
}
}
if (!mention.identifier || mention.kind == -1 || !mention.pubkey) goto fail;
}
ok:
block->type = BLOCK_MENTION_BECH32;
block->block.mention_bech32 = mention;
return 1;
fail:
free(mention.buffer);
cur->p = start;
return 0;
}
static int parse_mention_bech32(struct cursor *cur, struct block *block) {
const u8 *start, *start_entity, *end;
start = cur->p;
if (!parse_str(cur, "nostr:"))
return 0;
start_entity = cur->p;
if (!consume_until_whitespace(cur, 1)) {
cur->p = start;
return 0;
}
end = cur->p;
char str[end - start_entity + 1];
str[end - start_entity] = 0;
memcpy(str, start_entity, end - start_entity);
char prefix[end - start_entity];
u8 data[end - start_entity];
size_t data_len;
size_t max_input_len = end - start_entity + 2;
if (bech32_decode(prefix, data, &data_len, str, max_input_len) == BECH32_ENCODING_NONE) {
cur->p = start;
return 0;
}
struct mention_bech32_block mention = { 0 };
mention.kind = -1;
mention.buffer = (u8*)malloc(data_len);
mention.str.start = (const char*)start;
mention.str.end = (const char*)end;
size_t len = 0;
if (!bech32_convert_bits(mention.buffer, &len, 8, data, data_len, 5, 0)) {
goto fail;
}
// Parse type
if (strcmp(prefix, "note") == 0) {
mention.type = NOSTR_BECH32_NOTE;
} else if (strcmp(prefix, "npub") == 0) {
mention.type = NOSTR_BECH32_NPUB;
} else if (strcmp(prefix, "nprofile") == 0) {
mention.type = NOSTR_BECH32_NPROFILE;
} else if (strcmp(prefix, "nevent") == 0) {
mention.type = NOSTR_BECH32_NEVENT;
} else if (strcmp(prefix, "nrelay") == 0) {
mention.type = NOSTR_BECH32_NRELAY;
} else if (strcmp(prefix, "naddr") == 0) {
mention.type = NOSTR_BECH32_NADDR;
} else {
goto fail;
}
// Parse notes and npubs (non-TLV)
if (mention.type == NOSTR_BECH32_NOTE || mention.type == NOSTR_BECH32_NPUB) {
if (len != 32) goto fail;
if (mention.type == NOSTR_BECH32_NOTE) {
mention.event_id = mention.buffer;
} else {
mention.pubkey = mention.buffer;
}
goto ok;
}
// Parse TLV entities
const int MAX_VALUES = 16;
int values_count = 0;
u8 Ts[MAX_VALUES];
u8 Ls[MAX_VALUES];
u8* Vs[MAX_VALUES];
for (int i = 0; i < len - 1;) {
if (values_count == MAX_VALUES) goto fail;
Ts[values_count] = mention.buffer[i++];
Ls[values_count] = mention.buffer[i++];
if (Ls[values_count] > len - i) goto fail;
Vs[values_count] = &mention.buffer[i];
i += Ls[values_count];
++values_count;
}
// Decode and validate all TLV-type entities
if (mention.type == NOSTR_BECH32_NPROFILE) {
for (int i = 0; i < values_count; ++i) {
if (Ts[i] == TLV_SPECIAL) {
if (Ls[i] != 32 || mention.pubkey) goto fail;
mention.pubkey = Vs[i];
} else if (Ts[i] == TLV_RELAY) {
if (mention.relays_count == MAX_RELAYS) goto fail;
Vs[i][Ls[i]] = 0;
mention.relays[mention.relays_count++] = (char*)Vs[i];
} else {
goto fail;
}
}
if (!mention.pubkey) goto fail;
} else if (mention.type == NOSTR_BECH32_NEVENT) {
for (int i = 0; i < values_count; ++i) {
if (Ts[i] == TLV_SPECIAL) {
if (Ls[i] != 32 || mention.event_id) goto fail;
mention.event_id = Vs[i];
} else if (Ts[i] == TLV_RELAY) {
if (mention.relays_count == MAX_RELAYS) goto fail;
Vs[i][Ls[i]] = 0;
mention.relays[mention.relays_count++] = (char*)Vs[i];
} else if (Ts[i] == TLV_AUTHOR) {
if (Ls[i] != 32 || mention.pubkey) goto fail;
mention.pubkey = Vs[i];
} else {
goto fail;
}
}
if (!mention.event_id) goto fail;
} else if (mention.type == NOSTR_BECH32_NRELAY) {
if (values_count != 1 || Ts[0] != TLV_SPECIAL) goto fail;
Vs[0][Ls[0]] = 0;
mention.relays[mention.relays_count++] = (char*)Vs[0];
} else { // entity.type == NOSTR_BECH32_NADDR
for (int i = 0; i < values_count; ++i) {
if (Ts[i] == TLV_SPECIAL) {
Vs[i][Ls[i]] = 0;
mention.identifier = (char*)Vs[i];
} else if (Ts[i] == TLV_RELAY) {
if (mention.relays_count == MAX_RELAYS) goto fail;
Vs[i][Ls[i]] = 0;
mention.relays[mention.relays_count++] = (char*)Vs[i];
} else if (Ts[i] == TLV_AUTHOR) {
if (Ls[i] != 32 || mention.pubkey) goto fail;
mention.pubkey = Vs[i];
} else if (Ts[i] == TLV_KIND) {
if (Ls[i] != sizeof(int) || mention.kind != -1) goto fail;
mention.kind = *(int*)Vs[i];
} else {
goto fail;
}
}
if (!mention.identifier || mention.kind == -1 || !mention.pubkey) goto fail;
}
ok:
block->type = BLOCK_MENTION_BECH32;
block->block.mention_bech32 = mention;
return 1;
fail:
free(mention.buffer);
cur->p = start;
return 0;
}