Skip to content

Commit

Permalink
Memo hash offline_url change
Browse files Browse the repository at this point in the history
  • Loading branch information
relatko committed Apr 4, 2024
1 parent 058b354 commit 604de39
Show file tree
Hide file tree
Showing 150 changed files with 192 additions and 146 deletions.
36 changes: 17 additions & 19 deletions ledgerjs-fio/src/interactions/transactionTemplates/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,30 +413,28 @@ export function ADD_STORAGE_CHECK(check: VALUE_STORAGE_COMPARE, c: Command): Com
}
}

export function COMMAND_APPEND_DATA_MEMO_HASH(memo?: VarlenAsciiString, hash?: VarlenAsciiString, offline_url?: VarlenAsciiString): Command {
var varData: Buffer = Buffer.from("");
if (memo === undefined) {
validate(hash !== undefined, InvalidDataReason.INVALID_HASH);
validate(offline_url !== undefined, InvalidDataReason.INVALID_OFFLINE_URL);
varData = Buffer.concat([
Buffer.from("0001", "hex"),
varuint32_to_buf(hash.length),
Buffer.from(hash),
Buffer.from("01", "hex"),
varuint32_to_buf(offline_url.length),
Buffer.from(offline_url),
])
function serializeOptionalString(str?: VarlenAsciiString): Buffer {
if (str === undefined) {
return Buffer.from("00", "hex")
}
else {
validate(hash === undefined, InvalidDataReason.INVALID_HASH);
validate(hash === undefined, InvalidDataReason.INVALID_OFFLINE_URL);
varData = Buffer.concat([
return Buffer.concat([
Buffer.from("01", "hex"),
varuint32_to_buf(memo.length),
Buffer.from(memo),
Buffer.from("0000", "hex"),
varuint32_to_buf(str.length),
Buffer.from(str),
])
}
}

export function COMMAND_APPEND_DATA_MEMO_HASH(memo?: VarlenAsciiString, hash?: VarlenAsciiString, offline_url?: VarlenAsciiString): Command {
validate((hash !== undefined && offline_url !== undefined) || (hash === undefined && offline_url === undefined), InvalidDataReason.INVALID_HASH);

const varData = Buffer.concat([
serializeOptionalString(memo),
serializeOptionalString(hash),
serializeOptionalString(offline_url),
])

return {
...defaultCommand,
command: COMMAND.APPEND_DATA,
Expand Down
154 changes: 60 additions & 94 deletions src/decodeDH.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,78 +122,62 @@ static void decodeNewfundsreqMemo_ui_runStep() {
}

enum {
DECODE_NEWFUNDSREQ_HASH_UI_STEP_MESSAGE1 = 250,
DECODE_NEWFUNDSREQ_HASH_UI_STEP_MESSAGE2,
DECODE_NEWFUNDSREQ_HASH_UI_STEP_PAYEE_PUBLIC_ADDRESS,
DECODE_NEWFUNDSREQ_HASH_UI_STEP_AMOUNT,
DECODE_NEWFUNDSREQ_HASH_UI_STEP_CHAIN_CODE,
DECODE_NEWFUNDSREQ_HASH_UI_STEP_TOKEN_CODE,
DECODE_NEWFUNDSREQ_HASH_UI_STEP_HASH,
DECODE_NEWFUNDSREQ_HASH_UI_STEP_OFFLINE_URL,
DECODE_NEWFUNDSREQ_HASH_UI_STEP_CONFIRM,
DECODE_NEWFUNDSREQ_HASH_UI_STEP_RESPOND,
DECODE_NEWFUNDSREQ_HASH_UI_STEP_INVALID,
DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_MESSAGE1 = 250,
DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_MESSAGE2,
DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_PAYEE_PUBLIC_ADDRESS,
DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_AMOUNT,
DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_CHAIN_CODE,
DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_TOKEN_CODE,
DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_CONFIRM,
DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_RESPOND,
DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_INVALID,
};

static void decodeNewfundsreqHash_ui_runStep() {
static void decodeNewfundsreqNoMemo_ui_runStep() {
TRACE("UI step %d", ctx->ui_step);
ui_callback_fn_t *this_fn = decodeNewfundsreqHash_ui_runStep;
ui_callback_fn_t *this_fn = decodeNewfundsreqNoMemo_ui_runStep;

UI_STEP_BEGIN(ctx->ui_step, this_fn);

UI_STEP(DECODE_NEWFUNDSREQ_HASH_UI_STEP_MESSAGE1) {
UI_STEP(DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_MESSAGE1) {
ui_displayPaginatedText("Decrypt content", "", this_fn);
}
UI_STEP(DECODE_NEWFUNDSREQ_HASH_UI_STEP_MESSAGE2) {
UI_STEP(DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_MESSAGE2) {
ui_displayPaginatedText("Interpreting", "the message as Request funds", this_fn);
}
UI_STEP(DECODE_NEWFUNDSREQ_HASH_UI_STEP_PAYEE_PUBLIC_ADDRESS) {
UI_STEP(DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_PAYEE_PUBLIC_ADDRESS) {
ui_displayAsciiBufferScreen("Payee public address",
ctx->parsedContent.payee_public_address->data,
ctx->parsedContent.payee_public_address->length,
this_fn);
}
UI_STEP(DECODE_NEWFUNDSREQ_HASH_UI_STEP_AMOUNT) {
UI_STEP(DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_AMOUNT) {
ui_displayAsciiBufferScreen("Amount",
ctx->parsedContent.amount->data,
ctx->parsedContent.amount->length,
this_fn);
}
UI_STEP(DECODE_NEWFUNDSREQ_HASH_UI_STEP_CHAIN_CODE) {
UI_STEP(DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_CHAIN_CODE) {
ui_displayAsciiBufferScreen("Chain code",
ctx->parsedContent.chain_code->data,
ctx->parsedContent.chain_code->length,
this_fn);
}
UI_STEP(DECODE_NEWFUNDSREQ_HASH_UI_STEP_TOKEN_CODE) {
UI_STEP(DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_TOKEN_CODE) {
ui_displayAsciiBufferScreen("Token code",
ctx->parsedContent.token_code->data,
ctx->parsedContent.token_code->length,
this_fn);
}
UI_STEP(DECODE_NEWFUNDSREQ_HASH_UI_STEP_HASH) {
ASSERT(ctx->parsedContent.hash != NULL);
ui_displayAsciiBufferScreen("Hash",
ctx->parsedContent.hash->data,
ctx->parsedContent.hash->length,
this_fn);
}
UI_STEP(DECODE_NEWFUNDSREQ_HASH_UI_STEP_OFFLINE_URL) {
ASSERT(ctx->parsedContent.offline_url != NULL);
ui_displayAsciiBufferScreen("Offline URL",
ctx->parsedContent.offline_url->data,
ctx->parsedContent.offline_url->length,
this_fn);
}
UI_STEP(DECODE_NEWFUNDSREQ_HASH_UI_STEP_CONFIRM) {
UI_STEP(DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_CONFIRM) {
ui_displayPrompt("Confirm", "response", this_fn, dh_respond_with_user_reject);
}
UI_STEP(DECODE_NEWFUNDSREQ_HASH_UI_STEP_RESPOND) {
UI_STEP(DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_RESPOND) {
io_send_buf(SUCCESS, NULL, 0);
ui_displayBusy(); // needs to happen after I/O
ctx->stage = DECODE_STAGE_SEND_REST;
}
UI_STEP_END(DECODE_NEWFUNDSREQ_HASH_UI_STEP_INVALID);
UI_STEP_END(DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_INVALID);
}

// Parse newfundsreq data
Expand All @@ -210,18 +194,17 @@ static void decodeNewfundsreqUIFlow() {
readOptionalStringWithLength(&read, &ctx->parsedContent.hash);
readOptionalStringWithLength(&read, &ctx->parsedContent.offline_url);
VALIDATE(read == ctx->bufferLen, ERR_INVALID_DATA);
bool hasMemo = (ctx->parsedContent.memo != NULL);
bool hasHash = (ctx->parsedContent.hash != NULL);
bool hasOfflineUrl = (ctx->parsedContent.offline_url != NULL);
VALIDATE((hasHash && hasOfflineUrl) || (!hasHash && !hasOfflineUrl), ERR_INVALID_DATA);

if (ctx->parsedContent.memo != NULL && ctx->parsedContent.hash == NULL &&
ctx->parsedContent.offline_url == NULL) {
if (hasMemo) {
ctx->ui_step = DECODE_NEWFUNDSREQ_MEMO_UI_STEP_MESSAGE1;
decodeNewfundsreqMemo_ui_runStep();
} else if (ctx->parsedContent.memo == NULL && ctx->parsedContent.hash != NULL &&
ctx->parsedContent.offline_url != NULL) {
ctx->ui_step = DECODE_NEWFUNDSREQ_HASH_UI_STEP_MESSAGE1;
decodeNewfundsreqHash_ui_runStep();

} else {
THROW(ERR_INVALID_DATA);
ctx->ui_step = DECODE_NEWFUNDSREQ_NOMEMO_UI_STEP_MESSAGE1;
decodeNewfundsreqNoMemo_ui_runStep();
}
}

Expand Down Expand Up @@ -318,101 +301,85 @@ static void decodeRecordobtMemo_ui_runStep() {
}

enum {
DECODE_RECORDOBT_HASH_UI_STEP_MESSAGE1 = 350,
DECODE_RECORDOBT_HASH_UI_STEP_MESSAGE2,
DECODE_RECORDOBT_HASH_UI_STEP_PAYEE_PUBLIC_ADDRESS,
DECODE_RECORDOBT_HASH_UI_STEP_PAYER_PUBLIC_ADDRESS,
DECODE_RECORDOBT_HASH_UI_STEP_AMOUNT,
DECODE_RECORDOBT_HASH_UI_STEP_CHAIN_CODE,
DECODE_RECORDOBT_HASH_UI_STEP_TOKEN_CODE,
DECODE_RECORDOBT_HASH_UI_STEP_STATUS,
DECODE_RECORDOBT_HASH_UI_STEP_OBT_ID,
DECODE_RECORDOBT_HASH_UI_STEP_HASH,
DECODE_RECORDOBT_HASH_UI_STEP_OFFLINE_URL,
DECODE_RECORDOBT_HASH_UI_STEP_CONFIRM,
DECODE_RECORDOBT_HASH_UI_STEP_RESPOND,
DECODE_RECORDOBT_HASH_UI_STEP_INVALID,
DECODE_RECORDOBT_NO_MEMO_UI_STEP_MESSAGE1 = 350,
DECODE_RECORDOBT_NO_MEMO_UI_STEP_MESSAGE2,
DECODE_RECORDOBT_NO_MEMO_UI_STEP_PAYEE_PUBLIC_ADDRESS,
DECODE_RECORDOBT_NO_MEMO_UI_STEP_PAYER_PUBLIC_ADDRESS,
DECODE_RECORDOBT_NO_MEMO_UI_STEP_AMOUNT,
DECODE_RECORDOBT_NO_MEMO_UI_STEP_CHAIN_CODE,
DECODE_RECORDOBT_NO_MEMO_UI_STEP_TOKEN_CODE,
DECODE_RECORDOBT_NO_MEMO_UI_STEP_STATUS,
DECODE_RECORDOBT_NO_MEMO_UI_STEP_OBT_ID,
DECODE_RECORDOBT_NO_MEMO_UI_STEP_CONFIRM,
DECODE_RECORDOBT_NO_MEMO_UI_STEP_RESPOND,
DECODE_RECORDOBT_NO_MEMO_UI_STEP_INVALID,
};

static void decodeRecordobtHash_ui_runStep() {
static void decodeRecordobtNoMemo_ui_runStep() {
TRACE("UI step %d", ctx->ui_step);
ui_callback_fn_t *this_fn = decodeRecordobtHash_ui_runStep;
ui_callback_fn_t *this_fn = decodeRecordobtNoMemo_ui_runStep;

UI_STEP_BEGIN(ctx->ui_step, this_fn);

UI_STEP(DECODE_RECORDOBT_HASH_UI_STEP_MESSAGE1) {
UI_STEP(DECODE_RECORDOBT_NO_MEMO_UI_STEP_MESSAGE1) {
ui_displayPaginatedText("Decrypt content", "", this_fn);
}
UI_STEP(DECODE_RECORDOBT_HASH_UI_STEP_MESSAGE2) {
UI_STEP(DECODE_RECORDOBT_NO_MEMO_UI_STEP_MESSAGE2) {
ui_displayPaginatedText("Interpreting",
"the message as Record other blockchain transaction metadata",
this_fn);
}
UI_STEP(DECODE_RECORDOBT_HASH_UI_STEP_PAYEE_PUBLIC_ADDRESS) {
UI_STEP(DECODE_RECORDOBT_NO_MEMO_UI_STEP_PAYEE_PUBLIC_ADDRESS) {
ui_displayAsciiBufferScreen("Payee public address",
ctx->parsedContent.payee_public_address->data,
ctx->parsedContent.payee_public_address->length,
this_fn);
}
UI_STEP(DECODE_RECORDOBT_HASH_UI_STEP_PAYER_PUBLIC_ADDRESS) {
UI_STEP(DECODE_RECORDOBT_NO_MEMO_UI_STEP_PAYER_PUBLIC_ADDRESS) {
ui_displayAsciiBufferScreen("Payer public address",
ctx->parsedContent.payer_public_address->data,
ctx->parsedContent.payer_public_address->length,
this_fn);
}
UI_STEP(DECODE_RECORDOBT_HASH_UI_STEP_AMOUNT) {
UI_STEP(DECODE_RECORDOBT_NO_MEMO_UI_STEP_AMOUNT) {
ui_displayAsciiBufferScreen("Amount",
ctx->parsedContent.amount->data,
ctx->parsedContent.amount->length,
this_fn);
}
UI_STEP(DECODE_RECORDOBT_HASH_UI_STEP_CHAIN_CODE) {
UI_STEP(DECODE_RECORDOBT_NO_MEMO_UI_STEP_CHAIN_CODE) {
ui_displayAsciiBufferScreen("Chain code",
ctx->parsedContent.chain_code->data,
ctx->parsedContent.chain_code->length,
this_fn);
}
UI_STEP(DECODE_RECORDOBT_HASH_UI_STEP_TOKEN_CODE) {
UI_STEP(DECODE_RECORDOBT_NO_MEMO_UI_STEP_TOKEN_CODE) {
ui_displayAsciiBufferScreen("Token code",
ctx->parsedContent.token_code->data,
ctx->parsedContent.token_code->length,
this_fn);
}
UI_STEP(DECODE_RECORDOBT_HASH_UI_STEP_STATUS) {
UI_STEP(DECODE_RECORDOBT_NO_MEMO_UI_STEP_STATUS) {
ui_displayAsciiBufferScreen("Status",
ctx->parsedContent.status->data,
ctx->parsedContent.status->length,
this_fn);
}
UI_STEP(DECODE_RECORDOBT_HASH_UI_STEP_OBT_ID) {
UI_STEP(DECODE_RECORDOBT_NO_MEMO_UI_STEP_OBT_ID) {
ui_displayAsciiBufferScreen("Obt ID",
ctx->parsedContent.obt_id->data,
ctx->parsedContent.obt_id->length,
this_fn);
}
UI_STEP(DECODE_RECORDOBT_HASH_UI_STEP_HASH) {
ASSERT(ctx->parsedContent.hash != NULL);
ui_displayAsciiBufferScreen("Hash",
ctx->parsedContent.hash->data,
ctx->parsedContent.hash->length,
this_fn);
}
UI_STEP(DECODE_RECORDOBT_HASH_UI_STEP_OFFLINE_URL) {
ASSERT(ctx->parsedContent.offline_url != NULL);
ui_displayAsciiBufferScreen("Offline URL",
ctx->parsedContent.offline_url->data,
ctx->parsedContent.offline_url->length,
this_fn);
}
UI_STEP(DECODE_RECORDOBT_HASH_UI_STEP_CONFIRM) {
UI_STEP(DECODE_RECORDOBT_NO_MEMO_UI_STEP_CONFIRM) {
ui_displayPrompt("Confirm", "response", this_fn, dh_respond_with_user_reject);
}
UI_STEP(DECODE_RECORDOBT_HASH_UI_STEP_RESPOND) {
UI_STEP(DECODE_RECORDOBT_NO_MEMO_UI_STEP_RESPOND) {
io_send_buf(SUCCESS, NULL, 0);
ui_displayBusy(); // needs to happen after I/O
ctx->stage = DECODE_STAGE_SEND_REST;
}
UI_STEP_END(DECODE_RECORDOBT_HASH_UI_STEP_INVALID);
UI_STEP_END(DECODE_RECORDOBT_NO_MEMO_UI_STEP_INVALID);
}

// Parse newfundsreq data
Expand All @@ -432,18 +399,17 @@ static void decodeRecordobtUIFlow() {
readOptionalStringWithLength(&read, &ctx->parsedContent.hash);
readOptionalStringWithLength(&read, &ctx->parsedContent.offline_url);
VALIDATE(read == ctx->bufferLen, ERR_INVALID_DATA);
bool hasMemo = (ctx->parsedContent.memo != NULL);
bool hasHash = (ctx->parsedContent.hash != NULL);
bool hasOfflineUrl = (ctx->parsedContent.offline_url != NULL);
VALIDATE((hasHash && hasOfflineUrl) || (!hasHash && !hasOfflineUrl), ERR_INVALID_DATA);

if (ctx->parsedContent.memo != NULL && ctx->parsedContent.hash == NULL &&
ctx->parsedContent.offline_url == NULL) {
if (hasMemo) {
ctx->ui_step = DECODE_RECORDOBT_MEMO_UI_STEP_MESSAGE1;
decodeRecordobtMemo_ui_runStep();
} else if (ctx->parsedContent.memo == NULL && ctx->parsedContent.hash != NULL &&
ctx->parsedContent.offline_url != NULL) {
ctx->ui_step = DECODE_RECORDOBT_HASH_UI_STEP_MESSAGE1;
decodeRecordobtHash_ui_runStep();

} else {
THROW(ERR_INVALID_DATA);
ctx->ui_step = DECODE_RECORDOBT_NO_MEMO_UI_STEP_MESSAGE1;
decodeRecordobtNoMemo_ui_runStep();
}
}

Expand Down
51 changes: 25 additions & 26 deletions src/signTransactionParse.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,38 +86,37 @@ static void displayASCIIStringWithLength(const uint8_t *value,
display[strLen] = 0;
}

// helper for displayMemoHash
static bool validateOptional(const uint8_t *value, uint8_t valueLen, uint8_t *read) {
VALIDATE(valueLen >= *read + 1, ERR_INVALID_DATA);
uint8_t hasOptional = value[*read];
if (hasOptional) {
VALIDATE(hasOptional == 1, ERR_INVALID_DATA);
VALIDATE(valueLen >= *read + 2, ERR_INVALID_DATA);
uint8_t optionalLen = value[*read + 1];
VALIDATE(optionalLen < 127, ERR_INVALID_DATA);
*read += 2 + optionalLen;
return true;
} else {
*read += 1;
return false;
}
}

static void displayMemoHash(const uint8_t *value,
uint8_t valueLen,
char display[MAX_DISPLAY_VALUE_LENGTH]) {
// data format:
// hasMemo(0x00/0x01), if yes then memolength (1b, < 127) and memo
// then hash and offline url in the same manner
// Either memo is present, or both hash and offline url.
// hasHash(0x00/0x01), if yes then hashlength (1b, < 127) and hash
// hasOfflineUrl(0x00/0x01), if yes then offlineurllength (1b, < 127) and offlineurl
// hash and offline url have to be present at the same time.
TRACE_BUFFER(value, valueLen);
VALIDATE(valueLen >= 1, ERR_INVALID_DATA);
if (value[0] == 1) { // has memo
VALIDATE(valueLen >= 2,
ERR_INVALID_DATA); // this also checks that memo has length at least 1
size_t memoLen = value[1];
VALIDATE(memoLen < 127, ERR_INVALID_DATA);
VALIDATE(valueLen == memoLen + 4,
ERR_INVALID_DATA); // has memo, memo length, memo, no hash, no url
VALIDATE(value[2 + memoLen] == 0, ERR_INVALID_DATA); // no hash
VALIDATE(value[3 + memoLen] == 0, ERR_INVALID_DATA); // no offline_url
} else if (value[0] == 0) { // no memo
TRACE("No memo");
VALIDATE(valueLen >= 3, ERR_INVALID_DATA);
VALIDATE(value[1] == 1, ERR_INVALID_DATA); // has hash
size_t hashLen = value[2];
VALIDATE(hashLen < 127, ERR_INVALID_DATA);
VALIDATE(valueLen >= hashLen + 5, ERR_INVALID_DATA);
VALIDATE(value[hashLen + 3] == 1, ERR_INVALID_DATA); // has url
size_t urlLen = value[hashLen + 4];
VALIDATE(urlLen < 127, ERR_INVALID_DATA);
VALIDATE(valueLen == hashLen + urlLen + 5, ERR_INVALID_DATA);
} else {
VALIDATE(false, ERR_INVALID_DATA);
}
uint8_t read = 0;
bool hasMemo = validateOptional(value, valueLen, &read);
bool hasHash = validateOptional(value, valueLen, &read);
bool hasOfflineUrl = validateOptional(value, valueLen, &read);
VALIDATE((hasHash && hasOfflineUrl) || (!hasHash && !hasOfflineUrl), ERR_INVALID_DATA);
// These data are not meant to e displayed at themoement
snprintf(display, MAX_DISPLAY_VALUE_LENGTH, "NOT IMPLEMENTED");
}
Expand Down
Loading

0 comments on commit 604de39

Please sign in to comment.