Skip to content

Commit 9ee45f6

Browse files
committed
Merge branch 'dev' of https://github.com/CoolBitX-Technology/coolwallet3-sdk into CWC-42_error_handle_refactory
2 parents db82e08 + 6f9860d commit 9ee45f6

35 files changed

+1008
-645
lines changed

packages/core/src/apdu/backup.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { executeCommand } from './execute';
22
import { RESPONSE } from '../config/response';
33
import Transport from '../transport';
4+
import { commands } from "./command";
45

56
/**
67
* backup seed in SE.
@@ -9,7 +10,7 @@ import Transport from '../transport';
910
* @return {Promise<boolean>}
1011
*/
1112
export const backupSeed = async (transport: Transport, signedCommand: string): Promise<boolean> => {
12-
const { status } = await executeCommand(transport, 'BACKUP_REGISTER_DATA', 'SE', signedCommand);
13+
const { status } = await executeCommand(transport, commands.BACKUP_REGISTER_DATA, 'SE', signedCommand);
1314
return status === RESPONSE.SUCCESS;
1415
};
1516

@@ -19,7 +20,7 @@ export const backupSeed = async (transport: Transport, signedCommand: string): P
1920
* @return {Promise<boolean>}
2021
*/
2122
export const recoverSeed = async (transport: Transport): Promise<boolean> => {
22-
await executeCommand(transport, 'RECOVER_REGISER_DATA', 'SE');
23+
await executeCommand(transport, commands.RECOVER_REGISER_DATA, 'SE');
2324
return true;
2425
};
2526

@@ -29,7 +30,7 @@ export const recoverSeed = async (transport: Transport): Promise<boolean> => {
2930
* @return {Promise<boolean>} true: may need recovery after update.
3031
*/
3132
export const checkBackupStatus = async (transport: Transport): Promise<boolean> => {
32-
const { outputData } = await executeCommand(transport, 'CHECK_BACKUP_RECOVER', 'SE');
33+
const { outputData } = await executeCommand(transport, commands.CHECK_BACKUP_RECOVER, 'SE');
3334
return outputData === '01';
3435
};
3536

@@ -40,6 +41,6 @@ export const checkBackupStatus = async (transport: Transport): Promise<boolean>
4041
* @return {Promise<boolean>}
4142
*/
4243
export const deleteSeedBackup = async (transport: Transport, signedCommand: string) => {
43-
const { status } = await executeCommand(transport, 'DELETE_REGISTER_BACKUP', 'SE', signedCommand);
44+
const { status } = await executeCommand(transport, commands.DELETE_REGISTER_BACKUP, 'SE', signedCommand);
4445
return status === RESPONSE.SUCCESS;
4546
};

packages/core/src/apdu/coin.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { executeCommand } from './execute';
22
import Transport from '../transport';
3+
import { commands } from "./command";
34

45
/**
56
* Authorization for requesting account keys
@@ -8,7 +9,7 @@ import Transport from '../transport';
89
* @return { Promise<boolean> }
910
*/
1011
export const authGetExtendedKey = async (transport: Transport, signature: string, forceUseSC: boolean): Promise<boolean> => {
11-
await executeCommand(transport, 'AUTH_EXT_KEY', 'SE', signature, undefined, undefined, true, forceUseSC);
12+
await executeCommand(transport, commands.AUTH_EXT_KEY, 'SE', signature, undefined, undefined, true, forceUseSC);
1213
return true;
1314
};
1415

@@ -20,7 +21,7 @@ export const authGetExtendedKey = async (transport: Transport, signature: string
2021
* @return {Promise<string>}
2122
*/
2223
export const getAccountExtendedKey = async (transport: Transport, coinType: string, accIndex: string): Promise<string> => {
23-
const { outputData } = await executeCommand(transport, 'GET_EXT_KEY', 'SE', undefined, coinType, accIndex);
24+
const { outputData } = await executeCommand(transport, commands.GET_EXT_KEY, 'SE', undefined, coinType, accIndex);
2425
return outputData;
2526
};
2627

@@ -34,11 +35,11 @@ export const getAccountExtendedKey = async (transport: Transport, coinType: stri
3435
*/
3536
export const getEd25519AccountPublicKey = async (transport: Transport, coinType: string, accIndex: string, protocol: string): Promise<string> => {
3637
if (protocol === 'BIP44') {
37-
const { outputData } = await executeCommand(transport, 'GET_ED25519_ACC_PUBKEY', 'SE', undefined, coinType, accIndex);
38+
const { outputData } = await executeCommand(transport, commands.GET_ED25519_ACC_PUBKEY, 'SE', undefined, coinType, accIndex);
3839
return outputData;
3940
}
4041
if (protocol === 'SLIP0010') {
41-
const { outputData } = await executeCommand(transport, 'GET_XLM_ACC_PUBKEY', 'SE', undefined, coinType, accIndex);
42+
const { outputData } = await executeCommand(transport, commands.GET_XLM_ACC_PUBKEY, 'SE', undefined, coinType, accIndex);
4243
return outputData;
4344
}
4445
throw Error('Unsupported protocol');

packages/core/src/config/command.ts renamed to packages/core/src/apdu/command.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,8 @@ export type CommandType = {
55
P2: string | undefined
66
};
77

8-
type COMMANDS = {
9-
[key: string]: {
10-
CLA: string,
11-
INS: string,
12-
P1: string | undefined,
13-
P2: string | undefined
14-
};
15-
};
16-
178

18-
export const COMMAND: COMMANDS = {
9+
export const commands = {
1910
ECHO: {
2011
CLA: '80',
2112
INS: '68',

packages/core/src/apdu/control.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,14 @@
11
import { executeCommand } from './execute';
2-
import { RESPONSE } from '../config/response';
32
import Transport from '../transport';
4-
5-
/**
6-
* Response boolean (isCardRecognized)
7-
* @param {Transport} transport
8-
* @param {string} appId
9-
* @return {Promise<boolean>} isCardRecognized
10-
*/
11-
export const sayHi = async (transport: Transport, appId: string): Promise<boolean> => {
12-
try {
13-
const { status } = await executeCommand(transport, 'SAY_HI', 'SE', appId);
14-
return status === RESPONSE.SUCCESS;
15-
} catch (error) {
16-
return false;
17-
}
18-
};
3+
import { commands } from "./command";
194

205
/**
216
* Get nonce from CWS
227
* @param {Transport} transport
238
* @return {Promise<string>}
249
*/
2510
export const getNonce = async (transport: Transport): Promise<string> => {
26-
const { outputData: nonce } = await executeCommand(transport, 'GET_NONCE', 'SE');
11+
const { outputData: nonce } = await executeCommand(transport, commands.GET_NONCE, 'SE');
2712
return nonce;
2813
};
2914

@@ -32,7 +17,7 @@ export const getNonce = async (transport: Transport): Promise<string> => {
3217
* @param {Transport} transport
3318
*/
3419
export const cancelAPDU = async (transport: Transport) => {
35-
await executeCommand(transport, 'CANCEL_APDU', 'SE');
20+
await executeCommand(transport, commands.CANCEL_APDU, 'SE');
3621
};
3722

3823
/**
@@ -41,6 +26,6 @@ export const cancelAPDU = async (transport: Transport) => {
4126
* @return {Promise<boolean>}
4227
*/
4328
export const powerOff = async (transport: Transport): Promise<boolean> => {
44-
await executeCommand(transport, 'PWR_OFF', 'SE');
29+
await executeCommand(transport, commands.PWR_OFF, 'SE');
4530
return true;
4631
};

packages/core/src/apdu/dfu.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
import { executeCommand } from './execute';
22
import Transport from '../transport';
3+
import { commands } from "./command";
34

45
export const getFWStatus = async (transport: Transport) => {
5-
const { outputData } = await executeCommand(transport, 'CHECK_FW_STATUS', 'MCU');
6+
const { outputData } = await executeCommand(transport, commands.CHECK_FW_STATUS, 'MCU');
67
const fwStatus = outputData.slice(0, 4); // 3900
78
const cardMCUVersion = outputData.slice(4, 12).toUpperCase();
89
return { fwStatus, cardMCUVersion };
910
};
1011

11-
export const sendFWsign = async (transport: Transport, data: string) => executeCommand(transport, 'SEND_FW_SIGN', 'MCU', data);
12+
export const sendFWsign = async (transport: Transport, data: string) => executeCommand(transport, commands.SEND_FW_SIGN, 'MCU', data);
1213

13-
export const FWreset = async (transport: Transport) => executeCommand(transport, 'FW_RESET', 'MCU');
14+
export const FWreset = async (transport: Transport) => executeCommand(transport, commands.FW_RESET, 'MCU');
1415

15-
export const FWupdate = async (transport: Transport, P1: string, P2: string, data: string) => executeCommand(transport, 'FW_UPDATE', 'MCU', data, P1, P2);
16+
export const FWupdate = async (transport: Transport, P1: string, P2: string, data: string) => executeCommand(transport, commands.FW_UPDATE, 'MCU', data, P1, P2);
1617

1718
export const getMCUVersion = async (transport: Transport) => {
18-
const { outputData } = await executeCommand(transport, 'GET_MCU_VERSION', 'MCU');
19+
const { outputData } = await executeCommand(transport, commands.GET_MCU_VERSION, 'MCU');
1920
const fwStatus = outputData.slice(0, 4); // 3900
2021
const cardMCUVersion = outputData.slice(4, 12).toUpperCase();
2122
return { fwStatus, cardMCUVersion };

packages/core/src/apdu/display.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { executeCommand } from './execute';
22
import Transport from '../transport';
3+
import { commands } from "./command";
34

45
/**
56
* Display "UPDATE" on wallet display
67
* @param {Transport} transport
78
* @return {Promise<boolean>}
89
*/
910
export const showUpdate = async (transport: Transport): Promise<boolean> => {
10-
await executeCommand(transport, 'START_UPDATE', 'SE');
11+
await executeCommand(transport, commands.START_UPDATE, 'SE');
1112
return true;
1213
};
1314

@@ -17,7 +18,7 @@ export const showUpdate = async (transport: Transport): Promise<boolean> => {
1718
* @return {Promise<boolean>}
1819
*/
1920
export const hideUpdate = async (transport: Transport): Promise<boolean> => {
20-
await executeCommand(transport, 'FINISH_UPDATE', 'SE');
21+
await executeCommand(transport, commands.FINISH_UPDATE, 'SE');
2122
return true;
2223
};
2324

@@ -28,6 +29,6 @@ export const hideUpdate = async (transport: Transport): Promise<boolean> => {
2829
* @return {Promise<boolean>}
2930
*/
3031
export const updateBalance = async (transport: Transport, data: string): Promise<boolean> => {
31-
await executeCommand(transport, 'UPDATE_BALANCE', 'SE', data);
32+
await executeCommand(transport, commands.UPDATE_BALANCE, 'SE', data);
3233
return true;
3334
};

packages/core/src/apdu/execute.ts

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
// import { OperationCanceled, NoTransport } from '../error/index';
2-
import { COMMAND } from '../config/command';
1+
import { CommandType, commands } from './command';
32
import * as util from './utils';
4-
import { CODE } from '../config/apduStatus/code'
3+
import { error as Errors } from '../index';
54
import { SHA256 } from '../crypto/hash';
65
import Transport from '../transport/index';
76
import { SDKError, APDUError } from '../error/errorHandle';
7+
import { CODE } from '../config/apduStatus/code';
88

99

1010
/**
@@ -13,35 +13,46 @@ import { SDKError, APDUError } from '../error/errorHandle';
1313
* @param {{command:string, data:string}} apdu
1414
* @param {string} commandType SE or MCU
1515
*/
16-
const executeAPDU = async (commandName: string, transport: Transport, apdu: { command: string, data: string }, commandType: string): Promise<{ status: string, msg: string, outputData: string }> => {
16+
const executeAPDU = async (
17+
commandName: string,
18+
transport: Transport,
19+
apdu: { command: string, data: string },
20+
executedTarget: string
21+
): Promise<{
22+
status: string,
23+
msg: string,
24+
outputData: string
25+
}> => {
1726
if (typeof transport.request !== 'function') {
1827
throw new SDKError(executeAPDU.name, `Transport not specified or no connection established.`);
1928
}
20-
/*console.log("{")
21-
console.log(" command: " + apdu.command)
22-
console.log(" data: " + apdu.data)
23-
console.log("}")*/
24-
// TODO app transport
29+
console.debug("{")
30+
console.debug(" command: " + apdu.command)
31+
console.debug(" data: " + apdu.data)
32+
console.debug("}")
33+
2534
try{
35+
// TODO app transport
2636
if (transport.requestAPDUV2) {
2737
return await transport.requestAPDUV2(apdu);
2838
}
2939
let msg = ''
3040
const response = await transport.request(apdu.command, apdu.data);
31-
if (commandType === 'SE') {
41+
if (executedTarget === 'SE') {
3242
const status = response.slice(-4);
3343
const outputData = response.slice(0, -4);
3444
msg = util.getReturnMsg(status)
3545
return { status, msg, outputData };
46+
} else {
47+
const status = response.slice(4, 6);
48+
const outputData = response.slice(6);
49+
msg = util.getReturnMsg(status)
50+
return { status, msg, outputData };
3651
}
37-
const status = response.slice(4, 6);
38-
const outputData = response.slice(6);
39-
msg = util.getReturnMsg(status)
40-
return { status, msg, outputData };
52+
4153
} catch (error){
4254
throw new SDKError(executeAPDU.name, `executeAPDU error: ${error}`);
4355
}
44-
4556
};
4657

4758
/**
@@ -58,31 +69,31 @@ const executeAPDU = async (commandName: string, transport: Transport, apdu: { co
5869
*/
5970
export const executeCommand = async (
6071
transport: Transport,
61-
commandName: string,
62-
commandType: string = 'SE',
72+
command: CommandType,
73+
executedTarget: string = 'SE',
6374
data: string = '',
6475
params1: string | undefined = undefined,
6576
params2: string | undefined = undefined,
6677
supportSC: boolean = false,
6778
forceUseSC: boolean = false,
6879
): Promise<{ status: string, msg: string, outputData: string }> => {
69-
const commandParams = COMMAND[commandName];
80+
const P1 = params1 || command.P1;
81+
const P2 = params2 || command.P2;
7082

71-
const P1 = params1 || commandParams.P1;
72-
const P2 = params2 || commandParams.P2;
83+
if ((typeof (P1) == undefined) || (typeof (P2) == undefined)) {
84+
throw new Errors.SDKError('Unknown', command.toString())
85+
}
7386

7487
let response;
75-
7688
// data too long: divide and send with SECURE CHANNEL
7789
if (forceUseSC || (supportSC && data.length > 500)) {
78-
const apduHeader = commandParams.CLA + commandParams.INS + P1 + P2;
90+
const apduHeader = command.CLA + command.INS + P1 + P2;
7991
response = await sendWithSecureChannel(transport, apduHeader, data, forceUseSC);
8092
} else {
81-
const apdu = util.assemblyCommandAndData(commandParams.CLA, commandParams.INS, P1, P2, data);
82-
93+
const apdu = util.assemblyCommandAndData(command.CLA, command.INS, P1, P2, data);
8394
// eslint-disable-next-line no-console
84-
console.debug(`Execute Command: ${commandName}`);
85-
response = await executeAPDU(commandName, transport, apdu, commandType);
95+
console.debug(`Execute Command: ${command}`);
96+
response = await executeAPDU(command.toString(), transport, apdu, executedTarget);
8697
}
8798
return response;
8899

@@ -101,7 +112,7 @@ export const sendWithSecureChannel = async (transport: Transport, apduHeader: st
101112
const dataToHash = apduHeader.concat(salt, apduData);
102113
const hash = SHA256(dataToHash).toString('hex');
103114
const packedData = apduHeader.concat(hash, salt, apduData);
104-
//console.log("Before Secure channel: " + packedData)
115+
console.debug("Before Secure channel: " + packedData)
105116
const channelVersion = '01';
106117
const useSecure = '00';
107118
const useSign = forceUseSC ? '01' : '00';
@@ -116,7 +127,6 @@ export const sendWithSecureChannel = async (transport: Transport, apduHeader: st
116127
}
117128
const totalPackages = chunks.length;
118129

119-
120130
// Send Data
121131
let result;
122132
for (let i = 0; i < totalPackages; i++) {
@@ -128,22 +138,22 @@ export const sendWithSecureChannel = async (transport: Transport, apduHeader: st
128138
// Uncaught error in SC_SEND_SEGMENT command. Return to parent executeCommand
129139
if (status !== CODE._9000) {
130140
return result;
131-
}
141+
} else {
142+
const confirmHash = result.outputData.slice(4, 68);
143+
const confirmSalt = result.outputData.slice(68, 76);
144+
const apduReturn = result.outputData.slice(76);
132145

133-
const confirmHash = result.outputData.slice(4, 68);
134-
const confirmSalt = result.outputData.slice(68, 76);
135-
const apduReturn = result.outputData.slice(76);
146+
if (confirmSalt !== salt) {
147+
throw new SDKError(sendWithSecureChannel.name, 'SC: Returned salt check failed');
148+
}
136149

137-
if (confirmSalt !== salt) {
138-
throw new SDKError(sendWithSecureChannel.name, 'SC: Returned salt check failed');
139-
}
150+
const returnedDataHash = SHA256(confirmSalt + apduReturn).toString('hex');
151+
if (returnedDataHash !== confirmHash) {
152+
throw new SDKError(sendWithSecureChannel.name, 'SC: Returned hash check failed');
153+
}
140154

141-
const returnedDataHash = SHA256(confirmSalt + apduReturn).toString('hex');
142-
if (returnedDataHash !== confirmHash) {
143-
throw new SDKError(sendWithSecureChannel.name, 'SC: Returned hash check failed');
155+
return { status: status, msg: util.getReturnMsg(status), outputData: apduReturn };
144156
}
145-
146-
return { status: status, msg :util.getReturnMsg(status), outputData: apduReturn };
147157
} else {
148158
throw new SDKError(sendWithSecureChannel.name, 'sendWithSecureChannel failed')
149159
}
@@ -160,5 +170,5 @@ export const sendWithSecureChannel = async (transport: Transport, apduHeader: st
160170
const sendFragment = async (transport: Transport, data: string, index: number, totalPackages: number): Promise<{ status: string, msg: string, outputData: string }> => {
161171
const P1 = index.toString(16).padStart(2, '0');
162172
const P2 = totalPackages.toString(16).padStart(2, '0');
163-
return executeCommand(transport, 'SC_SEND_SEGMENT', 'SE', data, P1, P2, false);
173+
return executeCommand(transport, commands.SC_SEND_SEGMENT, 'SE', data, P1, P2, false);
164174
};

packages/core/src/apdu/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import * as setting from './setting';
22
import * as control from './control';
33
import * as display from './display';
4-
import * as tx from './transaction';
54
import * as dfu from './dfu';
65
import * as backup from './backup';
76
import * as coin from './coin';
87
import * as execute from './execute';
98

109
export {
11-
display, control, setting, tx, dfu, backup, coin, execute
10+
display, control, setting, dfu, backup, coin, execute
1211
};

0 commit comments

Comments
 (0)