Skip to content

Commit a829463

Browse files
authored
feat: add support to custom app error description at app class level (#63)
* feat: add support to error custom list on process functions * feat: add support to error custom list on responseError class * feat: add support to custom app error description at app class level
1 parent 68dd807 commit a829463

File tree

4 files changed

+19
-11
lines changed

4 files changed

+19
-11
lines changed

src/app.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export default class BaseApp {
3939
readonly P1_VALUES: P1_VALUESGeneric
4040
readonly REQUIRED_PATH_LENGTHS?: number[]
4141
readonly CHUNK_SIZE: number
42+
readonly CUSTOM_APP_ERROR_DESCRIPTION?: Readonly<Record<LedgerError, string>>
4243

4344
/**
4445
* Constructs a new BaseApp instance.
@@ -56,6 +57,7 @@ export default class BaseApp {
5657
this.P1_VALUES = params.p1Values
5758
this.CHUNK_SIZE = params.chunkSize
5859
this.REQUIRED_PATH_LENGTHS = params.acceptedPathLengths
60+
this.CUSTOM_APP_ERROR_DESCRIPTION = params.customAppErrorDescription
5961
}
6062

6163
/**
@@ -125,7 +127,7 @@ export default class BaseApp {
125127
const statusList = [LedgerError.NoErrors, LedgerError.DataIsInvalid, LedgerError.BadKeyHandle]
126128

127129
const responseBuffer = await this.transport.send(this.CLA, ins, payloadType, p2, chunk, statusList)
128-
const response = processResponse(responseBuffer)
130+
const response = processResponse(responseBuffer, this.CUSTOM_APP_ERROR_DESCRIPTION)
129131

130132
return response
131133
}
@@ -154,7 +156,7 @@ export default class BaseApp {
154156
async getVersion(): Promise<ResponseVersion> {
155157
try {
156158
const responseBuffer = await this.transport.send(this.CLA, this.INS.GET_VERSION, 0, 0)
157-
const response = processResponse(responseBuffer)
159+
const response = processResponse(responseBuffer, this.CUSTOM_APP_ERROR_DESCRIPTION)
158160

159161
// valid options are
160162
// test mode: 1 byte
@@ -224,7 +226,7 @@ export default class BaseApp {
224226
async appInfo(): Promise<ResponseAppInfo> {
225227
try {
226228
const responseBuffer = await this.transport.send(LEDGER_DASHBOARD_CLA, 0x01, 0, 0)
227-
const response = processResponse(responseBuffer)
229+
const response = processResponse(responseBuffer, this.CUSTOM_APP_ERROR_DESCRIPTION)
228230

229231
const formatId = response.readBytes(1).readUInt8()
230232

@@ -264,7 +266,7 @@ export default class BaseApp {
264266
async deviceInfo(): Promise<ResponseDeviceInfo> {
265267
try {
266268
const responseBuffer = await this.transport.send(0xe0, 0x01, 0, 0, Buffer.from([]), [LedgerError.NoErrors, 0x6e00])
267-
const response = processResponse(responseBuffer)
269+
const response = processResponse(responseBuffer, this.CUSTOM_APP_ERROR_DESCRIPTION)
268270

269271
const targetId = response.readBytes(4).toString('hex')
270272

src/common.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*****************************************************************************/
16-
import { LedgerError } from './consts'
16+
import { LedgerCustomError, LedgerError } from './consts'
1717
import { errorCodeToString } from './errors'
1818
import { ResponsePayload } from './payload'
1919
import { ResponseError } from './responseError'
@@ -35,18 +35,19 @@ function isDict(v: any): boolean {
3535
* the payload is returned directly. Otherwise, an error object is thrown.
3636
*
3737
* @param responseRaw - The raw response buffer from the device, potentially containing error codes or data.
38+
* @param customErrorList - Custom error description list to convert error code with.
3839
* @returns The payload as a buffer if no errors are found.
3940
* @throws {ResponseError} An object detailing the error if any is found.
4041
*/
41-
export function processResponse(responseRaw: Buffer): ResponsePayload {
42+
export function processResponse(responseRaw: Buffer, customErrorList?: Record<LedgerCustomError, string>): ResponsePayload {
4243
// Ensure the buffer is large enough to contain a return code
4344
if (responseRaw.length < 2) {
4445
throw ResponseError.fromReturnCode(LedgerError.EmptyBuffer)
4546
}
4647

4748
// Determine the return code from the last two bytes of the response
4849
const returnCode = responseRaw.readUInt16BE(responseRaw.length - 2)
49-
let errorMessage = errorCodeToString(returnCode)
50+
let errorMessage = errorCodeToString(returnCode, customErrorList)
5051

5152
// Isolate the payload (all bytes except the last two)
5253
const payload = responseRaw.subarray(0, responseRaw.length - 2)
@@ -70,12 +71,13 @@ export function processResponse(responseRaw: Buffer): ResponsePayload {
7071
* This function is deprecated and should not be used in new implementations.
7172
*
7273
* @param response - The raw response object that may contain error details.
74+
* @param customErrorList - Custom error description list to convert error code with.
7375
* @returns A standardized error response object.
7476
*/
75-
export function processErrorResponse(response: any): ResponseError {
77+
export function processErrorResponse(response: any, customErrorList?: Record<LedgerCustomError, string>): ResponseError {
7678
if (isDict(response)) {
7779
if (Object.prototype.hasOwnProperty.call(response, 'statusCode')) {
78-
return ResponseError.fromReturnCode(response.statusCode)
80+
return ResponseError.fromReturnCode(response.statusCode, customErrorList)
7981
}
8082

8183
if (Object.prototype.hasOwnProperty.call(response, 'returnCode') && Object.prototype.hasOwnProperty.call(response, 'errorMessage')) {

src/responseError.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*****************************************************************************/
16+
import { LedgerCustomError } from './consts'
1617
import { errorCodeToString } from './errors'
1718

1819
/**
@@ -37,9 +38,10 @@ export class ResponseError extends Error {
3738
/**
3839
* Creates a ResponseError instance from a return code.
3940
* @param returnCode - The return code to convert into a ResponseError.
41+
* @param customErrorList - Custom error description list to convert error code with.
4042
* @returns A new instance of ResponseError.
4143
*/
42-
static fromReturnCode(returnCode: number): ResponseError {
43-
return new ResponseError(returnCode, errorCodeToString(returnCode))
44+
static fromReturnCode(returnCode: number, customErrorList?: Record<LedgerCustomError, string>): ResponseError {
45+
return new ResponseError(returnCode, errorCodeToString(returnCode, customErrorList))
4446
}
4547
}

src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*****************************************************************************/
16+
import { LedgerCustomError } from './consts'
1617

1718
/**
1819
* Represents the version response from a device.
@@ -76,6 +77,7 @@ export interface ConstructorParams {
7677
p1Values: P1_VALUESGeneric
7778
chunkSize: number
7879
acceptedPathLengths?: number[]
80+
customAppErrorDescription?: Readonly<Record<LedgerCustomError, string>>
7981
}
8082

8183
export type BIP32Path = string

0 commit comments

Comments
 (0)