diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 0ed7a6241..86eefe620 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -182,14 +182,6 @@ App( sources=["plugins/supported_cards/ndef.c"], ) -App( - appid="emv_parser", - apptype=FlipperAppType.PLUGIN, - entry_point="emv_plugin_ep", - targets=["f7"], - requires=["nfc"], - sources=["plugins/supported_cards/emv.c"], -) App( appid="nfc_start", diff --git a/applications/main/nfc/helpers/nfc_emv_parser.c b/applications/main/nfc/helpers/nfc_emv_parser.c index 30e102405..f48a63d8f 100644 --- a/applications/main/nfc/helpers/nfc_emv_parser.c +++ b/applications/main/nfc/helpers/nfc_emv_parser.c @@ -34,7 +34,7 @@ static bool nfc_emv_parser_search_data( bool nfc_emv_parser_get_aid_name( Storage* storage, - uint8_t* aid, + const uint8_t* aid, uint8_t aid_len, FuriString* aid_name) { furi_assert(storage); diff --git a/applications/main/nfc/helpers/nfc_emv_parser.h b/applications/main/nfc/helpers/nfc_emv_parser.h index c636ca77d..03edab0a8 100644 --- a/applications/main/nfc/helpers/nfc_emv_parser.h +++ b/applications/main/nfc/helpers/nfc_emv_parser.h @@ -13,7 +13,7 @@ */ bool nfc_emv_parser_get_aid_name( Storage* storage, - uint8_t* aid, + const uint8_t* aid, uint8_t aid_len, FuriString* aid_name); diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv.c b/applications/main/nfc/helpers/protocol_support/emv/emv.c index 0b60bea6e..e543291cc 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv.c @@ -75,7 +75,7 @@ static void nfc_scene_read_success_on_enter_emv(NfcApp* instance) { // } const NfcProtocolSupportBase nfc_protocol_support_emv = { - .features = NfcProtocolFeatureNone, + .features = NfcProtocolFeatureMoreInfo, .scene_info = { diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c index 10333a936..463f7355e 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -1,6 +1,7 @@ #include "emv_render.h" #include "../iso14443_4a/iso14443_4a_render.h" +#include "nfc/nfc_app_i.h" void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str) { nfc_render_emv_name(data->emv_application.name, str); @@ -17,10 +18,18 @@ void nfc_render_emv_data(const EmvData* data, FuriString* str) { void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str) { if(len == 0) return; - furi_string_cat_printf(str, "PAN: "); - for(uint8_t i = 0; i < len; i += 2) { - furi_string_cat_printf(str, "%02X%02X ", data[i], data[i + 1]); + + FuriString* card_number = furi_string_alloc(); + for(uint8_t i = 0; i < len; i++) { + if((i % 2 == 0) && (i != 0)) furi_string_cat_printf(card_number, " "); + furi_string_cat_printf(card_number, "%02X", data[i]); } + + // Cut padding 'F' from card number + furi_string_trim(card_number, "F"); + furi_string_cat(str, card_number); + furi_string_free(card_number); + furi_string_cat_printf(str, "\n"); } @@ -29,16 +38,27 @@ void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str) { furi_string_cat_printf(str, "Exp: %02X/%02X\n", apl->exp_month, apl->exp_year); } -void nfc_render_emv_currency(const EmvApplication* apl, FuriString* str) { - UNUSED(apl); - UNUSED(str); - // nfc/assets/currency_code.nfc +void nfc_render_emv_currency(uint16_t cur_code, FuriString* str) { + if(!cur_code) return; + + Storage* storage = furi_record_open(RECORD_STORAGE); + FuriString* currency_name = furi_string_alloc(); + if(nfc_emv_parser_get_currency_name(storage, cur_code, currency_name)) { + furi_string_cat_printf(str, "Currency: %s\n", furi_string_get_cstr(currency_name)); + } + furi_string_free(currency_name); + furi_record_close(RECORD_STORAGE); } -void nfc_render_emv_country(const EmvApplication* apl, FuriString* str) { - UNUSED(apl); - UNUSED(str); - // nfc/assets/country_code.nfc +void nfc_render_emv_country(uint16_t country_code, FuriString* str) { + if(!country_code) return; + Storage* storage = furi_record_open(RECORD_STORAGE); + FuriString* country_name = furi_string_alloc(); + if(nfc_emv_parser_get_country_name(storage, country_code, country_name)) { + furi_string_cat_printf(str, "Country: %s\n", furi_string_get_cstr(country_name)); + } + furi_string_free(country_name); + furi_record_close(RECORD_STORAGE); } void nfc_render_emv_name(const char* data, FuriString* str) { @@ -50,28 +70,48 @@ void nfc_render_emv_name(const char* data, FuriString* str) { void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { const uint8_t len = apl->aid_len; - if(len) { - furi_string_cat_printf(str, "AID: "); - for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]); - // nfc/assets/aid.nfc - } else { - furi_string_cat_printf(str, "No Pay Application found"); + + if(!len) { + furi_string_cat_printf(str, "No Pay Application found\n"); + return; } + + furi_string_cat_printf(str, "AID: "); + Storage* storage = furi_record_open(RECORD_STORAGE); + FuriString* aid_name = furi_string_alloc(); + + if(nfc_emv_parser_get_aid_name(storage, apl->aid, len, aid_name)) { + furi_string_cat_printf(str, "%s", furi_string_get_cstr(aid_name)); + } else { + for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]); + } + furi_string_cat_printf(str, "\n"); + furi_string_free(aid_name); + furi_record_close(RECORD_STORAGE); } void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) { const uint8_t len = apl->active_tr; if(!len) { + furi_string_cat_printf(str, "No transaction info\n"); return; } - furi_string_cat_printf(str, "Transactions:\n"); + + Storage* storage = furi_record_open(RECORD_STORAGE); + FuriString* tmp = furi_string_alloc(); + + //furi_string_cat_printf(str, "Transactions:\n"); for(int i = 0; i < len; i++) { if(!apl->trans[i].amount) continue; + // transaction counter + furi_string_cat_printf(str, "\e#%d: ", apl->trans[i].atc); + + // Print transaction amount uint8_t* a = (uint8_t*)&apl->trans[i].amount; - furi_string_cat_printf(str, "%d: ", apl->trans[i].atc); bool top = true; for(int x = 0; x < 6; x++) { + // cents if(x == 5) { furi_string_cat_printf(str, ".%02X", a[x]); break; @@ -85,31 +125,46 @@ void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) { } } } - // TODO to string - furi_string_cat_printf(str, " %x\n", apl->trans[i].currency); - // TODO to string - if(apl->trans[i].country) - furi_string_cat_printf(str, "country: %x\n", apl->trans[i].country); + if(apl->trans[i].currency) { + furi_string_set_str(tmp, "UNK"); + nfc_emv_parser_get_currency_name(storage, apl->trans[i].currency, tmp); + furi_string_cat_printf(str, " %s\n", furi_string_get_cstr(tmp)); + } + + if(apl->trans[i].country) { + furi_string_set_str(tmp, "UNK"); + nfc_emv_parser_get_country_name(storage, apl->trans[i].country, tmp); + furi_string_cat_printf(str, "Country: %s\n", furi_string_get_cstr(tmp)); + } + + if(apl->trans[i].date) + furi_string_cat_printf( + str, + "%02lx/%02lx/%02lx ", + apl->trans[i].date >> 16, + (apl->trans[i].date >> 8) & 0xff, + apl->trans[i].date & 0xff); if(apl->trans[i].time) furi_string_cat_printf( str, - "%02lx:%02lx:%02lx ", + "%02lx:%02lx:%02lx\n", apl->trans[i].time & 0xff, (apl->trans[i].time >> 8) & 0xff, apl->trans[i].time >> 16); - if(apl->trans[i].date) - furi_string_cat_printf( - str, - "%02lx/%02lx/%02lx\n", - apl->trans[i].date >> 16, - (apl->trans[i].date >> 8) & 0xff, - apl->trans[i].date & 0xff); } + + furi_string_free(tmp); + furi_record_close(RECORD_STORAGE); } void nfc_render_emv_extra(const EmvData* data, FuriString* str) { + nfc_render_emv_currency(data->emv_application.currency_code, str); + nfc_render_emv_country(data->emv_application.country_code, str); nfc_render_emv_application(&data->emv_application, str); + // PIN try + // transactions counter + //nfc_render_emv_transactions(&data->emv_application, str); } diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h index fd73cfc6b..80f80d423 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h @@ -19,8 +19,8 @@ void nfc_render_emv_extra(const EmvData* data, FuriString* str); void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str); -void nfc_render_emv_country(const EmvApplication* apl, FuriString* str); +void nfc_render_emv_country(uint16_t country_code, FuriString* str); -void nfc_render_emv_currency(const EmvApplication* apl, FuriString* str); +void nfc_render_emv_currency(uint16_t cur_code, FuriString* str); void nfc_render_emv_transactions(const EmvApplication* data, FuriString* str); \ No newline at end of file diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 943d722f8..0339bf92e 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -30,6 +30,7 @@ #include "helpers/mf_ultralight_auth.h" #include "helpers/mf_user_dict.h" #include "helpers/mfkey32_logger.h" +#include "helpers/nfc_emv_parser.h" #include "helpers/mf_classic_key_cache.h" #include "helpers/nfc_supported_cards.h" diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c deleted file mode 100644 index 09eb804e5..000000000 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ /dev/null @@ -1,934 +0,0 @@ -/* - * Parser for EMV cards. - * - * Copyright 2023 Leptoptilos - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "core/string.h" -#include "furi_hal_rtc.h" -#include "nfc_supported_card_plugin.h" - -#include "protocols/emv/emv.h" -#include "protocols/nfc_protocol.h" -#include - -#include -#include - -#define TAG "EMV" - -char* get_country_name(uint16_t country_code) { - switch(country_code) { - case 0x0004: - return "AFG"; - case 0x0008: - return "ALB"; - case 0x0010: - return "ATA"; - case 0x0012: - return "DZA"; - case 0x0016: - return "ASM"; - case 0x0020: - return "AND"; - case 0x0024: - return "AGO"; - case 0x0028: - return "ATG"; - case 0x0031: - return "AZE"; - case 0x0032: - return "ARG"; - case 0x0036: - return "AUS"; - case 0x0040: - return "AUT"; - case 0x0044: - return "BHS"; - case 0x0048: - return "BHR"; - case 0x0050: - return "BGD"; - case 0x0051: - return "ARM"; - case 0x0052: - return "BRB"; - case 0x0056: - return "BEL"; - case 0x0060: - return "BMU"; - case 0x0064: - return "BTN"; - case 0x0068: - return "BOL"; - case 0x0070: - return "BIH"; - case 0x0072: - return "BWA"; - case 0x0074: - return "BVT"; - case 0x0076: - return "BRA"; - case 0x0084: - return "BLZ"; - case 0x0086: - return "IOT"; - case 0x0090: - return "SLB"; - case 0x0092: - return "VGB"; - case 0x0096: - return "BRN"; - case 0x0100: - return "BGR"; - case 0x0104: - return "MMR"; - case 0x0108: - return "BDI"; - case 0x0112: - return "BLR"; - case 0x0116: - return "KHM"; - case 0x0120: - return "CMR"; - case 0x0124: - return "CAN"; - case 0x0132: - return "CPV"; - case 0x0136: - return "CYM"; - case 0x0140: - return "CAF"; - case 0x0144: - return "LKA"; - case 0x0148: - return "TCD"; - case 0x0152: - return "CHL"; - case 0x0156: - return "CHN"; - case 0x0158: - return "TWN"; - case 0x0162: - return "CXR"; - case 0x0166: - return "CCK"; - case 0x0170: - return "COL"; - case 0x0174: - return "COM"; - case 0x0175: - return "MYT"; - case 0x0178: - return "COG"; - case 0x0180: - return "COD"; - case 0x0184: - return "COK"; - case 0x0188: - return "CRI"; - case 0x0191: - return "HRV"; - case 0x0192: - return "CUB"; - case 0x0196: - return "CYP"; - case 0x0203: - return "CZE"; - case 0x0204: - return "BEN"; - case 0x0208: - return "DNK"; - case 0x0212: - return "DMA"; - case 0x0214: - return "DOM"; - case 0x0218: - return "ECU"; - case 0x0222: - return "SLV"; - case 0x0226: - return "GNQ"; - case 0x0231: - return "ETH"; - case 0x0232: - return "ERI"; - case 0x0233: - return "EST"; - case 0x0234: - return "FRO"; - case 0x0238: - return "FLK"; - case 0x0239: - return "SGS"; - case 0x0242: - return "FJI"; - case 0x0246: - return "FIN"; - case 0x0248: - return "ALA"; - case 0x0250: - return "FRA"; - case 0x0254: - return "GUF"; - case 0x0258: - return "PYF"; - case 0x0260: - return "ATF"; - case 0x0262: - return "DJI"; - case 0x0266: - return "GAB"; - case 0x0268: - return "GEO"; - case 0x0270: - return "GMB"; - case 0x0275: - return "PSE"; - case 0x0276: - return "DEU"; - case 0x0288: - return "GHA"; - case 0x0292: - return "GIB"; - case 0x0296: - return "KIR"; - case 0x0300: - return "GRC"; - case 0x0304: - return "GRL"; - case 0x0308: - return "GRD"; - case 0x0312: - return "GLP"; - case 0x0316: - return "GUM"; - case 0x0320: - return "GTM"; - case 0x0324: - return "GIN"; - case 0x0328: - return "GUY"; - case 0x0332: - return "HTI"; - case 0x0334: - return "HMD"; - case 0x0336: - return "VAT"; - case 0x0340: - return "HND"; - case 0x0344: - return "HKG"; - case 0x0348: - return "HUN"; - case 0x0352: - return "ISL"; - case 0x0356: - return "IND"; - case 0x0360: - return "IDN"; - case 0x0364: - return "IRN"; - case 0x0368: - return "IRQ"; - case 0x0372: - return "IRL"; - case 0x0376: - return "ISR"; - case 0x0380: - return "ITA"; - case 0x0384: - return "CIV"; - case 0x0388: - return "JAM"; - case 0x0392: - return "JPN"; - case 0x0398: - return "KAZ"; - case 0x0400: - return "JOR"; - case 0x0404: - return "KEN"; - case 0x0408: - return "PRK"; - case 0x0410: - return "KOR"; - case 0x0414: - return "KWT"; - case 0x0417: - return "KGZ"; - case 0x0418: - return "LAO"; - case 0x0422: - return "LBN"; - case 0x0426: - return "LSO"; - case 0x0428: - return "LVA"; - case 0x0430: - return "LBR"; - case 0x0434: - return "LBY"; - case 0x0438: - return "LIE"; - case 0x0440: - return "LTU"; - case 0x0442: - return "LUX"; - case 0x0446: - return "MAC"; - case 0x0450: - return "MDG"; - case 0x0454: - return "MWI"; - case 0x0458: - return "MYS"; - case 0x0462: - return "MDV"; - case 0x0466: - return "MLI"; - case 0x0470: - return "MLT"; - case 0x0474: - return "MTQ"; - case 0x0478: - return "MRT"; - case 0x0480: - return "MUS"; - case 0x0484: - return "MEX"; - case 0x0492: - return "MCO"; - case 0x0496: - return "MNG"; - case 0x0498: - return "MDA"; - case 0x0499: - return "MNE"; - case 0x0500: - return "MSR"; - case 0x0504: - return "MAR"; - case 0x0508: - return "MOZ"; - case 0x0512: - return "OMN"; - case 0x0516: - return "NAM"; - case 0x0520: - return "NRU"; - case 0x0524: - return "NPL"; - case 0x0528: - return "NLD"; - case 0x0531: - return "CUW"; - case 0x0533: - return "ABW"; - case 0x0534: - return "SXM"; - case 0x0535: - return "BES"; - case 0x0540: - return "NCL"; - case 0x0548: - return "VUT"; - case 0x0554: - return "NZL"; - case 0x0558: - return "NIC"; - case 0x0562: - return "NER"; - case 0x0566: - return "NGA"; - case 0x0570: - return "NIU"; - case 0x0574: - return "NFK"; - case 0x0578: - return "NOR"; - case 0x0580: - return "MNP"; - case 0x0581: - return "UMI"; - case 0x0583: - return "FSM"; - case 0x0584: - return "MHL"; - case 0x0585: - return "PLW"; - case 0x0586: - return "PAK"; - case 0x0591: - return "PAN"; - case 0x0598: - return "PNG"; - case 0x0600: - return "PRY"; - case 0x0604: - return "PER"; - case 0x0608: - return "PHL"; - case 0x0612: - return "PCN"; - case 0x0616: - return "POL"; - case 0x0620: - return "PRT"; - case 0x0624: - return "GNB"; - case 0x0626: - return "TLS"; - case 0x0630: - return "PRI"; - case 0x0634: - return "QAT"; - case 0x0638: - return "REU"; - case 0x0642: - return "ROU"; - case 0x0643: - return "RUS"; - case 0x0646: - return "RWA"; - case 0x0652: - return "BLM"; - case 0x0654: - return "SHN"; - case 0x0659: - return "KNA"; - case 0x0660: - return "AIA"; - case 0x0662: - return "LCA"; - case 0x0663: - return "MAF"; - case 0x0666: - return "SPM"; - case 0x0670: - return "VCT"; - case 0x0674: - return "SMR"; - case 0x0678: - return "STP"; - case 0x0682: - return "SAU"; - case 0x0686: - return "SEN"; - case 0x0688: - return "SRB"; - case 0x0690: - return "SYC"; - case 0x0694: - return "SLE"; - case 0x0702: - return "SGP"; - case 0x0703: - return "SVK"; - case 0x0704: - return "VNM"; - case 0x0705: - return "SVN"; - case 0x0706: - return "SOM"; - case 0x0710: - return "ZAF"; - case 0x0716: - return "ZWE"; - case 0x0724: - return "ESP"; - case 0x0728: - return "SSD"; - case 0x0729: - return "SDN"; - case 0x0732: - return "ESH"; - case 0x0740: - return "SUR"; - case 0x0744: - return "SJM"; - case 0x0748: - return "SWZ"; - case 0x0752: - return "SWE"; - case 0x0756: - return "CHE"; - case 0x0760: - return "SYR"; - case 0x0762: - return "TJK"; - case 0x0764: - return "THA"; - case 0x0768: - return "TGO"; - case 0x0772: - return "TKL"; - case 0x0776: - return "TON"; - case 0x0780: - return "TTO"; - case 0x0784: - return "ARE"; - case 0x0788: - return "TUN"; - case 0x0792: - return "TUR"; - case 0x0795: - return "TKM"; - case 0x0796: - return "TCA"; - case 0x0798: - return "TUV"; - case 0x0800: - return "UGA"; - case 0x0804: - return "UKR"; - case 0x0807: - return "MKD"; - case 0x0818: - return "EGY"; - case 0x0826: - return "GBR"; - case 0x0831: - return "GGY"; - case 0x0832: - return "JEY"; - case 0x0833: - return "IMN"; - case 0x0834: - return "TZA"; - case 0x0840: - return "USA"; - case 0x0850: - return "VIR"; - case 0x0854: - return "BFA"; - case 0x0858: - return "URY"; - case 0x0860: - return "UZB"; - case 0x0862: - return "VEN"; - case 0x0876: - return "WLF"; - case 0x0882: - return "WSM"; - case 0x0887: - return "YEM"; - case 0x0894: - return "ZMB"; - default: - return "UNKNOWN"; - } -} - -char* get_currency_name(uint16_t currency_code) { - switch(currency_code) { - case 0x0997: - return "USN"; - case 0x0994: - return "XSU"; - case 0x0990: - return "CLF"; - case 0x0986: - return "BRL"; - case 0x0985: - return "PLN"; - case 0x0984: - return "BOV"; - case 0x0981: - return "GEL"; - case 0x0980: - return "UAH"; - case 0x0979: - return "MXV"; - case 0x0978: - return "EUR"; - case 0x0977: - return "BAM"; - case 0x0976: - return "CDF"; - case 0x0975: - return "BGN"; - case 0x0973: - return "AOA"; - case 0x0972: - return "TJS"; - case 0x0971: - return "AFN"; - case 0x0970: - return "COU"; - case 0x0969: - return "MGA"; - case 0x0968: - return "SRD"; - case 0x0967: - return "ZMW"; - case 0x0965: - return "XUA"; - case 0x0960: - return "XDR"; - case 0x0953: - return "XPF"; - case 0x0952: - return "XOF"; - case 0x0951: - return "XCD"; - case 0x0950: - return "XAF"; - case 0x0949: - return "TRY"; - case 0x0948: - return "CHW"; - case 0x0947: - return "CHE"; - case 0x0946: - return "RON"; - case 0x0944: - return "AZN"; - case 0x0943: - return "MZN"; - case 0x0941: - return "RSD"; - case 0x0940: - return "UYI"; - case 0x0938: - return "SDG"; - case 0x0937: - return "VEF"; - case 0x0936: - return "GHS"; - case 0x0934: - return "TMT"; - case 0x0933: - return "BYN"; - case 0x0932: - return "ZWL"; - case 0x0931: - return "CUC"; - case 0x0930: - return "STN"; - case 0x0929: - return "MRU"; - case 0x0901: - return "TWD"; - case 0x0886: - return "YER"; - case 0x0882: - return "WST"; - case 0x0860: - return "UZS"; - case 0x0858: - return "UYU"; - case 0x0840: - return "USD"; - case 0x0834: - return "TZS"; - case 0x0826: - return "GBP"; - case 0x0818: - return "EGP"; - case 0x0807: - return "MKD"; - case 0x0800: - return "UGX"; - case 0x0788: - return "TND"; - case 0x0784: - return "AED"; - case 0x0780: - return "TTD"; - case 0x0776: - return "TOP"; - case 0x0764: - return "THB"; - case 0x0760: - return "SYP"; - case 0x0756: - return "CHF"; - case 0x0752: - return "SEK"; - case 0x0748: - return "SZL"; - case 0x0728: - return "SSP"; - case 0x0710: - return "ZAR"; - case 0x0706: - return "SOS"; - case 0x0704: - return "VND"; - case 0x0702: - return "SGD"; - case 0x0694: - return "SLL"; - case 0x0690: - return "SCR"; - case 0x0682: - return "SAR"; - case 0x0654: - return "SHP"; - case 0x0646: - return "RWF"; - case 0x0643: - return "RUB"; - case 0x0634: - return "QAR"; - case 0x0608: - return "PHP"; - case 0x0604: - return "PEN"; - case 0x0600: - return "PYG"; - case 0x0598: - return "PGK"; - case 0x0590: - return "PAB"; - case 0x0586: - return "PKR"; - case 0x0578: - return "NOK"; - case 0x0566: - return "NGN"; - case 0x0558: - return "NIO"; - case 0x0554: - return "NZD"; - case 0x0548: - return "VUV"; - case 0x0533: - return "AWG"; - case 0x0532: - return "ANG"; - case 0x0524: - return "NPR"; - case 0x0516: - return "NAD"; - case 0x0512: - return "OMR"; - case 0x0504: - return "MAD"; - case 0x0498: - return "MDL"; - case 0x0496: - return "MNT"; - case 0x0484: - return "MXN"; - case 0x0480: - return "MUR"; - case 0x0462: - return "MVR"; - case 0x0458: - return "MYR"; - case 0x0454: - return "MWK"; - case 0x0446: - return "MOP"; - case 0x0434: - return "LYD"; - case 0x0430: - return "LRD"; - case 0x0426: - return "LSL"; - case 0x0422: - return "LBP"; - case 0x0418: - return "LAK"; - case 0x0417: - return "KGS"; - case 0x0414: - return "KWD"; - case 0x0410: - return "KRW"; - case 0x0408: - return "KPW"; - case 0x0404: - return "KES"; - case 0x0400: - return "JOD"; - case 0x0398: - return "KZT"; - case 0x0392: - return "JPY"; - case 0x0388: - return "JMD"; - case 0x0376: - return "ILS"; - case 0x0368: - return "IQD"; - case 0x0364: - return "IRR"; - case 0x0360: - return "IDR"; - case 0x0356: - return "INR"; - case 0x0352: - return "ISK"; - case 0x0348: - return "HUF"; - case 0x0344: - return "HKD"; - case 0x0340: - return "HNL"; - case 0x0332: - return "HTG"; - case 0x0328: - return "GYD"; - case 0x0324: - return "GNF"; - case 0x0320: - return "GTQ"; - case 0x0292: - return "GIP"; - case 0x0270: - return "GMD"; - case 0x0262: - return "DJF"; - case 0x0242: - return "FJD"; - case 0x0238: - return "FKP"; - case 0x0232: - return "ERN"; - case 0x0230: - return "ETB"; - case 0x0222: - return "SVC"; - case 0x0214: - return "DOP"; - case 0x0208: - return "DKK"; - case 0x0203: - return "CZK"; - case 0x0192: - return "CUP"; - case 0x0191: - return "HRK"; - case 0x0188: - return "CRC"; - case 0x0174: - return "KMF"; - case 0x0170: - return "COP"; - case 0x0156: - return "CNY"; - case 0x0152: - return "CLP"; - case 0x0144: - return "LKR"; - case 0x0136: - return "KYD"; - case 0x0132: - return "CVE"; - case 0x0124: - return "CAD"; - case 0x0116: - return "KHR"; - case 0x0108: - return "BIF"; - case 0x0104: - return "MMK"; - case 0x0096: - return "BND"; - case 0x0090: - return "SBD"; - case 0x0084: - return "BZD"; - case 0x0072: - return "BWP"; - case 0x0068: - return "BOB"; - case 0x0064: - return "BTN"; - case 0x0060: - return "BMD"; - case 0x0052: - return "BBD"; - case 0x0051: - return "AMD"; - case 0x0050: - return "BDT"; - case 0x0048: - return "BHD"; - case 0x0044: - return "BSD"; - case 0x0036: - return "AUD"; - case 0x0032: - return "ARS"; - case 0x0012: - return "DZD"; - case 0x0008: - return "ALL"; - default: - return "UNKNOWN"; - } -} - -static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { - furi_assert(device); - bool parsed = false; - - const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv); - const EmvApplication app = data->emv_application; - - do { - if(app.name_found) - furi_string_cat_printf(parsed_data, "\e#%s\n", app.name); - else - furi_string_cat_printf(parsed_data, "\e#%s\n", "EMV"); - - FuriString* card_number = furi_string_alloc(); - for(uint8_t i = 0; i < app.pan_len; i += 2) { - furi_string_cat_printf(card_number, "%02X%02X ", app.pan[i], app.pan[i + 1]); - } - - // Cut padding 'F' from card number - size_t end = furi_string_search_rchar(card_number, 'F'); - if(end) furi_string_left(card_number, end); - furi_string_cat(parsed_data, card_number); - furi_string_free(card_number); - - furi_string_cat_printf(parsed_data, "\nExp: %02X/%02X", app.exp_month, app.exp_year); - - furi_string_cat_printf(parsed_data, "\nCountry: %s", get_country_name(app.country_code)); - furi_string_cat_printf( - parsed_data, " Currency: %s", get_currency_name(app.currency_code)); - - parsed = true; - } while(false); - - return parsed; -} - -/* Actual implementation of app<>plugin interface */ -static const NfcSupportedCardsPlugin emv_plugin = { - .protocol = NfcProtocolEmv, - .verify = NULL, - .read = NULL, - .parse = emv_parse, -}; - -/* Plugin descriptor to comply with basic plugin specification */ -static const FlipperAppPluginDescriptor emv_plugin_descriptor = { - .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, - .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, - .entry_point = &emv_plugin, -}; - -/* Plugin entry point - must return a pointer to const descriptor */ -const FlipperAppPluginDescriptor* emv_plugin_ep() { - return &emv_plugin_descriptor; -} \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_emv_more_info.c b/applications/main/nfc/scenes/nfc_scene_emv_more_info.c index 5825190d1..0cddce20a 100644 --- a/applications/main/nfc/scenes/nfc_scene_emv_more_info.c +++ b/applications/main/nfc/scenes/nfc_scene_emv_more_info.c @@ -9,7 +9,7 @@ enum { }; enum SubmenuIndex { - SubmenuIndexCardInfo, + SubmenuIndexTransactions, SubmenuIndexDynamic, // dynamic indices start here }; @@ -21,8 +21,8 @@ void nfc_scene_emv_more_info_on_enter(void* context) { submenu_add_item( submenu, - "Card info", - SubmenuIndexCardInfo, + "Transactions", + SubmenuIndexTransactions, nfc_protocol_support_common_submenu_callback, nfc); @@ -37,17 +37,17 @@ bool nfc_scene_emv_more_info_on_event(void* context, SceneManagerEvent event) { const EmvData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolEmv); if(event.type == SceneManagerEventTypeCustom) { - TextBox* text_box = nfc->text_box; - furi_string_reset(nfc->text_box_store); - - if(event.event == SubmenuIndexCardInfo) { - nfc_render_emv_data(data, nfc->text_box_store); - text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + if(event.event == SubmenuIndexTransactions) { + FuriString* temp_str = furi_string_alloc(); + nfc_render_emv_transactions(&data->emv_application, temp_str); + widget_add_text_scroll_element( + nfc->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); scene_manager_set_scene_state( nfc->scene_manager, NfcSceneEmvMoreInfo, - EmvMoreInfoStateItem + SubmenuIndexCardInfo); + EmvMoreInfoStateItem + SubmenuIndexTransactions); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { @@ -69,7 +69,6 @@ void nfc_scene_emv_more_info_on_exit(void* context) { NfcApp* nfc = context; // Clear views - text_box_reset(nfc->text_box); - furi_string_reset(nfc->text_box_store); + widget_reset(nfc->widget); submenu_reset(nfc->submenu); }