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
pull/28192/head
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,34 +176,38 @@ export class Bot extends Client {
}); });
} }
if (!opts.startClient) {
return cli; return cli;
},
{
homeserver: this.homeserver.config,
credentials,
opts: this.opts,
},
);
// 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 }); await cli.initRustCrypto({ useIndexedDB: false });
cli.setGlobalErrorOnUnknownDevices(false); cli.setGlobalErrorOnUnknownDevices(false);
await cli.startClient(); await cli.startClient();
});
if (opts.bootstrapCrossSigning) { if (this.opts.bootstrapCrossSigning) {
// XXX: workaround https://github.com/element-hq/element-web/issues/26755 // 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. // 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]); await cli.getCrypto()!.getUserDeviceInfo([credentials.userId]);
}, credentials);
await cli.getCrypto()!.bootstrapCrossSigning({ await bootstrapCrossSigningForClient(clientHandle, credentials);
authUploadDeviceSigningKeys: async (func) => {
await func({
type: "m.login.password",
identifier: {
type: "m.id.user",
user: credentials.userId,
},
password: credentials.password,
});
},
});
} }
if (opts.bootstrapSecretStorage) { if (this.opts.bootstrapSecretStorage) {
await clientHandle.evaluate(async (cli) => {
const passphrase = "new passphrase"; const passphrase = "new passphrase";
const recoveryKey = await cli.getCrypto().createRecoveryKeyFromPassphrase(passphrase); const recoveryKey = await cli.getCrypto().createRecoveryKeyFromPassphrase(passphrase);
Object.assign(cli, { __playwright_recovery_key: recoveryKey }); Object.assign(cli, { __playwright_recovery_key: recoveryKey });
@ -209,16 +217,9 @@ export class Bot extends Client {
setupNewKeyBackup: true, setupNewKeyBackup: true,
createSecretStorageKey: () => Promise.resolve(recoveryKey), createSecretStorageKey: () => Promise.resolve(recoveryKey),
}); });
});
} }
return cli; return clientHandle;
},
{
homeserver: this.homeserver.config,
credentials: await this.getCredentials(),
opts: this.opts,
},
);
return this.handlePromise;
} }
} }

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 },
);
}