|
|
@@ -22,6 +22,17 @@ int select_new_app(
|
|
|
|
|
|
bit_buffer_reset(tx_buffer);
|
|
|
bit_buffer_append_bytes(tx_buffer, select_app, sizeof(select_app));
|
|
|
+ FURI_LOG_D(
|
|
|
+ TAG,
|
|
|
+ "SEND %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
|
+ select_app[0],
|
|
|
+ select_app[1],
|
|
|
+ select_app[2],
|
|
|
+ select_app[3],
|
|
|
+ select_app[4],
|
|
|
+ select_app[5],
|
|
|
+ select_app[6],
|
|
|
+ select_app[7]);
|
|
|
int error = iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
|
|
|
if(error != Iso14443_4bErrorNone) {
|
|
|
FURI_LOG_I(TAG, "Select File: iso14443_4b_poller_send_block error %d", error);
|
|
|
@@ -42,6 +53,14 @@ int read_new_file(
|
|
|
read_file[2] = new_file;
|
|
|
bit_buffer_reset(tx_buffer);
|
|
|
bit_buffer_append_bytes(tx_buffer, read_file, sizeof(read_file));
|
|
|
+ FURI_LOG_D(
|
|
|
+ TAG,
|
|
|
+ "SEND %02x %02x %02x %02x %02x",
|
|
|
+ read_file[0],
|
|
|
+ read_file[1],
|
|
|
+ read_file[2],
|
|
|
+ read_file[3],
|
|
|
+ read_file[4]);
|
|
|
Iso14443_4bError error =
|
|
|
iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
|
|
|
if(error != Iso14443_4bErrorNone) {
|
|
|
@@ -61,11 +80,14 @@ int check_response(
|
|
|
*response_length = bit_buffer_get_size_bytes(rx_buffer);
|
|
|
if(bit_buffer_get_byte(rx_buffer, *response_length - 2) != apdu_success[0] ||
|
|
|
bit_buffer_get_byte(rx_buffer, *response_length - 1) != apdu_success[1]) {
|
|
|
- FURI_LOG_I(
|
|
|
- TAG,
|
|
|
- "Select profile app/file failed: %02x%02x",
|
|
|
- bit_buffer_get_byte(rx_buffer, *response_length - 2),
|
|
|
- bit_buffer_get_byte(rx_buffer, *response_length - 1));
|
|
|
+ int error_code_1 = bit_buffer_get_byte(rx_buffer, *response_length - 2);
|
|
|
+ int error_code_2 = bit_buffer_get_byte(rx_buffer, *response_length - 1);
|
|
|
+ FURI_LOG_E(TAG, "Select profile app/file failed: %02x%02x", error_code_1, error_code_2);
|
|
|
+ if(error_code_1 == 0x6a && error_code_2 == 0x82) {
|
|
|
+ FURI_LOG_E(TAG, "Wrong parameter(s) P1-P2 - File not found");
|
|
|
+ } else if(error_code_1 == 0x69 && error_code_2 == 0x82) {
|
|
|
+ FURI_LOG_E(TAG, "Command not allowed - Security status not satisfied");
|
|
|
+ }
|
|
|
*stage = MetroflipPollerEventTypeFail;
|
|
|
view_dispatcher_send_custom_event(
|
|
|
app->view_dispatcher, MetroflipCustomEventPollerFileNotFound);
|
|
|
@@ -203,13 +225,13 @@ const char* get_navigo_type(int type) {
|
|
|
const char* get_tariff(int tariff) {
|
|
|
switch(tariff) {
|
|
|
case 0x0000:
|
|
|
- return "Navigo Mois"; // Theoric
|
|
|
+ return "Navigo Mois";
|
|
|
case 0x0001:
|
|
|
- return "Navigo Semaine"; // Theoric
|
|
|
+ return "Navigo Semaine";
|
|
|
case 0x0002:
|
|
|
return "Navigo Annuel";
|
|
|
case 0x0003:
|
|
|
- return "Navigo Jour"; // Theoric
|
|
|
+ return "Navigo Jour";
|
|
|
case 0x0004:
|
|
|
return "Imagine R Junior";
|
|
|
case 0x0005:
|
|
|
@@ -220,6 +242,10 @@ const char* get_tariff(int tariff) {
|
|
|
return "Paris-Visite"; // Theoric
|
|
|
case 0x1000:
|
|
|
return "Navigo Liberte+";
|
|
|
+ case 0x4000:
|
|
|
+ return "Navigo Mois 75%%";
|
|
|
+ case 0x4001:
|
|
|
+ return "Navigo Semaine 75%%";
|
|
|
case 0x4015:
|
|
|
return "Paris-Visite (Enfant)"; // Theoric
|
|
|
case 0x5000:
|
|
|
@@ -242,6 +268,8 @@ const char* get_tariff(int tariff) {
|
|
|
return "Metro-Train-RER (Reduit)"; // Theoric
|
|
|
case 0x501b:
|
|
|
return "Paris <> Aeroports (Reduit)"; // Theoric
|
|
|
+ case 0x8003:
|
|
|
+ return "Navigo Solidarite Gratuit";
|
|
|
default: {
|
|
|
char* tariff_str = malloc(6 * sizeof(char));
|
|
|
snprintf(tariff_str, 6, "%d", tariff);
|
|
|
@@ -582,7 +610,11 @@ void show_contract_info(NavigoCardContract* contract, FuriString* parsed_data) {
|
|
|
furi_string_cat_printf(
|
|
|
parsed_data, "Sales Agent: %s\n", get_service_provider(contract->sale_agent));
|
|
|
furi_string_cat_printf(parsed_data, "Sales Terminal: %d\n", contract->sale_device);
|
|
|
- furi_string_cat_printf(parsed_data, "Status: %d\n", contract->status);
|
|
|
+ if(contract->status == 1) {
|
|
|
+ furi_string_cat_printf(parsed_data, "Status: OK\n");
|
|
|
+ } else {
|
|
|
+ furi_string_cat_printf(parsed_data, "Status: Unknown (%d)\n", contract->status);
|
|
|
+ }
|
|
|
furi_string_cat_printf(parsed_data, "Authenticity Code: %d\n", contract->authenticator);
|
|
|
}
|
|
|
|
|
|
@@ -832,20 +864,34 @@ static NfcCommand metroflip_scene_navigo_poller_callback(NfcGenericEvent event,
|
|
|
}
|
|
|
icc_bit_representation[response_length * 8] = '\0';
|
|
|
|
|
|
- FURI_LOG_I(TAG, "ICC bit representation: %s", icc_bit_representation);
|
|
|
-
|
|
|
int start = 128, end = 159;
|
|
|
card->card_number = bit_slice_to_dec(icc_bit_representation, start, end);
|
|
|
|
|
|
+ // Select app for ticketing
|
|
|
+ error = select_new_app(
|
|
|
+ 0x20, 0x00, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
|
|
|
+ if(error != 0) {
|
|
|
+ FURI_LOG_E(TAG, "Failed to select app for ticketing");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check the response after selecting app
|
|
|
+ if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
|
|
|
+ FURI_LOG_E(TAG, "Failed to check response after selecting app for ticketing");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
// Select app for contracts
|
|
|
error = select_new_app(
|
|
|
0x20, 0x20, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
|
|
|
if(error != 0) {
|
|
|
+ FURI_LOG_E(TAG, "Failed to select app for contracts");
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
// Check the response after selecting app
|
|
|
if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
|
|
|
+ FURI_LOG_E(TAG, "Failed to check response after selecting app for contracts");
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
@@ -861,11 +907,13 @@ static NfcCommand metroflip_scene_navigo_poller_callback(NfcGenericEvent event,
|
|
|
error =
|
|
|
read_new_file(i, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
|
|
|
if(error != 0) {
|
|
|
+ FURI_LOG_E(TAG, "Failed to read contract %d", i);
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
// Check the response after reading the file
|
|
|
if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
|
|
|
+ FURI_LOG_E(TAG, "Failed to check response after reading contract %d", i);
|
|
|
break;
|
|
|
}
|
|
|
|