-
-
Notifications
You must be signed in to change notification settings - Fork 9
feat: add new hardware errors #421
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
d7e6756
8023f97
b86b627
5777cba
53206ed
7d906ee
cae2667
c4cd240
8cf427b
928e0de
9a617f4
a829975
6e59f1f
131e513
b3f1404
de46ef7
a555c4b
4c01d43
f5b2230
85fe698
ce66cea
954c66a
6fc8735
414fef0
b865d0a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| import { LEDGER_ERROR_MAPPINGS } from './hardware-error-mappings'; | ||
| import { ErrorCode, Severity, Category } from './hardware-errors-enums'; | ||
|
|
||
| describe('HARDWARE_ERROR_MAPPINGS', () => { | ||
| describe('Ledger mappings', () => { | ||
| const errorMappings = LEDGER_ERROR_MAPPINGS; | ||
|
|
||
| it('have errorMappings object', () => { | ||
| expect(errorMappings).toBeDefined(); | ||
| expect(typeof errorMappings).toBe('object'); | ||
| }); | ||
|
|
||
| describe('success codes', () => { | ||
| it('map 0x9000 to success', () => { | ||
| const mapping = errorMappings['0x9000']; | ||
| expect(mapping).toBeDefined(); | ||
| expect(mapping.customCode).toBe(ErrorCode.Success); | ||
| expect(mapping.severity).toBe(Severity.Info); | ||
| expect(mapping.category).toBe(Category.Success); | ||
| }); | ||
| }); | ||
|
|
||
| describe('authentication errors', () => { | ||
| it('map 0x6300 to authentication failed', () => { | ||
| const mapping = errorMappings['0x6300']; | ||
| expect(mapping.customCode).toBe(ErrorCode.AuthenticationFailed); | ||
| expect(mapping.severity).toBe(Severity.Err); | ||
| expect(mapping.category).toBe(Category.Authentication); | ||
| expect(mapping.userMessage).toBeDefined(); | ||
| }); | ||
|
|
||
| it('map 0x63c0 to PIN attempts remaining', () => { | ||
| const mapping = errorMappings['0x63c0']; | ||
| expect(mapping.customCode).toBe( | ||
| ErrorCode.AuthenticationPinAttemptsRemaining, | ||
| ); | ||
| expect(mapping.severity).toBe(Severity.Warning); | ||
| }); | ||
|
|
||
| it('map 0x5515 to device locked', () => { | ||
| const mapping = errorMappings['0x5515']; | ||
| expect(mapping.customCode).toBe(ErrorCode.AuthenticationDeviceLocked); | ||
| expect(mapping.severity).toBe(Severity.Err); | ||
| expect(mapping.userMessage).toContain('unlock'); | ||
| }); | ||
|
|
||
| it('map 0x9840 to device blocked', () => { | ||
| const mapping = errorMappings['0x9840']; | ||
| expect(mapping.customCode).toBe(ErrorCode.AuthenticationDeviceBlocked); | ||
| expect(mapping.severity).toBe(Severity.Critical); | ||
| }); | ||
| }); | ||
|
|
||
| describe('user action errors', () => { | ||
| it('map 0x6985 to user rejected', () => { | ||
| const mapping = errorMappings['0x6985']; | ||
| expect(mapping.customCode).toBe(ErrorCode.UserRejected); | ||
| expect(mapping.severity).toBe(Severity.Warning); | ||
| expect(mapping.category).toBe(Category.UserAction); | ||
| }); | ||
|
|
||
| it('map 0x5501 to user refused', () => { | ||
| const mapping = errorMappings['0x5501']; | ||
| expect(mapping.customCode).toBe(ErrorCode.UserRejected); | ||
| expect(mapping.severity).toBe(Severity.Warning); | ||
| }); | ||
| }); | ||
| describe('connection errors', () => { | ||
| it('map 0x650f to connection issue', () => { | ||
| const mapping = errorMappings['0x650f']; | ||
| expect(mapping.customCode).toBe(ErrorCode.ConnClosed); | ||
| expect(mapping.category).toBe(Category.Connection); | ||
| }); | ||
| }); | ||
|
|
||
| it('have valid structure for all mappings', () => { | ||
| Object.entries(errorMappings).forEach(([_, mapping]) => { | ||
| expect(mapping).toHaveProperty('customCode'); | ||
| expect(mapping).toHaveProperty('message'); | ||
| expect(mapping).toHaveProperty('severity'); | ||
| expect(mapping).toHaveProperty('category'); | ||
|
|
||
| const numericErrorCodes = Object.values(ErrorCode).filter( | ||
| (value): value is number => typeof value === 'number', | ||
| ); | ||
| expect(numericErrorCodes).toContain(mapping.customCode); | ||
| expect(Object.values(Severity)).toContain(mapping.severity); | ||
| expect(Object.values(Category)).toContain(mapping.category); | ||
| expect(typeof mapping.message).toBe('string'); | ||
| }); | ||
| }); | ||
|
|
||
| it('have valid userMessage when present', () => { | ||
| const mappingsWithUserMessage = Object.values(errorMappings).filter( | ||
| (mapping): mapping is typeof mapping & { userMessage: string } => | ||
| 'userMessage' in mapping && | ||
| typeof mapping.userMessage === 'string' && | ||
| mapping.userMessage.length > 0, | ||
| ); | ||
| expect(mappingsWithUserMessage.length).toBeGreaterThan(0); | ||
| mappingsWithUserMessage.forEach((mapping) => { | ||
| expect(typeof mapping.userMessage).toBe('string'); | ||
| expect(mapping.userMessage.length).toBeGreaterThan(0); | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| describe('consistency checks', () => { | ||
| it('have unique error codes', () => { | ||
| const ledgerCodes = Object.values(LEDGER_ERROR_MAPPINGS); | ||
| const ledgerCustomCodes = ledgerCodes.map( | ||
| (mapping) => mapping.customCode, | ||
| ); | ||
| expect(ledgerCustomCodes.length).toBeGreaterThan(0); | ||
| }); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test claims uniqueness validation but doesn't verify itLow Severity The test named "should have unique error codes within each vendor" only asserts that |
||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| /* eslint-disable @typescript-eslint/naming-convention */ | ||
| import { ErrorCode, Severity, Category } from './hardware-errors-enums'; | ||
|
|
||
| export const LEDGER_ERROR_MAPPINGS = { | ||
| '0x9000': { | ||
| customCode: ErrorCode.Success, | ||
| message: 'Operation successful', | ||
| severity: Severity.Info, | ||
| category: Category.Success, | ||
| }, | ||
| '0x6300': { | ||
| customCode: ErrorCode.AuthenticationFailed, | ||
| message: 'Authentication failed', | ||
| severity: Severity.Err, | ||
| category: Category.Authentication, | ||
| userMessage: 'Authentication failed. Please verify your credentials.', | ||
| }, | ||
| '0x63c0': { | ||
| customCode: ErrorCode.AuthenticationPinAttemptsRemaining, | ||
| message: 'PIN attempts remaining', | ||
| severity: Severity.Warning, | ||
| category: Category.Authentication, | ||
| userMessage: 'Incorrect PIN. Please try again.', | ||
| }, | ||
| '0x6982': { | ||
| customCode: ErrorCode.AuthenticationSecurityCondition, | ||
| message: 'Security conditions not satisfied', | ||
| severity: Severity.Err, | ||
| category: Category.Authentication, | ||
|
|
||
| userMessage: | ||
| 'Device is locked or access rights are insufficient. Please unlock your device.', | ||
| }, | ||
| '0x6985': { | ||
| customCode: ErrorCode.UserRejected, | ||
| message: 'User rejected action on device', | ||
| severity: Severity.Warning, | ||
| category: Category.UserAction, | ||
|
|
||
| userMessage: | ||
| 'Transaction was rejected. Please approve on your device to continue.', | ||
| }, | ||
| '0x9804': { | ||
| customCode: ErrorCode.AuthenticationSecurityCondition, | ||
| message: 'App update required', | ||
| severity: Severity.Err, | ||
| category: Category.Authentication, | ||
|
|
||
| userMessage: 'Please update your Ledger app to continue.', | ||
| }, | ||
| '0x9808': { | ||
| customCode: ErrorCode.AuthenticationFailed, | ||
| message: 'Contradiction in secret code status', | ||
| severity: Severity.Err, | ||
| category: Category.Authentication, | ||
| }, | ||
| '0x9840': { | ||
| customCode: ErrorCode.AuthenticationDeviceBlocked, | ||
| message: 'Code blocked', | ||
| severity: Severity.Critical, | ||
| category: Category.Authentication, | ||
|
|
||
| userMessage: | ||
| 'Your device is blocked due to too many failed attempts. Please follow device recovery procedures.', | ||
| }, | ||
| '0x650f': { | ||
| customCode: ErrorCode.ConnClosed, | ||
| message: 'App closed or connection issue', | ||
| severity: Severity.Err, | ||
| category: Category.Connection, | ||
| userMessage: | ||
| 'Connection lost or app closed. Please open the corresponding app on your Ledger device.', | ||
| }, | ||
| '0x5515': { | ||
| customCode: ErrorCode.AuthenticationDeviceLocked, | ||
| message: 'Device is locked', | ||
| severity: Severity.Err, | ||
| category: Category.Authentication, | ||
| userMessage: 'Please unlock your Ledger device to continue.', | ||
| }, | ||
| '0x5501': { | ||
| customCode: ErrorCode.UserRejected, | ||
| message: 'User refused on device', | ||
| severity: Severity.Warning, | ||
| category: Category.UserAction, | ||
| userMessage: | ||
| 'Operation was rejected. Please approve on your device to continue.', | ||
| }, | ||
| '0x6a80': { | ||
| customCode: ErrorCode.DeviceStateBlindSignNotSupported, | ||
| message: 'Blind signing not supported', | ||
| severity: Severity.Err, | ||
| category: Category.DeviceState, | ||
| userMessage: 'Blind signing is not supported on this device.', | ||
| }, | ||
| '0x6d00': { | ||
| customCode: ErrorCode.DeviceStateOnlyV4Supported, | ||
| message: 'Ledger Only V4 supported', | ||
| severity: Severity.Err, | ||
| category: Category.DeviceState, | ||
| userMessage: 'Only V4 is supported on this device.', | ||
| }, | ||
| '0x6e00': { | ||
| customCode: ErrorCode.DeviceStateEthAppClosed, | ||
| message: 'Ethereum app closed', | ||
| severity: Severity.Err, | ||
| category: Category.DeviceState, | ||
| userMessage: 'Ethereum app is closed. Please open it to continue.', | ||
| }, | ||
| '0x6501': { | ||
| customCode: ErrorCode.DeviceStateEthAppOutOfDate, | ||
| message: 'Ethereum app out of date', | ||
| severity: Severity.Err, | ||
| category: Category.DeviceState, | ||
| userMessage: 'Ethereum app is out of date. Please update it to continue.', | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused dependency added but never imported
Low Severity
The
@metamask/keyring-utilspackage is added as a dependency inpackage.jsonand as a TypeScript reference intsconfig.build.json, but there are no imports or usages of this package anywhere in the source files. All source files (hardware-error.ts,hardware-error-mappings.ts,hardware-errors-enums.ts) only import from the local./hardware-errors-enumsmodule. This appears to be leftover from refactoring or was intended for code that wasn't included.Additional Locations (1)
packages/hw-device-sdk/tsconfig.build.json#L7-L8