Skip to content

Commit

Permalink
Latest RM0218-1205-0.420.0-7bb30bf on PATREON - UPD METROFLIP
Browse files Browse the repository at this point in the history
  • Loading branch information
RogueMaster committed Feb 20, 2025
2 parents 8cca7f8 + d6894d0 commit 373b1d4
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 1 deletion.
1 change: 1 addition & 0 deletions ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ This software is for experimental purposes only and is not meant for any illegal
- Updated: [DeadZone v0.1 (By retrooper)](https://github.com/retrooper/deadzone)
- Updated: [Cross Remote v3.2 (By leedave)](https://github.com/leedave/flipper-zero-cross-remote)
- OFW: [Furi, USB, BLE, Debug: various bug fixes and improvements #4114 (By skotopes)](https://github.com/flipperdevices/flipperzero-firmware/pull/4114)
- Updated: [Metroflip v0.6 (By luu176)](https://github.com/luu176/Metroflip)
- OFW TO ADD: [Storage: remove LFS #3577](https://github.com/flipperdevices/flipperzero-firmware/pull/3577) [FuriEventLoop Pt.2 #3703](https://github.com/flipperdevices/flipperzero-firmware/pull/3703) [#3824](https://github.com/flipperdevices/flipperzero-firmware/pull/3824) [#3836](https://github.com/flipperdevices/flipperzero-firmware/pull/3836) [#3834](https://github.com/flipperdevices/flipperzero-firmware/pull/3834) [#3837](https://github.com/flipperdevices/flipperzero-firmware/pull/3837) [#3849](https://github.com/flipperdevices/flipperzero-firmware/pull/3849) [#3879](https://github.com/flipperdevices/flipperzero-firmware/pull/3879) [#3875](https://github.com/flipperdevices/flipperzero-firmware/pull/3875) [#3863](https://github.com/flipperdevices/flipperzero-firmware/pull/3863) [#3866](https://github.com/flipperdevices/flipperzero-firmware/pull/3866) [#3865](https://github.com/flipperdevices/flipperzero-firmware/pull/3865) [#3887](https://github.com/flipperdevices/flipperzero-firmware/pull/3887) [#3892](https://github.com/flipperdevices/flipperzero-firmware/pull/3892) [#3909](https://github.com/flipperdevices/flipperzero-firmware/pull/3909) [#3881](https://github.com/flipperdevices/flipperzero-firmware/pull/3881) [#3942](https://github.com/flipperdevices/flipperzero-firmware/pull/3942) [#3841](https://github.com/flipperdevices/flipperzero-firmware/pull/3841) [#3950](https://github.com/flipperdevices/flipperzero-firmware/pull/3950) [#3952](https://github.com/flipperdevices/flipperzero-firmware/pull/3952) [#3958](https://github.com/flipperdevices/flipperzero-firmware/pull/3958) [#3963](https://github.com/flipperdevices/flipperzero-firmware/pull/3963) [#3971](https://github.com/flipperdevices/flipperzero-firmware/pull/3971) [#3961](https://github.com/flipperdevices/flipperzero-firmware/pull/3961) [#3906](https://github.com/flipperdevices/flipperzero-firmware/pull/3906) [#3978](https://github.com/flipperdevices/flipperzero-firmware/pull/3978) [#3980](https://github.com/flipperdevices/flipperzero-firmware/pull/3980) [#3979](https://github.com/flipperdevices/flipperzero-firmware/pull/3979) [#4040](https://github.com/flipperdevices/flipperzero-firmware/pull/4040) [#3996](https://github.com/flipperdevices/flipperzero-firmware/pull/3996) [#4043](https://github.com/flipperdevices/flipperzero-firmware/pull/4043) [#4075](https://github.com/flipperdevices/flipperzero-firmware/pull/4075) [#4109](https://github.com/flipperdevices/flipperzero-firmware/pull/4109)

<a name="release">
Expand Down
9 changes: 9 additions & 0 deletions applications/external/metroflip/application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,15 @@ App(
fal_embedded=True,
)

App(
appid="gocard_plugin",
apptype=FlipperAppType.PLUGIN,
entry_point="gocard_plugin_ep",
requires=["metroflip"],
sources=["scenes/plugins/gocard.c"],
fal_embedded=True,
)

App(
appid="suica_plugin",
apptype=FlipperAppType.PLUGIN,
Expand Down
35 changes: 35 additions & 0 deletions applications/external/metroflip/scenes/keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ const MfClassicKeyPair metromoney_1k_verify_key[] = {
{.a = 0x9C616585E26D},
};

const uint8_t gocard_verify_data[1][14] = {
{0x16, 0x18, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x5A, 0x5B, 0x20, 0x21, 0x22, 0x23}};

const uint8_t gocard_verify_data2[1][14] = {
{0x16, 0x18, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x01, 0x01}};

static bool charliecard_verify(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) {
bool verified = false;
FURI_LOG_I(TAG, "verifying charliecard..");
Expand Down Expand Up @@ -244,6 +250,33 @@ static bool troika_verify(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) {
troika_verify_type(nfc, mfc_data, data_loaded, MfClassicType4k);
}

static bool gocard_verify(MfClassicData* mfc_data, bool data_loaded) {
bool verified = false;
FURI_LOG_I(TAG, "verifying charliecard..");
do {
if(data_loaded) {
uint8_t* buffer = &mfc_data->block[1].data[1];
size_t buffer_size = 14;

if(memcmp(buffer, gocard_verify_data[0], buffer_size) == 0) {
FURI_LOG_I(TAG, "Match!");
} else {
FURI_LOG_I(TAG, "No match.");
if(memcmp(buffer, gocard_verify_data2[0], buffer_size) == 0) {
FURI_LOG_I(TAG, "Match!");
} else {
FURI_LOG_I(TAG, "No match.");
break;
}
}

verified = true;
}
} while(false);

return verified;
}

CardType determine_card_type(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded) {
FURI_LOG_I(TAG, "checking keys..");
UNUSED(bip_verify);
Expand All @@ -258,6 +291,8 @@ CardType determine_card_type(Nfc* nfc, MfClassicData* mfc_data, bool data_loaded
return CARD_TYPE_TROIKA;
} else if(charliecard_verify(nfc, mfc_data, data_loaded)) {
return CARD_TYPE_CHARLIECARD;
} else if(gocard_verify(mfc_data, data_loaded)) {
return CARD_TYPE_GOCARD;
} else {
FURI_LOG_I(TAG, "its unknown");
return CARD_TYPE_UNKNOWN;
Expand Down
4 changes: 3 additions & 1 deletion applications/external/metroflip/scenes/keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ typedef enum {
CARD_TYPE_CHARLIECARD,
CARD_TYPE_SMARTRIDER,
CARD_TYPE_TROIKA,
CARD_TYPE_GOCARD,
CARD_TYPE_UNKNOWN
} CardType;

Expand All @@ -28,9 +29,10 @@ typedef struct {

extern const MfClassicKeyPair troika_1k_keys[16];
extern const MfClassicKeyPair troika_4k_keys[40];
extern const uint8_t SMARTRIDER_STANDARD_KEYS[3][6];
extern const MfClassicKeyPair charliecard_1k_keys[16];
extern const MfClassicKeyPair bip_1k_keys[16];
extern const MfClassicKeyPair metromoney_1k_keys[16];
extern const uint8_t gocard_verify_data[1][14];
extern const uint8_t gocard_verify_data2[1][14];

#endif // KEYS_H
4 changes: 4 additions & 0 deletions applications/external/metroflip/scenes/metroflip_scene_load.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ void metroflip_scene_load_on_enter(void* context) {
app->card_type = "troika";
FURI_LOG_I(TAG, "Detected: Troika\n");
break;
case CARD_TYPE_GOCARD:
app->card_type = "gocard";
FURI_LOG_I(TAG, "Detected: go card\n");
break;
case CARD_TYPE_UNKNOWN:
app->card_type = "unknown";
//popup_set_header(popup, "Unsupported\n card", 58, 31, AlignLeft, AlignTop);
Expand Down
183 changes: 183 additions & 0 deletions applications/external/metroflip/scenes/plugins/gocard.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@

#include <flipper_application.h>
#include "../../metroflip_i.h"

#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
#include <nfc/protocols/mf_classic/mf_classic.h>
#include <nfc/protocols/mf_classic/mf_classic_poller.h>

#include <dolphin/dolphin.h>
#include <bit_lib.h>
#include <furi_hal.h>
#include <nfc/nfc.h>
#include <nfc/nfc_device.h>
#include <nfc/nfc_listener.h>
#include "../../api/metroflip/metroflip_api.h"
#include "../../metroflip_plugins.h"

#define TAG "Metroflip:Scene:gocard"

unsigned short byteArrayToIntReversed(unsigned int dec1, unsigned int dec2) {
unsigned char byte1 = (unsigned char)dec1;
unsigned char byte2 = (unsigned char)dec2;
return ((unsigned short)byte2 << 8) | byte1;
}

static bool gocard_parse(FuriString* parsed_data, const MfClassicData* data) {
bool parsed = false;

do {
// Verify key
//const uint8_t ticket_sector_number = 1;
//const uint8_t ticket_block_number = 1;

//const MfClassicSectorTrailer* sec_tr =
// mf_classic_get_sector_trailer_by_sector(data, ticket_sector_number);

//const uint64_t key =
// bit_lib_bytes_to_num_be(sec_tr->key_a.data, COUNT_OF(sec_tr->key_a.data));
///if(key != gocard_1k_keys[ticket_sector_number].a) break;
//FURI_LOG_D(TAG, "passed key check");
// Parse data
//const uint8_t start_block_num =
// mf_classic_get_first_block_num_of_sector(ticket_sector_number);

//const uint8_t* block_start_ptr =
// &data->block[start_block_num + ticket_block_number].data[0];

//uint32_t balance = bit_lib_bytes_to_num_le(block_start_ptr, 4) - 100;

//uint32_t balance_lari = balance / 100;
//uint8_t balance_tetri = balance % 100;

int balance_slot = 4;

if(data->block[balance_slot].data[13] <= data->block[balance_slot + 1].data[13])
balance_slot++;

unsigned short balancecents = byteArrayToIntReversed(
data->block[balance_slot].data[2], data->block[balance_slot].data[3]);

// Check if the sign flag is set in 'balance'
if((balancecents & 0x8000) == 0x8000) {
balancecents = balancecents & 0x7fff; // Clear the sign flag.
balancecents *= -1; // Negate the balance.
}
// Otherwise, check the sign flag in data->block[4].data[1]
else if((data->block[balance_slot].data[1] & 0x80) == 0x80) {
// seq_go uses a sign flag in an adjacent byte.
balancecents *= -1;
}

double balance = balancecents / 100.0;
furi_string_printf(parsed_data, "\e#Go card\nValue: A$%.2f\n", balance);

parsed = true;
} while(false);

return parsed;
}

static void gocard_on_enter(Metroflip* app) {
dolphin_deed(DolphinDeedNfcRead);

app->sec_num = 0;

if(app->data_loaded) {
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* ff = flipper_format_file_alloc(storage);
if(flipper_format_file_open_existing(ff, app->file_path)) {
MfClassicData* mfc_data = mf_classic_alloc();
mf_classic_load(mfc_data, ff, 2);
FuriString* parsed_data = furi_string_alloc();
Widget* widget = app->widget;

furi_string_reset(app->text_box_store);
if(!gocard_parse(parsed_data, mfc_data)) {
furi_string_reset(app->text_box_store);
FURI_LOG_I(TAG, "Unknown card type");
furi_string_printf(parsed_data, "\e#Unknown card\n");
}
widget_add_text_scroll_element(
widget, 0, 0, 128, 64, furi_string_get_cstr(parsed_data));

widget_add_button_element(
widget, GuiButtonTypeRight, "Exit", metroflip_exit_widget_callback, app);
widget_add_button_element(
widget, GuiButtonTypeCenter, "Delete", metroflip_delete_widget_callback, app);
mf_classic_free(mfc_data);
furi_string_free(parsed_data);
view_dispatcher_switch_to_view(app->view_dispatcher, MetroflipViewWidget);
}
flipper_format_free(ff);
} else {
// Setup view
Popup* popup = app->popup;
popup_set_header(popup, "unsupported", 68, 30, AlignLeft, AlignTop);
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
}
}

static bool gocard_on_event(Metroflip* app, SceneManagerEvent event) {
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) {
if(event.event == MetroflipCustomEventCardDetected) {
Popup* popup = app->popup;
popup_set_header(popup, "DON'T\nMOVE", 68, 30, AlignLeft, AlignTop);
consumed = true;
} else if(event.event == MetroflipCustomEventCardLost) {
Popup* popup = app->popup;
popup_set_header(popup, "Card \n lost", 68, 30, AlignLeft, AlignTop);
consumed = true;
} else if(event.event == MetroflipCustomEventWrongCard) {
Popup* popup = app->popup;
popup_set_header(popup, "WRONG \n CARD", 68, 30, AlignLeft, AlignTop);
consumed = true;
} else if(event.event == MetroflipCustomEventPollerFail) {
Popup* popup = app->popup;
popup_set_header(popup, "Failed", 68, 30, AlignLeft, AlignTop);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, MetroflipSceneStart);
consumed = true;
}

return consumed;
}

static void gocard_on_exit(Metroflip* app) {
widget_reset(app->widget);

if(app->poller && !app->data_loaded) {
nfc_poller_stop(app->poller);
nfc_poller_free(app->poller);
}

// Clear view
popup_reset(app->popup);

metroflip_app_blink_stop(app);
}

/* Actual implementation of app<>plugin interface */
static const MetroflipPlugin gocard_plugin = {
.card_name = "gocard",
.plugin_on_enter = gocard_on_enter,
.plugin_on_event = gocard_on_event,
.plugin_on_exit = gocard_on_exit,

};

/* Plugin descriptor to comply with basic plugin specification */
static const FlipperAppPluginDescriptor gocard_plugin_descriptor = {
.appid = METROFLIP_SUPPORTED_CARD_PLUGIN_APP_ID,
.ep_api_version = METROFLIP_SUPPORTED_CARD_PLUGIN_API_VERSION,
.entry_point = &gocard_plugin,
};

/* Plugin entry point - must return a pointer to const descriptor */
const FlipperAppPluginDescriptor* gocard_plugin_ep(void) {
return &gocard_plugin_descriptor;
}

0 comments on commit 373b1d4

Please sign in to comment.