Skip to content

Commit

Permalink
Merge pull request #13 from fbsobreira/UPDATE_TOKEN_NAME
Browse files Browse the repository at this point in the history
Update token name
  • Loading branch information
fbsobreira committed Jan 28, 2019
2 parents d95b33b + d0e4ef8 commit 0fcea56
Show file tree
Hide file tree
Showing 10 changed files with 2,173 additions and 110 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.0.4
0.1.0
152 changes: 152 additions & 0 deletions signedList_Exchanges.txt

Large diffs are not rendered by default.

1,581 changes: 1,581 additions & 0 deletions signedList_TRC10.txt

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions signedList_TRC20.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{{0x41,0x38,0x43,0xC8,0xEC,0xF7,0x31,0x2F,0x5D,0xBC,0x17,0xB9,0x22,0x65,0xD7,0x7C,0xB6,0x73,0x21,0x2E,0x7A}, "$DEX ", 8},
{{0x41,0x62,0xFC,0xF1,0x2E,0x16,0x6C,0xE4,0x27,0x75,0x7A,0xDC,0xA3,0x1A,0xF0,0xE5,0x9E,0x92,0xA2,0xE1,0x66}, "$PCB ", 18},
{{0x41,0x65,0x0A,0xFD,0xF5,0x4A,0x3F,0x3D,0xEF,0x2C,0xB8,0x47,0xD5,0x24,0x00,0xB7,0xD6,0x32,0x07,0x27,0xFD}, "$DRS ", 6},
{{0x41,0x70,0x3F,0x3B,0x26,0xD3,0x0E,0x10,0x82,0x67,0x33,0xB7,0x30,0xC1,0x18,0x6C,0x37,0xF5,0x4D,0x0A,0x93}, "$RET ", 6},
{{0x41,0x57,0x41,0x38,0x56,0x2C,0xA8,0xBD,0x1D,0x35,0x06,0x8C,0x5B,0x21,0x27,0x96,0x10,0xC1,0xF5,0x83,0xC4}, "$DICE ", 6},
{{0x41,0xDE,0xAA,0x5F,0x32,0x96,0x3C,0x91,0x9C,0x2A,0x5A,0x8F,0x84,0x82,0xCC,0x8C,0x92,0xF5,0x04,0xB8,0xB2}, "$BET ", 6},
{{0x41,0x9F,0xC6,0xE2,0xD0,0x70,0xD0,0x1E,0x73,0x47,0x4D,0x47,0x3B,0x32,0xE4,0x18,0xC7,0xCD,0x9D,0x5D,0x5B}, "$FUN ", 6},
{{0x41,0xF8,0xAD,0xE6,0x3F,0x62,0x94,0xB1,0xE3,0x25,0x6C,0x46,0x9C,0x05,0xA7,0xE0,0x8A,0xE6,0xF1,0x53,0x2C}, "$GOC ", 6},
{{0x41,0x8A,0x81,0x02,0xD7,0xE2,0x48,0x30,0x67,0x6F,0x52,0x85,0xF4,0xB2,0x8F,0xAE,0xEE,0xB4,0xD8,0x70,0x8D}, "$AB ", 6},
{{0x41,0xF6,0xE1,0xFE,0xF4,0x4C,0x47,0xDF,0xF0,0xAB,0x57,0xA3,0xA5,0x7F,0x7F,0xC3,0x86,0x2E,0x0D,0x85,0x2E}, "$BFC ", 6},
{{0x41,0x0D,0x29,0x2C,0x98,0xA5,0xEC,0xA0,0x6C,0x20,0x85,0xFF,0xF9,0x93,0x99,0x64,0x23,0xCF,0x66,0xC9,0x3B}, "$WIN ", 6},
{{0x41,0xF5,0xE0,0xAE,0xC5,0x39,0x95,0xFB,0x93,0x58,0x8C,0xA6,0x56,0xA9,0x59,0xAC,0x46,0x75,0x23,0xDB,0x83}, "$GAME ", 18},
{{0x41,0x8D,0x0F,0xF4,0x2A,0x82,0xCA,0x54,0x54,0x1C,0x98,0x75,0x9A,0x99,0x95,0x1D,0x97,0x36,0xA5,0xDE,0x9F}, "$TWJ ", 8},
{{0x41,0x1A,0x44,0xE6,0x76,0xD4,0x86,0x46,0x60,0xD9,0x84,0xF6,0xD1,0xF4,0xEB,0x06,0xD0,0xF5,0xCC,0x52,0x08}, "$ANTE ", 6},
{{0x41,0x1A,0x32,0xD5,0x7D,0x10,0xD3,0x05,0x2E,0x43,0xB4,0xEB,0x67,0x20,0x8F,0x44,0x69,0x76,0xE4,0x02,0x09}, "$6KPEN ", 18},
{{0x41,0xB8,0x07,0x5B,0x0F,0xB5,0x2B,0x7A,0x8D,0xF8,0x12,0x2D,0xDA,0x49,0x78,0x78,0x29,0x52,0x9A,0x4A,0xB7}, "$CFT ", 6},
{{0x41,0x8B,0xE3,0x85,0xC9,0xC3,0x71,0x6E,0x28,0x63,0x70,0xAA,0x5D,0xB4,0xB6,0xF3,0x97,0x24,0x1D,0xFD,0xE6}, "$VCOIN ", 6},
{{0x41,0x7E,0xA0,0x7B,0x5B,0xE5,0xA0,0xFE,0x26,0xA6,0x4A,0xCA,0xF4,0x51,0xC8,0xD8,0x65,0x3F,0xDB,0x56,0xB6}, "$REY ", 6},
{{0x41,0xF8,0x2D,0x6D,0x39,0x8A,0x9B,0xA0,0xDA,0x8C,0x73,0x84,0xAE,0xA3,0x72,0x30,0xD2,0x68,0xCA,0x28,0x45}, "$PLAY ", 6},
{{0x41,0x6E,0x0D,0x26,0xAD,0xF5,0x32,0x3F,0x5B,0x82,0xD5,0x71,0x43,0x54,0xDC,0x3C,0x68,0x70,0xAD,0xEE,0x7C}, "$RING ", 18},
{{0x41,0x32,0x96,0x8E,0x93,0xDC,0x3A,0x56,0xEE,0xCF,0xF1,0x3E,0xDC,0xC4,0x00,0x9A,0xF4,0xEF,0x21,0xB0,0x7E}, "$BFB ", 8},
{{0x41,0x82,0xCD,0x8B,0x6D,0x85,0x7A,0xE9,0xB6,0xBE,0xCD,0x7D,0xDF,0xC6,0x49,0x5F,0xCB,0x45,0x0D,0x39,0xC5}, "$MLT ", 6},
{{0x41,0x14,0x29,0xF3,0xBE,0xF4,0x99,0x24,0x2C,0x2A,0x34,0x6E,0x32,0x20,0xFA,0x3F,0x94,0xF6,0xDD,0x46,0xC9}, "$BOG ", 4},
{{0x41,0x14,0x18,0x3f,0x3b,0xbc,0xa4,0xae,0x9f,0xc1,0xde,0x55,0xb9,0xbb,0xe2,0xd0,0x71,0x94,0x2d,0xc1,0xa6}, "CCT ", 6},
9 changes: 4 additions & 5 deletions src/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,26 @@ void getAddressFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *address,
void getBase58FromAddres(uint8_t *address, uint8_t *out,
cx_sha256_t* sha2) {
uint8_t sha256[32];
uint8_t checkSum[4];
uint8_t addchecksum[ADDRESS_SIZE+4];

cx_sha256_init(sha2);
cx_hash(sha2, CX_LAST, address, 21, sha256);
cx_hash((cx_hash_t*)sha2, CX_LAST, address, 21, sha256);
cx_sha256_init(sha2);
cx_hash(sha2, CX_LAST, sha256, 32, sha256);
cx_hash((cx_hash_t*)sha2, CX_LAST, sha256, 32, sha256);

os_memmove(addchecksum, address , ADDRESS_SIZE);
os_memmove(addchecksum+ADDRESS_SIZE, sha256, 4);


encode_base_58(&addchecksum[0],25,out,BASE58CHECK_ADDRESS_SIZE);
encode_base_58(&addchecksum[0],25,(char *)out,BASE58CHECK_ADDRESS_SIZE);

}

void transactionHash(uint8_t *raw, uint16_t dataLength,
uint8_t *out, cx_sha256_t* sha2) {

cx_sha256_init(sha2);
cx_hash(sha2, CX_LAST, raw, dataLength, out);
cx_hash((cx_hash_t*)sha2, CX_LAST, raw, dataLength, out);
}

void signTransaction(transactionContext_t *transactionContext) {
Expand Down
131 changes: 90 additions & 41 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "parse.h"
#include "uint256.h"

#include "tokens.h"

extern bool fidoActivated;

Expand All @@ -51,6 +52,7 @@ uint32_t set_result_get_publicKey(void);
#define P1_FIRST 0x00
#define P1_MORE 0x80
#define P1_LAST 0x90
#define P1_TRC10_NAME 0xA0
#define P1_SIGN 0x10

#define OFFSET_CLA 0
Expand All @@ -71,7 +73,7 @@ cx_sha256_t sha2;
volatile char fullAddress[BASE58CHECK_ADDRESS_SIZE+1];
volatile char addressSummary[35];
volatile char fullAmount[50];
volatile char fullContract[50];
volatile char fullContract[MAX_TOKEN_LENGTH];
volatile char fullHash[HASH_SIZE*2+1];
volatile char fullAmount2[50];
volatile char exchangeContractDetail[50];
Expand Down Expand Up @@ -1587,7 +1589,7 @@ const bagl_element_t ui_approval_nanos[] = {
NULL,
NULL,
NULL},
{{BAGL_LABELINE, 0x02, 23, 26, 82, 12, 0x80 | 10, 0, 0, 0xFFFFFF, 0x000000,
{{BAGL_LABELINE, 0x02, 12, 28, 104, 12, 0x00 | 10, 0, 0, 0xFFFFFF, 0x000000,
BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 26},
(char *)fullContract,
0,
Expand Down Expand Up @@ -1952,7 +1954,7 @@ const bagl_element_t ui_approval_exchange_withdraw_nanos[] = {

{{BAGL_LABELINE, 0x03, 0, 12, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000,
BAGL_FONT_OPEN_SANS_REGULAR_11px | BAGL_FONT_ALIGNMENT_CENTER, 0},
"Token ID",
"Token Name",
0,
0,
0,
Expand Down Expand Up @@ -2116,7 +2118,7 @@ const bagl_element_t ui_approval_exchange_transaction_nanos[] = {

{{BAGL_LABELINE, 0x03, 0, 12, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000,
BAGL_FONT_OPEN_SANS_REGULAR_11px | BAGL_FONT_ALIGNMENT_CENTER, 0},
"Token ID",
"Token Name",
0,
0,
0,
Expand Down Expand Up @@ -2475,7 +2477,7 @@ void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer,
#elif defined(TARGET_NANOS)
ux_step = 0;
ux_step_count = 2;
UX_DISPLAY(ui_address_nanos, ui_address_prepro);
UX_DISPLAY(ui_address_nanos, (bagl_element_callback_t) ui_address_prepro);
#endif // #if TARGET

*flags |= IO_ASYNCH_REPLY;
Expand Down Expand Up @@ -2517,6 +2519,11 @@ void handleSign(uint8_t p1, uint8_t p2, uint8_t *workBuffer,
}

//Parse contract type
// Prevent buffer overflow
if (dataLength>MAX_RAW_TX){
PRINTF("RawTX buffer overflow\n");
THROW(0x6A80);
}
// Load raw Data
os_memmove(tmpCtx.transactionContext.rawTx, workBuffer, dataLength);
tmpCtx.transactionContext.rawTxLength = dataLength;
Expand All @@ -2527,7 +2534,43 @@ void handleSign(uint8_t p1, uint8_t p2, uint8_t *workBuffer,
}
cx_sha256_init(&sha2); //init sha

} else if ((p1 != P1_MORE) && (p1 != P1_LAST)) {
} else if ((p1&0xF0) == P1_TRC10_NAME) {
switch (txContent.contractType){
case 2: // transafer asset
case 41: // create exchange
// Max 2 Tokens Name
if ((p1&0x07)>1)
THROW(0x6A80);
// Decode Token name and validate signature
if (parseTokenName((p1&0x07),workBuffer, dataLength, &txContent) != USTREAM_FINISHED) {
PRINTF("Unexpected parser status\n");
THROW(0x6A80);
}
// if not last token name, return
if (!(p1&0x08)) THROW(0x9000);
dataLength = 0;

break;
case 42: // exchange Inject
case 43: // exchange withdraw
case 44: // exchange transaction
// Max 1 pair set
if ((p1&0x07)>0)
THROW(0x6A80);
// error if not last
if (!(p1&0x08)) THROW(0x6A80);
// Decode Token name and validate signature
if (parseExchange((p1&0x07),workBuffer, dataLength, &txContent) != USTREAM_FINISHED) {
PRINTF("Unexpected parser status\n");
THROW(0x6A80);
}
dataLength = 0;
break;
default:
// Error if any other contract
THROW(0x6A80);
}
}else if ((p1 != P1_MORE) && (p1 != P1_LAST)) {
THROW(0x6B00);
}else {

Expand All @@ -2541,126 +2584,132 @@ void handleSign(uint8_t p1, uint8_t p2, uint8_t *workBuffer,
case 2: // TRC10 Transfer
case 31: // TRC20 Transfer
// get Hash
cx_hash((cx_hash_t *)&sha2, CX_LAST, tmpCtx.transactionContext.rawTx,
tmpCtx.transactionContext.rawTxLength, tmpCtx.transactionContext.hash);

cx_hash((cx_hash_t *)&sha2, 0, workBuffer, dataLength, NULL);
if ((p1 == P1_MORE) || (p1 == P1_FIRST)) {
THROW(0x9000);
}
cx_hash((cx_hash_t *)&sha2, CX_LAST, workBuffer,
0, tmpCtx.transactionContext.hash);

if (txContent.contractType==31){
convertUint256BE(txContent.TRC20Amount, 32, &uint256);
tostring256(&uint256, 10, (char *)fullAmount2, sizeof(fullAmount2));
if (!adjustDecimals((char *)fullAmount2, strlen(fullAmount2), (char *)fullAmount, sizeof(fullAmount), txContent.decimals))
if (!adjustDecimals((char *)fullAmount2, strlen((const char *)fullAmount2), (char *)fullAmount, sizeof(fullAmount), txContent.decimals[0]))
THROW(0x6B00);
}else
print_amount(txContent.amount,(void *)fullAmount,sizeof(fullAmount), (txContent.contractType==1)?SUN_DIG:0);
print_amount(txContent.amount,(void *)fullAmount,sizeof(fullAmount), (txContent.contractType==1)?SUN_DIG:txContent.decimals[0]);

getBase58FromAddres(txContent.destination,
(void *)fullAddress, &sha2);
fullAddress[BASE58CHECK_ADDRESS_SIZE]='\0';

// get token name
os_memmove((void *)fullContract, txContent.tokenName, txContent.tokenNameLength+1);
os_memmove((void *)fullContract, txContent.tokenNames[0], txContent.tokenNamesLength[0]+1);

#if defined(TARGET_BLUE)
G_ui_approval_blue_state = APPROVAL_TRANSFER;
ui_approval_transaction_blue_init();
#elif defined(TARGET_NANOS)
ux_step = 0;
ux_step_count = 4;
UX_DISPLAY(ui_approval_nanos, ui_approval_prepro);
UX_DISPLAY(ui_approval_nanos,(bagl_element_callback_t) ui_approval_prepro);
#endif // #if TARGET_ID

break;
case 41: // exchange create
cx_hash(&sha2, 0, workBuffer, dataLength, NULL);
cx_hash((cx_hash_t *)&sha2, 0, workBuffer, dataLength, NULL);
if ((p1 == P1_MORE) || (p1 == P1_FIRST)) {
THROW(0x9000);
}
cx_hash(&sha2, CX_LAST, workBuffer,
cx_hash((cx_hash_t *)&sha2, CX_LAST, workBuffer,
0, tmpCtx.transactionContext.hash);

os_memmove((void *)fullContract, txContent.tokenName, txContent.tokenNameLength+1);
os_memmove((void *)fullAddress, txContent.tokenName2, txContent.tokenName2Length+1);
print_amount(txContent.amount,(void *)fullAmount,sizeof(fullAmount), (strncmp(txContent.tokenName, "TRX", 3)==0)?SUN_DIG:0);
print_amount(txContent.amount2,(void *)fullAmount2,sizeof(fullAmount2), (strncmp(txContent.tokenName2, "TRX", 3)==0)?SUN_DIG:0);
os_memmove((void *)fullContract, txContent.tokenNames[0], txContent.tokenNamesLength[0]+1);
os_memmove((void *)fullAddress, txContent.tokenNames[1], txContent.tokenNamesLength[1]+1);
print_amount(txContent.amount,(void *)fullAmount,sizeof(fullAmount), (strncmp((const char *)txContent.tokenNames[0], "TRX", 3)==0)?SUN_DIG:txContent.decimals[0]);
print_amount(txContent.amount2,(void *)fullAmount2,sizeof(fullAmount2), (strncmp((const char *)txContent.tokenNames[1], "TRX", 3)==0)?SUN_DIG:txContent.decimals[1]);
// write exchange contract type
if (!setExchangeContractDetail(txContent.contractType, exchangeContractDetail)) THROW(0x6A80);
if (!setExchangeContractDetail(txContent.contractType, (void*)exchangeContractDetail)) THROW(0x6A80);

#if defined(TARGET_BLUE)
G_ui_approval_blue_state = APPROVAL_TRANSACTION;
ui_approval_exchange_create_blue_init();
#elif defined(TARGET_NANOS)
ux_step = 0;
ux_step_count = 5;
UX_DISPLAY(ui_approval_exchange_nanos, ui_approval_exchange_prepro);
UX_DISPLAY(ui_approval_exchange_nanos,(bagl_element_callback_t) ui_approval_exchange_prepro);
#endif // #if TARGET_ID
break;
case 42: // exchange Inject
case 43: // exchange withdraw
cx_hash(&sha2, 0, workBuffer, dataLength, NULL);
cx_hash((cx_hash_t *)&sha2, 0, workBuffer, dataLength, NULL);
if ((p1 == P1_MORE) || (p1 == P1_FIRST)) {
THROW(0x9000);
}
cx_hash(&sha2, CX_LAST, workBuffer,
cx_hash((cx_hash_t *)&sha2, CX_LAST, workBuffer,
0, tmpCtx.transactionContext.hash);

os_memmove((void *)fullContract, txContent.tokenName, txContent.tokenNameLength+1);
os_memmove((void *)fullContract, txContent.tokenNames[0], txContent.tokenNamesLength[0]+1);
print_amount(txContent.exchangeID,(void *)fullAddress,sizeof(fullAddress), 0);
print_amount(txContent.amount,(void *)fullAmount,sizeof(fullAmount), (strncmp(txContent.tokenName, "TRX", 3)==0)?SUN_DIG:0);
print_amount(txContent.amount,(void *)fullAmount,sizeof(fullAmount), (strncmp((const char *)txContent.tokenNames[0], "TRX", 3)==0)?SUN_DIG:txContent.decimals[0]);
// write exchange contract type
if (!setExchangeContractDetail(txContent.contractType, exchangeContractDetail)) THROW(0x6A80);
if (!setExchangeContractDetail(txContent.contractType, (void*)exchangeContractDetail)) THROW(0x6A80);

#if defined(TARGET_BLUE)
G_ui_approval_blue_state = APPROVAL_TRANSACTION;
ui_approval_exchange_withdraw_blue_init();
#elif defined(TARGET_NANOS)
ux_step = 0;
ux_step_count = 4;
UX_DISPLAY(ui_approval_exchange_withdraw_nanos, ui_approval_exchange_withdraw_prepro);
UX_DISPLAY(ui_approval_exchange_withdraw_nanos,(bagl_element_callback_t) ui_approval_exchange_withdraw_prepro);
#endif // #if TARGET_ID
break;
case 44: // exchange transaction
cx_hash(&sha2, 0, workBuffer, dataLength, NULL);
cx_hash((cx_hash_t *)&sha2, 0, workBuffer, dataLength, NULL);
if ((p1 == P1_MORE) || (p1 == P1_FIRST)) {
THROW(0x9000);
}
cx_hash(&sha2, CX_LAST, workBuffer,
cx_hash((cx_hash_t *)&sha2, CX_LAST, workBuffer,
0, tmpCtx.transactionContext.hash);

os_memmove((void *)fullContract, txContent.tokenName, txContent.tokenNameLength+1);
//os_memmove((void *)fullContract, txContent.tokenNames[0], txContent.tokenNamesLength[0]+1);
snprintf((char *)fullContract, sizeof(fullContract), "%s -> %s", txContent.tokenNames[0], txContent.tokenNames[1]);

print_amount(txContent.exchangeID,(void *)fullAddress,sizeof(fullAddress), 0);
print_amount(txContent.amount,(void *)fullAmount,sizeof(fullAmount), (strncmp(txContent.tokenName, "TRX", 3)==0)?SUN_DIG:0);
print_amount(txContent.amount2,(void *)fullAmount2,sizeof(fullAmount2), (strncmp(txContent.tokenName, "TRX", 3)==0)?0:SUN_DIG);
print_amount(txContent.amount,(void *)fullAmount,sizeof(fullAmount), txContent.decimals[0]);
print_amount(txContent.amount2,(void *)fullAmount2,sizeof(fullAmount2), txContent.decimals[1]);
// write exchange contract type
if (!setExchangeContractDetail(txContent.contractType, exchangeContractDetail)) THROW(0x6A80);
if (!setExchangeContractDetail(txContent.contractType, (void*)exchangeContractDetail)) THROW(0x6A80);

#if defined(TARGET_BLUE)
G_ui_approval_blue_state = APPROVAL_TRANSACTION;
ui_approval_exchange_transaction_blue_init();
#elif defined(TARGET_NANOS)
ux_step = 0;
ux_step_count = 5;
UX_DISPLAY(ui_approval_exchange_transaction_nanos, ui_approval_exchange_transaction_prepro);
UX_DISPLAY(ui_approval_exchange_transaction_nanos, (bagl_element_callback_t)ui_approval_exchange_transaction_prepro);
#endif // #if TARGET_ID
break;
default:
cx_hash(&sha2, 0, workBuffer, dataLength, NULL);
cx_hash((cx_hash_t *)&sha2, 0, workBuffer, dataLength, NULL);
if ((p1 == P1_MORE) || (p1 == P1_FIRST)) {
THROW(0x9000);
}
cx_hash(&sha2, CX_LAST, workBuffer,
cx_hash((cx_hash_t *)&sha2, CX_LAST, workBuffer,
0, tmpCtx.transactionContext.hash);

// Write fullHash
array_hexstr(fullHash, tmpCtx.transactionContext.hash, 32);
array_hexstr((char *)fullHash, tmpCtx.transactionContext.hash, 32);
// write contract type
if (!setContractType(txContent.contractType, fullContract)) THROW(0x6A80);
if (!setContractType(txContent.contractType, (void*)fullContract)) THROW(0x6A80);

#if defined(TARGET_BLUE)
G_ui_approval_blue_state = APPROVAL_TRANSACTION;
ui_approval_simple_transaction_blue_init();
#elif defined(TARGET_NANOS)
ux_step = 0;
ux_step_count = 3;
UX_DISPLAY(ui_approval_simple_nanos, ui_approval_simple_prepro);
UX_DISPLAY(ui_approval_simple_nanos,(bagl_element_callback_t) ui_approval_simple_prepro);
#endif // #if TARGET_ID
break;
}
Expand Down Expand Up @@ -2714,7 +2763,7 @@ void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx) {
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC], flags, tx);
break;

case INS_GET_APP_CONFIGURATION:
// Request App configuration
handleGetAppConfiguration(
Expand Down

0 comments on commit 0fcea56

Please sign in to comment.