mirror of
https://github.com/the-draupnir-project/Draupnir.git
synced 2026-06-04 06:41:18 +00:00
312 lines
9.8 KiB
TypeScript
312 lines
9.8 KiB
TypeScript
/**
|
|
* Copyright (C) 2022 Gnuxie <Gnuxie@protonmail.com>
|
|
* All rights reserved.
|
|
*
|
|
* This file is modified and is NOT licensed under the Apache License.
|
|
* This modified file incorperates work from mjolnir
|
|
* https://github.com/matrix-org/mjolnir
|
|
* which included the following license notice:
|
|
|
|
Copyright 2019, 2021 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.
|
|
*
|
|
* However, this file is modified and the modifications in this file
|
|
* are NOT distributed, contributed, committed, or licensed under the Apache License.
|
|
*/
|
|
|
|
import * as fs from "fs";
|
|
import { load } from "js-yaml";
|
|
import { MatrixClient, LogService } from "matrix-bot-sdk";
|
|
import Config from "config";
|
|
import path from "path";
|
|
|
|
/**
|
|
* The configuration, as read from production.yaml
|
|
*
|
|
* See file default.yaml for the documentation on individual options.
|
|
*/
|
|
// The object is magically generated by external lib `config`
|
|
// from the file specified by `NODE_ENV`, e.g. production.yaml
|
|
// or harness.yaml.
|
|
export interface IConfig {
|
|
homeserverUrl: string;
|
|
rawHomeserverUrl: string;
|
|
accessToken: string;
|
|
pantalaimon: {
|
|
use: boolean;
|
|
username: string;
|
|
password: string;
|
|
};
|
|
dataPath: string;
|
|
/**
|
|
* If true, Mjolnir will only accept invites from users present in managementRoom.
|
|
* Otherwise a space must be provided to `acceptInvitesFromSpace`.
|
|
*/
|
|
autojoinOnlyIfManager: boolean;
|
|
/** Mjolnir will accept invites from members of this space if `autojoinOnlyIfManager` is false. */
|
|
acceptInvitesFromSpace: string;
|
|
recordIgnoredInvites: boolean;
|
|
managementRoom: string;
|
|
verboseLogging: boolean;
|
|
logLevel: "DEBUG" | "INFO" | "WARN" | "ERROR";
|
|
logMutedModules: string[],
|
|
syncOnStartup: boolean;
|
|
verifyPermissionsOnStartup: boolean;
|
|
disableServerACL: boolean;
|
|
noop: boolean;
|
|
protectedRooms: string[]; // matrix.to urls
|
|
fasterMembershipChecks: boolean;
|
|
automaticallyRedactForReasons: string[]; // case-insensitive globs
|
|
protectAllJoinedRooms: boolean;
|
|
/**
|
|
* Backgrounded tasks: number of milliseconds to wait between the completion
|
|
* of one background task and the start of the next one.
|
|
*/
|
|
backgroundDelayMS: number;
|
|
pollReports: boolean;
|
|
/**
|
|
* Whether or not new reports, received either by webapi or polling,
|
|
* should be printed to our managementRoom.
|
|
*/
|
|
displayReports: boolean;
|
|
admin?: {
|
|
enableMakeRoomAdminCommand?: boolean;
|
|
}
|
|
commands: {
|
|
allowNoPrefix: boolean;
|
|
additionalPrefixes: string[];
|
|
confirmWildcardBan: boolean;
|
|
features: string[];
|
|
ban: {
|
|
defaultReasons: string[]
|
|
}
|
|
};
|
|
protections: {
|
|
wordlist: {
|
|
words: string[];
|
|
minutesBeforeTrusting: number;
|
|
};
|
|
};
|
|
health: {
|
|
healthz: {
|
|
enabled: boolean;
|
|
port: number;
|
|
address: string;
|
|
endpoint: string;
|
|
healthyStatus: number;
|
|
unhealthyStatus: number;
|
|
};
|
|
// If specified, attempt to upload any crash statistics to sentry.
|
|
sentry?: {
|
|
dsn: string;
|
|
|
|
// Frequency of performance monitoring.
|
|
//
|
|
// A number in [0.0, 1.0], where 0.0 means "don't bother with tracing"
|
|
// and 1.0 means "trace performance at every opportunity".
|
|
tracesSampleRate: number;
|
|
};
|
|
};
|
|
web: {
|
|
enabled: boolean;
|
|
port: number;
|
|
address: string;
|
|
abuseReporting: {
|
|
enabled: boolean;
|
|
}
|
|
ruleServer?: {
|
|
enabled: boolean;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Config options only set at runtime. Try to avoid using the objects
|
|
* here as much as possible.
|
|
*/
|
|
RUNTIME: {
|
|
client?: MatrixClient;
|
|
};
|
|
}
|
|
|
|
const defaultConfig: IConfig = {
|
|
homeserverUrl: "http://localhost:8008",
|
|
rawHomeserverUrl: "http://localhost:8008",
|
|
accessToken: "NONE_PROVIDED",
|
|
pantalaimon: {
|
|
use: false,
|
|
username: "",
|
|
password: "",
|
|
},
|
|
dataPath: "/data/storage",
|
|
acceptInvitesFromSpace: '!noop:example.org',
|
|
autojoinOnlyIfManager: true,
|
|
recordIgnoredInvites: false,
|
|
managementRoom: "!noop:example.org",
|
|
verboseLogging: false,
|
|
logLevel: "INFO",
|
|
logMutedModules: ['MatrixHttpClient', 'MatrixClientLite'],
|
|
syncOnStartup: true,
|
|
verifyPermissionsOnStartup: true,
|
|
noop: false,
|
|
disableServerACL: false,
|
|
protectedRooms: [],
|
|
fasterMembershipChecks: false,
|
|
automaticallyRedactForReasons: ["spam", "advertising"],
|
|
protectAllJoinedRooms: false,
|
|
backgroundDelayMS: 500,
|
|
pollReports: false,
|
|
displayReports: true,
|
|
commands: {
|
|
allowNoPrefix: false,
|
|
additionalPrefixes: ["draupnir"],
|
|
confirmWildcardBan: true,
|
|
features: [
|
|
"synapse admin",
|
|
],
|
|
ban: {
|
|
defaultReasons: [
|
|
"spam",
|
|
"brigading",
|
|
"harassment",
|
|
"disagreement",
|
|
]
|
|
}
|
|
},
|
|
protections: {
|
|
wordlist: {
|
|
words: [],
|
|
minutesBeforeTrusting: 20
|
|
}
|
|
},
|
|
health: {
|
|
healthz: {
|
|
enabled: false,
|
|
port: 8080,
|
|
address: "0.0.0.0",
|
|
endpoint: "/healthz",
|
|
healthyStatus: 200,
|
|
unhealthyStatus: 418,
|
|
},
|
|
},
|
|
web: {
|
|
enabled: false,
|
|
port: 8080,
|
|
address: "localhost",
|
|
abuseReporting: {
|
|
enabled: false,
|
|
},
|
|
ruleServer: {
|
|
enabled: false,
|
|
},
|
|
},
|
|
|
|
// Needed to make the interface happy.
|
|
RUNTIME: {
|
|
},
|
|
};
|
|
|
|
export function getDefaultConfig(): IConfig {
|
|
return Config.util.cloneDeep(defaultConfig);
|
|
}
|
|
|
|
/**
|
|
* Grabs an explicit path provided for mjolnir's config from an arguments vector if provided, otherwise returns undefined.
|
|
* @param argv An arguments vector sourced from `process.argv`.
|
|
* @returns The path if one was provided or undefined.
|
|
*/
|
|
function configPathFromArguments(argv: string[]): undefined|string {
|
|
const configOptionIndex = argv.findIndex(arg => arg === "--draupnir-config");
|
|
if (configOptionIndex > 0) {
|
|
const configOptionPath = argv.at(configOptionIndex + 1);
|
|
if (!configOptionPath) {
|
|
throw new Error("No path provided with option --draupnir-config");
|
|
}
|
|
return configOptionPath;
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
export function read(): IConfig {
|
|
const explicitConfigPath = configPathFromArguments(process.argv);
|
|
if (explicitConfigPath) {
|
|
const content = fs.readFileSync(explicitConfigPath, "utf8");
|
|
const parsed = load(content);
|
|
return Config.util.extendDeep({}, defaultConfig, parsed);
|
|
} else {
|
|
const config = Config.util.extendDeep({}, defaultConfig, Config.util.toObject()) as IConfig;
|
|
return config;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Provides a config for each newly provisioned mjolnir in appservice mode.
|
|
* @param managementRoomId A room that has been created to serve as the mjolnir's management room for the owner.
|
|
* @returns A config that can be directly used by the new mjolnir.
|
|
*/
|
|
export function getProvisionedMjolnirConfig(managementRoomId: string): IConfig {
|
|
// These are keys that are allowed to be configured for provisioned mjolnirs.
|
|
// We need a restricted set so that someone doesn't accidentally enable webservers etc
|
|
// on every created Mjolnir, which would result in very confusing error messages.
|
|
const allowedKeys = [
|
|
"commands",
|
|
"verboseLogging",
|
|
"logLevel",
|
|
"syncOnStartup",
|
|
"verifyPermissionsOnStartup",
|
|
"fasterMembershipChecks",
|
|
"automaticallyRedactForReasons",
|
|
"protectAllJoinedRooms",
|
|
"backgroundDelayMS",
|
|
];
|
|
const configTemplate = read(); // we use the standard bot config as a template for every provisioned mjolnir.
|
|
const unusedKeys = Object.keys(configTemplate).filter(key => !allowedKeys.includes(key));
|
|
if (unusedKeys.length > 0) {
|
|
LogService.warn("config", "The config provided for provisioned mjolnirs contains keys which are not used by the appservice.", unusedKeys);
|
|
}
|
|
const config = Config.util.extendDeep(
|
|
getDefaultConfig(),
|
|
allowedKeys.reduce((existingConfig: any, key: string) => {
|
|
return { ...existingConfig, [key]: configTemplate[key as keyof IConfig] }
|
|
}, {})
|
|
);
|
|
|
|
config.managementRoom = managementRoomId;
|
|
config.protectedRooms = [];
|
|
return config;
|
|
}
|
|
|
|
export const PACKAGE_JSON = (() => {
|
|
try {
|
|
return JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf-8'));
|
|
} catch (e) {
|
|
LogService.error("config", "Could not read Draupnir package.json", e);
|
|
return {};
|
|
}
|
|
})();
|
|
|
|
export const SOFTWARE_VERSION = (() => {
|
|
let versionFile;
|
|
const defaultText = PACKAGE_JSON.version ?? "A version was either not provided when building Draupnir or could not be read.";
|
|
try {
|
|
versionFile = fs.readFileSync(path.join(__dirname, '../version.txt'), 'utf-8');
|
|
} catch (e) {
|
|
LogService.error("config", "Could not read Draupnir version", e);
|
|
versionFile = defaultText;
|
|
}
|
|
// it's important to ignore the newline if the version is going to be put
|
|
// into <pre> or <code> where it will create an unnecessary newline.
|
|
return /^(.*)$/m.exec(versionFile)?.at(0) ?? defaultText;
|
|
})();
|