Skip to content

Commit

Permalink
Squashed 'applications/external/' changes from 6d33a43ab56..7a7f74be1ad
Browse files Browse the repository at this point in the history
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
RogueMaster committed Jul 29, 2024
1 parent 58686c1 commit 4a9b439
Show file tree
Hide file tree
Showing 37 changed files with 1,807 additions and 85 deletions.
2 changes: 1 addition & 1 deletion qrcode/.github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
- 'v[0-9]+.[0-9]+.[0-9]+'

env:
firmware_version: '0.103.1'
firmware_version: '0.104.0'

jobs:
build:
Expand Down
144 changes: 144 additions & 0 deletions seader/apdu_log.c
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;
}
63 changes: 63 additions & 0 deletions seader/apdu_log.h
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
178 changes: 178 additions & 0 deletions seader/apdu_runner.c
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);
}
Loading

0 comments on commit 4a9b439

Please sign in to comment.