nixos/mautrix-discord: refactor (#469813)
This commit is contained in:
@@ -65,6 +65,42 @@
|
||||
"module-services-keycloak-unix-socket": [
|
||||
"index.html#module-services-keycloak-unix-socket"
|
||||
],
|
||||
"module-services-mautrix-discord": [
|
||||
"index.html#module-services-mautrix-discord"
|
||||
],
|
||||
"module-services-mautrix-discord-advanced": [
|
||||
"index.html#module-services-mautrix-discord-advanced"
|
||||
],
|
||||
"module-services-mautrix-discord-authentication": [
|
||||
"index.html#module-services-mautrix-discord-authentication"
|
||||
],
|
||||
"module-services-mautrix-discord-backfill": [
|
||||
"index.html#module-services-mautrix-discord-backfill"
|
||||
],
|
||||
"module-services-mautrix-discord-basic-example": [
|
||||
"index.html#module-services-mautrix-discord-basic-example"
|
||||
],
|
||||
"module-services-mautrix-discord-basic-usage": [
|
||||
"index.html#module-services-mautrix-discord-basic-usage"
|
||||
],
|
||||
"module-services-mautrix-discord-double-puppet": [
|
||||
"index.html#module-services-mautrix-discord-double-puppet"
|
||||
],
|
||||
"module-services-mautrix-discord-encryption": [
|
||||
"index.html#module-services-mautrix-discord-encryption"
|
||||
],
|
||||
"module-services-mautrix-discord-server-defaults": [
|
||||
"index.html#module-services-mautrix-discord-server-defaults"
|
||||
],
|
||||
"module-services-mautrix-discord-setup": [
|
||||
"index.html#module-services-mautrix-discord-setup"
|
||||
],
|
||||
"module-services-mautrix-discord-synapse": [
|
||||
"index.html#module-services-mautrix-discord-synapse"
|
||||
],
|
||||
"module-services-mautrix-discord-troubleshooting": [
|
||||
"index.html#module-services-mautrix-discord-troubleshooting"
|
||||
],
|
||||
"module-services-tandoor-recipes-migrating-media-option-move": [
|
||||
"index.html#module-services-tandoor-recipes-migrating-media-option-move",
|
||||
"index.html#module-services-tandoor-recipes-migrating-media-option-1"
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
# Mautrix-Discord {#module-services-mautrix-discord}
|
||||
|
||||
*Source:* {file}`modules/services/matrix/mautrix-discord`
|
||||
|
||||
*Upstream documentation:* <https://docs.mau.fi/bridges/go/discord/index.html>
|
||||
|
||||
[Mautrix-Discord](https://github.com/mautrix/discord) is a Matrix-Discord bridge.
|
||||
|
||||
## Basic Usage {#module-services-mautrix-discord-basic-usage}
|
||||
|
||||
The common setup is to enable the bridge, point it at your homeserver, and set the permissions you want to allow:
|
||||
|
||||
1. Set `services.mautrix-discord.enable` to `true`.
|
||||
2. Set `services.mautrix-discord.settings.homeserver.address` and `services.mautrix-discord.settings.homeserver.domain`.
|
||||
3. Override `services.mautrix-discord.settings.bridge.permissions` if the default relay permissions do not fit your deployment.
|
||||
|
||||
The module provides sensible defaults for the appservice listener, registration tokens, and relay permissions.
|
||||
|
||||
### Basic Example {#module-services-mautrix-discord-basic-example}
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord = {
|
||||
enable = true;
|
||||
registerToSynapse = true;
|
||||
settings = {
|
||||
homeserver = {
|
||||
address = "http://localhost:8008";
|
||||
domain = "example.com";
|
||||
};
|
||||
bridge.permissions = {
|
||||
"example.com" = "user";
|
||||
"@admin:example.com" = "admin";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Server Defaults {#module-services-mautrix-discord-server-defaults}
|
||||
|
||||
By default, the bridge listens on `http://localhost:29334` and generates its appservice tokens automatically.
|
||||
|
||||
## Authentication {#module-services-mautrix-discord-authentication}
|
||||
|
||||
If you want to store the bridge database outside the default SQLite file, set `settings.appservice.database` to use PostgreSQL instead of SQLite:
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord.settings.appservice.database = {
|
||||
type = "postgres";
|
||||
uri = "postgresql:///mautrix-discord?host=/run/postgresql";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
If the connection needs a password, combine it with `services.mautrix-discord.environmentFile`:
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord = {
|
||||
environmentFile = "/run/secrets/mautrix-discord-env";
|
||||
settings.appservice.database.uri = "postgresql://mautrix:$DB_PASSWORD@localhost/mautrix-discord";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Use `services.mautrix-discord.environmentFile` for any secret you do not want in the Nix store.
|
||||
This includes database passwords, shared secrets, and similar values.
|
||||
|
||||
Example:
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord = {
|
||||
environmentFile = "/run/secrets/mautrix-discord-env";
|
||||
settings.bridge.login_shared_secret_map = {
|
||||
"example.com" = "$SHARED_SECRET";
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Bridge Setup {#module-services-mautrix-discord-setup}
|
||||
|
||||
After the service starts, open a chat with `@discordbot:example.com`, send `login`, and follow the instructions to link your Discord account.
|
||||
|
||||
For more detail, see the [Mautrix-Discord documentation](https://docs.mau.fi/bridges/go/discord/index.html).
|
||||
|
||||
## Advanced Configuration {#module-services-mautrix-discord-advanced}
|
||||
|
||||
The upstream default configuration is available at [example-config.yaml](https://github.com/mautrix/discord/blob/main/example-config.yaml). To print the generated default configuration from the package, run:
|
||||
|
||||
```bash
|
||||
nix-shell -p mautrix-discord --run "mautrix-discord -e"
|
||||
```
|
||||
|
||||
### Encryption {#module-services-mautrix-discord-encryption}
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord.settings.bridge.encryption = {
|
||||
allow = true;
|
||||
default = true;
|
||||
require = false;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Encryption needs additional bridge-side setup. See the [bridge encryption documentation](https://docs.mau.fi/bridges/general/end-to-bridge-encryption.html) for details.
|
||||
|
||||
### Backfill {#module-services-mautrix-discord-backfill}
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord.settings.bridge.backfill.forward_limits.initial = {
|
||||
dm = 50;
|
||||
channel = 50;
|
||||
thread = 50;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Double Puppeting {#module-services-mautrix-discord-double-puppet}
|
||||
|
||||
```nix
|
||||
{
|
||||
services.mautrix-discord = {
|
||||
environmentFile = "/run/secrets/mautrix-discord-env";
|
||||
settings.bridge.login_shared_secret_map = {
|
||||
"example.com" = "$SHARED_SECRET";
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
where `/run/secrets/mautrix-discord-env` contains
|
||||
```
|
||||
SHARED_SECRET=aProtectedSecret
|
||||
```
|
||||
|
||||
## Synapse Integration {#module-services-mautrix-discord-synapse}
|
||||
|
||||
When `services.mautrix-discord.registerToSynapse` is `true`, the bridge writes its registration file automatically and Synapse picks it up.
|
||||
|
||||
If Synapse is enabled, this option defaults to `true`.
|
||||
|
||||
## Troubleshooting {#module-services-mautrix-discord-troubleshooting}
|
||||
|
||||
- View logs with `journalctl -u mautrix-discord.service -f`.
|
||||
- Check `systemctl status mautrix-discord` if the bridge does not start.
|
||||
- Verify the homeserver can reach the configured appservice address.
|
||||
- Ensure the registration file exists and Synapse can read it.
|
||||
|
||||
For more help, see the
|
||||
[Mautrix-Discord documentation](https://docs.mau.fi/bridges/go/discord/index.html)
|
||||
or the support room at [#discord:maunium.net](https://matrix.to/#/#discord:maunium.net).
|
||||
@@ -5,15 +5,59 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
defaultDataDir = "/var/lib/mautrix-discord";
|
||||
cfg = config.services.mautrix-discord;
|
||||
dataDir = cfg.dataDir;
|
||||
format = pkgs.formats.yaml { };
|
||||
serviceDependencies = [
|
||||
"mautrix-discord-registration.service"
|
||||
]
|
||||
++ (lib.lists.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit)
|
||||
++ (lib.lists.optional config.services.matrix-conduit.enable "matrix-conduit.service")
|
||||
++ (lib.lists.optional config.services.dendrite.enable "dendrite.service");
|
||||
|
||||
registrationFile = "${dataDir}/discord-registration.yaml";
|
||||
|
||||
settingsFile = "${dataDir}/config.yaml";
|
||||
settingsFileUnformatted = format.generate "discord-config-unsubstituted.yaml" cfg.settings;
|
||||
default_token = "This value is generated when generating the registration";
|
||||
settingsDefault = {
|
||||
homeserver = {
|
||||
address = "";
|
||||
domain = "";
|
||||
};
|
||||
|
||||
appservice = {
|
||||
address = "http://localhost:29334";
|
||||
hostname = "0.0.0.0";
|
||||
port = 29334;
|
||||
database = {
|
||||
type = "sqlite3";
|
||||
uri = "file:${defaultDataDir}/mautrix-discord.db?_txlock=immediate";
|
||||
};
|
||||
id = "discord";
|
||||
bot = {
|
||||
username = "discordbot";
|
||||
displayname = "Discord bridge bot";
|
||||
avatar = "mxc://maunium.net/nIdEykemnwdisvHbpxflpDlC";
|
||||
};
|
||||
as_token = default_token;
|
||||
hs_token = default_token;
|
||||
};
|
||||
|
||||
bridge.permissions."*" = "relay";
|
||||
|
||||
logging = {
|
||||
min_level = "info";
|
||||
writers = [
|
||||
{
|
||||
type = "stdout";
|
||||
format = "pretty-colored";
|
||||
time_format = " ";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options = {
|
||||
@@ -23,238 +67,14 @@ in
|
||||
package = lib.mkPackageOption pkgs "mautrix-discord" { };
|
||||
|
||||
settings = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
freeformType = format.type;
|
||||
|
||||
config = {
|
||||
_module.args = { inherit cfg lib; };
|
||||
};
|
||||
|
||||
options = {
|
||||
homeserver = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
default = {
|
||||
software = "standard";
|
||||
status_endpoint = null;
|
||||
message_send_checkpoint_endpoint = null;
|
||||
async_media = false;
|
||||
websocket = false;
|
||||
ping_interval_seconds = 0;
|
||||
};
|
||||
description = ''
|
||||
fullDataDiration.
|
||||
See [example-config.yaml](https://github.com/mautrix/discord/blob/main/example-config.yaml)
|
||||
for more information.
|
||||
'';
|
||||
};
|
||||
|
||||
appservice = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
default = {
|
||||
address = "http://localhost:29334";
|
||||
hostname = "0.0.0.0";
|
||||
port = 29334;
|
||||
database = {
|
||||
type = "sqlite3";
|
||||
uri = "file:/var/lib/mautrix-discord/mautrix-discord.db?_txlock=immediate";
|
||||
max_open_conns = 20;
|
||||
max_idle_conns = 2;
|
||||
max_conn_idle_time = null;
|
||||
max_conn_lifetime = null;
|
||||
};
|
||||
id = "discord";
|
||||
bot = {
|
||||
username = "discordbot";
|
||||
displayname = "Discord bridge bot";
|
||||
avatar = "mxc://maunium.net/nIdEykemnwdisvHbpxflpDlC";
|
||||
};
|
||||
ephemeral_events = true;
|
||||
async_transactions = false;
|
||||
as_token = "This value is generated when generating the registration";
|
||||
hs_token = "This value is generated when generating the registration";
|
||||
};
|
||||
defaultText = lib.literalExpression ''
|
||||
{
|
||||
address = "http://localhost:29334";
|
||||
hostname = "0.0.0.0";
|
||||
port = 29334;
|
||||
database = {
|
||||
type = "sqlite3";
|
||||
uri = "file:''${config.services.mautrix-discord.dataDir}/mautrix-discord.db?_txlock=immediate";
|
||||
max_open_conns = 20;
|
||||
max_idle_conns = 2;
|
||||
max_conn_idle_time = null;
|
||||
max_conn_lifetime = null;
|
||||
};
|
||||
id = "discord";
|
||||
bot = {
|
||||
username = "discordbot";
|
||||
displayname = "Discord bridge bot";
|
||||
avatar = "mxc://maunium.net/nIdEykemnwdisvHbpxflpDlC";
|
||||
};
|
||||
ephemeral_events = true;
|
||||
async_transactions = false;
|
||||
as_token = "This value is generated when generating the registration";
|
||||
hs_token = "This value is generated when generating the registration";
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Appservice configuration.
|
||||
See [example-config.yaml](https://github.com/mautrix/discord/blob/main/example-config.yaml)
|
||||
for more information.
|
||||
'';
|
||||
};
|
||||
|
||||
bridge = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
default = {
|
||||
username_template = "discord_{{.}}";
|
||||
displayname_template = "{{if .Webhook}}Webhook{{else}}{{or .GlobalName .Username}}{{if .Bot}} (bot){{end}}{{end}}";
|
||||
channel_name_template = "{{if or (eq .Type 3) (eq .Type 4)}}{{.Name}}{{else}}#{{.Name}}{{end}}";
|
||||
guild_name_template = "{{.Name}}";
|
||||
private_chat_portal_meta = "default";
|
||||
public_address = null;
|
||||
avatar_proxy_key = "generate";
|
||||
portal_message_buffer = 128;
|
||||
startup_private_channel_create_limit = 5;
|
||||
delivery_receipts = false;
|
||||
message_status_events = false;
|
||||
message_error_notices = true;
|
||||
restricted_rooms = true;
|
||||
autojoin_thread_on_open = true;
|
||||
embed_fields_as_tables = true;
|
||||
mute_channels_on_create = false;
|
||||
sync_direct_chat_list = false;
|
||||
resend_bridge_info = false;
|
||||
custom_emoji_reactions = true;
|
||||
delete_portal_on_channel_delete = false;
|
||||
delete_guild_on_leave = true;
|
||||
federate_rooms = true;
|
||||
prefix_webhook_messages = true;
|
||||
enable_webhook_avatars = false;
|
||||
use_discord_cdn_upload = true;
|
||||
#proxy =
|
||||
cache_media = "unencrypted";
|
||||
direct_media = {
|
||||
enabled = false;
|
||||
#server_name = "discord-media.example.com";
|
||||
#well_known_response =
|
||||
allow_proxy = true;
|
||||
server_key = "generate";
|
||||
};
|
||||
animated_sticker = {
|
||||
target = "webp";
|
||||
args = {
|
||||
width = 320;
|
||||
height = 320;
|
||||
fps = 25;
|
||||
};
|
||||
};
|
||||
double_puppet_server_map = {
|
||||
#"example.com" = "https://example.com";
|
||||
};
|
||||
double_puppet_allow_discovery = false;
|
||||
login_shared_secret_map = {
|
||||
#"example.com" = "foobar";
|
||||
};
|
||||
command_prefix = "!discord";
|
||||
management_room_text = {
|
||||
welcome = "Hello, I'm a Discord bridge bot.";
|
||||
welcome_connected = "Use `help` for help.";
|
||||
welcome_unconnected = "Use `help` for help or `login` to log in.";
|
||||
additional_help = "";
|
||||
};
|
||||
backfill = {
|
||||
forward_limits = {
|
||||
initial = {
|
||||
dm = 0;
|
||||
channel = 0;
|
||||
thread = 0;
|
||||
};
|
||||
missed = {
|
||||
dm = 0;
|
||||
channel = 0;
|
||||
thread = 0;
|
||||
};
|
||||
max_guild_members = -1;
|
||||
};
|
||||
};
|
||||
encryption = {
|
||||
allow = false;
|
||||
default = false;
|
||||
appservice = false;
|
||||
msc4190 = false;
|
||||
require = false;
|
||||
allow_key_sharing = false;
|
||||
plaintext_mentions = false;
|
||||
delete_keys = {
|
||||
delete_outbound_on_ack = false;
|
||||
dont_store_outbound = false;
|
||||
ratchet_on_decrypt = false;
|
||||
delete_fully_used_on_decrypt = false;
|
||||
delete_prev_on_new_session = false;
|
||||
delete_on_device_delete = false;
|
||||
periodically_delete_expired = false;
|
||||
delete_outdated_inbound = false;
|
||||
};
|
||||
verification_levels = {
|
||||
receive = "unverified";
|
||||
send = "unverified";
|
||||
share = "cross-signed-tofu";
|
||||
};
|
||||
rotation = {
|
||||
enable_custom = false;
|
||||
milliseconds = 604800000;
|
||||
messages = 100;
|
||||
disable_device_change_key_rotation = false;
|
||||
};
|
||||
};
|
||||
provisioning = {
|
||||
prefix = "/_matrix/provision";
|
||||
shared_secret = "generate";
|
||||
debug_endpoints = false;
|
||||
};
|
||||
permissions = {
|
||||
"*" = "relay";
|
||||
#"example.com" = "user";
|
||||
#"@admin:example.com": "admin";
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
Bridge configuration.
|
||||
See [example-config.yaml](https://github.com/mautrix/discord/blob/main/example-config.yaml)
|
||||
for more information.
|
||||
'';
|
||||
};
|
||||
logging = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
default = {
|
||||
min_level = "info";
|
||||
writers = lib.singleton {
|
||||
type = "stdout";
|
||||
format = "pretty-colored";
|
||||
time_format = " ";
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
Logging configuration.
|
||||
See [example-config.yaml](https://github.com/mautrix/discord/blob/main/example-config.yaml)
|
||||
for more information.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
apply = lib.recursiveUpdate settingsDefault;
|
||||
type = format.type;
|
||||
default = settingsDefault;
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
homeserver = {
|
||||
address = "http://localhost:8008";
|
||||
domain = "public-domain.tld";
|
||||
};
|
||||
|
||||
appservice.public = {
|
||||
prefix = "/public";
|
||||
external = "https://public-appservice-address/public";
|
||||
domain = "example.com";
|
||||
};
|
||||
|
||||
bridge.permissions = {
|
||||
@@ -265,8 +85,12 @@ in
|
||||
'';
|
||||
description = ''
|
||||
{file}`config.yaml` configuration as a Nix attribute set.
|
||||
|
||||
Configuration options should match those described in
|
||||
[example-config.yaml](https://github.com/mautrix/discord/blob/main/example-config.yaml).
|
||||
|
||||
Secret tokens should be specified using {option}`environmentFile`
|
||||
instead of this world-readable attribute set.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -282,12 +106,9 @@ in
|
||||
|
||||
dataDir = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = "/var/lib/mautrix-discord";
|
||||
defaultText = "/var/lib/mautrix-discord";
|
||||
description = ''
|
||||
Directory to store the bridge's configuration and database files.
|
||||
This directory will be created if it does not exist.
|
||||
'';
|
||||
default = defaultDataDir;
|
||||
defaultText = defaultDataDir;
|
||||
description = "Directory to store the bridge's data.";
|
||||
};
|
||||
|
||||
# TODO: Get upstream to add an environment File option. Refer to https://github.com/NixOS/nixpkgs/pull/404871#issuecomment-2895663652 and https://github.com/mautrix/discord/issues/187
|
||||
@@ -295,92 +116,31 @@ in
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
File containing environment variables to substitute when copying the configuration
|
||||
out of Nix store to the `services.mautrix-discord.dataDir`.
|
||||
Can be used for storing the secrets without making them available in the Nix store.
|
||||
For example, you can set `services.mautrix-discord.settings.appservice.as_token = "$MAUTRIX_DISCORD_APPSERVICE_AS_TOKEN"`
|
||||
and then specify `MAUTRIX_DISCORD_APPSERVICE_AS_TOKEN="{token}"` in the environment file.
|
||||
This value will get substituted into the configuration file as a token.
|
||||
File containing environment variables for secret substitution.
|
||||
Variables in the config like `$VARIABLE` will be replaced.
|
||||
'';
|
||||
};
|
||||
|
||||
serviceUnit = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
readOnly = true;
|
||||
default = "mautrix-discord.service";
|
||||
description = ''
|
||||
The systemd unit (a service or a target) for other services to depend on if they
|
||||
need to be started after matrix-synapse.
|
||||
This option is useful as the actual parent unit for all matrix-synapse processes
|
||||
changes when configuring workers.
|
||||
'';
|
||||
};
|
||||
|
||||
registrationServiceUnit = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
readOnly = true;
|
||||
default = "mautrix-discord-registration.service";
|
||||
description = ''
|
||||
The registration service that generates the registration file.
|
||||
Systemd unit (a service or a target) for other services to depend on if they
|
||||
need to be started after mautrix-discord registration service.
|
||||
This option is useful as the actual parent unit for all matrix-synapse processes
|
||||
changes when configuring workers.
|
||||
'';
|
||||
};
|
||||
|
||||
serviceDependencies = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [
|
||||
cfg.registrationServiceUnit
|
||||
]
|
||||
++ (lib.lists.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit)
|
||||
++ (lib.lists.optional config.services.matrix-conduit.enable "matrix-conduit.service")
|
||||
++ (lib.lists.optional config.services.dendrite.enable "dendrite.service");
|
||||
|
||||
defaultText = ''
|
||||
[ cfg.registrationServiceUnit ] ++
|
||||
(lib.lists.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit) ++
|
||||
(lib.lists.optional config.services.matrix-conduit.enable "matrix-conduit.service") ++
|
||||
(lib.lists.optional config.services.dendrite.enable "dendrite.service");
|
||||
'';
|
||||
description = ''
|
||||
List of Systemd services to require and wait for when starting the application service.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
assertions = [
|
||||
{
|
||||
assertion =
|
||||
cfg.settings.homeserver.domain or "" != "" && cfg.settings.homeserver.address or "" != "";
|
||||
message = ''
|
||||
The options with information about the homeserver:
|
||||
`services.mautrix-discord.settings.homeserver.domain` and
|
||||
`services.mautrix-discord.settings.homeserver.address` have to be set.
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion = cfg.settings.bridge.permissions or { } != { };
|
||||
message = ''
|
||||
The option `services.mautrix-discord.settings.bridge.permissions` has to be set.
|
||||
'';
|
||||
cfg.settings.homeserver.address or "" != "" && cfg.settings.homeserver.domain or "" != "";
|
||||
message = "services.mautrix-discord.settings.homeserver.{address,domain} must be set.";
|
||||
}
|
||||
];
|
||||
|
||||
users.users.mautrix-discord = {
|
||||
isSystemUser = true;
|
||||
group = "mautrix-discord";
|
||||
extraGroups = [ "mautrix-discord-registration" ];
|
||||
home = dataDir;
|
||||
description = "Mautrix-Discord bridge user";
|
||||
};
|
||||
|
||||
users.groups.mautrix-discord = { };
|
||||
users.groups.mautrix-discord-registration = {
|
||||
members = lib.lists.optional config.services.matrix-synapse.enable "matrix-synapse";
|
||||
};
|
||||
|
||||
services.matrix-synapse = lib.mkIf cfg.registerToSynapse {
|
||||
settings.app_service_config_files = [ registrationFile ];
|
||||
@@ -392,7 +152,9 @@ in
|
||||
|
||||
systemd.services = {
|
||||
matrix-synapse = lib.mkIf cfg.registerToSynapse {
|
||||
serviceConfig.SupplementaryGroups = [ "mautrix-discord-registration" ];
|
||||
serviceConfig.SupplementaryGroups = [
|
||||
"mautrix-discord"
|
||||
];
|
||||
# Make synapse depend on the registration service when auto-registering
|
||||
wants = [ "mautrix-discord-registration.service" ];
|
||||
after = [ "mautrix-discord-registration.service" ];
|
||||
@@ -471,15 +233,18 @@ in
|
||||
'${settingsFile}' '${registrationFile}' > '${registrationFile}.tmp'
|
||||
mv '${registrationFile}.tmp' '${registrationFile}'
|
||||
|
||||
# Application services should not be rate limited by default.
|
||||
yq -Y '.rate_limited = false' '${registrationFile}' > '${registrationFile}.tmp'
|
||||
mv '${registrationFile}.tmp' '${registrationFile}'
|
||||
|
||||
umask $old_umask
|
||||
chown :mautrix-discord-registration '${registrationFile}'
|
||||
chmod 640 '${registrationFile}'
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
UMask = 27;
|
||||
UMask = "027";
|
||||
|
||||
User = "mautrix-discord";
|
||||
Group = "mautrix-discord";
|
||||
@@ -501,8 +266,8 @@ in
|
||||
description = "Mautrix-Discord, a Matrix-Discord puppeting/relaybot bridge";
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ] ++ cfg.serviceDependencies;
|
||||
after = [ "network-online.target" ] ++ cfg.serviceDependencies;
|
||||
wants = [ "network-online.target" ] ++ serviceDependencies;
|
||||
after = [ "network-online.target" ] ++ serviceDependencies;
|
||||
path = [
|
||||
pkgs.lottieconverter
|
||||
pkgs.ffmpeg-headless
|
||||
@@ -536,6 +301,8 @@ in
|
||||
ProtectHostname = true;
|
||||
ProtectClock = true;
|
||||
|
||||
UMask = "027";
|
||||
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallErrorNumber = "EPERM";
|
||||
SystemCallFilter = "@system-service";
|
||||
@@ -546,10 +313,12 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
meta = {
|
||||
maintainers = with lib.maintainers; [
|
||||
mistyttm
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
meta = {
|
||||
maintainers = with lib.maintainers; [
|
||||
mistyttm
|
||||
];
|
||||
doc = ./mautrix-discord.md;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ pkgs, lib, ... }:
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
homeserverUrl = "http://homeserver:8008";
|
||||
in
|
||||
@@ -53,6 +53,7 @@ in
|
||||
|
||||
appservice = {
|
||||
address = "http://homeserver:8009";
|
||||
hostname = "0.0.0.0";
|
||||
port = 8009;
|
||||
id = "discord";
|
||||
bot = {
|
||||
@@ -60,8 +61,6 @@ in
|
||||
displayname = "Discord bridge bot";
|
||||
avatar = "mxc://maunium.net/nIdEykemnwdisvHbpxflpDlC";
|
||||
};
|
||||
# Don't override as_token/hs_token - let them use the default placeholder
|
||||
# which will trigger automatic generation
|
||||
|
||||
database = {
|
||||
type = "sqlite3";
|
||||
@@ -75,6 +74,17 @@ in
|
||||
"*" = "relay";
|
||||
};
|
||||
};
|
||||
|
||||
logging = {
|
||||
min_level = "info";
|
||||
writers = [
|
||||
{
|
||||
type = "stdout";
|
||||
format = "pretty-colored";
|
||||
time_format = " ";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -157,6 +167,57 @@ in
|
||||
with subtest("verify registration file was created"):
|
||||
homeserver.wait_until_succeeds("test -f /var/lib/mautrix-discord/discord-registration.yaml")
|
||||
|
||||
# Verify the module wrote the expected bridge configuration.
|
||||
config_homeserver_address = homeserver.succeed("yq -r '.homeserver.address' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_homeserver_domain = homeserver.succeed("yq -r '.homeserver.domain' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_appservice_address = homeserver.succeed("yq -r '.appservice.address' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_appservice_hostname = homeserver.succeed("yq -r '.appservice.hostname' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_appservice_port = homeserver.succeed("yq -r '.appservice.port' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_appservice_id = homeserver.succeed("yq -r '.appservice.id' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_bot_username = homeserver.succeed("yq -r '.appservice.bot.username' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_bot_displayname = homeserver.succeed("yq -r '.appservice.bot.displayname' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_bot_avatar = homeserver.succeed("yq -r '.appservice.bot.avatar' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_database_type = homeserver.succeed("yq -r '.appservice.database.type' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_database_uri = homeserver.succeed("yq -r '.appservice.database.uri' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_permission = homeserver.succeed("yq -r '.bridge.permissions[\"*\"]' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_logging_min_level = homeserver.succeed("yq -r '.logging.min_level' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_logging_writer_type = homeserver.succeed("yq -r '.logging.writers[0].type' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_logging_writer_format = homeserver.succeed("yq -r '.logging.writers[0].format' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
reg_rate_limited = homeserver.succeed("yq -r '.rate_limited' /var/lib/mautrix-discord/discord-registration.yaml").strip()
|
||||
|
||||
assert config_homeserver_address == "http://homeserver:8008", \
|
||||
f"Unexpected homeserver address: {config_homeserver_address}"
|
||||
assert config_homeserver_domain == "homeserver", \
|
||||
f"Unexpected homeserver domain: {config_homeserver_domain}"
|
||||
assert config_appservice_address == "http://homeserver:8009", \
|
||||
f"Unexpected appservice address: {config_appservice_address}"
|
||||
assert config_appservice_hostname == "0.0.0.0", \
|
||||
f"Unexpected appservice hostname: {config_appservice_hostname}"
|
||||
assert config_appservice_port == "8009", \
|
||||
f"Unexpected appservice port: {config_appservice_port}"
|
||||
assert config_appservice_id == "discord", \
|
||||
f"Unexpected appservice id: {config_appservice_id}"
|
||||
assert config_bot_username == "discordbot", \
|
||||
f"Unexpected bot username: {config_bot_username}"
|
||||
assert config_bot_displayname == "Discord bridge bot", \
|
||||
f"Unexpected bot displayname: {config_bot_displayname}"
|
||||
assert config_bot_avatar == "mxc://maunium.net/nIdEykemnwdisvHbpxflpDlC", \
|
||||
f"Unexpected bot avatar: {config_bot_avatar}"
|
||||
assert config_database_type == "sqlite3-fk-wal", \
|
||||
f"Unexpected database type: {config_database_type}"
|
||||
assert config_database_uri == "file:/var/lib/mautrix-discord/mautrix-discord.db?_txlock=immediate", \
|
||||
f"Unexpected database uri: {config_database_uri}"
|
||||
assert config_permission == "relay", \
|
||||
f"Unexpected default permission mapping: {config_permission}"
|
||||
assert config_logging_min_level == "info", \
|
||||
f"Unexpected logging min_level: {config_logging_min_level}"
|
||||
assert config_logging_writer_type == "stdout", \
|
||||
f"Unexpected logging writer type: {config_logging_writer_type}"
|
||||
assert config_logging_writer_format == "pretty-colored", \
|
||||
f"Unexpected logging writer format: {config_logging_writer_format}"
|
||||
assert reg_rate_limited == "false", \
|
||||
f"Registration file should disable rate limiting by default, got: {reg_rate_limited}"
|
||||
|
||||
# Verify tokens were generated and are not default values
|
||||
config_as_token = homeserver.succeed("yq -r '.appservice.as_token' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
config_hs_token = homeserver.succeed("yq -r '.appservice.hs_token' /var/lib/mautrix-discord/config.yaml").strip()
|
||||
|
||||
Reference in New Issue
Block a user