Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NFC: Improve URI decoding in NDEF parser #267

Merged
merged 8 commits into from
Oct 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
- NFC:
- Added 6 new Mifare Classic keys from Bulgaria Hotel (#216 by @z3r0l1nk)
- NDEF parser supports NTAG I2C Plus 1k and 2k chips too (by @RocketGod-git)
- NDEF parser decodes URL-encoded URI characters (#267 by @jaylikesbunda)
- UL: Add iq aparts hotel key (by @xMasterX)
- OFW/UL: Rename 'Detect Reader' to 'Extract MFC Keys' (by @bettse & @xMasterX)
- OFW: Plantain parser improvements (by @assasinfil)
Expand Down
55 changes: 40 additions & 15 deletions applications/main/nfc/plugins/supported_cards/ndef.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,7 @@ static void
print_data(FuriString* str, const char* prefix, const uint8_t* buf, size_t len, bool force_hex) {
if(prefix) furi_string_cat_printf(str, "%s: ", prefix);
if(!force_hex && is_text(buf, len)) {
char* tmp = malloc(len + 1);
memcpy(tmp, buf, len);
tmp[len] = '\0';
furi_string_cat_printf(str, "%s", tmp);
free(tmp);
furi_string_cat_printf(str, "%.*s", len, buf);
} else {
for(uint8_t i = 0; i < len; i++) {
furi_string_cat_printf(str, "%02X ", buf[i]);
Expand All @@ -40,6 +36,17 @@ static void
furi_string_cat(str, "\n");
}

static inline uint8_t hex_to_int(char c) {
if(c >= '0' && c <= '9') return c - '0';
if(c >= 'A' && c <= 'F') return c - 'A' + 10;
if(c >= 'a' && c <= 'f') return c - 'a' + 10;
return 0;
}

static char decode_char(const char* str) {
return (hex_to_int(str[1]) << 4) | hex_to_int(str[2]);
}

static void parse_ndef_uri(FuriString* str, const uint8_t* payload, uint32_t payload_len) {
// https://learn.adafruit.com/adafruit-pn532-rfid-nfc/ndef#uri-records-0x55-slash-u-607763
const char* prepends[] = {
Expand Down Expand Up @@ -88,26 +95,44 @@ static void parse_ndef_uri(FuriString* str, const uint8_t* payload, uint32_t pay
size_t prepend_len = strlen(prepend);

size_t uri_len = prepend_len + (payload_len - 1);
char* const uri_buf = malloc(uri_len);
char* const uri_buf = malloc(uri_len); // const to keep the original pointer to free later
memcpy(uri_buf, prepend, prepend_len);
memcpy(uri_buf + prepend_len, payload + 1, payload_len - 1);
char* uri = uri_buf;
char* uri = uri_buf; // cursor we can iterate and shift freely

// Encoded chars take 3 bytes (%AB), decoded chars take 1 byte
// We can decode by iterating and overwriting the same buffer
size_t decoded_len = 0;
for(size_t encoded_idx = 0; encoded_idx < uri_len; encoded_idx++) {
if(uri[encoded_idx] == '%' && encoded_idx + 2 < uri_len) {
char hi = toupper(uri[encoded_idx + 1]);
char lo = toupper(uri[encoded_idx + 2]);
if(((hi >= 'A' && hi <= 'F') || (hi >= '0' && hi <= '9')) &&
((lo >= 'A' && lo <= 'F') || (lo >= '0' && lo <= '9'))) {
uri[decoded_len++] = decode_char(&uri[encoded_idx]);
encoded_idx += 2;
continue;
}
}
uri[decoded_len++] = uri[encoded_idx];
}

const char* type = "URI";
if(strncmp(uri, "http", strlen("http")) == 0) {
if(strncmp(uri, "http", 4) == 0) {
type = "URL";
} else if(strncmp(uri, "tel:", strlen("tel:")) == 0) {
} else if(strncmp(uri, "tel:", 4) == 0) {
type = "Phone";
uri += strlen("tel:");
uri_len -= strlen("tel:");
} else if(strncmp(uri, "mailto:", strlen("mailto:")) == 0) {
uri += 4;
decoded_len -= 4;
} else if(strncmp(uri, "mailto:", 7) == 0) {
type = "Mail";
uri += strlen("mailto:");
uri_len -= strlen("mailto:");
uri += 7;
decoded_len -= 7;
}

furi_string_cat_printf(str, "%s\n", type);
print_data(str, NULL, (uint8_t*)uri, uri_len, false);
print_data(str, NULL, (uint8_t*)uri, decoded_len, false);

free(uri_buf);
}

Expand Down
Loading