Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draupnir: init at 2.0.0-beta.6 #274052

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
4fffcb7
maintainers: add RorySys
TheArcaneBrony Apr 25, 2024
1e396ac
draupnir: init at 2.0.0-beta.4
TheArcaneBrony Apr 25, 2024
bbadc5e
nixos/draupnir: init
TheArcaneBrony Apr 25, 2024
ee8cbf8
draupnir: add tests
TheArcaneBrony Apr 25, 2024
4ac0923
fixup! draupnir: init at 2.0.0-beta.4 - Remove hook call echos
TheArcaneBrony Jul 22, 2024
4727e58
fixup! draupnir: init at 2.0.0-beta.4 - set fetchYarnDeps name
TheArcaneBrony Jul 22, 2024
cbdb027
fixup! nixos/draupnir: init - remove dead code
TheArcaneBrony Jul 22, 2024
8c6092f
fixup! nixos/draupnir: init - Moderation bot, not tool
TheArcaneBrony Jul 22, 2024
0ed8bbc
fixup! nixos/draupnir: init - witout -> without
TheArcaneBrony Jul 22, 2024
65b7eff
fixup! nixos/draupnir: init - clean up null stripping
TheArcaneBrony Jul 22, 2024
dfc2fb1
fixup! nixos/draupnir: init - move homeserverUrl to global
TheArcaneBrony Jul 22, 2024
e3adb0c
fixup! nixos/draupnir: init - drop module config reference
TheArcaneBrony Jul 22, 2024
1fac8d3
fixup! draupnir: add tests - move homeserverUrl
TheArcaneBrony Jul 22, 2024
a13cc66
fixup! nixos/draupnir: init - remove parial assertion
TheArcaneBrony Jul 22, 2024
0c8581d
fixup! nixos/draupnir: init - Update docs somewhat
TheArcaneBrony Aug 8, 2024
dbf6ae4
fixup! draupnir: init at 2.0.0-beta.4 - Add sqlite as native build input
TheArcaneBrony Aug 8, 2024
c2a5e05
fixup! draupnir: init at 2.0.0-beta.6 - ugly sed hack to drop corepack
TheArcaneBrony Sep 15, 2024
bd7179d
fixup! draupnir: init at 2.0.0-beta.4 - Switch to pkgConfig for matri…
TheArcaneBrony Sep 16, 2024
eb031b1
fixup! draupnir: init at 2.0.0-beta.8
TheArcaneBrony Oct 31, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions maintainers/maintainer-list.nix
TheArcaneBrony marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -17503,6 +17503,13 @@
githubId = 76747196;
name = "Robert Rose";
};
RorySys = {
email = "root@rory.gay";
github = "TheArcaneBrony";
githubId = 13570458;
matrix = "@emma:rory.gay"; # preferred
name = "Rory&";
};
rosehobgoblin = {
name = "J. L. Bowden";
github = "rosehobgoblin";
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,7 @@
./services/matrix/conduit.nix
./services/matrix/dendrite.nix
./services/matrix/hebbot.nix
./services/matrix/draupnir.nix
./services/matrix/maubot.nix
./services/matrix/mautrix-facebook.nix
./services/matrix/mautrix-meta.nix
Expand Down
80 changes: 80 additions & 0 deletions nixos/modules/services/matrix/draupnir.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Draupnir (Matrix Moderation Tool) {#module-services-draupnir}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@teutat3s (sorry for replying this way, github only allows threading in diff comments...)
In reply to your comment about tests

I'm aware that draupnir doesnt officially support pantalaimon (see module warns), thanks for reminding me though, given i'd completely forgotten (and tbh just copied the tests for mjolnir)

I wonder if i should drop the tests with pantalaimon? or well, at least rework it to not use pantal...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People coming from mjolnir will probably have pantalaimon running. It would be good to notice when things break in obvious ways.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pantalaimon/e2ee warning at eval time is enough, is it not?


This chapter will show you how to set up your own, self-hosted
[Draupnir](https://github.com/the-draupnir-project/Draupnir) instance.

As an all-in-one moderation tool, it can protect your server from
malicious invites, spam messages, and whatever else you don't want.
In addition to server-level protection, Draupnir is great for communities
wanting to protect their rooms without having to use their personal
accounts for moderation.

The bot by default includes support for bans, redactions, anti-spam,
server ACLs, room directory changes, room alias transfers, account
deactivation, room shutdown, and more.

See the [README](https://github.com/the-draupnir-project/draupnir#readme)
page and the [Moderator's guide](https://github.com/the-draupnir-project/Draupnir/blob/main/docs/moderators.md)
for additional instructions on how to setup and use Draupnir.

For [additional settings](#opt-services.draupnir.settings)
see [the default configuration](https://github.com/the-draupnir-project/Draupnir/blob/main/config/default.yaml).

## Draupnir Setup {#module-services-draupnir-setup}

First create a new Room which will be used as a management room for Draupnir. In
this room, Draupnir will log possible errors and debugging information. You'll
need to set this Room-ID in [services.draupnir.settings.managementRoom](#opt-services.draupnir.settings.managementRoom).

Next, create a new user for Draupnir on your homeserver, if not present already.

The Draupnir Matrix user expects to be free of any rate limiting.
See [Synapse #6286](https://github.com/matrix-org/synapse/issues/6286)
for an example on how to achieve this.

If you want Draupnir to be able to deactivate users, move room aliases, shut down rooms, etc.
you'll need to make the Draupnir user a Matrix server admin.

Now invite the Draupnir user to the management room.

It is recommended to use [Pantalaimon](https://github.com/matrix-org/pantalaimon),
so your management room can be encrypted. This also applies if you are looking to moderate an encrypted room.

To enable the Pantalaimon E2E Proxy for draupnir, enable
[services.draupnir.pantalaimon](#opt-services.draupnir.pantalaimon.enable). This will
autoconfigure a new Pantalaimon instance, which will connect to the homeserver
set in [services.draupnir.settings.homeserverUrl](#opt-services.draupnir.settings.homeserverUrl) and Draupnir itself
TheArcaneBrony marked this conversation as resolved.
Show resolved Hide resolved
will be configured to connect to the new Pantalaimon instance.

```
{
services.draupnir = {
enable = true;
pantalaimon = {
enable = true;
username = "draupnir";
passwordFile = "/run/secrets/draupnir-password";
options = {
homeserver = "http://localhost:8008";
ssl = false;
};
};
settings = {
managementRoom = "!yyy:domain.tld";
protectedRooms = [
"https://matrix.to/#/!xxx:domain.tld"
];
};
};
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure to format this with nixfmt-rfc-style.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can nixfmt-rfc-style handle markdown files, or should i extract this nix excerpt into a separate file to process?

Copy link
Member

@mweinelt mweinelt Jul 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extract, format, reinsert.

```

### Element Matrix Services (EMS) {#module-services-draupnir-setup-ems}

If you are using a managed ["Element Matrix Services (EMS)"](https://ems.element.io/)
server, you will need to consent to the terms and conditions. Upon startup, an error
log entry with a URL to the consent page will be generated.

## Synapse Antispam Module {#module-services-draupnir-matrix-synapse-antispam}

Use the Mjolnir Antispam module, Draupnir made no changes here and as such was not packaged.
260 changes: 260 additions & 0 deletions nixos/modules/services/matrix/draupnir.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
{ config, lib, pkgs, utils, ... }:

let
cfg = config.services.draupnir;

format = pkgs.formats.yaml {};
configFile = format.generate "draupnir.yaml" (pkgs.lib.filterAttrsRecursive (name: value: value != null) cfg.settings);
TheArcaneBrony marked this conversation as resolved.
Show resolved Hide resolved
in
{
#region Options
options.services.draupnir = {
enable = lib.mkEnableOption ("Draupnir, a moderation tool for Matrix");
TheArcaneBrony marked this conversation as resolved.
Show resolved Hide resolved

package = lib.mkPackageOption pkgs "draupnir" { };

accessTokenFile = lib.mkOption {
type = with lib.types; nullOr path;
default = null;
description = ''
File containing the access token for Draupnir's Matrix account.
Make sure this does not contain newlines if writing manually: `:set noeol nofixeol` for vim or -L for nano.
'';
};

#region Pantalaimon options
pantalaimon = lib.mkOption {
description = ''
`pantalaimon` options (enables E2E Encryption support).

This will create a `pantalaimon` instance with the name "draupnir".
'';
default = { };
type = lib.types.submodule {
options = {
enable = lib.mkEnableOption (''
pantalaimon, in order to enable E2EE support.
If `true`, accessToken is ignored and the username/password below will be
used instead. The access token of the bot will be stored in /var/lib/draupnir.
'');
Comment on lines +43 to +47
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
enable = lib.mkEnableOption (''
pantalaimon, in order to enable E2EE support.
If `true`, accessToken is ignored and the username/password below will be
used instead. The access token of the bot will be stored in /var/lib/draupnir.
'');
enable = lib.mkEnableOption '''
pantalaimon, in order to enable E2EE support.
If `true`, accessToken is ignored and the username/password below will be
used instead. The access token of the bot will be stored in /var/lib/draupnir.
'';


username = lib.mkOption {
type = lib.types.str;
description = ''
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest adding a default here:

default = "draupnir";

Account name on the Matrix homeserver.
'';
};

passwordFile = lib.mkOption {
type = with lib.types; nullOr path;
default = null;
description = ''
File containing the password for the Matrix account.
Make sure this does not contain newlines if writing manually: `:set noeol nofixeol` for vim or -L for nano.
'';
};

options = lib.mkOption {
type = lib.types.submodule (import ./pantalaimon-options.nix { inherit lib; inherit config; name = "draupnir"; });
default = { };
description = ''
Pass through additional options to the `pantalaimon` service.
'';
};
};
};
};
#endregion

#region Draupnir settings
settings = lib.mkOption {
example = lib.literalExpression ''
{
autojoinOnlyIfManager = true;
automaticallyRedactForReasons = [ "spam" "advertising" ];
}
'';
description = ''
Draupnir settings (see [Draupnir's default configuration](https://github.com/the-draupnir-project/Draupnir/blob/main/config/default.yaml) for available settings).
These settings will override settings made by the module config.
TheArcaneBrony marked this conversation as resolved.
Show resolved Hide resolved
'';
default = { };
type = lib.types.submodule {
freeformType = format.type;
options = {
#region Readonly settings - these settings are not configurable
dataPath = lib.mkOption {
type = lib.types.str;
default = "/var/lib/draupnir";
readOnly = true;
description = ''
The path where Draupnir stores its data.
mweinelt marked this conversation as resolved.
Show resolved Hide resolved

::: {.note}
If you want to customize where this data is stored, use a bind mount.
:::
'';
};
#endregion

#region Base settings
homeserverUrl = lib.mkOption {
type = lib.types.str;

defaultText = ''
URL to the pantalaimon instance, if enabled. Else unset.
'';
description = ''
Base URL of the Matrix homeserver, that provides the Client-Server API.
If `services.draupnir.pantalaimon.enable` is `true`, this option will become read only. Configure `services.draupnir.pantalaimon.options.homeserver` instead in that case.
The listen address of `pantalaimon` will then become the `homeserverUrl` of `draupnir`.
'';
};

managementRoom = lib.mkOption {
type = lib.types.str;
example = "#moderators:example.org";
description = ''
The room ID or alias where moderators can use the bot's functionality.

The bot has no access controls, so anyone in this room can use the bot - secure this room!

Warning: When using a room alias, make sure the alias used is on the local homeserver!
This prevents an issue where the control room becomes undefined when the alias can't be resolved.
'';
};

# protectedRooms = lib.mkOption {
# type = lib.types.listOf lib.types.str;
# default = [ ];
# example = lib.literalExpression ''
# [
# "https://matrix.to/#/#yourroom:example.org"
# "https://matrix.to/#/#anotherroom:example.org"
# ]
# '';
# description = ''
# A list of rooms to protect (matrix.to URLs).
# These can also be configured interactively.

# Note that this option does nothing in Draupnir v2+!
# '';
# };
TheArcaneBrony marked this conversation as resolved.
Show resolved Hide resolved
#endregion
};
};
};
#endregion
};
#endregion

#region Service configuration
config = lib.mkIf cfg.enable {
assertions = [
# pantalaimon enabled - use passwordFile instead of accessTokenFile
{
assertion = cfg.pantalaimon.enable -> cfg.pantalaimon.passwordFile != null;
message = "Set services.draupnir.pantailaimon.passwordFile, as it is required in order to use Pantalaimon.";
}
{
assertion = cfg.pantalaimon.enable -> cfg.accessTokenFile == null;
message = "Unset services.draupnir.accessTokenFile, as it has no effect when Pantalaimon is enabled.";
}

# pantalaimon disabled - use accessTokenFile instead of passwordFile
{
assertion = !cfg.pantalaimon.enable -> cfg.accessTokenFile != null;
message = "Set services.draupnir.accessTokenFile, as it is required in order to use Draupnir witout Pantalaimon.";
TheArcaneBrony marked this conversation as resolved.
Show resolved Hide resolved
}
{
assertion = !cfg.pantalaimon.enable -> cfg.pantalaimon.passwordFile == null;
message = "Unset services.draupnir.pantalaimon.passwordFile, as it has no effect when Pantalaimon is disabled.";
}

# Removed options for those migrating from the Mjolnir module - mkRemovedOption module does *not* work with submodules.

# Noop in v2, but should ideally not be used in mjolnir or 1.x either.
{
assertion = (cfg.settings ? protectedRooms) == false;
message = "Unset services.draupnir.settings.protectedRooms, as it is unsupported on Draupnir. Add these rooms via `!draupnir rooms add` instead.";
}
];

warnings = [ ]
# Unsupported but available options
# - Crypto
++ lib.optionals (cfg.pantalaimon.enable) [ ''Using Draupnir with Pantalaimon is known to break some features, and is thus unsupported.
Encryption support should only be enabled if you require an encrypted management room or use Draupnir in encrypted rooms.'' ]
++ lib.optionals (cfg.settings ? experimentalRustCrypto && cfg.settings.experimentalRustCrypto) [ ''Using Draupnir with experimental Rust Crypto support is untested and unsupported.
Encryption support should only be enabled if you require an encrypted management room or use Draupnir in encrypted rooms.'' ]

# - Deprecated options
++ lib.optionals (cfg.settings ? verboseLogging && cfg.settings.verboseLogging) [ "Verbose logging in Draupnir is deprecated and may be removed in a future version." ]
;

services.pantalaimon-headless.instances."draupnir" = lib.mkIf cfg.pantalaimon.enable (cfg.pantalaimon.options);
services.draupnir.settings.homeserverUrl = lib.mkIf cfg.pantalaimon.enable ("http://${config.services.pantalaimon-headless.instances."draupnir".listenAddress}:${toString config.services.pantalaimon-headless.instances."draupnir".listenPort}/");
TheArcaneBrony marked this conversation as resolved.
Show resolved Hide resolved
services.draupnir.settings.pantalaimon = lib.mkIf cfg.pantalaimon.enable ({
use = true;
username = cfg.pantalaimon.username;
});

systemd.services.draupnir = {
description = "Draupnir - a moderation tool for Matrix";
requires = lib.optionals (cfg.pantalaimon.enable) [
"pantalaimon-draupnir.service"
];
wants = [
"network-online.target"
"matrix-synapse.service"
"conduit.service"
"dendrite.service"
];
after = [
"network-online.target"
"matrix-synapse.service"
"conduit.service"
"dendrite.service"
];
wantedBy = [ "multi-user.target" ];

serviceConfig = {
ExecStart = utils.escapeSystemdExecArgs ([
(lib.getExe cfg.package)
"--draupnir-config" configFile
mweinelt marked this conversation as resolved.
Show resolved Hide resolved
] ++ lib.optionals (cfg.pantalaimon.enable && cfg.pantalaimon.passwordFile != null) [
"--pantalaimon-password-path"
"/run/credentials/draupnir.service/pantalaimon_password"
mweinelt marked this conversation as resolved.
Show resolved Hide resolved
] ++ lib.optionals (!cfg.pantalaimon.enable && cfg.accessTokenFile != null) [
"--access-token-path"
"/run/credentials/draupnir.service/access_token"
mweinelt marked this conversation as resolved.
Show resolved Hide resolved
]);

WorkingDirectory = "/var/lib/draupnir";
StateDirectory = "draupnir";
StateDirectoryMode = "0700";
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
NoNewPrivileges = true;
PrivateDevices = true;
Restart = "on-failure";

DynamicUser = true;
LoadCredential =
lib.optionals (cfg.accessTokenFile != null) [
"access_token:${cfg.accessTokenFile}"
]
++ lib.optionals (cfg.pantalaimon.enable && cfg.pantalaimon.passwordFile != null) [
"pantalaimon_password:${cfg.pantalaimon.passwordFile}"
];
};
};
};
#endregion

meta = {
doc = ./draupnir.md;
maintainers = with lib.maintainers; [ RorySys ];
};
}
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ in {
domination = handleTest ./domination.nix {};
dovecot = handleTest ./dovecot.nix {};
drawterm = discoverTests (import ./drawterm.nix);
draupnir = handleTest ./matrix/draupnir.nix {};
drbd = handleTest ./drbd.nix {};
dublin-traceroute = handleTest ./dublin-traceroute.nix {};
earlyoom = handleTestOn ["x86_64-linux"] ./earlyoom.nix {};
Expand Down
Loading