Support running multiple tests in one process

This commit is contained in:
Simon Warta 2020-09-29 18:01:41 +02:00
parent 53b20f5338
commit 9106d17c4d
5 changed files with 39 additions and 13 deletions

View File

@ -18,6 +18,12 @@ export interface LedgerAppErrorResponse {
}
/* eslint-enable */
interface ConnectedApp {
/** The transport used by the app */
readonly transport: Transport;
readonly app: CosmosApp;
}
const defaultInteractionTimeout = 120; // seconds to wait for user action on Ledger, currently is always limited to 60
const requiredCosmosAppVersion = "1.5.3";
@ -53,7 +59,7 @@ export class LaunchpadLedger {
private readonly testModeAllowed: boolean;
private readonly hdPaths: readonly HdPath[];
private readonly prefix: string;
private cosmosApp: CosmosApp | null;
private connectedApp: ConnectedApp | null;
public readonly platform: string;
public readonly userAgent: string | null;
@ -70,7 +76,7 @@ export class LaunchpadLedger {
this.testModeAllowed = testModeAllowed;
this.hdPaths = hdPaths;
this.prefix = prefix;
this.cosmosApp = null;
this.connectedApp = null;
try {
this.platform = navigator.platform;
@ -83,9 +89,9 @@ export class LaunchpadLedger {
public async getCosmosAppVersion(): Promise<string> {
await this.ensureConnected();
assert(this.cosmosApp, "Cosmos Ledger App is not connected");
assert(this.connectedApp, "Cosmos Ledger App is not connected");
const response = await this.cosmosApp.getVersion();
const response = await this.connectedApp.app.getVersion();
this.handleLedgerErrors(response);
// eslint-disable-next-line @typescript-eslint/naming-convention
const { major, minor, patch, test_mode: testMode } = response as VersionResponse;
@ -95,11 +101,11 @@ export class LaunchpadLedger {
public async getPubkey(hdPath?: HdPath): Promise<Uint8Array> {
await this.ensureConnected();
assert(this.cosmosApp, "Cosmos Ledger App is not connected");
assert(this.connectedApp, "Cosmos Ledger App is not connected");
const hdPathToUse = hdPath || this.hdPaths[0];
// ledger-cosmos-js hardens the first three indices
const response = await this.cosmosApp.publicKey(unharden(hdPathToUse));
const response = await this.connectedApp.app.publicKey(unharden(hdPathToUse));
this.handleLedgerErrors(response);
return Uint8Array.from((response as PublicKeyResponse).compressed_pk);
}
@ -119,18 +125,25 @@ export class LaunchpadLedger {
public async sign(message: Uint8Array, hdPath?: HdPath): Promise<Uint8Array> {
await this.ensureConnected();
assert(this.cosmosApp, "Cosmos Ledger App is not connected");
assert(this.connectedApp, "Cosmos Ledger App is not connected");
const hdPathToUse = hdPath || this.hdPaths[0];
// ledger-cosmos-js hardens the first three indices
const response = await this.cosmosApp.sign(unharden(hdPathToUse), fromUtf8(message));
const response = await this.connectedApp.app.sign(unharden(hdPathToUse), fromUtf8(message));
this.handleLedgerErrors(response, "Transaction signing request was rejected by the user");
return Secp256k1Signature.fromDer((response as SignResponse).signature).toFixedLength();
}
public async disconnect(): Promise<void> {
if (this.connectedApp) {
await this.connectedApp.transport.close();
this.connectedApp = null;
}
}
private async ensureConnected(timeout = defaultInteractionTimeout): Promise<void> {
// assume good connection if connected once
if (this.cosmosApp) {
if (this.connectedApp) {
return;
}
@ -139,7 +152,10 @@ export class LaunchpadLedger {
}
const transport = await this.createTransport(timeout * 1000);
this.cosmosApp = new CosmosApp(transport);
this.connectedApp = {
transport: transport,
app: new CosmosApp(transport),
};
await this.verifyDeviceIsReady();
}
@ -189,9 +205,9 @@ export class LaunchpadLedger {
private async getOpenAppName(): Promise<string> {
await this.ensureConnected();
assert(this.cosmosApp, "Cosmos Ledger App is not connected");
assert(this.connectedApp, "Cosmos Ledger App is not connected");
const response = await this.cosmosApp.appInfo();
const response = await this.connectedApp.app.appInfo();
this.handleLedgerErrors(response);
return (response as AppInfoResponse).appName;
}

View File

@ -46,6 +46,8 @@ describe("LedgerSigner", () => {
pubkey: fromBase64("A2ZnLEcbpyjS30H5UF1vezq29aBcT9oo5EARATIW9Cpj"),
},
]);
await signer.disconnect();
});
});
@ -87,6 +89,8 @@ describe("LedgerSigner", () => {
fistAccount.pubkey,
);
expect(valid).toEqual(true);
await signer.disconnect();
},
interactiveTimeout,
);

View File

@ -52,4 +52,8 @@ export class LedgerSigner implements OfflineSigner {
signature: encodeSecp256k1Signature(accountForAddress.pubkey, signature),
};
}
public async disconnect(): Promise<void> {
return this.ledger.disconnect();
}
}

View File

@ -12,7 +12,7 @@ export declare class LaunchpadLedger {
private readonly testModeAllowed;
private readonly hdPaths;
private readonly prefix;
private cosmosApp;
private connectedApp;
readonly platform: string;
readonly userAgent: string | null;
constructor(options?: LaunchpadLedgerOptions);
@ -21,6 +21,7 @@ export declare class LaunchpadLedger {
getPubkeys(): Promise<readonly Uint8Array[]>;
getCosmosAddress(pubkey?: Uint8Array): Promise<string>;
sign(message: Uint8Array, hdPath?: HdPath): Promise<Uint8Array>;
disconnect(): Promise<void>;
private ensureConnected;
private createTransport;
private verifyAppMode;

View File

@ -8,4 +8,5 @@ export declare class LedgerSigner implements OfflineSigner {
constructor(options?: LaunchpadLedgerOptions);
getAccounts(): Promise<readonly AccountData[]>;
sign(signerAddress: string, signDoc: StdSignDoc): Promise<SignResponse>;
disconnect(): Promise<void>;
}