mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-22 19:14:52 +01:00
Merge pull request #906 from vector-im/playwright
Implement integration tests in Hydrogen using playwright
This commit is contained in:
commit
5f57c2d361
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,3 +10,4 @@ lib
|
|||||||
*.tar.gz
|
*.tar.gz
|
||||||
.eslintcache
|
.eslintcache
|
||||||
.tmp
|
.tmp
|
||||||
|
playwright/synapselogs
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
"start": "vite --port 3000",
|
"start": "vite --port 3000",
|
||||||
"build": "vite build && ./scripts/cleanup.sh",
|
"build": "vite build && ./scripts/cleanup.sh",
|
||||||
"build:sdk": "./scripts/sdk/build.sh",
|
"build:sdk": "./scripts/sdk/build.sh",
|
||||||
"watch:sdk": "./scripts/sdk/build.sh && yarn run vite build -c vite.sdk-lib-config.js --watch"
|
"watch:sdk": "./scripts/sdk/build.sh && yarn run vite build -c vite.sdk-lib-config.js --watch",
|
||||||
|
"test:app": "./scripts/test-app.sh"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -31,6 +32,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/vector-im/hydrogen-web/#readme",
|
"homepage": "https://github.com/vector-im/hydrogen-web/#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.27.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.29.2",
|
"@typescript-eslint/eslint-plugin": "^4.29.2",
|
||||||
"@typescript-eslint/parser": "^4.29.2",
|
"@typescript-eslint/parser": "^4.29.2",
|
||||||
"acorn": "^8.6.0",
|
"acorn": "^8.6.0",
|
||||||
|
21
playwright.config.ts
Normal file
21
playwright.config.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import type { PlaywrightTestConfig } from "@playwright/test";
|
||||||
|
|
||||||
|
const BASE_URL = process.env["BASE_URL"] ?? "http://127.0.0.1:3000";
|
||||||
|
|
||||||
|
const config: PlaywrightTestConfig = {
|
||||||
|
use: {
|
||||||
|
headless: false,
|
||||||
|
viewport: { width: 1280, height: 720 },
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
|
video: "on-first-retry",
|
||||||
|
baseURL: BASE_URL,
|
||||||
|
},
|
||||||
|
testDir: "./playwright/tests",
|
||||||
|
globalSetup: require.resolve("./playwright/global-setup"),
|
||||||
|
webServer: {
|
||||||
|
command: "yarn start",
|
||||||
|
url: `${BASE_URL}/#/login`,
|
||||||
|
},
|
||||||
|
workers: 1
|
||||||
|
};
|
||||||
|
export default config;
|
28
playwright/global-setup.ts
Normal file
28
playwright/global-setup.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const env = {
|
||||||
|
SYNAPSE_IP_ADDRESS: "172.18.0.5",
|
||||||
|
SYNAPSE_PORT: "8008",
|
||||||
|
DEX_IP_ADDRESS: "172.18.0.4",
|
||||||
|
DEX_PORT: "5556",
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function setupEnvironmentVariables() {
|
||||||
|
for (const [key, value] of Object.entries(env)) {
|
||||||
|
process.env[key] = value;
|
||||||
|
}
|
||||||
|
}
|
108
playwright/plugins/dex/index.ts
Normal file
108
playwright/plugins/dex/index.ts
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
import * as path from "path";
|
||||||
|
import * as os from "os";
|
||||||
|
import * as fse from "fs-extra";
|
||||||
|
|
||||||
|
import {dockerRun, dockerStop } from "../docker";
|
||||||
|
|
||||||
|
// A cypress plugins to add command to start & stop dex instances
|
||||||
|
|
||||||
|
interface DexConfig {
|
||||||
|
configDir: string;
|
||||||
|
baseUrl: string;
|
||||||
|
port: number;
|
||||||
|
host: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DexInstance extends DexConfig {
|
||||||
|
dexId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dexConfigs = new Map<string, DexInstance>();
|
||||||
|
|
||||||
|
async function produceConfigWithSynapseURLAdded(): Promise<DexConfig> {
|
||||||
|
const templateDir = path.join(__dirname, "template");
|
||||||
|
|
||||||
|
const stats = await fse.stat(templateDir);
|
||||||
|
if (!stats?.isDirectory) {
|
||||||
|
throw new Error(`Template directory at ${templateDir} not found!`);
|
||||||
|
}
|
||||||
|
const tempDir = await fse.mkdtemp(path.join(os.tmpdir(), 'hydrogen-testing-dex-'));
|
||||||
|
|
||||||
|
// copy the contents of the template dir, omitting config.yaml as we'll template that
|
||||||
|
console.log(`Copy ${templateDir} -> ${tempDir}`);
|
||||||
|
await fse.copy(templateDir, tempDir, { filter: f => path.basename(f) !== 'config.yaml' });
|
||||||
|
|
||||||
|
// now copy config.yaml, applying substitutions
|
||||||
|
console.log(`Gen ${path.join(templateDir, "config.yaml")}`);
|
||||||
|
let hsYaml = await fse.readFile(path.join(templateDir, "config.yaml"), "utf8");
|
||||||
|
const synapseHost = process.env.SYNAPSE_IP_ADDRESS;
|
||||||
|
const synapsePort = process.env.SYNAPSE_PORT;
|
||||||
|
const synapseAddress = `${synapseHost}:${synapsePort}`;
|
||||||
|
hsYaml = hsYaml.replace(/{{SYNAPSE_ADDRESS}}/g, synapseAddress);
|
||||||
|
const dexHost = process.env.DEX_IP_ADDRESS!;
|
||||||
|
const dexPort = parseInt(process.env.DEX_PORT!, 10);
|
||||||
|
const dexAddress = `${dexHost}:${dexPort}`;
|
||||||
|
hsYaml = hsYaml.replace(/{{DEX_ADDRESS}}/g, dexAddress);
|
||||||
|
await fse.writeFile(path.join(tempDir, "config.yaml"), hsYaml);
|
||||||
|
|
||||||
|
const baseUrl = `http://${dexHost}:${dexPort}`;
|
||||||
|
return {
|
||||||
|
host: dexHost,
|
||||||
|
port: dexPort,
|
||||||
|
baseUrl,
|
||||||
|
configDir: tempDir,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function dexStart(): Promise<DexInstance> {
|
||||||
|
const dexCfg = await produceConfigWithSynapseURLAdded();
|
||||||
|
console.log(`Starting dex with config dir ${dexCfg.configDir}...`);
|
||||||
|
const dexId = await dockerRun({
|
||||||
|
image: "bitnami/dex:latest",
|
||||||
|
containerName: "hydrogen-dex",
|
||||||
|
dockerParams: [
|
||||||
|
"--rm",
|
||||||
|
"-v", `${dexCfg.configDir}:/data`,
|
||||||
|
`--ip=${dexCfg.host}`,
|
||||||
|
"-p", `${dexCfg.port}:5556/tcp`,
|
||||||
|
"--network=hydrogen"
|
||||||
|
],
|
||||||
|
applicationParams: [
|
||||||
|
"serve",
|
||||||
|
"data/config.yaml",
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Started dex with id ${dexId} on port ${dexCfg.port}.`);
|
||||||
|
|
||||||
|
const dex: DexInstance = { dexId, ...dexCfg };
|
||||||
|
dexConfigs.set(dexId, dex);
|
||||||
|
return dex;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function dexStop(id: string): Promise<void> {
|
||||||
|
const dexCfg = dexConfigs.get(id);
|
||||||
|
if (!dexCfg) throw new Error("Unknown dex ID");
|
||||||
|
await dockerStop({ containerId: id, });
|
||||||
|
await fse.remove(dexCfg.configDir);
|
||||||
|
dexConfigs.delete(id);
|
||||||
|
console.log(`Stopped dex id ${id}.`);
|
||||||
|
}
|
56
playwright/plugins/dex/template/config.yaml
Executable file
56
playwright/plugins/dex/template/config.yaml
Executable file
@ -0,0 +1,56 @@
|
|||||||
|
issuer: http://{{DEX_ADDRESS}}/dex
|
||||||
|
|
||||||
|
storage:
|
||||||
|
type: sqlite3
|
||||||
|
config:
|
||||||
|
file: data/dev.db
|
||||||
|
|
||||||
|
|
||||||
|
# Configuration for the HTTP endpoints.
|
||||||
|
web:
|
||||||
|
http: 0.0.0.0:5556
|
||||||
|
# Uncomment for HTTPS options.
|
||||||
|
# https: 127.0.0.1:5554
|
||||||
|
# tlsCert: /etc/dex/tls.crt
|
||||||
|
# tlsKey: /etc/dex/tls.key
|
||||||
|
|
||||||
|
# Configuration for telemetry
|
||||||
|
telemetry:
|
||||||
|
http: 0.0.0.0:5558
|
||||||
|
# enableProfiling: true
|
||||||
|
|
||||||
|
staticClients:
|
||||||
|
- id: synapse
|
||||||
|
secret: secret
|
||||||
|
redirectURIs:
|
||||||
|
- 'http://{{SYNAPSE_ADDRESS}}/_synapse/client/oidc/callback'
|
||||||
|
name: 'Synapse'
|
||||||
|
connectors:
|
||||||
|
- type: mockCallback
|
||||||
|
id: mock
|
||||||
|
name: Example
|
||||||
|
# - type: google
|
||||||
|
# id: google
|
||||||
|
# name: Google
|
||||||
|
# config:
|
||||||
|
# issuer: https://accounts.google.com
|
||||||
|
# # Connector config values starting with a "$" will read from the environment.
|
||||||
|
# clientID: $GOOGLE_CLIENT_ID
|
||||||
|
# clientSecret: $GOOGLE_CLIENT_SECRET
|
||||||
|
# redirectURI: http://127.0.0.1:5556/dex/callback
|
||||||
|
# hostedDomains:
|
||||||
|
# - $GOOGLE_HOSTED_DOMAIN
|
||||||
|
|
||||||
|
# Let dex keep a list of passwords which can be used to login to dex.
|
||||||
|
enablePasswordDB: true
|
||||||
|
|
||||||
|
# A static list of passwords to login the end user. By identifying here, dex
|
||||||
|
# won't look in its underlying storage for passwords.
|
||||||
|
#
|
||||||
|
# If this option isn't chosen users may be added through the gRPC API.
|
||||||
|
staticPasswords:
|
||||||
|
- email: "admin@example.com"
|
||||||
|
# bcrypt hash of the string "password": $(echo password | htpasswd -BinC 10 admin | cut -d: -f2)
|
||||||
|
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
|
||||||
|
username: "admin"
|
||||||
|
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
|
BIN
playwright/plugins/dex/template/dev.db
Executable file
BIN
playwright/plugins/dex/template/dev.db
Executable file
Binary file not shown.
151
playwright/plugins/docker/index.ts
Normal file
151
playwright/plugins/docker/index.ts
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
import * as os from "os";
|
||||||
|
import * as childProcess from "child_process";
|
||||||
|
import * as fse from "fs-extra";
|
||||||
|
|
||||||
|
export function dockerRun(args: {
|
||||||
|
image: string;
|
||||||
|
containerName: string;
|
||||||
|
dockerParams?: string[];
|
||||||
|
applicationParams?: string[];
|
||||||
|
}): Promise<string> {
|
||||||
|
const userInfo = os.userInfo();
|
||||||
|
const params = args.dockerParams ?? [];
|
||||||
|
const appParams = args.applicationParams ?? [];
|
||||||
|
|
||||||
|
if (userInfo.uid >= 0) {
|
||||||
|
// On *nix we run the docker container as our uid:gid otherwise cleaning it up its media_store can be difficult
|
||||||
|
params.push("-u", `${userInfo.uid}:${userInfo.gid}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
childProcess.execFile('docker', [
|
||||||
|
"run",
|
||||||
|
"--name", args.containerName,
|
||||||
|
"-d",
|
||||||
|
...params,
|
||||||
|
args.image,
|
||||||
|
... appParams
|
||||||
|
], (err, stdout) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
resolve(stdout.trim());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dockerExec(args: {
|
||||||
|
containerId: string;
|
||||||
|
params: string[];
|
||||||
|
}): Promise<void> {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
childProcess.execFile("docker", [
|
||||||
|
"exec", args.containerId,
|
||||||
|
...args.params,
|
||||||
|
], { encoding: 'utf8' }, (err, stdout, stderr) => {
|
||||||
|
if (err) {
|
||||||
|
console.log(stdout);
|
||||||
|
console.log(stderr);
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a docker network; does not fail if network already exists
|
||||||
|
*/
|
||||||
|
export function dockerCreateNetwork(args: {
|
||||||
|
networkName: string;
|
||||||
|
}): Promise<void> {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
childProcess.execFile("docker", [
|
||||||
|
"network",
|
||||||
|
"create",
|
||||||
|
args.networkName
|
||||||
|
], { encoding: 'utf8' }, (err, stdout, stderr) => {
|
||||||
|
if(err) {
|
||||||
|
if (stderr.includes(`network with name ${args.networkName} already exists`)) {
|
||||||
|
// Don't consider this as error
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function dockerLogs(args: {
|
||||||
|
containerId: string;
|
||||||
|
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",
|
||||||
|
args.containerId,
|
||||||
|
], {
|
||||||
|
stdio: ["ignore", stdoutFile, stderrFile],
|
||||||
|
}).once('close', resolve);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (args.stdoutFile) await fse.close(<number>stdoutFile);
|
||||||
|
if (args.stderrFile) await fse.close(<number>stderrFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dockerStop(args: {
|
||||||
|
containerId: string;
|
||||||
|
}): Promise<void> {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
childProcess.execFile('docker', [
|
||||||
|
"stop",
|
||||||
|
args.containerId,
|
||||||
|
], err => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dockerRm(args: {
|
||||||
|
containerId: string;
|
||||||
|
}): Promise<void> {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
childProcess.execFile('docker', [
|
||||||
|
"rm",
|
||||||
|
args.containerId,
|
||||||
|
], err => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
203
playwright/plugins/synapsedocker/index.ts
Normal file
203
playwright/plugins/synapsedocker/index.ts
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
import * as path from "path";
|
||||||
|
import * as os from "os";
|
||||||
|
import * as crypto from "crypto";
|
||||||
|
import * as fse from "fs-extra";
|
||||||
|
|
||||||
|
import {dockerCreateNetwork, dockerExec, dockerLogs, dockerRun, dockerStop} from "../docker";
|
||||||
|
import {request} from "@playwright/test";
|
||||||
|
|
||||||
|
|
||||||
|
// A cypress plugins to add command to start & stop synapses in
|
||||||
|
// docker with preset templates.
|
||||||
|
|
||||||
|
interface SynapseConfig {
|
||||||
|
configDir: string;
|
||||||
|
registrationSecret: string;
|
||||||
|
// Synapse must be configured with its public_baseurl so we have to allocate a port & url at this stage
|
||||||
|
baseUrl: string;
|
||||||
|
port: number;
|
||||||
|
host: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SynapseInstance extends SynapseConfig {
|
||||||
|
synapseId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const synapses = new Map<string, SynapseInstance>();
|
||||||
|
|
||||||
|
function randB64Bytes(numBytes: number): string {
|
||||||
|
return crypto.randomBytes(numBytes).toString("base64").replace(/=*$/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function cfgDirFromTemplate(template: string): Promise<SynapseConfig> {
|
||||||
|
const templateDir = path.join(__dirname, "templates", template);
|
||||||
|
|
||||||
|
const stats = await fse.stat(templateDir);
|
||||||
|
if (!stats?.isDirectory) {
|
||||||
|
throw new Error(`No such template: ${template}`);
|
||||||
|
}
|
||||||
|
const tempDir = await fse.mkdtemp(path.join(os.tmpdir(), '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 synapseHost = process.env["SYNAPSE_IP_ADDRESS"]!!;
|
||||||
|
const synapsePort = parseInt(process.env["SYNAPSE_PORT"]!, 10);
|
||||||
|
const baseUrl = `http://${synapseHost}:${synapsePort}`;
|
||||||
|
|
||||||
|
|
||||||
|
// now copy homeserver.yaml, applying substitutions
|
||||||
|
console.log(`Gen ${path.join(templateDir, "homeserver.yaml")}`);
|
||||||
|
let hsYaml = await fse.readFile(path.join(templateDir, "homeserver.yaml"), "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);
|
||||||
|
|
||||||
|
const dexHost = process.env["DEX_IP_ADDRESS"];
|
||||||
|
const dexPort = process.env["DEX_PORT"];
|
||||||
|
const dexUrl = `http://${dexHost}:${dexPort}/dex`;
|
||||||
|
hsYaml = hsYaml.replace(/{{OIDC_ISSUER}}/g, dexUrl);
|
||||||
|
await fse.writeFile(path.join(tempDir, "homeserver.yaml"), 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);
|
||||||
|
console.log(`Gen ${path.join(templateDir, "localhost.signing.key")}`);
|
||||||
|
await fse.writeFile(path.join(tempDir, "localhost.signing.key"), `ed25519 x ${signingKey}`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
port: synapsePort,
|
||||||
|
host: synapseHost,
|
||||||
|
baseUrl,
|
||||||
|
configDir: tempDir,
|
||||||
|
registrationSecret,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a synapse instance: the template must be the name of
|
||||||
|
// one of the templates in the cypress/plugins/synapsedocker/templates
|
||||||
|
// directory
|
||||||
|
export async function synapseStart(template: string): Promise<SynapseInstance> {
|
||||||
|
const synCfg = await cfgDirFromTemplate(template);
|
||||||
|
console.log(`Starting synapse with config dir ${synCfg.configDir}...`);
|
||||||
|
await dockerCreateNetwork({ networkName: "hydrogen" });
|
||||||
|
const synapseId = await dockerRun({
|
||||||
|
image: "matrixdotorg/synapse:develop",
|
||||||
|
containerName: `hydrogen-synapse`,
|
||||||
|
dockerParams: [
|
||||||
|
"--rm",
|
||||||
|
"-v", `${synCfg.configDir}:/data`,
|
||||||
|
`--ip=${synCfg.host}`,
|
||||||
|
/**
|
||||||
|
* When using -p flag with --ip, the docker internal port must be used to access from the host
|
||||||
|
*/
|
||||||
|
"-p", `${synCfg.port}:8008/tcp`,
|
||||||
|
"--network=hydrogen",
|
||||||
|
],
|
||||||
|
applicationParams: [
|
||||||
|
"run"
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Started synapse with id ${synapseId} on port ${synCfg.port}.`);
|
||||||
|
|
||||||
|
// Await Synapse healthcheck
|
||||||
|
await dockerExec({
|
||||||
|
containerId: synapseId,
|
||||||
|
params: [
|
||||||
|
"curl",
|
||||||
|
"--connect-timeout", "30",
|
||||||
|
"--retry", "30",
|
||||||
|
"--retry-delay", "1",
|
||||||
|
"--retry-all-errors",
|
||||||
|
"--silent",
|
||||||
|
"http://localhost:8008/health",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const synapse: SynapseInstance = { synapseId, ...synCfg };
|
||||||
|
synapses.set(synapseId, synapse);
|
||||||
|
return synapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function synapseStop(id: string): Promise<void> {
|
||||||
|
const synCfg = synapses.get(id);
|
||||||
|
|
||||||
|
if (!synCfg) throw new Error("Unknown synapse ID");
|
||||||
|
|
||||||
|
const synapseLogsPath = path.join("playwright", "synapselogs", id);
|
||||||
|
await fse.ensureDir(synapseLogsPath);
|
||||||
|
|
||||||
|
await dockerLogs({
|
||||||
|
containerId: id,
|
||||||
|
stdoutFile: path.join(synapseLogsPath, "stdout.log"),
|
||||||
|
stderrFile: path.join(synapseLogsPath, "stderr.log"),
|
||||||
|
});
|
||||||
|
|
||||||
|
await dockerStop({
|
||||||
|
containerId: id,
|
||||||
|
});
|
||||||
|
|
||||||
|
await fse.remove(synCfg.configDir);
|
||||||
|
synapses.delete(id);
|
||||||
|
console.log(`Stopped synapse id ${id}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
interface Credentials {
|
||||||
|
accessToken: string;
|
||||||
|
userId: string;
|
||||||
|
deviceId: string;
|
||||||
|
homeServer: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function registerUser(synapse: SynapseInstance, username: string, password: string, displayName?: string,): Promise<Credentials> {
|
||||||
|
const url = `${synapse.baseUrl}/_synapse/admin/v1/register`;
|
||||||
|
const context = await request.newContext({ baseURL: url });
|
||||||
|
const { nonce } = await (await context.get(url)).json();
|
||||||
|
const mac = crypto.createHmac('sha1', synapse.registrationSecret).update(
|
||||||
|
`${nonce}\0${username}\0${password}\0notadmin`,
|
||||||
|
).digest('hex');
|
||||||
|
const response = await (await context.post(url, {
|
||||||
|
data: {
|
||||||
|
nonce,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
mac,
|
||||||
|
admin: false,
|
||||||
|
displayname: displayName,
|
||||||
|
}
|
||||||
|
})).json();
|
||||||
|
return {
|
||||||
|
homeServer: response.home_server,
|
||||||
|
accessToken: response.access_token,
|
||||||
|
userId: response.user_id,
|
||||||
|
deviceId: response.device_id,
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
# Meta-template for synapse templates
|
||||||
|
|
||||||
|
To make another template, you can copy this directory
|
@ -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/synapsedocker/templates/COPYME/log.config
Normal file
50
playwright/plugins/synapsedocker/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
|
@ -0,0 +1 @@
|
|||||||
|
A synapse configured with user privacy consent enabled
|
@ -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
|
@ -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,23 @@
|
|||||||
|
<!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 schon</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1 @@
|
|||||||
|
A synapse configured with user privacy consent disabled
|
@ -0,0 +1,76 @@
|
|||||||
|
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"
|
@ -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,89 @@
|
|||||||
|
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: dex
|
||||||
|
idp_name: "My Dex server"
|
||||||
|
skip_verification: true # This is needed as Dex is served on an insecure endpoint
|
||||||
|
issuer: "{{OIDC_ISSUER}}"
|
||||||
|
client_id: "synapse"
|
||||||
|
client_secret: "secret"
|
||||||
|
scopes: ["openid", "profile"]
|
||||||
|
user_mapping_provider:
|
||||||
|
config:
|
||||||
|
localpart_template: "{{ user.name }}"
|
||||||
|
display_name_template: "{{ user.name|capitalize }}"
|
50
playwright/plugins/synapsedocker/templates/sso/log.config
Normal file
50
playwright/plugins/synapsedocker/templates/sso/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
|
59
playwright/tests/login.spec.ts
Normal file
59
playwright/tests/login.spec.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
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 {test} from '@playwright/test';
|
||||||
|
import {synapseStart, synapseStop, registerUser} from "../plugins/synapsedocker";
|
||||||
|
import {dexStart, dexStop} from "../plugins/dex";
|
||||||
|
import type {DexInstance} from "../plugins/dex";
|
||||||
|
import type {SynapseInstance} from "../plugins/synapsedocker";
|
||||||
|
|
||||||
|
test.describe("Login", () => {
|
||||||
|
let synapse: SynapseInstance;
|
||||||
|
let dex: DexInstance;
|
||||||
|
|
||||||
|
test.beforeEach(async () => {
|
||||||
|
dex = await dexStart();
|
||||||
|
synapse = await synapseStart("sso");
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterEach(async () => {
|
||||||
|
await synapseStop(synapse.synapseId);
|
||||||
|
await dexStop(dex.dexId);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Login using username/password", async ({ page }) => {
|
||||||
|
const username = "foobaraccount";
|
||||||
|
const password = "password123";
|
||||||
|
await registerUser(synapse, username, password);
|
||||||
|
await page.goto("/");
|
||||||
|
await page.locator("#homeserver").fill("");
|
||||||
|
await page.locator("#homeserver").type(synapse.baseUrl);
|
||||||
|
await page.locator("#username").type(username);
|
||||||
|
await page.locator("#password").type(password);
|
||||||
|
await page.getByText('Log In', { exact: true }).click();
|
||||||
|
await page.locator(".SessionView").waitFor();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Login using SSO", async ({ page }) => {
|
||||||
|
await page.goto("/");
|
||||||
|
await page.locator("#homeserver").fill("");
|
||||||
|
await page.locator("#homeserver").type(synapse.baseUrl);
|
||||||
|
await page.locator(".StartSSOLoginView_button").click();
|
||||||
|
await page.getByText("Log in with Example").click();
|
||||||
|
await page.locator(".dex-btn-text", {hasText: "Grant Access"}).click();
|
||||||
|
await page.locator(".primary-button", {hasText: "Continue"}).click();
|
||||||
|
await page.locator(".SessionView").waitFor();
|
||||||
|
});
|
||||||
|
});
|
21
playwright/tests/startup.spec.ts
Normal file
21
playwright/tests/startup.spec.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
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 {test} from '@playwright/test';
|
||||||
|
|
||||||
|
test("App has no startup errors that prevent UI render", async ({ page }) => {
|
||||||
|
await page.goto("/");
|
||||||
|
await page.getByText("Log In", { exact: true }).waitFor();
|
||||||
|
});
|
19
scripts/test-app.sh
Executable file
19
scripts/test-app.sh
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Make sure docker is available
|
||||||
|
if ! docker info > /dev/null 2>&1; then
|
||||||
|
echo "You need to intall docker before you can run the tests!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stop running containers
|
||||||
|
if docker stop hydrogen-synapse > /dev/null 2>&1; then
|
||||||
|
echo "Existing 'hydrogen-synapse' container stopped ✔"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if docker stop hydrogen-dex > /dev/null 2>&1; then
|
||||||
|
echo "Existing 'hydrogen-dex' container stopped ✔"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run playwright
|
||||||
|
yarn playwright test
|
Loading…
Reference in New Issue
Block a user