forked from flipperdevices/flipperzero-firmware
-
-
Notifications
You must be signed in to change notification settings - Fork 547
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Squashed 'applications/external/' changes from 6d33a43ab56..7a7f74be1ad
7a7f74be1ad T5577 Raw Writer: Use system icon c3b24c90bb5 Format 6453eadc700 Add t5577_raw_writer from https://github.com/zinongli/T5577_Raw_Writer 38502d54598 Merge seader from https://github.com/xMasterX/all-the-plugins e41dcd8e0e6 Merge seader from https://github.com/bettse/seader dc8494512d4 Merge qrcode from https://github.com/bmatcuk/flipperzero-qrcode a730651 Merge branch 'main' of https://github.com/zinongli/T5577_Raw_Writer a154ac8 update about screen 5a14b8f Revert "why not allowing changes to block 0" d337057 Update README.md 374c5a6 Merge branch 'main' of https://github.com/zinongli/T5577_Raw_Writer c7d8ec0 why not allowing changes to block 0 51ee3ef Merge pull request #7 from zinongli/config_rework c0cc986 fixed issue. add/edit manually live 6a752e9 byte input functioning but can't be saved yet 13279fb restart add manually. views added. 47e7438 clean up and update comments 55538af clean ups cbb366c clean ups 88aef3b Update README.md 1fb14cc Update README.md b8f459c Merge pull request #5 from zinongli/popup 6222b01 minot calculation debug e2db89b Merge pull request #3 from zinongli/popup e0f9031 success screen added c1ea848 Merge pull request #2 from zinongli/popup 7a9ab7d Writing ends after 3 second. Config memory loss fixed. d86debe07cf fix e0d2ee8564e upd seader 33b687f writing gui 58c9b45 update to firmware 0.104.0 f054082 example file 28fd381 uncreative fap icon 9e95c2c Update app name 4157699 branch managing e69c75a initial df8738a Initial commit 21223f1 Remove unrolling in loclass to save space in memory 3adb8d0 Remove redundant setting of credential type 227c6b8 Improve debug logging 16fa7cd Check for SeaderPollerEventTypeFail b28f155 typo 493c703 Merge pull request #21 from bettse/apdu_runner 6002037 dry up sam_present call to save ui state 5643b32 reudce SeaderUartTxWorker stack 8b65648 APDURunner b5c45a9 more use of malloc 0d677d5 use malloc for seader_send_apdu 4aaef3d Dry up seader_send_t1 and use malloc 61724f9 Move display array into function using it e58f5ef812f upd seader 3361e70 Merge pull request #20 from bettse/t_1 29f36f5 T=1 support git-subtree-dir: applications/external git-subtree-split: 7a7f74be1adbdc8f901c5f92d19460f75f105197
- Loading branch information
1 parent
58686c1
commit 4a9b439
Showing
37 changed files
with
1,807 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
#include "apdu_log.h" | ||
|
||
#include <storage/storage.h> | ||
#include <flipper_format/flipper_format.h> | ||
#include <toolbox/stream/file_stream.h> | ||
#include <toolbox/stream/buffered_file_stream.h> | ||
#include <toolbox/args.h> | ||
|
||
#define TAG "APDULog" | ||
|
||
struct APDULog { | ||
Stream* stream; | ||
size_t total_lines; | ||
}; | ||
|
||
static inline void apdu_log_add_ending_new_line(APDULog* instance) { | ||
if(stream_seek(instance->stream, -1, StreamOffsetFromEnd)) { | ||
uint8_t last_char = 0; | ||
|
||
// Check if the last char is new line or add a new line | ||
if(stream_read(instance->stream, &last_char, 1) == 1 && last_char != '\n') { | ||
FURI_LOG_D(TAG, "Adding new line ending"); | ||
stream_write_char(instance->stream, '\n'); | ||
} | ||
|
||
stream_rewind(instance->stream); | ||
} | ||
} | ||
|
||
static bool apdu_log_read_log_line(APDULog* instance, FuriString* line, bool* is_endfile) { | ||
if(stream_read_line(instance->stream, line) == false) { | ||
*is_endfile = true; | ||
} | ||
|
||
else { | ||
size_t newline_index = furi_string_search_char(line, '\n', 0); | ||
|
||
if(newline_index != FURI_STRING_FAILURE) { | ||
furi_string_left(line, newline_index); | ||
} | ||
|
||
FURI_LOG_T( | ||
TAG, "Read line: %s, len: %zu", furi_string_get_cstr(line), furi_string_size(line)); | ||
|
||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
bool apdu_log_check_presence(const char* path) { | ||
furi_check(path); | ||
|
||
Storage* storage = furi_record_open(RECORD_STORAGE); | ||
|
||
bool log_present = storage_common_stat(storage, path, NULL) == FSE_OK; | ||
|
||
furi_record_close(RECORD_STORAGE); | ||
|
||
return log_present; | ||
} | ||
|
||
APDULog* apdu_log_alloc(const char* path, APDULogMode mode) { | ||
furi_check(path); | ||
|
||
APDULog* instance = malloc(sizeof(APDULog)); | ||
|
||
Storage* storage = furi_record_open(RECORD_STORAGE); | ||
instance->stream = buffered_file_stream_alloc(storage); | ||
|
||
FS_OpenMode open_mode = (mode == APDULogModeOpenAlways) ? FSOM_OPEN_ALWAYS : | ||
FSOM_OPEN_EXISTING; | ||
|
||
instance->total_lines = 0; | ||
|
||
bool file_exists = | ||
buffered_file_stream_open(instance->stream, path, FSAM_READ_WRITE, open_mode); | ||
|
||
if(!file_exists) { | ||
buffered_file_stream_close(instance->stream); | ||
} else { | ||
// Eventually add new line character in the last line to avoid skipping lines | ||
apdu_log_add_ending_new_line(instance); | ||
} | ||
|
||
FuriString* line = furi_string_alloc(); | ||
|
||
bool is_endfile = false; | ||
|
||
// In this loop we only count the entries in the file | ||
// We prefer not to load the whole file in memory for space reasons | ||
while(file_exists && !is_endfile) { | ||
bool read_log = apdu_log_read_log_line(instance, line, &is_endfile); | ||
if(read_log) { | ||
instance->total_lines++; | ||
} | ||
} | ||
stream_rewind(instance->stream); | ||
FURI_LOG_I(TAG, "Loaded log with %zu lines", instance->total_lines); | ||
|
||
furi_string_free(line); | ||
|
||
return instance; | ||
} | ||
|
||
void apdu_log_free(APDULog* instance) { | ||
furi_check(instance); | ||
furi_check(instance->stream); | ||
|
||
buffered_file_stream_close(instance->stream); | ||
stream_free(instance->stream); | ||
free(instance); | ||
|
||
furi_record_close(RECORD_STORAGE); | ||
} | ||
|
||
size_t apdu_log_get_total_lines(APDULog* instance) { | ||
furi_check(instance); | ||
|
||
return instance->total_lines; | ||
} | ||
|
||
bool apdu_log_rewind(APDULog* instance) { | ||
furi_check(instance); | ||
furi_check(instance->stream); | ||
|
||
return stream_rewind(instance->stream); | ||
} | ||
|
||
bool apdu_log_get_next_log_str(APDULog* instance, FuriString* log) { | ||
furi_assert(instance); | ||
furi_assert(instance->stream); | ||
furi_assert(log); | ||
|
||
bool log_read = false; | ||
bool is_endfile = false; | ||
|
||
furi_string_reset(log); | ||
|
||
while(!log_read && !is_endfile) | ||
log_read = apdu_log_read_log_line(instance, log, &is_endfile); | ||
|
||
return log_read; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#pragma once | ||
|
||
#include <flipper_format/flipper_format.h> | ||
#include <stdbool.h> | ||
#include <stdint.h> | ||
#include <stddef.h> | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
typedef enum { | ||
APDULogModeOpenExisting, | ||
APDULogModeOpenAlways, | ||
} APDULogMode; | ||
|
||
typedef struct APDULog APDULog; | ||
|
||
/** Check if the file list exists | ||
* | ||
* @param path - list path | ||
* | ||
* @return true if list exists, false otherwise | ||
*/ | ||
bool apdu_log_check_presence(const char* path); | ||
|
||
/** Open or create list | ||
* Depending on mode, list will be opened or created. | ||
* | ||
* @param path - Path of the file that contain the list | ||
* @param mode - ListKeysMode value | ||
* | ||
* @return Returns APDULog list instance | ||
*/ | ||
APDULog* apdu_log_alloc(const char* path, APDULogMode mode); | ||
|
||
/** Close list | ||
* | ||
* @param instance - APDULog list instance | ||
*/ | ||
void apdu_log_free(APDULog* instance); | ||
|
||
/** Get total number of lines in list | ||
* | ||
* @param instance - APDULog list instance | ||
* | ||
* @return Returns total number of lines in list | ||
*/ | ||
size_t apdu_log_get_total_lines(APDULog* instance); | ||
|
||
/** Rewind list | ||
* | ||
* @param instance - APDULog list instance | ||
* | ||
* @return Returns true if rewind was successful, false otherwise | ||
*/ | ||
bool apdu_log_rewind(APDULog* instance); | ||
|
||
bool apdu_log_get_next_log_str(APDULog* instance, FuriString* log); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
#include "apdu_runner.h" | ||
|
||
#define TAG "APDU_Runner" | ||
|
||
// Max length of firmware upgrade: 731 bytes | ||
#define SEADER_APDU_MAX_LEN 732 | ||
|
||
void seader_apdu_runner_cleanup(Seader* seader, SeaderWorkerEvent event) { | ||
SeaderWorker* seader_worker = seader->worker; | ||
seader_worker_change_state(seader_worker, SeaderWorkerStateReady); | ||
apdu_log_free(seader->apdu_log); | ||
seader->apdu_log = NULL; | ||
if(seader_worker->callback) { | ||
seader_worker->callback(event, seader_worker->context); | ||
} | ||
} | ||
|
||
bool seader_apdu_runner_send_next_line(Seader* seader) { | ||
SeaderWorker* seader_worker = seader->worker; | ||
SeaderUartBridge* seader_uart = seader_worker->uart; | ||
SeaderAPDURunnerContext* apdu_runner_ctx = &(seader->apdu_runner_ctx); | ||
|
||
FuriString* line = furi_string_alloc(); | ||
apdu_log_get_next_log_str(seader->apdu_log, line); | ||
|
||
size_t len = furi_string_size(line) / 2; // String is in HEX, divide by 2 for bytes | ||
uint8_t* apdu = malloc(len); | ||
if(apdu == NULL) { | ||
FURI_LOG_E(TAG, "Failed to allocate memory for APDU"); | ||
seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError); | ||
return false; | ||
} | ||
|
||
if(len > SEADER_UART_RX_BUF_SIZE) { | ||
FURI_LOG_E(TAG, "APDU length is too long"); | ||
seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError); | ||
free(apdu); | ||
return false; | ||
} | ||
|
||
if(!hex_chars_to_uint8(furi_string_get_cstr(line), apdu)) { | ||
FURI_LOG_E(TAG, "Failed to convert line to number"); | ||
seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError); | ||
free(apdu); | ||
return false; | ||
} | ||
FURI_LOG_I( | ||
TAG, | ||
"APDU Runner => (%d/%d): %s", | ||
apdu_runner_ctx->current_line, | ||
apdu_runner_ctx->total_lines, | ||
furi_string_get_cstr(line)); | ||
|
||
if(seader_worker->callback) { | ||
seader_worker->callback(SeaderWorkerEventAPDURunnerUpdate, seader_worker->context); | ||
} | ||
|
||
apdu_runner_ctx->current_line++; | ||
if(seader_uart->T == 1) { | ||
seader_send_t1(seader_uart, apdu, len); | ||
} else { | ||
seader_ccid_XfrBlock(seader_uart, apdu, len); | ||
} | ||
furi_string_free(line); | ||
free(apdu); | ||
|
||
return true; | ||
} | ||
|
||
void seader_apdu_runner_init(Seader* seader) { | ||
SeaderAPDURunnerContext* apdu_runner_ctx = &(seader->apdu_runner_ctx); | ||
|
||
if(apdu_log_check_presence(SEADER_APDU_RUNNER_FILE_NAME)) { | ||
FURI_LOG_I(TAG, "APDU log file exists"); | ||
} else { | ||
FURI_LOG_W(TAG, "APDU log file does not exist"); | ||
return; | ||
} | ||
|
||
seader->apdu_log = apdu_log_alloc(SEADER_APDU_RUNNER_FILE_NAME, APDULogModeOpenExisting); | ||
apdu_runner_ctx->current_line = 0; | ||
apdu_runner_ctx->total_lines = apdu_log_get_total_lines(seader->apdu_log); | ||
FURI_LOG_I(TAG, "APDU log lines: %d", apdu_runner_ctx->total_lines); | ||
|
||
seader_apdu_runner_send_next_line(seader); | ||
} | ||
|
||
bool seader_apdu_runner_response(Seader* seader, uint8_t* r_apdu, size_t r_len) { | ||
SeaderUartBridge* seader_uart = seader->worker->uart; | ||
SeaderAPDURunnerContext* apdu_runner_ctx = &(seader->apdu_runner_ctx); | ||
uint8_t GET_RESPONSE[] = {0x00, 0xc0, 0x00, 0x00, 0xff}; | ||
|
||
uint8_t SW1 = r_apdu[r_len - 2]; | ||
uint8_t SW2 = r_apdu[r_len - 1]; | ||
|
||
switch(SW1) { | ||
case 0x61: | ||
//FURI_LOG_D(TAG, "Request %d bytes", SW2); | ||
GET_RESPONSE[4] = SW2; | ||
seader_ccid_XfrBlock(seader_uart, GET_RESPONSE, sizeof(GET_RESPONSE)); | ||
return true; | ||
} | ||
|
||
if(r_len < SEADER_UART_RX_BUF_SIZE) { | ||
char* display = malloc(r_len * 2 + 1); | ||
if(display == NULL) { | ||
FURI_LOG_E(TAG, "Failed to allocate memory for display"); | ||
seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError); | ||
return false; | ||
} | ||
memset(display, 0, r_len * 2 + 1); | ||
for(uint8_t i = 0; i < r_len; i++) { | ||
snprintf(display + (i * 2), sizeof(display), "%02x", r_apdu[i]); | ||
} | ||
FURI_LOG_I( | ||
TAG, | ||
"APDU Runner <=: (%d/%d): %s", | ||
apdu_runner_ctx->current_line, | ||
apdu_runner_ctx->total_lines, | ||
display); | ||
free(display); | ||
} else { | ||
FURI_LOG_I(TAG, "APDU Runner <=: Response too long to display"); | ||
} | ||
|
||
/** Compare last two bytes to expected line **/ | ||
|
||
FuriString* line = furi_string_alloc(); | ||
apdu_log_get_next_log_str(seader->apdu_log, line); | ||
if(furi_string_size(line) % 2 == 1) { | ||
FURI_LOG_E(TAG, "APDU log file has odd number of characters"); | ||
seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError); | ||
return false; | ||
} | ||
|
||
size_t len = furi_string_size(line) / 2; // String is in HEX, divide by 2 for bytes | ||
uint8_t* apdu = malloc(len); | ||
if(apdu == NULL) { | ||
FURI_LOG_E(TAG, "Failed to allocate memory for APDU"); | ||
seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError); | ||
return false; | ||
} | ||
|
||
if(!hex_chars_to_uint8(furi_string_get_cstr(line), apdu)) { | ||
FURI_LOG_E(TAG, "Failed to convert line to byte array"); | ||
seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError); | ||
free(apdu); | ||
// TODO: Send failed event | ||
return false; | ||
} | ||
|
||
apdu_runner_ctx->current_line++; | ||
furi_string_free(line); | ||
|
||
if(memcmp(r_apdu + r_len - 2, apdu + len - 2, 2) != 0) { | ||
FURI_LOG_W( | ||
TAG, | ||
"APDU runner response does not match. Response %02x%02x != expected %02x%02x", | ||
r_apdu[r_len - 2], | ||
r_apdu[r_len - 1], | ||
apdu[len - 2], | ||
apdu[len - 1]); | ||
seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError); | ||
free(apdu); | ||
return false; | ||
} | ||
free(apdu); | ||
|
||
// Check if we are at the end of the log | ||
if(apdu_runner_ctx->current_line >= apdu_runner_ctx->total_lines) { | ||
FURI_LOG_I(TAG, "APDU runner finished"); | ||
seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerSuccess); | ||
return false; | ||
} | ||
|
||
// Send next line | ||
return seader_apdu_runner_send_next_line(seader); | ||
} |
Oops, something went wrong.