From 218f0ba03c3a717fe3964e37628adab852b7d3e5 Mon Sep 17 00:00:00 2001 From: Aine <97398200+aine-etke@users.noreply.github.com> Date: Sat, 5 Apr 2025 18:08:29 +0000 Subject: [PATCH] Configurable CORS credentials (#456) * Configurable CORS credentials * update readme --- README.md | 8 ++++++++ docs/config.md | 6 ++++++ docs/cors-credentials.md | 35 ++++++++++++++++++++++++++++++++ src/synapse/authProvider.test.ts | 3 +++ src/synapse/authProvider.ts | 2 ++ src/synapse/dataProvider.ts | 2 ++ src/utils/config.ts | 6 ++++++ 7 files changed, 62 insertions(+) create mode 100644 docs/cors-credentials.md diff --git a/README.md b/README.md index 9cf0ba2..590d978 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ * [Configuration](#configuration) * [Prefilling login form](#prefilling-login-form) * [Restricting available homeserver](#restricting-available-homeserver) + * [Configuring CORS credentials](#configuring-cors-credentials) * [Protecting appservice managed users](#protecting-appservice-managed-users) * [Adding custom menu items](#adding-custom-menu-items) * [Usage](#usage) @@ -111,6 +112,7 @@ The following changes are already implemented: * [Respect base url (`BASE_PATH` / `vite build --base`) when loading `config.json`](https://github.com/etkecc/synapse-admin/pull/274) * [Add Users' Account Data tab](https://github.com/etkecc/synapse-admin/pull/276) * [Make bulk registration CSV import more user-friendly](https://github.com/etkecc/synapse-admin/pull/411) +* [Configurable CORS Credentials](https://github.com/etkecc/synapse-admin/pull/456) #### exclusive for [etke.cc](https://etke.cc) customers @@ -180,6 +182,12 @@ You can restrict the homeserver(s), so that the user can no longer define it him [Documentation](./docs/restrict-hs.md) +### Configuring CORS credentials + +You can configure the CORS credentials mode for the Synapse Admin instance. + +[Documentation](./docs/cors-credentials.md) + ### Protecting appservice managed users To avoid accidental adjustments of appservice-managed users (e.g., puppets created by a bridge) and breaking the bridge, diff --git a/docs/config.md b/docs/config.md index 67e05c3..f41fa54 100644 --- a/docs/config.md +++ b/docs/config.md @@ -28,6 +28,12 @@ In this case, you could provide the configuration in the `/.well-known/matrix/cl The homeserver URL should be the _actual_ homeserver URL, and not the delegated one. Example: `https://matrix.example.com` or `https://synapse.example.net` [More details](restrict-hs.md) +* `corsCredentials` - configure the CORS credentials for the Synapse Admin instance. + It accepts the following values: + * `same-origin` (default): Cookies will be sent only if the request is made from the same origin as the server. + * `include`: Cookies will be sent regardless of the origin of the request. + * `omit`: Cookies will not be sent with the request. + [More details](cors-credentials.md) * `asManagedUsers` - protect system user accounts managed by appservices (such as bridges) / system (such as bots) from accidental changes. By defining a list of MXID regex patterns, you can protect these accounts from accidental changes. Example: `^@baibot:example\\.com$`, `^@slackbot:example\\.com$`, `^@slack_[a-zA-Z0-9\\-]+:example\\.com$`, `^@telegrambot:example\\.com$`, `^@telegram_[a-zA-Z0-9]+:example\\.com$` diff --git a/docs/cors-credentials.md b/docs/cors-credentials.md new file mode 100644 index 0000000..1202b6a --- /dev/null +++ b/docs/cors-credentials.md @@ -0,0 +1,35 @@ +# CORS Credentials + +If you'd like to use cookie-based authentication +(for example, [ForwardAuth with Authelia](https://github.com/Awesome-Technologies/synapse-admin/issues/655)), +you can configure the `corsCredentials` option in the `config.json` file or in the `/.well-known/matrix/client` file. + +## Configuration + +> [Documentation on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#including_credentials) + +The `corsCredentials` option accepts the following values: + +* `same-origin` (default): Cookies will be sent only if the request is made from the same origin as the server. +* `include`: Cookies will be sent regardless of the origin of the request. +* `omit`: Cookies will not be sent with the request. + +[Configuration options](config.md) + +### config.json + +```json +{ + "corsCredentials": "include" +} +``` + +### `/.well-known/matrix/client` + +```json +{ + "cc.etke.synapse-admin": { + "corsCredentials": "include" + } +} +``` diff --git a/src/synapse/authProvider.test.ts b/src/synapse/authProvider.test.ts index 6317a6d..2038607 100644 --- a/src/synapse/authProvider.test.ts +++ b/src/synapse/authProvider.test.ts @@ -35,6 +35,7 @@ describe("authProvider", () => { Accept: "application/json", "Content-Type": "application/json", }), + credentials: "same-origin", method: "POST", }); expect(localStorage.getItem("base_url")).toEqual("http://example.com"); @@ -66,6 +67,7 @@ describe("authProvider", () => { Accept: "application/json", "Content-Type": "application/json", }), + credentials: "same-origin", method: "POST", }); expect(localStorage.getItem("base_url")).toEqual("https://example.com"); @@ -88,6 +90,7 @@ describe("authProvider", () => { Authorization: "Bearer foo", }), method: "POST", + credentials: "same-origin", user: { authenticated: true, token: "Bearer foo" }, }); expect(localStorage.getItem("access_token")).toBeNull(); diff --git a/src/synapse/authProvider.ts b/src/synapse/authProvider.ts index f26a2f3..0d4f373 100644 --- a/src/synapse/authProvider.ts +++ b/src/synapse/authProvider.ts @@ -23,6 +23,7 @@ const authProvider: AuthProvider = { console.log("login "); let options: Options = { method: "POST", + credentials: GetConfig().corsCredentials, body: JSON.stringify( Object.assign( { @@ -151,6 +152,7 @@ const authProvider: AuthProvider = { const options: Options = { method: "POST", + credentials: GetConfig().corsCredentials, user: { authenticated: true, token: `Bearer ${access_token}`, diff --git a/src/synapse/dataProvider.ts b/src/synapse/dataProvider.ts index a44bd30..3bc911a 100644 --- a/src/synapse/dataProvider.ts +++ b/src/synapse/dataProvider.ts @@ -14,6 +14,7 @@ import { } from "react-admin"; import { returnMXID } from "../utils/mxid"; +import { GetConfig } from "../utils/config"; import { MatrixError, displayError } from "../utils/error"; const CACHED_MANY_REF: Record = {}; @@ -22,6 +23,7 @@ const CACHED_MANY_REF: Record = {}; const jsonClient = async (url: string, options: Options = {}) => { const token = localStorage.getItem("access_token"); console.log("httpClient " + url); + options.credentials = GetConfig().corsCredentials; if (token !== null) { options.user = { authenticated: true, diff --git a/src/utils/config.ts b/src/utils/config.ts index c2c0fef..ca45928 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -1,5 +1,6 @@ export interface Config { restrictBaseUrl: string | string[]; + corsCredentials: string; asManagedUsers: RegExp[]; menu: MenuItem[]; etkeccAdmin?: string; @@ -16,6 +17,7 @@ export const WellKnownKey = "cc.etke.synapse-admin"; // current configuration let config: Config = { restrictBaseUrl: "", + corsCredentials: "same-origin", asManagedUsers: [], menu: [], etkeccAdmin: "" @@ -69,6 +71,10 @@ export const LoadConfig = (context: any) => { config.restrictBaseUrl = context.restrictBaseUrl as string | string[]; } + if (context?.corsCredentials) { + config.corsCredentials = context.corsCredentials; + } + if (context?.asManagedUsers) { config.asManagedUsers = context.asManagedUsers.map((regex: string) => new RegExp(regex)); }