Add a login test against Synapse to Playwright (#11913)
* Install playwright Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add foundations for writing tests under Playwright Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * .gitignore juggling Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add tsconfig and fix eslint rules Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add docker & synapse plugins Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add login.spec.ts Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Wire up fixture which sets up ElementAppPage & bakes config.json Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove launch test, it has served its purpose Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove test which has been ported to Playwright Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix test not cleaning up after itself Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Move registerUser to the Homeserver interface Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove unused fixture param Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Remove redundant launch test Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add newline --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: R Midhun Suresh <hi@midhun.dev>
This commit is contained in:
parent
ecc46aeb8c
commit
52e3e0de1f
26 changed files with 1138 additions and 89 deletions
|
@ -26,65 +26,6 @@ describe("Login", () => {
|
|||
cy.stopHomeserver(homeserver);
|
||||
});
|
||||
|
||||
describe("m.login.password", () => {
|
||||
const username = "user1234";
|
||||
const password = "p4s5W0rD";
|
||||
|
||||
beforeEach(() => {
|
||||
cy.startHomeserver("consent").then((data) => {
|
||||
homeserver = data;
|
||||
cy.registerUser(homeserver, username, password);
|
||||
cy.visit("/#/login");
|
||||
});
|
||||
});
|
||||
|
||||
it("logs in with an existing account and lands on the home screen", () => {
|
||||
cy.injectAxe();
|
||||
|
||||
// first pick the homeserver, as otherwise the user picker won't be visible
|
||||
cy.findByRole("button", { name: "Edit" }).click();
|
||||
cy.findByRole("textbox", { name: "Other homeserver" }).type(homeserver.baseUrl);
|
||||
cy.findByRole("button", { name: "Continue" }).click();
|
||||
// wait for the dialog to go away
|
||||
cy.get(".mx_ServerPickerDialog").should("not.exist");
|
||||
|
||||
cy.get(".mx_Spinner").should("not.exist");
|
||||
cy.get(".mx_ServerPicker_server").should("have.text", homeserver.baseUrl);
|
||||
|
||||
cy.findByRole("button", { name: "Edit" }).click();
|
||||
|
||||
// select the default server again
|
||||
cy.get(".mx_StyledRadioButton").first().click();
|
||||
cy.findByRole("button", { name: "Continue" }).click();
|
||||
cy.get(".mx_ServerPickerDialog").should("not.exist");
|
||||
cy.get(".mx_Spinner").should("not.exist");
|
||||
// name of default server
|
||||
cy.get(".mx_ServerPicker_server").should("have.text", "server.invalid");
|
||||
|
||||
// switch back to the custom homeserver
|
||||
|
||||
cy.findByRole("button", { name: "Edit" }).click();
|
||||
cy.findByRole("textbox", { name: "Other homeserver" }).type(homeserver.baseUrl);
|
||||
cy.findByRole("button", { name: "Continue" }).click();
|
||||
// wait for the dialog to go away
|
||||
cy.get(".mx_ServerPickerDialog").should("not.exist");
|
||||
|
||||
cy.get(".mx_Spinner").should("not.exist");
|
||||
cy.get(".mx_ServerPicker_server").should("have.text", homeserver.baseUrl);
|
||||
|
||||
cy.findByRole("textbox", { name: "Username", timeout: 15000 }).should("be.visible");
|
||||
// Disabled because flaky - see https://github.com/vector-im/element-web/issues/24688
|
||||
//cy.percySnapshot("Login");
|
||||
cy.checkA11y();
|
||||
|
||||
cy.findByRole("textbox", { name: "Username" }).type(username);
|
||||
cy.findByPlaceholderText("Password").type(password);
|
||||
cy.findByRole("button", { name: "Sign in" }).click();
|
||||
|
||||
cy.url().should("contain", "/#/home", { timeout: 30000 });
|
||||
});
|
||||
});
|
||||
|
||||
// tests for old-style SSO login, in which we exchange tokens with Synapse, and Synapse talks to an auth server
|
||||
describe("SSO login", () => {
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -33,6 +33,7 @@ describe("Soft logout", () => {
|
|||
|
||||
afterEach(() => {
|
||||
cy.stopHomeserver(homeserver);
|
||||
cy.task("stopOAuthServer");
|
||||
});
|
||||
|
||||
describe("with password user", () => {
|
||||
|
|
|
@ -184,6 +184,7 @@
|
|||
"@typescript-eslint/parser": "^5.6.0",
|
||||
"allchange": "^1.1.0",
|
||||
"axe-core": "4.8.2",
|
||||
"axe-playwright": "^1.2.3",
|
||||
"babel-jest": "^29.0.0",
|
||||
"blob-polyfill": "^7.0.0",
|
||||
"cypress": "^12.0.0",
|
||||
|
|
1
playwright/.gitignore
vendored
1
playwright/.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
/test-results/
|
||||
/html-report/
|
||||
/synapselogs/
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
test.describe("App launch", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/");
|
||||
});
|
||||
|
||||
test("should launch and render the welcome view successfully", async ({ page }) => {
|
||||
await page.locator("#matrixchat").waitFor();
|
||||
await page.locator(".mx_Welcome").waitFor();
|
||||
await expect(page).toHaveURL("http://localhost:8080/#/welcome");
|
||||
});
|
||||
});
|
78
playwright/e2e/login/login.spec.ts
Normal file
78
playwright/e2e/login/login.spec.ts
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { checkA11y, injectAxe } from "axe-playwright";
|
||||
|
||||
import { test, expect } from "../../element-web-test";
|
||||
|
||||
test.describe("Consent", () => {
|
||||
test.describe("m.login.password", () => {
|
||||
test.use({ startHomeserverOpts: "consent" });
|
||||
|
||||
const username = "user1234";
|
||||
const password = "p4s5W0rD";
|
||||
|
||||
test.beforeEach(async ({ page, homeserver }) => {
|
||||
await homeserver.registerUser(username, password);
|
||||
await page.goto("/#/login");
|
||||
});
|
||||
|
||||
test("logs in with an existing account and lands on the home screen", async ({ page, homeserver }) => {
|
||||
await injectAxe(page);
|
||||
|
||||
// first pick the homeserver, as otherwise the user picker won't be visible
|
||||
await page.getByRole("button", { name: "Edit" }).click();
|
||||
await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.config.baseUrl);
|
||||
await page.getByRole("button", { name: "Continue", exact: true }).click();
|
||||
// wait for the dialog to go away
|
||||
await expect(page.locator(".mx_ServerPickerDialog")).toHaveCount(0);
|
||||
|
||||
await expect(page.locator(".mx_Spinner")).toHaveCount(0);
|
||||
await expect(page.locator(".mx_ServerPicker_server")).toHaveText(homeserver.config.baseUrl);
|
||||
|
||||
await page.getByRole("button", { name: "Edit" }).click();
|
||||
|
||||
// select the default server again
|
||||
await page.locator(".mx_StyledRadioButton").first().click();
|
||||
await page.getByRole("button", { name: "Continue", exact: true }).click();
|
||||
await expect(page.locator(".mx_ServerPickerDialog")).toHaveCount(0);
|
||||
await expect(page.locator(".mx_Spinner")).toHaveCount(0);
|
||||
// name of default server
|
||||
await expect(page.locator(".mx_ServerPicker_server")).toHaveText("server.invalid");
|
||||
|
||||
// switch back to the custom homeserver
|
||||
await page.getByRole("button", { name: "Edit" }).click();
|
||||
await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.config.baseUrl);
|
||||
await page.getByRole("button", { name: "Continue", exact: true }).click();
|
||||
// wait for the dialog to go away
|
||||
await expect(page.locator(".mx_ServerPickerDialog")).toHaveCount(0);
|
||||
|
||||
await expect(page.locator(".mx_Spinner")).toHaveCount(0);
|
||||
await expect(page.locator(".mx_ServerPicker_server")).toHaveText(homeserver.config.baseUrl);
|
||||
|
||||
await expect(page.getByRole("textbox", { name: "Username" })).toBeVisible();
|
||||
// Disabled because flaky - see https://github.com/vector-im/element-web/issues/24688
|
||||
// cy.percySnapshot("Login");
|
||||
await checkA11y(page);
|
||||
|
||||
await page.getByRole("textbox", { name: "Username" }).fill(username);
|
||||
await page.getByPlaceholder("Password").fill(password);
|
||||
await page.getByRole("button", { name: "Sign in" }).click();
|
||||
|
||||
await expect(page).toHaveURL(/\/#\/home$/);
|
||||
});
|
||||
});
|
||||
});
|
64
playwright/element-web-test.ts
Normal file
64
playwright/element-web-test.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as base } from "@playwright/test";
|
||||
|
||||
import { HomeserverInstance, StartHomeserverOpts } from "./plugins/utils/homeserver";
|
||||
import { Synapse } from "./plugins/synapse";
|
||||
|
||||
const CONFIG_JSON = {
|
||||
// This is deliberately quite a minimal config.json, so that we can test that the default settings
|
||||
// actually work.
|
||||
//
|
||||
// The only thing that we really *need* (otherwise Element refuses to load) is a default homeserver.
|
||||
// We point that to a guaranteed-invalid domain.
|
||||
default_server_config: {
|
||||
"m.homeserver": {
|
||||
base_url: "https://server.invalid",
|
||||
},
|
||||
},
|
||||
|
||||
// the location tests want a map style url.
|
||||
map_style_url: "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx",
|
||||
};
|
||||
|
||||
export const test = base.extend<{
|
||||
startHomeserverOpts: StartHomeserverOpts | string;
|
||||
homeserver: HomeserverInstance;
|
||||
}>({
|
||||
page: async ({ context, page }, use) => {
|
||||
await context.route(`http://localhost:8080/config.json*`, async (route) => {
|
||||
await route.fulfill({ json: CONFIG_JSON });
|
||||
});
|
||||
|
||||
await use(page);
|
||||
},
|
||||
|
||||
startHomeserverOpts: "default",
|
||||
homeserver: async ({ request, startHomeserverOpts: opts }, use) => {
|
||||
if (typeof opts === "string") {
|
||||
opts = { template: opts };
|
||||
}
|
||||
|
||||
const server = new Synapse(request);
|
||||
await use(await server.start(opts));
|
||||
await server.stop();
|
||||
},
|
||||
});
|
||||
|
||||
test.use({});
|
||||
|
||||
export { expect } from "@playwright/test";
|
153
playwright/plugins/docker/index.ts
Normal file
153
playwright/plugins/docker/index.ts
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as os from "os";
|
||||
import * as crypto from "crypto";
|
||||
import * as childProcess from "child_process";
|
||||
import * as fse from "fs-extra";
|
||||
|
||||
export class Docker {
|
||||
public id: string;
|
||||
|
||||
async run(opts: { image: string; containerName: string; params?: string[]; cmd?: string[] }): Promise<string> {
|
||||
const userInfo = os.userInfo();
|
||||
const params = opts.params ?? [];
|
||||
|
||||
if (params?.includes("-v") && userInfo.uid >= 0) {
|
||||
// Run the docker container as our uid:gid to prevent problems with permissions.
|
||||
if (await Docker.isPodman()) {
|
||||
// Note: this setup is for podman rootless containers.
|
||||
|
||||
// In podman, run as root in the container, which maps to the current
|
||||
// user on the host. This is probably the default since Synapse's
|
||||
// Dockerfile doesn't specify, but we're being explicit here
|
||||
// because it's important for the permissions to work.
|
||||
params.push("-u", "0:0");
|
||||
|
||||
// Tell Synapse not to switch UID
|
||||
params.push("-e", "UID=0");
|
||||
params.push("-e", "GID=0");
|
||||
} else {
|
||||
params.push("-u", `${userInfo.uid}:${userInfo.gid}`);
|
||||
}
|
||||
}
|
||||
|
||||
const args = [
|
||||
"run",
|
||||
"--name",
|
||||
`${opts.containerName}-${crypto.randomBytes(4).toString("hex")}`,
|
||||
"-d",
|
||||
"--rm",
|
||||
...params,
|
||||
opts.image,
|
||||
];
|
||||
|
||||
if (opts.cmd) args.push(...opts.cmd);
|
||||
|
||||
this.id = await new Promise<string>((resolve, reject) => {
|
||||
childProcess.execFile("docker", args, (err, stdout) => {
|
||||
if (err) reject(err);
|
||||
resolve(stdout.trim());
|
||||
});
|
||||
});
|
||||
return this.id;
|
||||
}
|
||||
|
||||
stop(): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
childProcess.execFile("docker", ["stop", this.id], (err) => {
|
||||
if (err) reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
exec(params: string[]): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
childProcess.execFile(
|
||||
"docker",
|
||||
["exec", this.id, ...params],
|
||||
{ encoding: "utf8" },
|
||||
(err, stdout, stderr) => {
|
||||
if (err) {
|
||||
console.log(stdout);
|
||||
console.log(stderr);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
rm(): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
childProcess.execFile("docker", ["rm", this.id], (err) => {
|
||||
if (err) reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getContainerIp(): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
childProcess.execFile(
|
||||
"docker",
|
||||
["inspect", "-f", "{{ .NetworkSettings.IPAddress }}", this.id],
|
||||
(err, stdout) => {
|
||||
if (err) reject(err);
|
||||
else resolve(stdout.trim());
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async persistLogsToFile(args: { stdoutFile?: string; stderrFile?: string }): Promise<void> {
|
||||
const stdoutFile = args.stdoutFile ? await fse.open(args.stdoutFile, "w") : "ignore";
|
||||
const stderrFile = args.stderrFile ? await fse.open(args.stderrFile, "w") : "ignore";
|
||||
await new Promise<void>((resolve) => {
|
||||
childProcess
|
||||
.spawn("docker", ["logs", this.id], {
|
||||
stdio: ["ignore", stdoutFile, stderrFile],
|
||||
})
|
||||
.once("close", resolve);
|
||||
});
|
||||
if (args.stdoutFile) await fse.close(<number>stdoutFile);
|
||||
if (args.stderrFile) await fse.close(<number>stderrFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects whether the docker command is actually podman.
|
||||
* To do this, it looks for "podman" in the output of "docker --help".
|
||||
*/
|
||||
static isPodman(): Promise<boolean> {
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
childProcess.execFile("docker", ["--help"], (err, stdout) => {
|
||||
if (err) reject(err);
|
||||
else resolve(stdout.toLowerCase().includes("podman"));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Supply the right hostname to use to talk to the host machine. On Docker this
|
||||
* is "host.docker.internal" and on Podman this is "host.containers.internal".
|
||||
*/
|
||||
static async hostnameOfHost(): Promise<"host.containers.internal" | "host.docker.internal"> {
|
||||
return (await Docker.isPodman()) ? "host.containers.internal" : "host.docker.internal";
|
||||
}
|
||||
}
|
205
playwright/plugins/synapse/index.ts
Normal file
205
playwright/plugins/synapse/index.ts
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as path from "path";
|
||||
import * as os from "os";
|
||||
import * as crypto from "crypto";
|
||||
import * as fse from "fs-extra";
|
||||
import { APIRequestContext } from "@playwright/test";
|
||||
|
||||
import { getFreePort } from "../utils/port";
|
||||
import { Docker } from "../docker";
|
||||
import {
|
||||
HomeserverConfig,
|
||||
HomeserverInstance,
|
||||
Homeserver,
|
||||
StartHomeserverOpts,
|
||||
Credentials,
|
||||
} from "../utils/homeserver";
|
||||
|
||||
function randB64Bytes(numBytes: number): string {
|
||||
return crypto.randomBytes(numBytes).toString("base64").replace(/=*$/, "");
|
||||
}
|
||||
|
||||
async function cfgDirFromTemplate(
|
||||
opts: StartHomeserverOpts,
|
||||
): Promise<HomeserverConfig & { registrationSecret: string }> {
|
||||
const templateDir = path.join(__dirname, "templates", opts.template);
|
||||
|
||||
const stats = await fse.stat(templateDir);
|
||||
if (!stats?.isDirectory) {
|
||||
throw new Error(`No such template: ${opts.template}`);
|
||||
}
|
||||
const tempDir = await fse.mkdtemp(path.join(os.tmpdir(), "react-sdk-synapsedocker-"));
|
||||
|
||||
// copy the contents of the template dir, omitting homeserver.yaml as we'll template that
|
||||
console.log(`Copy ${templateDir} -> ${tempDir}`);
|
||||
await fse.copy(templateDir, tempDir, { filter: (f) => path.basename(f) !== "homeserver.yaml" });
|
||||
|
||||
const registrationSecret = randB64Bytes(16);
|
||||
const macaroonSecret = randB64Bytes(16);
|
||||
const formSecret = randB64Bytes(16);
|
||||
|
||||
const port = await getFreePort();
|
||||
const baseUrl = `http://localhost:${port}`;
|
||||
|
||||
// now copy homeserver.yaml, applying substitutions
|
||||
const templateHomeserver = path.join(templateDir, "homeserver.yaml");
|
||||
const outputHomeserver = path.join(tempDir, "homeserver.yaml");
|
||||
console.log(`Gen ${templateHomeserver} -> ${outputHomeserver}`);
|
||||
let hsYaml = await fse.readFile(templateHomeserver, "utf8");
|
||||
hsYaml = hsYaml.replace(/{{REGISTRATION_SECRET}}/g, registrationSecret);
|
||||
hsYaml = hsYaml.replace(/{{MACAROON_SECRET_KEY}}/g, macaroonSecret);
|
||||
hsYaml = hsYaml.replace(/{{FORM_SECRET}}/g, formSecret);
|
||||
hsYaml = hsYaml.replace(/{{PUBLIC_BASEURL}}/g, baseUrl);
|
||||
if (opts.oAuthServerPort) {
|
||||
hsYaml = hsYaml.replace(/{{OAUTH_SERVER_PORT}}/g, opts.oAuthServerPort.toString());
|
||||
}
|
||||
hsYaml = hsYaml.replace(/{{HOST_DOCKER_INTERNAL}}/g, await Docker.hostnameOfHost());
|
||||
if (opts.variables) {
|
||||
let fetchedHostContainer: Awaited<ReturnType<typeof Docker.hostnameOfHost>> | null = null;
|
||||
for (const key in opts.variables) {
|
||||
let value = String(opts.variables[key]);
|
||||
|
||||
if (value === "{{HOST_DOCKER_INTERNAL}}") {
|
||||
if (!fetchedHostContainer) {
|
||||
fetchedHostContainer = await Docker.hostnameOfHost();
|
||||
}
|
||||
value = fetchedHostContainer;
|
||||
}
|
||||
|
||||
hsYaml = hsYaml.replace(new RegExp("%" + key + "%", "g"), value);
|
||||
}
|
||||
}
|
||||
|
||||
await fse.writeFile(outputHomeserver, hsYaml);
|
||||
|
||||
// now generate a signing key (we could use synapse's config generation for
|
||||
// this, or we could just do this...)
|
||||
// NB. This assumes the homeserver.yaml specifies the key in this location
|
||||
const signingKey = randB64Bytes(32);
|
||||
const outputSigningKey = path.join(tempDir, "localhost.signing.key");
|
||||
console.log(`Gen -> ${outputSigningKey}`);
|
||||
await fse.writeFile(outputSigningKey, `ed25519 x ${signingKey}`);
|
||||
|
||||
return {
|
||||
port,
|
||||
baseUrl,
|
||||
configDir: tempDir,
|
||||
registrationSecret,
|
||||
};
|
||||
}
|
||||
|
||||
export class Synapse implements Homeserver, HomeserverInstance {
|
||||
private docker: Docker = new Docker();
|
||||
public config: HomeserverConfig & { serverId: string; registrationSecret: string };
|
||||
|
||||
public constructor(private readonly request: APIRequestContext) {}
|
||||
|
||||
/**
|
||||
* Start a synapse instance: the template must be the name of
|
||||
* one of the templates in the playwright/plugins/synapsedocker/templates
|
||||
* directory.
|
||||
*
|
||||
* Any value in opts.variables that is set to `{{HOST_DOCKER_INTERNAL}}'
|
||||
* will be replaced with 'host.docker.internal' (if we are on Docker) or
|
||||
* 'host.containers.internal' if we are on Podman.
|
||||
*/
|
||||
public async start(opts: StartHomeserverOpts): Promise<HomeserverInstance> {
|
||||
if (this.config) await this.stop();
|
||||
|
||||
const synCfg = await cfgDirFromTemplate(opts);
|
||||
console.log(`Starting synapse with config dir ${synCfg.configDir}...`);
|
||||
const dockerSynapseParams = ["--rm", "-v", `${synCfg.configDir}:/data`, "-p", `${synCfg.port}:8008/tcp`];
|
||||
if (await Docker.isPodman()) {
|
||||
// Make host.containers.internal work to allow Synapse to talk to the test OIDC server.
|
||||
dockerSynapseParams.push("--network");
|
||||
dockerSynapseParams.push("slirp4netns:allow_host_loopback=true");
|
||||
} else {
|
||||
// Make host.docker.internal work to allow Synapse to talk to the test OIDC server.
|
||||
dockerSynapseParams.push("--add-host");
|
||||
dockerSynapseParams.push("host.docker.internal:host-gateway");
|
||||
}
|
||||
const synapseId = await this.docker.run({
|
||||
image: "matrixdotorg/synapse:develop",
|
||||
containerName: `react-sdk-playwright-synapse`,
|
||||
params: dockerSynapseParams,
|
||||
cmd: ["run"],
|
||||
});
|
||||
console.log(`Started synapse with id ${synapseId} on port ${synCfg.port}.`);
|
||||
// Await Synapse healthcheck
|
||||
await this.docker.exec([
|
||||
"curl",
|
||||
"--connect-timeout",
|
||||
"30",
|
||||
"--retry",
|
||||
"30",
|
||||
"--retry-delay",
|
||||
"1",
|
||||
"--retry-all-errors",
|
||||
"--silent",
|
||||
"http://localhost:8008/health",
|
||||
]);
|
||||
|
||||
this.config = {
|
||||
...synCfg,
|
||||
serverId: synapseId,
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
public async stop(): Promise<void> {
|
||||
if (!this.config) throw new Error("Missing existing synapse instance, did you call stop() before start()?");
|
||||
const id = this.config.serverId;
|
||||
const synapseLogsPath = path.join("playwright", "synapselogs", id);
|
||||
await fse.ensureDir(synapseLogsPath);
|
||||
await this.docker.persistLogsToFile({
|
||||
stdoutFile: path.join(synapseLogsPath, "stdout.log"),
|
||||
stderrFile: path.join(synapseLogsPath, "stderr.log"),
|
||||
});
|
||||
await this.docker.stop();
|
||||
await fse.remove(this.config.configDir);
|
||||
console.log(`Stopped synapse id ${id}.`);
|
||||
}
|
||||
|
||||
public async registerUser(username: string, password: string, displayName?: string): Promise<Credentials> {
|
||||
const url = `${this.config.baseUrl}/_synapse/admin/v1/register`;
|
||||
const { nonce } = await this.request.get(url).then((r) => r.json());
|
||||
const mac = crypto
|
||||
.createHmac("sha1", this.config.registrationSecret)
|
||||
.update(`${nonce}\0${username}\0${password}\0notadmin`)
|
||||
.digest("hex");
|
||||
const res = await this.request.post(url, {
|
||||
data: {
|
||||
nonce,
|
||||
username,
|
||||
password,
|
||||
mac,
|
||||
admin: false,
|
||||
displayname: displayName,
|
||||
},
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
return {
|
||||
homeServer: data.home_server,
|
||||
accessToken: data.access_token,
|
||||
userId: data.user_id,
|
||||
deviceId: data.device_id,
|
||||
password,
|
||||
};
|
||||
}
|
||||
}
|
3
playwright/plugins/synapse/templates/COPYME/README.md
Normal file
3
playwright/plugins/synapse/templates/COPYME/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Meta-template for synapse templates
|
||||
|
||||
To make another template, you can copy this directory
|
72
playwright/plugins/synapse/templates/COPYME/homeserver.yaml
Normal file
72
playwright/plugins/synapse/templates/COPYME/homeserver.yaml
Normal file
|
@ -0,0 +1,72 @@
|
|||
server_name: "localhost"
|
||||
pid_file: /data/homeserver.pid
|
||||
# XXX: This won't actually be right: it lets docker allocate an ephemeral port,
|
||||
# so we have a chicken-and-egg problem
|
||||
public_baseurl: http://localhost:8008/
|
||||
# Listener is always port 8008 (configured in the container)
|
||||
listeners:
|
||||
- port: 8008
|
||||
tls: false
|
||||
bind_addresses: ["::"]
|
||||
type: http
|
||||
x_forwarded: true
|
||||
|
||||
resources:
|
||||
- names: [client, federation, consent]
|
||||
compress: false
|
||||
|
||||
# An sqlite in-memory database is fast & automatically wipes each time
|
||||
database:
|
||||
name: "sqlite3"
|
||||
args:
|
||||
database: ":memory:"
|
||||
|
||||
# Needs to be configured to log to the console like a good docker process
|
||||
log_config: "/data/log.config"
|
||||
|
||||
rc_messages_per_second: 10000
|
||||
rc_message_burst_count: 10000
|
||||
rc_registration:
|
||||
per_second: 10000
|
||||
burst_count: 10000
|
||||
|
||||
rc_login:
|
||||
address:
|
||||
per_second: 10000
|
||||
burst_count: 10000
|
||||
account:
|
||||
per_second: 10000
|
||||
burst_count: 10000
|
||||
failed_attempts:
|
||||
per_second: 10000
|
||||
burst_count: 10000
|
||||
|
||||
media_store_path: "/data/media_store"
|
||||
uploads_path: "/data/uploads"
|
||||
enable_registration: true
|
||||
enable_registration_without_verification: true
|
||||
disable_msisdn_registration: false
|
||||
# These placeholders will be be replaced with values generated at start
|
||||
registration_shared_secret: "{{REGISTRATION_SECRET}}"
|
||||
report_stats: false
|
||||
macaroon_secret_key: "{{MACAROON_SECRET_KEY}}"
|
||||
form_secret: "{{FORM_SECRET}}"
|
||||
# Signing key must be here: it will be generated to this file
|
||||
signing_key_path: "/data/localhost.signing.key"
|
||||
email:
|
||||
enable_notifs: false
|
||||
smtp_host: "localhost"
|
||||
smtp_port: 25
|
||||
smtp_user: "exampleusername"
|
||||
smtp_pass: "examplepassword"
|
||||
require_transport_security: False
|
||||
notif_from: "Your Friendly %(app)s homeserver <noreply@example.com>"
|
||||
app_name: Matrix
|
||||
notif_template_html: notif_mail.html
|
||||
notif_template_text: notif_mail.txt
|
||||
notif_for_new_users: True
|
||||
client_base_url: "http://localhost/element"
|
||||
|
||||
trusted_key_servers:
|
||||
- server_name: "matrix.org"
|
||||
suppress_key_server_warning: true
|
50
playwright/plugins/synapse/templates/COPYME/log.config
Normal file
50
playwright/plugins/synapse/templates/COPYME/log.config
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Log configuration for Synapse.
|
||||
#
|
||||
# This is a YAML file containing a standard Python logging configuration
|
||||
# dictionary. See [1] for details on the valid settings.
|
||||
#
|
||||
# Synapse also supports structured logging for machine readable logs which can
|
||||
# be ingested by ELK stacks. See [2] for details.
|
||||
#
|
||||
# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
|
||||
# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html
|
||||
|
||||
version: 1
|
||||
|
||||
formatters:
|
||||
precise:
|
||||
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
|
||||
|
||||
handlers:
|
||||
# A handler that writes logs to stderr. Unused by default, but can be used
|
||||
# instead of "buffer" and "file" in the logger handlers.
|
||||
console:
|
||||
class: logging.StreamHandler
|
||||
formatter: precise
|
||||
|
||||
loggers:
|
||||
synapse.storage.SQL:
|
||||
# beware: increasing this to DEBUG will make synapse log sensitive
|
||||
# information such as access tokens.
|
||||
level: INFO
|
||||
|
||||
twisted:
|
||||
# We send the twisted logging directly to the file handler,
|
||||
# to work around https://github.com/matrix-org/synapse/issues/3471
|
||||
# when using "buffer" logger. Use "console" to log to stderr instead.
|
||||
handlers: [console]
|
||||
propagate: false
|
||||
|
||||
root:
|
||||
level: INFO
|
||||
|
||||
# Write logs to the `buffer` handler, which will buffer them together in memory,
|
||||
# then write them to a file.
|
||||
#
|
||||
# Replace "buffer" with "console" to log to stderr instead. (Note that you'll
|
||||
# also need to update the configuration for the `twisted` logger above, in
|
||||
# this case.)
|
||||
#
|
||||
handlers: [console]
|
||||
|
||||
disable_existing_loggers: false
|
1
playwright/plugins/synapse/templates/consent/README.md
Normal file
1
playwright/plugins/synapse/templates/consent/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
A synapse configured with user privacy consent enabled
|
84
playwright/plugins/synapse/templates/consent/homeserver.yaml
Normal file
84
playwright/plugins/synapse/templates/consent/homeserver.yaml
Normal file
|
@ -0,0 +1,84 @@
|
|||
server_name: "localhost"
|
||||
pid_file: /data/homeserver.pid
|
||||
public_baseurl: "{{PUBLIC_BASEURL}}"
|
||||
listeners:
|
||||
- port: 8008
|
||||
tls: false
|
||||
bind_addresses: ["::"]
|
||||
type: http
|
||||
x_forwarded: true
|
||||
|
||||
resources:
|
||||
- names: [client, federation, consent]
|
||||
compress: false
|
||||
|
||||
database:
|
||||
name: "sqlite3"
|
||||
args:
|
||||
database: ":memory:"
|
||||
|
||||
log_config: "/data/log.config"
|
||||
|
||||
rc_messages_per_second: 10000
|
||||
rc_message_burst_count: 10000
|
||||
rc_registration:
|
||||
per_second: 10000
|
||||
burst_count: 10000
|
||||
|
||||
rc_login:
|
||||
address:
|
||||
per_second: 10000
|
||||
burst_count: 10000
|
||||
account:
|
||||
per_second: 10000
|
||||
burst_count: 10000
|
||||
failed_attempts:
|
||||
per_second: 10000
|
||||
burst_count: 10000
|
||||
|
||||
media_store_path: "/data/media_store"
|
||||
uploads_path: "/data/uploads"
|
||||
enable_registration: true
|
||||
enable_registration_without_verification: true
|
||||
disable_msisdn_registration: false
|
||||
registration_shared_secret: "{{REGISTRATION_SECRET}}"
|
||||
report_stats: false
|
||||
macaroon_secret_key: "{{MACAROON_SECRET_KEY}}"
|
||||
form_secret: "{{FORM_SECRET}}"
|
||||
signing_key_path: "/data/localhost.signing.key"
|
||||
email:
|
||||
enable_notifs: false
|
||||
smtp_host: "localhost"
|
||||
smtp_port: 25
|
||||
smtp_user: "exampleusername"
|
||||
smtp_pass: "examplepassword"
|
||||
require_transport_security: False
|
||||
notif_from: "Your Friendly %(app)s homeserver <noreply@example.com>"
|
||||
app_name: Matrix
|
||||
notif_template_html: notif_mail.html
|
||||
notif_template_text: notif_mail.txt
|
||||
notif_for_new_users: True
|
||||
client_base_url: "http://localhost/element"
|
||||
|
||||
user_consent:
|
||||
template_dir: /data/res/templates/privacy
|
||||
version: 1.0
|
||||
server_notice_content:
|
||||
msgtype: m.text
|
||||
body: >-
|
||||
To continue using this homeserver you must review and agree to the
|
||||
terms and conditions at %(consent_uri)s
|
||||
send_server_notice_to_guests: True
|
||||
block_events_error: >-
|
||||
To continue using this homeserver you must review and agree to the
|
||||
terms and conditions at %(consent_uri)s
|
||||
require_at_registration: true
|
||||
|
||||
server_notices:
|
||||
system_mxid_localpart: notices
|
||||
system_mxid_display_name: "Server Notices"
|
||||
system_mxid_avatar_url: "mxc://localhost:5005/oumMVlgDnLYFaPVkExemNVVZ"
|
||||
room_name: "Server Notices"
|
||||
trusted_key_servers:
|
||||
- server_name: "matrix.org"
|
||||
suppress_key_server_warning: true
|
50
playwright/plugins/synapse/templates/consent/log.config
Normal file
50
playwright/plugins/synapse/templates/consent/log.config
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Log configuration for Synapse.
|
||||
#
|
||||
# This is a YAML file containing a standard Python logging configuration
|
||||
# dictionary. See [1] for details on the valid settings.
|
||||
#
|
||||
# Synapse also supports structured logging for machine readable logs which can
|
||||
# be ingested by ELK stacks. See [2] for details.
|
||||
#
|
||||
# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
|
||||
# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html
|
||||
|
||||
version: 1
|
||||
|
||||
formatters:
|
||||
precise:
|
||||
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
|
||||
|
||||
handlers:
|
||||
# A handler that writes logs to stderr. Unused by default, but can be used
|
||||
# instead of "buffer" and "file" in the logger handlers.
|
||||
console:
|
||||
class: logging.StreamHandler
|
||||
formatter: precise
|
||||
|
||||
loggers:
|
||||
synapse.storage.SQL:
|
||||
# beware: increasing this to DEBUG will make synapse log sensitive
|
||||
# information such as access tokens.
|
||||
level: DEBUG
|
||||
|
||||
twisted:
|
||||
# We send the twisted logging directly to the file handler,
|
||||
# to work around https://github.com/matrix-org/synapse/issues/3471
|
||||
# when using "buffer" logger. Use "console" to log to stderr instead.
|
||||
handlers: [console]
|
||||
propagate: false
|
||||
|
||||
root:
|
||||
level: DEBUG
|
||||
|
||||
# Write logs to the `buffer` handler, which will buffer them together in memory,
|
||||
# then write them to a file.
|
||||
#
|
||||
# Replace "buffer" with "console" to log to stderr instead. (Note that you'll
|
||||
# also need to update the configuration for the `twisted` logger above, in
|
||||
# this case.)
|
||||
#
|
||||
handlers: [console]
|
||||
|
||||
disable_existing_loggers: false
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Test Privacy policy</title>
|
||||
</head>
|
||||
<body>
|
||||
{% if has_consented %}
|
||||
<p>Thank you, you've already accepted the license.</p>
|
||||
{% else %}
|
||||
<p>Please accept the license!</p>
|
||||
<form method="post" action="consent">
|
||||
<input type="hidden" name="v" value="{{version}}" />
|
||||
<input type="hidden" name="u" value="{{user}}" />
|
||||
<input type="hidden" name="h" value="{{userhmac}}" />
|
||||
<input type="submit" value="Sure thing!" />
|
||||
</form>
|
||||
{% endif %}
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Test Privacy policy</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Danke schoen</p>
|
||||
</body>
|
||||
</html>
|
1
playwright/plugins/synapse/templates/default/README.md
Normal file
1
playwright/plugins/synapse/templates/default/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
A synapse configured with user privacy consent disabled
|
94
playwright/plugins/synapse/templates/default/homeserver.yaml
Normal file
94
playwright/plugins/synapse/templates/default/homeserver.yaml
Normal file
|
@ -0,0 +1,94 @@
|
|||
server_name: "localhost"
|
||||
pid_file: /data/homeserver.pid
|
||||
public_baseurl: "{{PUBLIC_BASEURL}}"
|
||||
listeners:
|
||||
- port: 8008
|
||||
tls: false
|
||||
bind_addresses: ["::"]
|
||||
type: http
|
||||
x_forwarded: true
|
||||
|
||||
resources:
|
||||
- names: [client]
|
||||
compress: false
|
||||
|
||||
database:
|
||||
name: "sqlite3"
|
||||
args:
|
||||
database: ":memory:"
|
||||
|
||||
log_config: "/data/log.config"
|
||||
|
||||
rc_messages_per_second: 10000
|
||||
rc_message_burst_count: 10000
|
||||
rc_registration:
|
||||
per_second: 10000
|
||||
burst_count: 10000
|
||||
rc_joins:
|
||||
local:
|
||||
per_second: 9999
|
||||
burst_count: 9999
|
||||
remote:
|
||||
per_second: 9999
|
||||
burst_count: 9999
|
||||
rc_joins_per_room:
|
||||
per_second: 9999
|
||||
burst_count: 9999
|
||||
rc_3pid_validation:
|
||||
per_second: 1000
|
||||
burst_count: 1000
|
||||
|
||||
rc_invites:
|
||||
per_room:
|
||||
per_second: 1000
|
||||
burst_count: 1000
|
||||
per_user:
|
||||
per_second: 1000
|
||||
burst_count: 1000
|
||||
|
||||
rc_login:
|
||||
address:
|
||||
per_second: 10000
|
||||
burst_count: 10000
|
||||
account:
|
||||
per_second: 10000
|
||||
burst_count: 10000
|
||||
failed_attempts:
|
||||
per_second: 10000
|
||||
burst_count: 10000
|
||||
|
||||
media_store_path: "/data/media_store"
|
||||
uploads_path: "/data/uploads"
|
||||
enable_registration: true
|
||||
enable_registration_without_verification: true
|
||||
disable_msisdn_registration: false
|
||||
registration_shared_secret: "{{REGISTRATION_SECRET}}"
|
||||
report_stats: false
|
||||
macaroon_secret_key: "{{MACAROON_SECRET_KEY}}"
|
||||
form_secret: "{{FORM_SECRET}}"
|
||||
signing_key_path: "/data/localhost.signing.key"
|
||||
|
||||
trusted_key_servers:
|
||||
- server_name: "matrix.org"
|
||||
suppress_key_server_warning: true
|
||||
|
||||
ui_auth:
|
||||
session_timeout: "300s"
|
||||
|
||||
oidc_providers:
|
||||
- idp_id: test
|
||||
idp_name: "OAuth test"
|
||||
issuer: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth"
|
||||
authorization_endpoint: "http://localhost:{{OAUTH_SERVER_PORT}}/oauth/auth.html"
|
||||
# the token endpoint receives requests from synapse, rather than the webapp, so needs to escape the docker container.
|
||||
# Hence, HOST_DOCKER_INTERNAL rather than localhost. This is set to
|
||||
# host.docker.internal on Docker and host.containers.internal on Podman.
|
||||
token_endpoint: "http://{{HOST_DOCKER_INTERNAL}}:{{OAUTH_SERVER_PORT}}/oauth/token"
|
||||
userinfo_endpoint: "http://{{HOST_DOCKER_INTERNAL}}:{{OAUTH_SERVER_PORT}}/oauth/userinfo"
|
||||
client_id: "synapse"
|
||||
discover: false
|
||||
scopes: ["profile"]
|
||||
skip_verification: true
|
||||
user_mapping_provider:
|
||||
config:
|
||||
display_name_template: "{{ user.name }}"
|
50
playwright/plugins/synapse/templates/default/log.config
Normal file
50
playwright/plugins/synapse/templates/default/log.config
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Log configuration for Synapse.
|
||||
#
|
||||
# This is a YAML file containing a standard Python logging configuration
|
||||
# dictionary. See [1] for details on the valid settings.
|
||||
#
|
||||
# Synapse also supports structured logging for machine readable logs which can
|
||||
# be ingested by ELK stacks. See [2] for details.
|
||||
#
|
||||
# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
|
||||
# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html
|
||||
|
||||
version: 1
|
||||
|
||||
formatters:
|
||||
precise:
|
||||
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
|
||||
|
||||
handlers:
|
||||
# A handler that writes logs to stderr. Unused by default, but can be used
|
||||
# instead of "buffer" and "file" in the logger handlers.
|
||||
console:
|
||||
class: logging.StreamHandler
|
||||
formatter: precise
|
||||
|
||||
loggers:
|
||||
synapse.storage.SQL:
|
||||
# beware: increasing this to DEBUG will make synapse log sensitive
|
||||
# information such as access tokens.
|
||||
level: DEBUG
|
||||
|
||||
twisted:
|
||||
# We send the twisted logging directly to the file handler,
|
||||
# to work around https://github.com/matrix-org/synapse/issues/3471
|
||||
# when using "buffer" logger. Use "console" to log to stderr instead.
|
||||
handlers: [console]
|
||||
propagate: false
|
||||
|
||||
root:
|
||||
level: DEBUG
|
||||
|
||||
# Write logs to the `buffer` handler, which will buffer them together in memory,
|
||||
# then write them to a file.
|
||||
#
|
||||
# Replace "buffer" with "console" to log to stderr instead. (Note that you'll
|
||||
# also need to update the configuration for the `twisted` logger above, in
|
||||
# this case.)
|
||||
#
|
||||
handlers: [console]
|
||||
|
||||
disable_existing_loggers: false
|
1
playwright/plugins/synapse/templates/email/README.md
Normal file
1
playwright/plugins/synapse/templates/email/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
A synapse configured to require an email for registration
|
44
playwright/plugins/synapse/templates/email/homeserver.yaml
Normal file
44
playwright/plugins/synapse/templates/email/homeserver.yaml
Normal file
|
@ -0,0 +1,44 @@
|
|||
server_name: "localhost"
|
||||
pid_file: /data/homeserver.pid
|
||||
public_baseurl: "{{PUBLIC_BASEURL}}"
|
||||
listeners:
|
||||
- port: 8008
|
||||
tls: false
|
||||
bind_addresses: ["::"]
|
||||
type: http
|
||||
x_forwarded: true
|
||||
|
||||
resources:
|
||||
- names: [client]
|
||||
compress: false
|
||||
|
||||
database:
|
||||
name: "sqlite3"
|
||||
args:
|
||||
database: ":memory:"
|
||||
|
||||
log_config: "/data/log.config"
|
||||
|
||||
media_store_path: "/data/media_store"
|
||||
uploads_path: "/data/uploads"
|
||||
enable_registration: true
|
||||
registrations_require_3pid:
|
||||
- email
|
||||
registration_shared_secret: "{{REGISTRATION_SECRET}}"
|
||||
report_stats: false
|
||||
macaroon_secret_key: "{{MACAROON_SECRET_KEY}}"
|
||||
form_secret: "{{FORM_SECRET}}"
|
||||
signing_key_path: "/data/localhost.signing.key"
|
||||
|
||||
trusted_key_servers:
|
||||
- server_name: "matrix.org"
|
||||
suppress_key_server_warning: true
|
||||
|
||||
ui_auth:
|
||||
session_timeout: "300s"
|
||||
|
||||
email:
|
||||
smtp_host: "%SMTP_HOST%"
|
||||
smtp_port: %SMTP_PORT%
|
||||
notif_from: "Your Friendly %(app)s homeserver <noreply@example.com>"
|
||||
app_name: my_branded_matrix_server
|
50
playwright/plugins/synapse/templates/email/log.config
Normal file
50
playwright/plugins/synapse/templates/email/log.config
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Log configuration for Synapse.
|
||||
#
|
||||
# This is a YAML file containing a standard Python logging configuration
|
||||
# dictionary. See [1] for details on the valid settings.
|
||||
#
|
||||
# Synapse also supports structured logging for machine readable logs which can
|
||||
# be ingested by ELK stacks. See [2] for details.
|
||||
#
|
||||
# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
|
||||
# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html
|
||||
|
||||
version: 1
|
||||
|
||||
formatters:
|
||||
precise:
|
||||
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
|
||||
|
||||
handlers:
|
||||
# A handler that writes logs to stderr. Unused by default, but can be used
|
||||
# instead of "buffer" and "file" in the logger handlers.
|
||||
console:
|
||||
class: logging.StreamHandler
|
||||
formatter: precise
|
||||
|
||||
loggers:
|
||||
synapse.storage.SQL:
|
||||
# beware: increasing this to DEBUG will make synapse log sensitive
|
||||
# information such as access tokens.
|
||||
level: INFO
|
||||
|
||||
twisted:
|
||||
# We send the twisted logging directly to the file handler,
|
||||
# to work around https://github.com/matrix-org/synapse/issues/3471
|
||||
# when using "buffer" logger. Use "console" to log to stderr instead.
|
||||
handlers: [console]
|
||||
propagate: false
|
||||
|
||||
root:
|
||||
level: INFO
|
||||
|
||||
# Write logs to the `buffer` handler, which will buffer them together in memory,
|
||||
# then write them to a file.
|
||||
#
|
||||
# Replace "buffer" with "console" to log to stderr instead. (Note that you'll
|
||||
# also need to update the configuration for the `twisted` logger above, in
|
||||
# this case.)
|
||||
#
|
||||
handlers: [console]
|
||||
|
||||
disable_existing_loggers: false
|
57
playwright/plugins/utils/homeserver.ts
Normal file
57
playwright/plugins/utils/homeserver.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
export interface HomeserverConfig {
|
||||
readonly configDir: string;
|
||||
readonly baseUrl: string;
|
||||
readonly port: number;
|
||||
}
|
||||
|
||||
export interface HomeserverInstance {
|
||||
readonly config: HomeserverConfig;
|
||||
|
||||
/**
|
||||
* Register a user on the given Homeserver using the shared registration secret.
|
||||
* @param username the username of the user to register
|
||||
* @param password the password of the user to register
|
||||
* @param displayName optional display name to set on the newly registered user
|
||||
*/
|
||||
registerUser(username: string, password: string, displayName?: string): Promise<Credentials>;
|
||||
}
|
||||
|
||||
export interface StartHomeserverOpts {
|
||||
/** path to template within playwright/plugins/{homeserver}docker/template/ directory. */
|
||||
template: string;
|
||||
|
||||
/** Port of an OAuth server to configure the homeserver to use */
|
||||
oAuthServerPort?: number;
|
||||
|
||||
/** Additional variables to inject into the configuration template **/
|
||||
variables?: Record<string, string | number>;
|
||||
}
|
||||
|
||||
export interface Homeserver {
|
||||
start(opts: StartHomeserverOpts): Promise<HomeserverInstance>;
|
||||
stop(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface Credentials {
|
||||
accessToken: string;
|
||||
userId: string;
|
||||
deviceId: string;
|
||||
homeServer: string;
|
||||
password: string;
|
||||
}
|
27
playwright/plugins/utils/port.ts
Normal file
27
playwright/plugins/utils/port.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as net from "net";
|
||||
|
||||
export async function getFreePort(): Promise<number> {
|
||||
return new Promise<number>((resolve) => {
|
||||
const srv = net.createServer();
|
||||
srv.listen(0, () => {
|
||||
const port = (<net.AddressInfo>srv.address()).port;
|
||||
srv.close(() => resolve(port));
|
||||
});
|
||||
});
|
||||
}
|
24
yarn.lock
24
yarn.lock
|
@ -3434,7 +3434,7 @@ aws4@^1.8.0:
|
|||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3"
|
||||
integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==
|
||||
|
||||
axe-core@4.8.2:
|
||||
axe-core@4.8.2, axe-core@^4.5.1:
|
||||
version "4.8.2"
|
||||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.2.tgz#2f6f3cde40935825cf4465e3c1c9e77b240ff6ae"
|
||||
integrity sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g==
|
||||
|
@ -3444,6 +3444,23 @@ axe-core@=4.7.0:
|
|||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf"
|
||||
integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==
|
||||
|
||||
axe-html-reporter@2.2.3:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/axe-html-reporter/-/axe-html-reporter-2.2.3.tgz#2d56e239fe9bd1f09ba0735d94596bf79dd389a7"
|
||||
integrity sha512-io8aCEt4fJvv43W+33n3zEa8rdplH5Ti2v5fOnth3GBKLhLHarNs7jj46xGfpnGnpaNrz23/tXPHC3HbwTzwwA==
|
||||
dependencies:
|
||||
mustache "^4.0.1"
|
||||
rimraf "^3.0.2"
|
||||
|
||||
axe-playwright@^1.2.3:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/axe-playwright/-/axe-playwright-1.2.3.tgz#b590b4edf3898ed5784c4932cbad2937115b31f2"
|
||||
integrity sha512-bTxCTNp3kx6sQRMjmuLv8pG3+v+kOCvFXATim1+XUXzW6ykulbbuJdQfgB+vQPNAF9uvYbW2qrv9pg81ZSFV/A==
|
||||
dependencies:
|
||||
axe-core "^4.5.1"
|
||||
axe-html-reporter "2.2.3"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
axios-retry@^3.7.0:
|
||||
version "3.9.1"
|
||||
resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.9.1.tgz#c8924a8781c8e0a2c5244abf773deb7566b3830d"
|
||||
|
@ -7748,6 +7765,11 @@ murmurhash-js@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/murmurhash-js/-/murmurhash-js-1.0.0.tgz#b06278e21fc6c37fa5313732b0412bcb6ae15f51"
|
||||
integrity sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==
|
||||
|
||||
mustache@^4.0.1:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64"
|
||||
integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==
|
||||
|
||||
nanoid@^3.3.6:
|
||||
version "3.3.6"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
|
||||
|
|
Loading…
Reference in a new issue