Skip to content

Commit 7815f9f

Browse files
authored
bug: Keychain - Disable shielded key import for nano S (#1953)
1 parent 54e2562 commit 7815f9f

File tree

4 files changed

+36
-11
lines changed

4 files changed

+36
-11
lines changed

apps/extension/src/Setup/Ledger/LedgerConnect.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,16 @@ export const LedgerConnect: React.FC<Props> = ({
5959
if (returnCode !== LedgerError.NoErrors) {
6060
throw new Error(errorMessage);
6161
}
62-
const canImportShielded = await ledger?.isZip32Supported();
63-
setIsZip32Supported(canImportShielded);
62+
const isMaspSupported = await ledger?.isZip32Supported();
63+
setIsZip32Supported(isMaspSupported);
6464

6565
setIsLedgerConnecting(true);
6666
setCurrentApprovalStep(1);
6767
const { address, publicKey } = await ledger.showAddressAndPublicKey(
6868
makeBip44Path(chains.namada.bip44.coinType, bip44Path)
6969
);
7070

71-
if (canImportShielded) {
71+
if (isMaspSupported) {
7272
// Import Shielded Keys
7373
const path = makeSaplingPath(chains.namada.bip44.coinType, {
7474
account: zip32Path.account,
@@ -157,8 +157,8 @@ export const LedgerConnect: React.FC<Props> = ({
157157

158158
{isLedgerConnecting && !isZip32Supported && (
159159
<Alert type="warning">
160-
Shielded key import will be enabled in NamadaApp v
161-
{LEDGER_MIN_VERSION_ZIP32}
160+
Shielded key import is not available for the Nano S or on versions
161+
below {LEDGER_MIN_VERSION_ZIP32}
162162
</Alert>
163163
)}
164164

packages/sdk/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Make Ledger available for direct-import as it is not dependent on Sdk initialization
22
export {
3+
LEDGER_MASP_BLACKLISTED,
34
LEDGER_MIN_VERSION_ZIP32,
45
Ledger,
56
initLedgerUSBTransport,

packages/sdk/src/ledger.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@ export type LedgerProofGenerationKey = {
2828
export type LedgerStatus = {
2929
version: ResponseVersion;
3030
info: ResponseAppInfo;
31+
deviceId?: string;
32+
deviceName?: string;
3133
};
3234

3335
export const LEDGER_MIN_VERSION_ZIP32 = "3.0.0";
36+
export const LEDGER_MASP_BLACKLISTED = "nanoS";
3437

3538
export type Bparams = {
3639
spend: {
@@ -119,10 +122,13 @@ export class Ledger {
119122
public async status(): Promise<LedgerStatus> {
120123
const version = await this.namadaApp.getVersion();
121124
const info = await this.namadaApp.getAppInfo();
125+
const device = this.namadaApp.transport.deviceModel;
122126

123127
return {
124128
version,
125129
info,
130+
deviceId: device?.id,
131+
deviceName: device?.productName,
126132
};
127133
}
128134

@@ -235,7 +241,7 @@ export class Ledger {
235241
promptUser = true
236242
): Promise<LedgerViewingKey> {
237243
try {
238-
await this.validateVersionForZip32();
244+
await this.validateZip32Support();
239245

240246
const { xfvk }: ResponseViewKey = await this.namadaApp.retrieveKeys(
241247
path,
@@ -268,7 +274,7 @@ export class Ledger {
268274
promptUser = true
269275
): Promise<LedgerProofGenerationKey> {
270276
try {
271-
await this.validateVersionForZip32();
277+
await this.validateZip32Support();
272278

273279
const { ak, nsk }: ResponseProofGenKey =
274280
await this.namadaApp.retrieveKeys(
@@ -343,21 +349,33 @@ export class Ledger {
343349
public async isZip32Supported(): Promise<boolean> {
344350
const {
345351
info: { appVersion },
352+
deviceId,
346353
} = await this.status();
347-
return !semver.lt(appVersion, LEDGER_MIN_VERSION_ZIP32);
354+
const isSupportedVersion = !semver.lt(appVersion, LEDGER_MIN_VERSION_ZIP32);
355+
const isSupportedDevice = deviceId !== LEDGER_MASP_BLACKLISTED;
356+
357+
return isSupportedVersion && isSupportedDevice;
348358
}
349359

350360
/**
351-
* Validate the version against the minimum required version for Zip32 functionality.
361+
* Validate the version against the minimum required version and
362+
* device type for Zip32 functionality.
352363
* Throw error if it is unsupported or app is not initialized.
353364
* @async
354365
* @returns void
355366
*/
356-
private async validateVersionForZip32(): Promise<void> {
367+
private async validateZip32Support(): Promise<void> {
357368
if (!(await this.isZip32Supported())) {
358369
const {
359370
info: { appVersion },
371+
deviceId,
372+
deviceName,
360373
} = await this.status();
374+
375+
if (deviceId === LEDGER_MASP_BLACKLISTED) {
376+
throw new Error(`This method is not supported on ${deviceName}!`);
377+
}
378+
361379
throw new Error(
362380
`This method requires Zip32 and is unsupported in ${appVersion}! ` +
363381
`Please update to at least ${LEDGER_MIN_VERSION_ZIP32}!`

packages/sdk/src/tests/ledger.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,23 @@ describe("ledger", () => {
100100
it("should return the status of the ledger", async () => {
101101
const version = { version: "1.0.0" };
102102
const info = { info: "info" };
103+
const deviceId = "nanoSP";
104+
const deviceName = "Ledger Nano S+";
105+
103106
const namadaApp = {
104107
getVersion: jest.fn().mockReturnValue(version),
105108
getAppInfo: jest.fn().mockReturnValue(info),
109+
transport: {
110+
deviceModel: { id: deviceId, productName: deviceName },
111+
},
106112
};
107113
const ledger: Ledger = new (Ledger as any)(namadaApp as any);
108114

109115
const res = await ledger.status();
110116

111117
expect(namadaApp.getVersion).toHaveBeenCalled();
112118
expect(namadaApp.getAppInfo).toHaveBeenCalled();
113-
expect(res).toEqual({ version, info });
119+
expect(res).toEqual({ version, info, deviceId, deviceName });
114120
});
115121
});
116122

0 commit comments

Comments
 (0)