Playwright: factor out some common code (#49)

* playwright: factor out `bootstrapCrossSigningForClient` method

Pull this out so it can be used elsewhere. Also expose the `resetKeys` param,
which might be useful in future.

* playwright: bot.ts: use `bootstrapCrossSigningForClient`

... instead of reinventing it.

* Only setup cross signing if `startClient` is set
This commit is contained in:
Richard van der Hoff 2024-09-19 08:13:04 +01:00 committed by GitHub
parent 154bf33fa1
commit 1e7631386e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 75 additions and 59 deletions

View file

@ -14,7 +14,7 @@ import type { Logger } from "matrix-js-sdk/src/logger";
import type { SecretStorageKeyDescription } from "matrix-js-sdk/src/secret-storage"; import type { SecretStorageKeyDescription } from "matrix-js-sdk/src/secret-storage";
import type { Credentials, HomeserverInstance } from "../plugins/homeserver"; import type { Credentials, HomeserverInstance } from "../plugins/homeserver";
import type { GeneratedSecretStorageKey } from "matrix-js-sdk/src/crypto-api"; import type { GeneratedSecretStorageKey } from "matrix-js-sdk/src/crypto-api";
import { Client } from "./client"; import { bootstrapCrossSigningForClient, Client } from "./client";
export interface CreateBotOpts { export interface CreateBotOpts {
/** /**
@ -90,9 +90,13 @@ export class Bot extends Client {
} }
protected async getClientHandle(): Promise<JSHandle<ExtendedMatrixClient>> { protected async getClientHandle(): Promise<JSHandle<ExtendedMatrixClient>> {
if (this.handlePromise) return this.handlePromise; if (!this.handlePromise) this.handlePromise = this.buildClient();
return this.handlePromise;
}
this.handlePromise = this.page.evaluateHandle( private async buildClient(): Promise<JSHandle<ExtendedMatrixClient>> {
const credentials = await this.getCredentials();
const clientHandle = await this.page.evaluateHandle(
async ({ homeserver, credentials, opts }) => { async ({ homeserver, credentials, opts }) => {
function getLogger(loggerName: string): Logger { function getLogger(loggerName: string): Logger {
const logger = { const logger = {
@ -172,53 +176,50 @@ export class Bot extends Client {
}); });
} }
if (!opts.startClient) {
return cli;
}
await cli.initRustCrypto({ useIndexedDB: false });
cli.setGlobalErrorOnUnknownDevices(false);
await cli.startClient();
if (opts.bootstrapCrossSigning) {
// XXX: workaround https://github.com/element-hq/element-web/issues/26755
// wait for out device list to be available, as a proxy for the device keys having been uploaded.
await cli.getCrypto()!.getUserDeviceInfo([credentials.userId]);
await cli.getCrypto()!.bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (func) => {
await func({
type: "m.login.password",
identifier: {
type: "m.id.user",
user: credentials.userId,
},
password: credentials.password,
});
},
});
}
if (opts.bootstrapSecretStorage) {
const passphrase = "new passphrase";
const recoveryKey = await cli.getCrypto().createRecoveryKeyFromPassphrase(passphrase);
Object.assign(cli, { __playwright_recovery_key: recoveryKey });
await cli.getCrypto()!.bootstrapSecretStorage({
setupNewSecretStorage: true,
setupNewKeyBackup: true,
createSecretStorageKey: () => Promise.resolve(recoveryKey),
});
}
return cli; return cli;
}, },
{ {
homeserver: this.homeserver.config, homeserver: this.homeserver.config,
credentials: await this.getCredentials(), credentials,
opts: this.opts, opts: this.opts,
}, },
); );
return this.handlePromise;
// If we weren't configured to start the client, bail out now.
if (!this.opts.startClient) {
return clientHandle;
}
await clientHandle.evaluate(async (cli) => {
await cli.initRustCrypto({ useIndexedDB: false });
cli.setGlobalErrorOnUnknownDevices(false);
await cli.startClient();
});
if (this.opts.bootstrapCrossSigning) {
// XXX: workaround https://github.com/element-hq/element-web/issues/26755
// wait for out device list to be available, as a proxy for the device keys having been uploaded.
await clientHandle.evaluate(async (cli, credentials) => {
await cli.getCrypto()!.getUserDeviceInfo([credentials.userId]);
}, credentials);
await bootstrapCrossSigningForClient(clientHandle, credentials);
}
if (this.opts.bootstrapSecretStorage) {
await clientHandle.evaluate(async (cli) => {
const passphrase = "new passphrase";
const recoveryKey = await cli.getCrypto().createRecoveryKeyFromPassphrase(passphrase);
Object.assign(cli, { __playwright_recovery_key: recoveryKey });
await cli.getCrypto()!.bootstrapSecretStorage({
setupNewSecretStorage: true,
setupNewKeyBackup: true,
createSecretStorageKey: () => Promise.resolve(recoveryKey),
});
});
}
return clientHandle;
} }
} }

View file

@ -356,24 +356,11 @@ export class Client {
} }
/** /**
* Boostraps cross-signing. * Bootstraps cross-signing.
*/ */
public async bootstrapCrossSigning(credentials: Credentials): Promise<void> { public async bootstrapCrossSigning(credentials: Credentials): Promise<void> {
const client = await this.prepareClient(); const client = await this.prepareClient();
return client.evaluate(async (client, credentials) => { return bootstrapCrossSigningForClient(client, credentials);
await client.getCrypto().bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (func) => {
await func({
type: "m.login.password",
identifier: {
type: "m.id.user",
user: credentials.userId,
},
password: credentials.password,
});
},
});
}, credentials);
} }
/** /**
@ -439,3 +426,31 @@ export class Client {
); );
} }
} }
/** Call `CryptoApi.bootstrapCrossSigning` on the given Matrix client, using the given credentials to authenticate
* the UIA request.
*/
export function bootstrapCrossSigningForClient(
client: JSHandle<MatrixClient>,
credentials: Credentials,
resetKeys: boolean = false,
) {
return client.evaluate(
async (client, { credentials, resetKeys }) => {
await client.getCrypto().bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (func) => {
await func({
type: "m.login.password",
identifier: {
type: "m.id.user",
user: credentials.userId,
},
password: credentials.password,
});
},
setupNewCrossSigning: resetKeys,
});
},
{ credentials, resetKeys },
);
}