WIP of syn2mas tool

This commit is contained in:
Hugh Nimmo-Smith
2023-08-11 16:28:02 +01:00
committed by Quentin Gliech
parent 90aaf395d8
commit 38ed5e264e
33 changed files with 6936 additions and 0 deletions

View File

@@ -68,3 +68,8 @@ updates:
graphql-codegen:
patterns:
- "@graphql-codegen/*"
- package-ecosystem: "npm"
directory: "/tools/syn2mas/"
schedule:
interval: "weekly"

View File

@@ -5,6 +5,8 @@ on:
branches: [ main ]
tags:
- 'v*'
paths-ignore:
- 'tools/**'
# Only run for pull requests if relevant files were changed
pull_request:
@@ -13,6 +15,7 @@ on:
- Dockerfile
- docker-bake.hcl
- .github/workflows/build.yaml
- 'tools/**'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}

View File

@@ -5,8 +5,12 @@ on:
branches: [ main ]
tags:
- 'v*'
paths-ignore:
- 'tools/**'
pull_request:
branches: [ main ]
paths-ignore:
- 'tools/**'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}

View File

@@ -3,8 +3,12 @@ name: Coverage
on:
push:
branches: [ main ]
paths-ignore:
- 'tools/**'
pull_request:
branches: [ main ]
paths-ignore:
- 'tools/**'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}

View File

@@ -3,8 +3,12 @@ name: Build and deploy the documentation
on:
push:
branches: [ main ]
paths-ignore:
- 'tools/**'
pull_request:
branches: [ main ]
paths-ignore:
- 'tools/**'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}

50
.github/workflows/tools.yaml vendored Normal file
View File

@@ -0,0 +1,50 @@
name: CI for tools
on:
push:
paths:
- 'tools/**'
pull_request:
paths:
- 'tools/**'
concurrency:
group: tools-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
syn2mas-lint:
name: Check syn2mas style
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout the code
uses: actions/checkout@v3.5.3
- name: Install Node
uses: actions/setup-node@v3.7.0
with:
node-version-file: ./tools/syn2mas/.nvmrc
- name: Install Node dependencies
working-directory: ./tools/syn2mas
run: npm ci
- name: Lint
working-directory: ./tools/syn2mas
run: npm run lint
tests-done:
name: Tests done
if: ${{ always() }}
needs:
- syn2mas-lint
runs-on: ubuntu-latest
steps:
- uses: matrix-org/done-action@v2
with:
needs: ${{ toJSON(needs) }}

View File

@@ -0,0 +1,22 @@
module.exports = {
plugins: [
'matrix-org',
],
extends: [
'plugin:matrix-org/typescript',
],
env: {
browser: false,
node: true,
},
parser: '@typescript-eslint/parser',
parserOptions: {
project: "./tsconfig.json",
},
rules: {
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-misused-promises': 'error',
'@typescript-eslint/promise-function-async': 'error',
'@typescript-eslint/await-thenable': 'error',
},
};

2
tools/syn2mas/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules
dist

1
tools/syn2mas/.nvmrc Normal file
View File

@@ -0,0 +1 @@
18

16
tools/syn2mas/README.md Normal file
View File

@@ -0,0 +1,16 @@
# syn2mas - Synapse to Matrix Authentication Service
Tool to help with the migration of a Matrix Synapse installation to the Matrix Authentication Service.
The tool has two modes of operation:
- Advisor mode: Analyses the Synapse configuration and reports on any issues that would prevent a successful migration.
- Migration mode: Performs the migration of the Synapse database into the Matrix Authentication Service database.
## Usage
Pre-migration advisor:
```sh
npm run dev -- advisor --synapseConfigFile homeserver.yaml
```

6202
tools/syn2mas/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
{
"name": "syn2mas",
"version": "0.0.0",
"license": "Apache-2.0",
"author": "Matrix.org",
"type": "module",
"scripts": {
"build": "tsc",
"dev": "ts-node --esm src/index.ts",
"lint": "npm run lint:types && npm run lint:style",
"lint:style": "eslint src",
"lint:types": "tsc --noEmit --skipLibCheck",
"start": "node dist/index.js"
},
"devDependencies": {
"@types/command-line-args": "^5.2.0",
"@types/node": "^18.15.10",
"@typescript-eslint/eslint-plugin": "^5.55.0",
"@typescript-eslint/parser": "^5.55.0",
"eslint": "^8.36.0",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-matrix-org": "github:matrix-org/eslint-plugin-matrix-org",
"eslint-plugin-unicorn": "^46.0.0",
"prettier": "^2.8.7",
"ts-node": "^10.9.1",
"typescript": "^5.0.2"
},
"dependencies": {
"command-line-args": "^5.2.1",
"id128": "^1.6.6",
"knex": "^2.4.2",
"log4js": "^6.9.1",
"pg": "^8.10.0",
"sqlite3": "^5.1.6",
"ts-command-line-args": "^2.4.2",
"yaml": "^2.2.1"
}
}

View File

@@ -0,0 +1,141 @@
import { readFile } from "node:fs/promises";
import { parse } from "ts-command-line-args";
import log4js from "log4js";
import yaml from "yaml";
import { Knex } from "knex";
import { SUser } from "./types/SUser";
import { SynapseConfig, SynapseOIDCProvider } from "./types/SynapseConfig";
import { connectToSynapseDatabase } from "./db.mjs";
import { SUserThreePid } from "./types/SUserThreePid";
import { SAccessToken } from "./types/SAccessToken";
import { SRefreshToken } from "./types/SRefreshToken";
const log = log4js.getLogger("migrate");
interface Options {
command: string;
synapseConfigFile: string;
help?: boolean;
}
export async function advisor(argv?: string[]): Promise<void> {
const args = parse<Options>({
command: { type: String, description: "Command to run", defaultOption: true, typeLabel: "migrate" },
synapseConfigFile: { type: String, description: "Path to synapse homeserver.yaml config file" },
help: { type: Boolean, optional: true, alias: "h", description: "Prints this usage guide" },
},
{
helpArg: "help",
});
const warnings: string[] = [];
function warn(message: string): void {
log.warn(message);
warnings.push(message);
}
const errors: string[] = [];
function error(message: string): void {
log.error(message);
errors.push(message);
}
// load synapse config
const synapseConfig: SynapseConfig = yaml.parse(await readFile(args.synapseConfigFile, "utf8"));
// connect to synapse databases
const synapse = connectToSynapseDatabase(synapseConfig);
async function count(query: Knex.QueryBuilder): Promise<number> {
const res = await (query.first());
if (!res) {
return 0;
}
return res["count(*)"] as number;
}
const adminUsers = await count(synapse.count("*").from<SUser>("users").where({ admin: 1 }));
if (adminUsers > 0) {
warn(`Synapse database contains ${adminUsers} admin users which will need to be added to the MAS configuration.`);
}
const guestUsers = await count(synapse.count("*").from<SUser>("users").where({ is_guest: 1 }));
if (guestUsers > 0) {
error(`Synapse database contains ${guestUsers} guest users which aren't supported by MAS: https://github.com/matrix-org/matrix-authentication-service/issues/1445`);
}
if (synapseConfig.allow_guest_access) {
if (guestUsers > 0) {
error("Synapse config allows guest access which isn't supported by MAS: https://github.com/matrix-org/matrix-authentication-service/issues/1445");
} else {
error("Synapse config allows guest access which isn't supported by MAS, but no guest users were found in the database so the option could be disabled: https://github.com/matrix-org/matrix-authentication-service/issues/1445");
}
}
if (synapseConfig.enable_registration) {
warn("Synapse config has registration enabled which will need to be disabled after migration");
}
if (synapseConfig.enable_registration_captcha) {
error("Synapse config has registration CAPTCHA enabled which isn't supported by MAS: https://github.com/matrix-org/matrix-authentication-service/issues/138");
}
const usersWithoutEmailAddress = await count(synapse.count("*").from<SUser>("users").leftOuterJoin<SUserThreePid>("user_threepids", "users.name", "user_threepids.user_id").whereNull("user_threepids.user_id"));
if (usersWithoutEmailAddress > 0) {
warn(`Synapse database contains ${usersWithoutEmailAddress} users without a verified email address who will need to verify their email address before they can login after migration: https://github.com/matrix-org/matrix-authentication-service/issues/1505`);
}
const deactivatedUsers = await count(synapse.count("*").from<SUser>("users").where({ deactivated: 1 }));
if (deactivatedUsers > 0) {
error(`Synapse database contains ${deactivatedUsers} deactivated users which aren't supported during migration`);
}
const accessTokensWithoutDeviceId = await count(synapse.count("*").from<SAccessToken>("access_tokens").where({ device_id: "" }).orWhereNull("device_id"));
if (accessTokensWithoutDeviceId > 0) {
error(`Synapse database contains ${accessTokensWithoutDeviceId} access tokens without an associated device_id which aren't supported during migration`);
}
const nonEmailThreePids = await count(synapse.count("*").from<SUserThreePid>("user_threepids").whereNot({ medium: "email" }));
if (nonEmailThreePids > 0) {
error(`Synapse database contains ${nonEmailThreePids} non-email 3pids which will be ignored during migration`);
}
const oidcProviders: SynapseOIDCProvider[] = [...(synapseConfig.oidc_providers ?? []), ...(synapseConfig.oidc_config ? [synapseConfig.oidc_config] : [])];
for (const provider of oidcProviders) {
warn(`Synapse config contains OIDC auth configuration which will need mapping to be manually mapped to an upstream OpenID Provider during migration: ${provider.issuer}`);
}
if (synapseConfig.cas_config?.enabled) {
warn("Synapse config contains CAS auth configuration which will need mapping to be manually mapped to an upstream OpenID Provider during migration");
}
if (synapseConfig.saml2_config?.sp_config) {
warn("Synapse config contains SAML2 auth configuration which will need mapping to be manually mapped to an upstream OpenID Provider during migration");
}
if (synapseConfig.jwt_config?.enabled) {
warn("Synapse config contains JWT auth configuration which will need mapping to be manually mapped to an upstream OpenID Provider during migration");
}
if (synapseConfig.password_config?.enabled !== false && synapseConfig.password_config?.localdb_enabled === false) {
warn("Synapse has a non-standard password auth enabled which won't work after migration and will need to be manually mapped to an upstream OpenID Provider during migration");
} else if (synapseConfig.password_config?.enabled !== false) {
warn("Migration of Synapse password auth is not yet supported");
}
const externalIdAuthProviders = await synapse.select("auth_provider").count("* as Count").from("user_external_ids").groupBy("auth_provider") as { auth_provider: string; "Count": number }[];
for (const row of externalIdAuthProviders) {
warn(`An upstream OpenID Provider will need to be configured for the ${row.Count} users with auth provider ${row.auth_provider}`);
}
const usersWithPassword = await count(synapse.count("*").from<SUser>("users").whereNotNull("password_hash"));
if (usersWithPassword > 0) {
warn(`Synapse database contains ${usersWithPassword} users with a password which will be migrated. However, support for password auth in MAS is not feature complete`);
}
const accessTokensToImport = await count(synapse.count("*").from<SAccessToken>("access_tokens").whereNotNull("device_id"));
if (accessTokensToImport > 0) {
log.info(`Synapse database contains ${accessTokensToImport} access tokens which will be migrated`);
}
const synapseRefreshToken = await count(synapse.select("*").from<SRefreshToken>("refresh_tokens"));
if (synapseRefreshToken > 0) {
log.info(`Synapse database contains ${synapseRefreshToken} refresh tokens which will be migrated`);
}
}

26
tools/syn2mas/src/db.mts Normal file
View File

@@ -0,0 +1,26 @@
import knex, { Knex } from "knex";
import { SynapseConfig } from "./types/SynapseConfig";
import { MASConfig } from "./types/MASConfig";
export function connectToSynapseDatabase({ database }: SynapseConfig): Knex<{}, unknown[]> {
if (database?.name === "sqlite3") {
return knex({ client: "sqlite3", connection: { filename: database.args.database }, useNullAsDefault: true });
}
if (database.name === "psycopg2") {
return knex({ client: "pg", connection: {
user: database?.args?.user,
database: database?.args?.database,
password: database?.args?.password,
port: database?.args?.port,
host: database?.args?.host,
} });
}
throw new Error(`Unsupported database type ${database?.name}. Must be sqlite3 or psycopg2`);
}
export function connectToMASDatabase({ database }: MASConfig): Knex<{}, unknown[]> {
return knex({ client: "pg", connection: database?.uri });
}

View File

@@ -0,0 +1,46 @@
import { ArgumentConfig, parse } from "ts-command-line-args";
import log4js from "log4js";
// import { migrate } from "./migrate.mjs";
import { advisor } from "./advisor.mjs";
log4js.configure({
appenders: {
console: { type: "console" },
},
categories: {
default: { appenders: ["console"], level: "debug" },
},
});
const log = log4js.getLogger();
interface MainOptions {
command: string;
help?: boolean;
}
const mainArgOptions: ArgumentConfig<MainOptions> = {
command: { type: String, description: "Command to run", defaultOption: true, typeLabel: "<advisor|migrate>" },
help: { type: Boolean, optional: true, alias: "h", description: "Prints this usage guide" },
};
export const mainArgs = parse<MainOptions>(mainArgOptions, { stopAtFirstUnknown: true });
try {
// if (mainArgs.command === "migrate") {
// await migrate();
// process.exit(0);
// }
if (mainArgs.command === "advisor") {
await advisor();
process.exit(0);
}
parse<MainOptions>(mainArgOptions, { helpArg: "help" });
process.exit(1);
} catch (e) {
log.error(e);
process.exit(1);
}

View File

@@ -0,0 +1,8 @@
export interface MASConfig {
database?: {
uri?: string;
};
secrets?: {
encryption?: string;
};
}

View File

@@ -0,0 +1,29 @@
import { UUID } from "./index";
import { MCompatSession } from "./MCompatSession";
/*
+------------------------+--------------------------+-----------+
| Column | Type | Modifiers |
|------------------------+--------------------------+-----------|
| compat_access_token_id | uuid | not null |
| compat_session_id | uuid | not null |
| access_token | text | not null |
| created_at | timestamp with time zone | not null |
| expires_at | timestamp with time zone | |
+------------------------+--------------------------+-----------+
Indexes:
"compat_access_tokens_pkey" PRIMARY KEY, btree (compat_access_token_id)
"compat_access_tokens_access_token_unique" UNIQUE CONSTRAINT, btree (access_token)
Foreign-key constraints:
"compat_access_tokens_compat_session_id_fkey" FOREIGN KEY (compat_session_id) REFERENCES compat_sessions(compat_session_id)
Referenced by:
TABLE "compat_refresh_tokens" CONSTRAINT "compat_refresh_tokens_compat_access_token_id_fkey" FOREIGN KEY (compat_access_token_id) REFERENCES compat_access_tokens(compat_access_toke
n_id)
*/
export interface MCompatAccessToken {
compat_access_token_id: UUID<MCompatAccessToken>;
compat_session_id: UUID<MCompatSession>;
access_token: string;
created_at: Date;
expires_at?: Date;
}

View File

@@ -0,0 +1,30 @@
import { MCompatAccessToken } from "./MCompatAccessToken";
import { UUID } from "./index";
import { MCompatSession } from "./MCompatSession";
/*
+-------------------------+--------------------------+-----------+
| Column | Type | Modifiers |
|-------------------------+--------------------------+-----------|
| compat_refresh_token_id | uuid | not null |
| compat_session_id | uuid | not null |
| compat_access_token_id | uuid | not null |
| refresh_token | text | not null |
| created_at | timestamp with time zone | not null |
| consumed_at | timestamp with time zone | |
+-------------------------+--------------------------+-----------+
Indexes:
"compat_refresh_tokens_pkey" PRIMARY KEY, btree (compat_refresh_token_id)
"compat_refresh_tokens_refresh_token_unique" UNIQUE CONSTRAINT, btree (refresh_token)
Foreign-key constraints:
"compat_refresh_tokens_compat_access_token_id_fkey" FOREIGN KEY (compat_access_token_id) REFERENCES compat_access_tokens(compat_access_token_id)
"compat_refresh_tokens_compat_session_id_fkey" FOREIGN KEY (compat_session_id) REFERENCES compat_sessions(compat_session_id)
*/
export interface MCompatRefreshToken {
compat_refresh_token_id: UUID<MCompatRefreshToken>;
compat_session_id: UUID<MCompatSession>;
compat_access_token_id: UUID<MCompatAccessToken>;
refresh_token: string;
created_at: Date;
consumed_at?: Date;
}

View File

@@ -0,0 +1,33 @@
import { MUser } from "./MUser";
import { UUID } from "./index";
/*
+-------------------+--------------------------+-----------+
| Column | Type | Modifiers |
|-------------------+--------------------------+-----------|
| compat_session_id | uuid | not null |
| user_id | uuid | not null |
| device_id | text | not null |
| created_at | timestamp with time zone | not null |
| finished_at | timestamp with time zone | |
| is_synapse_admin | boolean | not null |
+-------------------+--------------------------+-----------+
Indexes:
"compat_sessions_pkey" PRIMARY KEY, btree (compat_session_id)
"compat_sessions_device_id_unique" UNIQUE CONSTRAINT, btree (device_id)
Foreign-key constraints:
"compat_sessions_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(user_id)
Referenced by:
TABLE "compat_sso_logins" CONSTRAINT "compat_sso_logins_compat_session_id_fkey" FOREIGN KEY (compat_session_id) REFERENCES compat_sessions(compat_session_id) ON DELETE SET NULL
TABLE "compat_access_tokens" CONSTRAINT "compat_access_tokens_compat_session_id_fkey" FOREIGN KEY (compat_session_id) REFERENCES compat_sessions(compat_session_id)
TABLE "compat_refresh_tokens" CONSTRAINT "compat_refresh_tokens_compat_session_id_fkey" FOREIGN KEY (compat_session_id) REFERENCES compat_sessions(compat_session_id)
*/
export interface MCompatSession {
compat_session_id: UUID<MCompatSession>;
user_id: UUID<MUser>;
device_id: string;
created_at: Date;
finished_at?: Date;
is_synapse_admin: boolean;
}

View File

@@ -0,0 +1,30 @@
import { MUser } from "./MUser";
import { UUID } from "./index";
import { MUpstreamOauthProvider } from "./MUpstreamOauthProvider";
/*
+----------------------------+--------------------------+-----------+
| Column | Type | Modifiers |
|----------------------------+--------------------------+-----------|
| upstream_oauth_link_id | uuid | not null |
| upstream_oauth_provider_id | uuid | not null |
| user_id | uuid | |
| subject | text | not null |
| created_at | timestamp with time zone | not null |
+----------------------------+--------------------------+-----------+
Indexes:
"upstream_oauth_links_pkey" PRIMARY KEY, btree (upstream_oauth_link_id)
"upstream_oauth_links_subject_unique" UNIQUE CONSTRAINT, btree (upstream_oauth_provider_id, subject)
Foreign-key constraints:
"upstream_oauth_link_user_fkey" FOREIGN KEY (user_id) REFERENCES users(user_id)
"upstream_oauth_links_provider_fkey" FOREIGN KEY (upstream_oauth_provider_id) REFERENCES upstream_oauth_providers(upstream_oauth_provider_id)
Referenced by:
TABLE "upstream_oauth_authorization_sessions" CONSTRAINT "upstream_oauth_authorization_sessions_link_fkey" FOREIGN KEY (upstream_oauth_link_id) REFERENCES upstream_oauth_links(upstream_oauth_link_id)
*/
export interface MUpstreamOauthLink {
upstream_oauth_link_id: UUID<MUpstreamOauthLink>;
upstream_oauth_provider_id: UUID<MUpstreamOauthProvider>;
user_id?: UUID<MUser>;
subject: string;
created_at: Date;
}

View File

@@ -0,0 +1,32 @@
import { UUID } from "./index";
/*
+----------------------------+--------------------------+-----------+
| Column | Type | Modifiers |
|----------------------------+--------------------------+-----------|
| upstream_oauth_provider_id | uuid | not null |
| issuer | text | not null |
| scope | text | not null |
| client_id | text | not null |
| encrypted_client_secret | text | |
| token_endpoint_signing_alg | text | |
| token_endpoint_auth_method | text | not null |
| created_at | timestamp with time zone | not null |
+----------------------------+--------------------------+-----------+
Indexes:
"upstream_oauth_providers_pkey" PRIMARY KEY, btree (upstream_oauth_provider_id)
Referenced by:
TABLE "upstream_oauth_links" CONSTRAINT "upstream_oauth_links_provider_fkey" FOREIGN KEY (upstream_oauth_provider_id) REFERENCES upstream_oauth_providers(upstream_oauth_provider_id)
TABLE "upstream_oauth_authorization_sessions" CONSTRAINT "upstream_oauth_authorization_sessions_provider_fkey" FOREIGN KEY (upstream_oauth_provider_id) REFERENCES upstream_oauth_providers(upstream_oauth_provider_id)
*/
export interface MUpstreamOauthProvider {
upstream_oauth_provider_id: UUID<MUpstreamOauthProvider>;
issuer: string;
scope: string;
client_id: string;
encrypted_client_secret?: string;
token_endpoint_signing_alg?: string;
token_endpoint_auth_method: string;
created_at: Date;
}

9
tools/syn2mas/src/types/MUser.d.ts vendored Normal file
View File

@@ -0,0 +1,9 @@
import { UUID } from "./index";
import { MUserEmail } from "./MUserEmail";
export interface MUser {
user_id: UUID<MUser>;
username: string; // localpart only without @
created_at: Date;
primary_user_email_id?: UUID<MUserEmail>;
}

22
tools/syn2mas/src/types/MUserEmail.d.ts vendored Normal file
View File

@@ -0,0 +1,22 @@
import { MUser } from "./MUser";
import { UUID } from "./index";
/*
+---------------+--------------------------+-----------+
| Column | Type | Modifiers |
|---------------+--------------------------+-----------|
| user_email_id | uuid | not null |
| user_id | uuid | not null |
| email | text | not null |
| created_at | timestamp with time zone | not null |
| confirmed_at | timestamp with time zone | |
+---------------+--------------------------+-----------+
*/
export interface MUserEmail {
user_email_id: UUID<MUserEmail>;
user_id: UUID<MUser>;
email: string;
created_at: Date;
confirmed_at?: Date;
}

View File

@@ -0,0 +1,11 @@
import { MUser } from "./MUser";
import { UUID } from "./index";
export interface MUserPassword {
user_password_id: UUID<MUserPassword>;
user_id: UUID<MUser>;
hashed_password: string;
created_at: Date;
version: number;
upgraded_from_id?: UUID<MUserPassword>;
}

View File

@@ -0,0 +1,27 @@
import { Id, SynapseUserId } from "./index";
import { SRefreshToken } from "./SRefreshToken";
/*
CREATE TABLE access_tokens (
id bigint NOT NULL,
user_id text NOT NULL,
device_id text,
token text NOT NULL,
valid_until_ms bigint,
puppets_user_id text,
last_validated bigint,
refresh_token_id bigint,
used boolean
);
*/
export interface SAccessToken {
id: Id<SAccessToken>;
user_id: SynapseUserId;
device_id?: string;
token: string;
valid_until_ms?: number;
puppets_user_id?: SynapseUserId;
last_validated?: number;
refresh_token_id?: Id<SRefreshToken>;
used: boolean;
}

View File

@@ -0,0 +1,24 @@
import { Id, SynapseUserId } from "./index";
/*
);
CREATE TABLE refresh_tokens (
id bigint NOT NULL,
user_id text NOT NULL,
device_id text NOT NULL,
token text NOT NULL,
next_token_id bigint,
expiry_ts bigint,
ultimate_session_expiry_ts bigint
);
*/
export interface SRefreshToken {
id: Id<SRefreshToken>;
user_id: SynapseUserId;
device_id: string;
token: string;
next_token_id?: number; // refresh or access?
expiry_ts?: number;
ultimate_session_expiry_ts?: number;
}

10
tools/syn2mas/src/types/SUser.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
import { SynapseUserId, UnixTimestamp } from "./index";
export interface SUser {
name: SynapseUserId; // '@test2:localhost:8008'
password_hash?: string;
admin: number;
is_guest: number;
deactivated: number;
creation_ts: UnixTimestamp;
}

View File

@@ -0,0 +1,7 @@
import { SynapseUserId } from "./index";
export interface SUserExternalId {
auth_provider: string;
external_id: string;
user_id: SynapseUserId;
}

View File

@@ -0,0 +1,18 @@
import { SynapseUserId } from "./index";
/*
CREATE TABLE user_threepids (
user_id text NOT NULL,
medium text NOT NULL,
address text NOT NULL,
validated_at bigint NOT NULL,
added_at bigint NOT NULL
);
*/
export interface SUserThreePid {
user_id: SynapseUserId;
medium: string;
address: string;
validated_at: number;
added_at: number;
}

View File

@@ -0,0 +1,51 @@
export interface SynapseOIDCProvider {
idp_id: string;
idp_name: string;
issuer: string;
client_id: string;
scopes: string[];
client_auth_method?: "client_secret_basic" | "client_secret_post" | "none";
client_secret?: string;
client_secret_jwt_key?: string;
}
export interface SynapseConfig {
database?: {
name: "sqlite3";
args?: {
database: string;
};
} | {
name: "psycopg2";
args?: {
user?: string;
password?: string;
database?: string;
host?: string;
port?: number;
};
} | any;
oidc_providers?: SynapseOIDCProvider[];
oidc_config?: SynapseOIDCProvider;
allow_guest_access?: boolean;
cas_config?: {
enabled?: boolean;
};
saml2_config?: {
sp_config?: {};
};
sso?: {
client_whitelist?: string[];
update_profile_information?: boolean;
};
jwt_config?: {
enabled?: boolean;
};
password_config?: {
enabled?: boolean;
localdb_enabled?: boolean;
};
enable_registration_captcha?: boolean;
enable_registration?: boolean;
}

6
tools/syn2mas/src/types/index.d.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
export type UnixTimestamp = number;
export type SynapseUserId = string;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export type Id<T> = number;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export type UUID<T> = string;

7
tools/syn2mas/src/types/knex.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
import "knex/types/result";
declare module "knex/types/result" {
interface Registry {
Count: number;
}
}

View File

@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"lib": ["ES2022"],
"moduleResolution": "node",
"strict": true,
"sourceMap": true,
"declaration": false,
"outDir": "./dist",
"rootDir": "./src",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true
}
}