mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-22 19:14:52 +01:00
Write plugin for Dex
This commit is contained in:
parent
193415ac1d
commit
2376ef8b8c
132
cypress/plugins/dex/index.ts
Normal file
132
cypress/plugins/dex/index.ts
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
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 PluginEvents = Cypress.PluginEvents;
|
||||
import PluginConfigOptions = Cypress.PluginConfigOptions;
|
||||
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>();
|
||||
let env;
|
||||
|
||||
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 synapseAddress = `${env.SYNAPSE_IP_ADDRESS}:${env.SYNAPSE_PORT}`;
|
||||
hsYaml = hsYaml.replace(/{{SYNAPSE_ADDRESS}}/g, synapseAddress);
|
||||
const host = env.DEX_IP_ADDRESS;
|
||||
const port = env.DEX_PORT;
|
||||
const dexAddress = `${host}:${port}`;
|
||||
hsYaml = hsYaml.replace(/{{DEX_ADDRESS}}/g, dexAddress);
|
||||
await fse.writeFile(path.join(tempDir, "config.yaml"), hsYaml);
|
||||
|
||||
const baseUrl = `http://${host}:${port}`;
|
||||
return {
|
||||
host,
|
||||
port,
|
||||
baseUrl,
|
||||
configDir: tempDir,
|
||||
};
|
||||
}
|
||||
|
||||
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: "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;
|
||||
}
|
||||
|
||||
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}.`);
|
||||
// cypress deliberately fails if you return 'undefined', so
|
||||
// return null to signal all is well, and we've handled the task.
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
export function dexDocker(on: PluginEvents, config: PluginConfigOptions) {
|
||||
env = config.env;
|
||||
|
||||
on("task", {
|
||||
dexStart,
|
||||
dexStop,
|
||||
});
|
||||
|
||||
on("after:spec", async (spec) => {
|
||||
for (const dexId of dexConfigs.keys()) {
|
||||
console.warn(`Cleaning up dex ID ${dexId} after ${spec.name}`);
|
||||
await dexStop(dexId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
56
cypress/plugins/dex/template/config.yaml
Executable file
56
cypress/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
cypress/plugins/dex/template/dev.db
Executable file
BIN
cypress/plugins/dex/template/dev.db
Executable file
Binary file not shown.
@ -20,6 +20,7 @@ import PluginEvents = Cypress.PluginEvents;
|
||||
import PluginConfigOptions = Cypress.PluginConfigOptions;
|
||||
import { performance } from "./performance";
|
||||
import { synapseDocker } from "./synapsedocker";
|
||||
import { dexDocker } from "./dex";
|
||||
import { webserver } from "./webserver";
|
||||
import { docker } from "./docker";
|
||||
import { log } from "./log";
|
||||
@ -31,6 +32,7 @@ export default function(on: PluginEvents, config: PluginConfigOptions) {
|
||||
docker(on, config);
|
||||
performance(on, config);
|
||||
synapseDocker(on, config);
|
||||
dexDocker(on, config);
|
||||
webserver(on, config);
|
||||
log(on, config);
|
||||
}
|
||||
|
51
cypress/support/dex.ts
Normal file
51
cypress/support/dex.ts
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
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 Chainable = Cypress.Chainable;
|
||||
import AUTWindow = Cypress.AUTWindow;
|
||||
import { DexInstance } from "../plugins/dex";
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
/**
|
||||
* Start the dex server
|
||||
*/
|
||||
startDex(): Chainable<DexInstance>;
|
||||
|
||||
/**
|
||||
* Stop the dex server
|
||||
* @param dex the dex instance returned by startSynapse
|
||||
*/
|
||||
stopDex(dex: DexInstance): Chainable<AUTWindow>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startDex(): Chainable<DexInstance> {
|
||||
return cy.task<DexInstance>("dexStart");
|
||||
}
|
||||
|
||||
function stopDex(dex?: DexInstance): Chainable<AUTWindow> {
|
||||
if (!dex) return;
|
||||
cy.task("dexStop", dex.dexId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add("startDex", startDex);
|
||||
Cypress.Commands.add("stopDex", stopDex);
|
@ -17,3 +17,4 @@ limitations under the License.
|
||||
/// <reference types="cypress" />
|
||||
|
||||
import "./synapse";
|
||||
import "./dex";
|
||||
|
Loading…
Reference in New Issue
Block a user