Skip to content

Commit

Permalink
♻️ (core) [DSDK-292]: Use custom errors SdkError everywhere (#77)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdabbech-ledger authored May 14, 2024
2 parents 06e4121 + b2c5820 commit a807f59
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 18 deletions.
46 changes: 46 additions & 0 deletions packages/core/src/api/command/Errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { SdkError } from "@api/Error";

export class InvalidStatusWordError implements SdkError {
readonly _tag = "InvalidStatusWordError";
originalError?: Error;

constructor(message?: string) {
this.originalError = new Error(message ?? "Invalid status word.");
}
}

export class InvalidBatteryStatusTypeError implements SdkError {
readonly _tag = "InvalidBatteryStatusTypeError";
originalError: Error;

constructor(message?: string) {
this.originalError = new Error(message ?? "Invalid battery status type.");
}
}

export class InvalidBatteryDataError implements SdkError {
readonly _tag = "InvalidBatteryDataError";
originalError: Error;

constructor(message?: string) {
this.originalError = new Error(message ?? "Invalid battery data.");
}
}

export class InvalidBatteryFlagsError implements SdkError {
readonly _tag = "InvalidBatteryFlagsError";
originalError: Error;

constructor(message?: string) {
this.originalError = new Error(message ?? "Invalid battery flags.");
}
}

export class InvalidResponseFormatError implements SdkError {
readonly _tag = "InvalidResponseFormatError";
originalError: Error;

constructor(message?: string) {
this.originalError = new Error(message ?? "Invalid response format.");
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { Command } from "@api/command/Command";
import {
InvalidResponseFormatError,
InvalidStatusWordError,
} from "@api/command/Errors";
import { ApduResponse } from "@internal/device-session/model/ApduResponse";

import {
Expand Down Expand Up @@ -71,7 +75,7 @@ describe("GetAppAndVersionCommand", () => {
});

expect(() => command.parseResponse(FAILED_RESPONSE)).toThrow(
"Unexpected status word: 6700",
InvalidStatusWordError,
);
});
it("should throw an error if the response returned unsupported format", () => {
Expand All @@ -81,7 +85,7 @@ describe("GetAppAndVersionCommand", () => {
});

expect(() => command.parseResponse(ERROR_RESPONSE)).toThrow(
"getAppAndVersion: format not supported",
InvalidResponseFormatError,
);
});
});
Expand Down
12 changes: 8 additions & 4 deletions packages/core/src/api/command/os/GetAppAndVersionCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import { Apdu } from "@api/apdu/model/Apdu";
import { ApduBuilder, ApduBuilderArgs } from "@api/apdu/utils/ApduBuilder";
import { ApduParser } from "@api/apdu/utils/ApduParser";
import { Command } from "@api/command/Command";
import {
InvalidResponseFormatError,
InvalidStatusWordError,
} from "@api/command/Errors";
import { CommandUtils } from "@api/command/utils/CommandUtils";
import { ApduResponse } from "@internal/device-session/model/ApduResponse";

Expand All @@ -26,18 +30,18 @@ export class GetAppAndVersionCommand

parseResponse(apduResponse: ApduResponse): GetAppAndVersionResponse {
const parser = new ApduParser(apduResponse);
// [SHOULD] Implement new error treatment logic
if (!CommandUtils.isSuccessResponse(apduResponse)) {
throw new Error(
throw new InvalidStatusWordError(
`Unexpected status word: ${parser.encodeToHexaString(
apduResponse.statusCode,
)}`,
);
}

if (parser.extract8BitUint() !== 1) {
// TODO: Make dedicated error object
throw new Error("getAppAndVersion: format not supported");
throw new InvalidResponseFormatError(
"getAppAndVersion: format not supported",
);
}

const name = parser.encodeToString(parser.extractFieldLVEncoded());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { Command } from "@api/command/Command";
import {
InvalidBatteryStatusTypeError,
InvalidStatusWordError,
} from "@api/command/Errors";
import { ApduResponse } from "@internal/device-session/model/ApduResponse";

import {
Expand Down Expand Up @@ -106,7 +110,7 @@ describe("GetBatteryStatus", () => {
data: PERCENTAGE_RESPONSE_HEX.slice(0, -2),
});
expect(() => command.parseResponse(PERCENTAGE_RESPONSE)).toThrow(
"Call getApdu to initialise battery status type.",
InvalidBatteryStatusTypeError,
);
});
it("should throw an error if the response returned unsupported format", () => {
Expand All @@ -116,7 +120,7 @@ describe("GetBatteryStatus", () => {
});
command.getApdu(BatteryStatusType.BATTERY_PERCENTAGE);
expect(() => command.parseResponse(FAILED_RESPONSE)).toThrow(
"Unexpected status word: 6700",
InvalidStatusWordError,
);
});
});
Expand Down
23 changes: 15 additions & 8 deletions packages/core/src/api/command/os/GetBatteryStatusCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import { Apdu } from "@api/apdu/model/Apdu";
import { ApduBuilder, ApduBuilderArgs } from "@api/apdu/utils/ApduBuilder";
import { ApduParser } from "@api/apdu/utils/ApduParser";
import { Command } from "@api/command/Command";
import {
InvalidBatteryDataError,
InvalidBatteryFlagsError,
InvalidBatteryStatusTypeError,
InvalidStatusWordError,
} from "@api/command/Errors";
import { CommandUtils } from "@api/command/utils/CommandUtils";
import { ApduResponse } from "@internal/device-session/model/ApduResponse";

Expand Down Expand Up @@ -56,13 +62,14 @@ export class GetBatteryStatusCommand

parseResponse(apduResponse: ApduResponse): GetBatteryStatusResponse {
if (this._statusType === undefined) {
throw new Error("Call getApdu to initialise battery status type.");
throw new InvalidBatteryStatusTypeError(
"Call getApdu to initialise battery status type.",
);
}

const parser = new ApduParser(apduResponse);
// [SHOULD] Implement new error treatment logic
if (!CommandUtils.isSuccessResponse(apduResponse)) {
throw new Error(
throw new InvalidStatusWordError(
`Unexpected status word: ${parser.encodeToHexaString(
apduResponse.statusCode,
)}`,
Expand All @@ -73,29 +80,29 @@ export class GetBatteryStatusCommand
case BatteryStatusType.BATTERY_PERCENTAGE: {
const percentage = parser.extract8BitUint();
if (!percentage) {
throw new Error("Cannot parse APDU response");
throw new InvalidBatteryDataError("Cannot parse APDU response");
}
return percentage > 100 ? -1 : percentage;
}
case BatteryStatusType.BATTERY_VOLTAGE: {
const data = parser.extract16BitUInt();
if (!data) {
throw new Error("Cannot parse APDU response");
throw new InvalidBatteryDataError("Cannot parse APDU response");
}
return data;
}
case BatteryStatusType.BATTERY_TEMPERATURE:
case BatteryStatusType.BATTERY_CURRENT: {
const data = parser.extract8BitUint();
if (!data) {
throw new Error("Cannot parse APDU response");
throw new InvalidBatteryDataError("Cannot parse APDU response");
}
return (data << 24) >> 24;
}
case BatteryStatusType.BATTERY_FLAGS: {
const flags = parser.extract32BitUInt();
if (!flags) {
throw new Error("Cannot parse APDU response");
throw new InvalidBatteryFlagsError("Cannot parse APDU response");
}
const chargingUSB = !!(flags & FlagMasks.USB_POWERED);
const chargingQi = !chargingUSB && !!(flags & FlagMasks.CHARGING);
Expand All @@ -116,6 +123,6 @@ export class GetBatteryStatusCommand
}

private _exhaustiveMatchingGuard(_: never): never {
throw new Error("One or some case(s) not covered");
throw new InvalidBatteryStatusTypeError("One or some case(s) not covered");
}
}
3 changes: 2 additions & 1 deletion packages/core/src/api/command/os/GetOsVersionCommand.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Command } from "@api/command/Command";
import { InvalidStatusWordError } from "@api/command/Errors";
import { DeviceModelId } from "@api/device/DeviceModel";
import { ApduResponse } from "@internal/device-session/model/ApduResponse";

Expand Down Expand Up @@ -129,7 +130,7 @@ describe("GetOsVersionCommand", () => {

expect(() =>
command.parseResponse(response, DeviceModelId.NANO_X),
).toThrow("Unexpected status word: 6e80");
).toThrow(InvalidStatusWordError);
});
});
});
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/api/command/os/GetOsVersionCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Apdu } from "@api/apdu/model/Apdu";
import { ApduBuilder } from "@api/apdu/utils/ApduBuilder";
import { ApduParser } from "@api/apdu/utils/ApduParser";
import { Command } from "@api/command/Command";
import { InvalidStatusWordError } from "@api/command/Errors";
import { CommandUtils } from "@api/command/utils/CommandUtils";
import { DeviceModelId } from "@api/device/DeviceModel";
import { ApduResponse } from "@internal/device-session/model/ApduResponse";
Expand Down Expand Up @@ -30,7 +31,7 @@ export class GetOsVersionCommand implements Command<GetOsVersionResponse> {
const parser = new ApduParser(responseApdu);
if (!CommandUtils.isSuccessResponse(responseApdu)) {
// [ASK] How de we handle unsuccessful responses?
throw new Error(
throw new InvalidStatusWordError(
`Unexpected status word: ${parser.encodeToHexaString(responseApdu.statusCode)}`,
);
}
Expand Down

0 comments on commit a807f59

Please sign in to comment.