diff --git a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
index 9580006878108..b78cfad63b94b 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
@@ -71,6 +71,13 @@
services.persistent-evdev.
+
+
+ schleuder, a
+ mailing list manager with PGP support. Enable using
+ services.schleuder.
+
+
expressvpn,
diff --git a/nixos/doc/manual/release-notes/rl-2211.section.md b/nixos/doc/manual/release-notes/rl-2211.section.md
index 1a14885ed8c38..436d590fb9a63 100644
--- a/nixos/doc/manual/release-notes/rl-2211.section.md
+++ b/nixos/doc/manual/release-notes/rl-2211.section.md
@@ -31,6 +31,8 @@ In addition to numerous new and upgraded packages, this release has the followin
Available as [services.infnoise](options.html#opt-services.infnoise.enable).
- [persistent-evdev](https://github.com/aiberia/persistent-evdev), a daemon to add virtual proxy devices that mirror a physical input device but persist even if the underlying hardware is hot-plugged. Available as [services.persistent-evdev](#opt-services.persistent-evdev.enable).
+- [schleuder](https://schleuder.org/), a mailing list manager with PGP support. Enable using [services.schleuder](#opt-services.schleuder.enable).
+
- [expressvpn](https://www.expressvpn.com), the CLI client for ExpressVPN. Available as [services.expressvpn](#opt-services.expressvpn.enable).
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 43ae28ac02c5f..3aae26f385439 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -516,6 +516,7 @@
./services/mail/rspamd.nix
./services/mail/rss2email.nix
./services/mail/roundcube.nix
+ ./services/mail/schleuder.nix
./services/mail/sympa.nix
./services/mail/nullmailer.nix
./services/matrix/appservice-discord.nix
diff --git a/nixos/modules/services/mail/schleuder.nix b/nixos/modules/services/mail/schleuder.nix
new file mode 100644
index 0000000000000..7ba15f1070bde
--- /dev/null
+++ b/nixos/modules/services/mail/schleuder.nix
@@ -0,0 +1,162 @@
+{ config, pkgs, lib, ... }:
+let
+ cfg = config.services.schleuder;
+ settingsFormat = pkgs.formats.yaml { };
+ postfixMap = entries: lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: "${name} ${value}") entries);
+ writePostfixMap = name: entries: pkgs.writeText name (postfixMap entries);
+ configScript = pkgs.writeScript "schleuder-cfg" ''
+ #!${pkgs.runtimeShell}
+ set -exuo pipefail
+ umask 0077
+ ${pkgs.yq}/bin/yq \
+ --slurpfile overrides <(${pkgs.yq}/bin/yq . <${lib.escapeShellArg cfg.extraSettingsFile}) \
+ < ${settingsFormat.generate "schleuder.yml" cfg.settings} \
+ '. * $overrides[0]' \
+ > /etc/schleuder/schleuder.yml
+ chown schleuder: /etc/schleuder/schleuder.yml
+ '';
+in
+{
+ options.services.schleuder = {
+ enable = lib.mkEnableOption "Schleuder secure remailer";
+ enablePostfix = lib.mkEnableOption "automatic postfix integration" // { default = true; };
+ lists = lib.mkOption {
+ description = ''
+ List of list addresses that should be handled by Schleuder.
+
+ Note that this is only handled by the postfix integration, and
+ the setup of the lists, their members and their keys has to be
+ performed separately via schleuder's API, using a tool such as
+ schleuder-cli.
+ '';
+ type = lib.types.listOf lib.types.str;
+ default = [ ];
+ example = [ "widget-team@example.com" "security@example.com" ];
+ };
+ /* maybe one day....
+ domains = lib.mkOption {
+ description = "Domains for which all mail should be handled by Schleuder.";
+ type = lib.types.listOf lib.types.str;
+ default = [];
+ example = ["securelists.example.com"];
+ };
+ */
+ settings = lib.mkOption {
+ description = ''
+ Settings for schleuder.yml.
+
+ Check the example configuration for possible values.
+ '';
+ type = lib.types.submodule {
+ freeformType = settingsFormat.type;
+ options.keyserver = lib.mkOption {
+ type = lib.types.str;
+ description = ''
+ Key server from which to fetch and update keys.
+
+ Note that NixOS uses a different default from upstream, since the upstream default sks-keyservers.net is deprecated.
+ '';
+ default = "keys.openpgp.org";
+ };
+ };
+ default = { };
+ };
+ extraSettingsFile = lib.mkOption {
+ description = "YAML file to merge into the schleuder config at runtime. This can be used for secrets such as API keys.";
+ type = lib.types.nullOr lib.types.path;
+ default = null;
+ };
+ listDefaults = lib.mkOption {
+ description = ''
+ Default settings for lists (list-defaults.yml).
+
+ Check the example configuration for possible values.
+ '';
+ type = settingsFormat.type;
+ default = { };
+ };
+ };
+ config = lib.mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = !(cfg.settings.api ? valid_api_keys);
+ message = ''
+ services.schleuder.settings.api.valid_api_keys is set. Defining API keys via NixOS config results in them being copied to the world-readable Nix store. Please use the extraSettingsFile option to store API keys in a non-public location.
+ '';
+ }
+ {
+ assertion = !(lib.any (db: db ? password) (lib.attrValues cfg.settings.database or {}));
+ message = ''
+ A password is defined for at least one database in services.schleuder.settings.database. Defining passwords via NixOS config results in them being copied to the world-readable Nix store. Please use the extraSettingsFile option to store database passwords in a non-public location.
+ '';
+ }
+ ];
+ users.users.schleuder.isSystemUser = true;
+ users.users.schleuder.group = "schleuder";
+ users.groups.schleuder = {};
+ environment.systemPackages = [
+ pkgs.schleuder-cli
+ ];
+ services.postfix = lib.mkIf cfg.enablePostfix {
+ extraMasterConf = ''
+ schleuder unix - n n - - pipe
+ flags=DRhu user=schleuder argv=/${pkgs.schleuder}/bin/schleuder work ''${recipient}
+ '';
+ transport = lib.mkIf (cfg.lists != [ ]) (postfixMap (lib.genAttrs cfg.lists (_: "schleuder:")));
+ extraConfig = ''
+ schleuder_destination_recipient_limit = 1
+ '';
+ # review: does this make sense?
+ localRecipients = lib.mkIf (cfg.lists != [ ]) cfg.lists;
+ };
+ systemd.services = let commonServiceConfig = {
+ # We would have liked to use DynamicUser, but since the default
+ # database is SQLite and lives in StateDirectory, and that same
+ # database needs to be readable from the postfix service, this
+ # isn't trivial to do.
+ User = "schleuder";
+ StateDirectory = "schleuder";
+ StateDirectoryMode = "0700";
+ }; in
+ {
+ schleuder-init = {
+ serviceConfig = commonServiceConfig // {
+ ExecStartPre = lib.mkIf (cfg.extraSettingsFile != null) [
+ "+${configScript}"
+ ];
+ ExecStart = [ "${pkgs.schleuder}/bin/schleuder install" ];
+ Type = "oneshot";
+ };
+ };
+ schleuder-api-daemon = {
+ after = [ "local-fs.target" "network.target" "schleuder-init.service" ];
+ wantedBy = [ "multi-user.target" ];
+ requires = [ "schleuder-init.service" ];
+ serviceConfig = commonServiceConfig // {
+ ExecStart = [ "${pkgs.schleuder}/bin/schleuder-api-daemon" ];
+ };
+ };
+ schleuder-weekly-key-maintenance = {
+ after = [ "local-fs.target" "network.target" ];
+ startAt = "weekly";
+ serviceConfig = commonServiceConfig // {
+ ExecStart = [
+ "${pkgs.schleuder}/bin/schleuder refresh_keys"
+ "${pkgs.schleuder}/bin/schleuder check_keys"
+ ];
+ };
+ };
+ };
+
+ environment.etc."schleuder/schleuder.yml" = lib.mkIf (cfg.extraSettingsFile == null) {
+ source = settingsFormat.generate "schleuder.yml" cfg.settings;
+ };
+ environment.etc."schleuder/list-defaults.yml".source = settingsFormat.generate "list-defaults.yml" cfg.listDefaults;
+
+ services.schleuder = {
+ #lists_dir = "/var/lib/schleuder.lists";
+ settings.filters_dir = lib.mkDefault "/var/lib/schleuder/filters";
+ settings.keyword_handlers_dir = lib.mkDefault "/var/lib/schleuder/keyword_handlers";
+ };
+ };
+}
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 38c320886d1a4..658c62b2a4e20 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -485,6 +485,7 @@ in {
samba = handleTest ./samba.nix {};
samba-wsdd = handleTest ./samba-wsdd.nix {};
sanoid = handleTest ./sanoid.nix {};
+ schleuder = handleTest ./schleuder.nix {};
sddm = handleTest ./sddm.nix {};
seafile = handleTest ./seafile.nix {};
searx = handleTest ./searx.nix {};
diff --git a/nixos/tests/schleuder.nix b/nixos/tests/schleuder.nix
new file mode 100644
index 0000000000000..a9e4cc325bc76
--- /dev/null
+++ b/nixos/tests/schleuder.nix
@@ -0,0 +1,128 @@
+let
+ certs = import ./common/acme/server/snakeoil-certs.nix;
+ domain = certs.domain;
+in
+import ./make-test-python.nix {
+ name = "schleuder";
+ nodes.machine = { pkgs, ... }: {
+ imports = [ ./common/user-account.nix ];
+ services.postfix = {
+ enable = true;
+ enableSubmission = true;
+ tlsTrustedAuthorities = "${certs.ca.cert}";
+ sslCert = "${certs.${domain}.cert}";
+ sslKey = "${certs.${domain}.key}";
+ inherit domain;
+ destination = [ domain ];
+ localRecipients = [ "root" "alice" "bob" ];
+ };
+ services.schleuder = {
+ enable = true;
+ # Don't do it like this in production! The point of this setting
+ # is to allow loading secrets from _outside_ the world-readable
+ # Nix store.
+ extraSettingsFile = pkgs.writeText "schleuder-api-keys.yml" ''
+ api:
+ valid_api_keys:
+ - fnord
+ '';
+ lists = [ "security@${domain}" ];
+ settings.api = {
+ tls_cert_file = "${certs.${domain}.cert}";
+ tls_key_file = "${certs.${domain}.key}";
+ };
+ };
+
+ environment.systemPackages = [
+ pkgs.gnupg
+ pkgs.msmtp
+ (pkgs.writeScriptBin "do-test" ''
+ #!${pkgs.runtimeShell}
+ set -exuo pipefail
+
+ # Generate a GPG key with no passphrase and export it
+ sudo -u alice gpg --passphrase-fd 0 --batch --yes --quick-generate-key 'alice@${domain}' rsa4096 sign,encr < <(echo)
+ sudo -u alice gpg --armor --export alice@${domain} > alice.asc
+ # Create a new mailing list with alice as the owner, and alice's key
+ schleuder-cli list new security@${domain} alice@${domain} alice.asc
+
+ # Send an email from a non-member of the list. Use --auto-from so we don't have to specify who it's from twice.
+ msmtp --auto-from security@${domain} --host=${domain} --port=25 --tls --tls-starttls < list.asc
+
+ # Import the key into alice's keyring, so we can verify it as well as decrypting
+ sudo -u alice gpg --import decrypted
+ # And check that the text matches.
+ grep "big security problem" decrypted
+ '')
+
+ # For debugging:
+ # pkgs.vim pkgs.openssl pkgs.sqliteinteractive
+ ];
+
+ security.pki.certificateFiles = [ certs.ca.cert ];
+
+ # Since we don't have internet here, use dnsmasq to provide MX records from /etc/hosts
+ services.dnsmasq = {
+ enable = true;
+ extraConfig = ''
+ selfmx
+ '';
+ };
+
+ networking.extraHosts = ''
+ 127.0.0.1 ${domain}
+ '';
+
+ # schleuder-cli's config is not quite optimal in several ways:
+ # - A fingerprint _must_ be pinned, it doesn't even have an option
+ # to trust the PKI
+ # - It compares certificate fingerprints rather than key
+ # fingerprints, so renewals break the pin (though that's not
+ # relevant for this test)
+ # - It compares them as strings, which means we need to match the
+ # expected format exactly. This means removing the :s and
+ # lowercasing it.
+ # Refs:
+ # https://0xacab.org/schleuder/schleuder-cli/-/issues/16
+ # https://0xacab.org/schleuder/schleuder-cli/-/blob/f8895b9f47083d8c7b99a2797c93f170f3c6a3c0/lib/schleuder-cli/helper.rb#L230-238
+ systemd.tmpfiles.rules = let cliconfig = pkgs.runCommand "schleuder-cli.yml"
+ {
+ nativeBuildInputs = [ pkgs.jq pkgs.openssl ];
+ } ''
+ fp=$(openssl x509 -in ${certs.${domain}.cert} -noout -fingerprint -sha256 | cut -d = -f 2 | tr -d : | tr 'A-Z' 'a-z')
+ cat > $out < 1.0, >= 1.0.2)
+ i18n (>= 1.6, < 2)
+ minitest (>= 5.1)
+ tzinfo (~> 2.0)
+ zeitwerk (~> 2.3)
+ bcrypt (3.1.16)
+ charlock_holmes (0.7.7)
+ concurrent-ruby (1.1.9)
+ daemons (1.4.1)
+ eventmachine (1.2.7)
+ gpgme (2.0.20)
+ mini_portile2 (~> 2.3)
+ i18n (1.8.11)
+ concurrent-ruby (~> 1.0)
+ mail (2.7.1)
+ mini_mime (>= 0.1.1)
+ mail-gpg (0.4.4)
+ gpgme (~> 2.0, >= 2.0.2)
+ mail (~> 2.5, >= 2.5.3)
+ mini_mime (1.1.2)
+ mini_portile2 (2.7.1)
+ minitest (5.15.0)
+ multi_json (1.15.0)
+ mustermann (1.1.1)
+ ruby2_keywords (~> 0.0.1)
+ rack (2.2.3)
+ rack-protection (2.1.0)
+ rack
+ rake (13.0.6)
+ ruby2_keywords (0.0.5)
+ schleuder (4.0.2)
+ activerecord (~> 6.1.3)
+ bcrypt (~> 3.1.2)
+ charlock_holmes (~> 0.7.6)
+ gpgme (~> 2.0, >= 2.0.19)
+ mail (~> 2.7.1)
+ mail-gpg (~> 0.3)
+ rake (>= 10.5.0)
+ sinatra (~> 2)
+ sinatra-contrib (~> 2)
+ sqlite3 (~> 1.4.2)
+ thin (~> 1)
+ thor (~> 0)
+ sinatra (2.1.0)
+ mustermann (~> 1.0)
+ rack (~> 2.2)
+ rack-protection (= 2.1.0)
+ tilt (~> 2.0)
+ sinatra-contrib (2.1.0)
+ multi_json
+ mustermann (~> 1.0)
+ rack-protection (= 2.1.0)
+ sinatra (= 2.1.0)
+ tilt (~> 2.0)
+ sqlite3 (1.4.2)
+ thin (1.8.1)
+ daemons (~> 1.0, >= 1.0.9)
+ eventmachine (~> 1.0, >= 1.0.4)
+ rack (>= 1, < 3)
+ thor (0.20.3)
+ tilt (2.0.10)
+ tzinfo (2.0.4)
+ concurrent-ruby (~> 1.0)
+ zeitwerk (2.5.3)
+
+PLATFORMS
+ x86_64-linux
+
+DEPENDENCIES
+ schleuder!
+
+BUNDLED WITH
+ 2.2.24
diff --git a/pkgs/tools/security/schleuder/cli/Gemfile b/pkgs/tools/security/schleuder/cli/Gemfile
new file mode 100644
index 0000000000000..428e856aecc65
--- /dev/null
+++ b/pkgs/tools/security/schleuder/cli/Gemfile
@@ -0,0 +1,4 @@
+source "https://rubygems.org"
+
+gem "schleuder-cli", git: "https://0xacab.org/schleuder/schleuder-cli", tag: "schleuder-cli-0.1.0"
+
diff --git a/pkgs/tools/security/schleuder/cli/Gemfile.lock b/pkgs/tools/security/schleuder/cli/Gemfile.lock
new file mode 100644
index 0000000000000..bd47b9df7f9a0
--- /dev/null
+++ b/pkgs/tools/security/schleuder/cli/Gemfile.lock
@@ -0,0 +1,21 @@
+GIT
+ remote: https://0xacab.org/schleuder/schleuder-cli
+ revision: 1de2548695d9a74f47b7868954561b48cbc966f9
+ tag: schleuder-cli-0.1.0
+ specs:
+ schleuder-cli (0.1.0)
+ thor (~> 0)
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ thor (0.20.3)
+
+PLATFORMS
+ x86_64-linux
+
+DEPENDENCIES
+ schleuder-cli!
+
+BUNDLED WITH
+ 2.3.6
diff --git a/pkgs/tools/security/schleuder/cli/default.nix b/pkgs/tools/security/schleuder/cli/default.nix
new file mode 100644
index 0000000000000..e34afa699f042
--- /dev/null
+++ b/pkgs/tools/security/schleuder/cli/default.nix
@@ -0,0 +1,34 @@
+{ lib
+, bundlerApp
+, ruby
+, bundlerUpdateScript
+}:
+
+bundlerApp {
+ inherit ruby;
+
+ pname = "schleuder-cli";
+
+ gemdir = ./.;
+
+ installManpages = false;
+
+ exes = [
+ "schleuder-cli"
+ ];
+
+ passthru.updateScript = bundlerUpdateScript "schleuder-cli";
+
+ meta = with lib; {
+ description = "A command line tool to create and manage schleuder-lists";
+ longDescription = ''
+ Schleuder-cli enables creating, configuring, and deleting lists,
+ subscriptions, keys, etc. It uses the Schleuder API, provided by
+ schleuder-api-daemon (part of Schleuder).
+ '';
+ homepage = "https://schleuder.org";
+ changelog = "https://0xacab.org/schleuder/schleuder-cli/-/blob/main/CHANGELOG.md";
+ license = licenses.gpl3Plus;
+ maintainers = with maintainers; [ hexa ];
+ };
+}
diff --git a/pkgs/tools/security/schleuder/cli/gemset.nix b/pkgs/tools/security/schleuder/cli/gemset.nix
new file mode 100644
index 0000000000000..45ff62f891370
--- /dev/null
+++ b/pkgs/tools/security/schleuder/cli/gemset.nix
@@ -0,0 +1,25 @@
+{
+ schleuder-cli = {
+ dependencies = ["thor"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ fetchSubmodules = false;
+ rev = "1de2548695d9a74f47b7868954561b48cbc966f9";
+ sha256 = "0k4i33w9a0bscw4wbs301vxca367g7pa89y6cr24i0014pbmhs9z";
+ type = "git";
+ url = "https://0xacab.org/schleuder/schleuder-cli";
+ };
+ version = "0.1.0";
+ };
+ thor = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "1yhrnp9x8qcy5vc7g438amd5j9sw83ih7c30dr6g6slgw9zj3g29";
+ type = "gem";
+ };
+ version = "0.20.3";
+ };
+}
diff --git a/pkgs/tools/security/schleuder/default.nix b/pkgs/tools/security/schleuder/default.nix
new file mode 100644
index 0000000000000..84597f6f51bf7
--- /dev/null
+++ b/pkgs/tools/security/schleuder/default.nix
@@ -0,0 +1,38 @@
+{ lib
+, bundlerApp
+, ruby
+, bundlerUpdateScript
+, defaultGemConfig
+, nixosTests
+}:
+
+bundlerApp {
+ inherit ruby;
+
+ pname = "schleuder";
+
+ gemdir = ./.;
+
+ exes = [
+ "schleuder"
+ "schleuder-api-daemon"
+ ];
+
+ passthru.updateScript = bundlerUpdateScript "schleuder";
+ passthru.tests = {
+ inherit (nixosTests) schleuder;
+ };
+
+ meta = with lib; {
+ description = "Schleuder is an encrypting mailing list manager with remailing-capabilities";
+ longDescription = ''
+ Schleuder is a group's email-gateway: subscribers can exchange
+ encrypted emails among themselves, receive emails from
+ non-subscribers and send emails to non-subscribers via the list.
+ '';
+ homepage = "https://schleuder.org";
+ changelog = "https://0xacab.org/schleuder/schleuder/blob/main/CHANGELOG.md";
+ license = licenses.gpl3Plus;
+ maintainers = with maintainers; [ hexa lheckemann ];
+ };
+}
diff --git a/pkgs/tools/security/schleuder/gemset.nix b/pkgs/tools/security/schleuder/gemset.nix
new file mode 100644
index 0000000000000..9bd9cadbb883b
--- /dev/null
+++ b/pkgs/tools/security/schleuder/gemset.nix
@@ -0,0 +1,316 @@
+{
+ activemodel = {
+ dependencies = ["activesupport"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0g3qdz8dw6zkgz45jd13lwfdnm7rhgczv1pssw63g9k6qj3bkxjm";
+ type = "gem";
+ };
+ version = "6.1.4.4";
+ };
+ activerecord = {
+ dependencies = ["activemodel" "activesupport"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "090d4wl1pq06m9mibpck0m5nm8h45fwhs3fjx27297kjmnv4gzik";
+ type = "gem";
+ };
+ version = "6.1.4.4";
+ };
+ activesupport = {
+ dependencies = ["concurrent-ruby" "i18n" "minitest" "tzinfo" "zeitwerk"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0rvnz9lsf9mrkpji748sf51f54m027snkw6rm8flyvf7fq18rm98";
+ type = "gem";
+ };
+ version = "6.1.4.4";
+ };
+ bcrypt = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "02r1c3isfchs5fxivbq99gc3aq4vfyn8snhcy707dal1p8qz12qb";
+ type = "gem";
+ };
+ version = "3.1.16";
+ };
+ charlock_holmes = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0hybw8jw9ryvz5zrki3gc9r88jqy373m6v46ynxsdzv1ysiyr40p";
+ type = "gem";
+ };
+ version = "0.7.7";
+ };
+ concurrent-ruby = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0nwad3211p7yv9sda31jmbyw6sdafzmdi2i2niaz6f0wk5nq9h0f";
+ type = "gem";
+ };
+ version = "1.1.9";
+ };
+ daemons = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "07cszb0zl8mqmwhc8a2yfg36vi6lbgrp4pa5bvmryrpcz9v6viwg";
+ type = "gem";
+ };
+ version = "1.4.1";
+ };
+ eventmachine = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0wh9aqb0skz80fhfn66lbpr4f86ya2z5rx6gm5xlfhd05bj1ch4r";
+ type = "gem";
+ };
+ version = "1.2.7";
+ };
+ gpgme = {
+ dependencies = ["mini_portile2"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0xbgh9d8nbvsvyzqnd0mzhz0nr9hx4qn025kmz6d837lry4lc6gw";
+ type = "gem";
+ };
+ version = "2.0.20";
+ };
+ i18n = {
+ dependencies = ["concurrent-ruby"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0vdd1kii40qhbr9n8qx71k2gskq6rkl8ygy8hw5hfj8bb5a364xf";
+ type = "gem";
+ };
+ version = "1.8.11";
+ };
+ mail = {
+ dependencies = ["mini_mime"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "00wwz6ys0502dpk8xprwcqfwyf3hmnx6lgxaiq6vj43mkx43sapc";
+ type = "gem";
+ };
+ version = "2.7.1";
+ };
+ mail-gpg = {
+ dependencies = ["gpgme" "mail"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "1rz936m8nacy7agksvpvkf6b37d1h5qvh5xkrjqvv5wbdqs3cyfj";
+ type = "gem";
+ };
+ version = "0.4.4";
+ };
+ mini_mime = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0lbim375gw2dk6383qirz13hgdmxlan0vc5da2l072j3qw6fqjm5";
+ type = "gem";
+ };
+ version = "1.1.2";
+ };
+ mini_portile2 = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0d3ga166pahsxavzwj19yjj4lr13rw1vsb36s2qs8blcxigrdp6z";
+ type = "gem";
+ };
+ version = "2.7.1";
+ };
+ minitest = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "06xf558gid4w8lwx13jwfdafsch9maz8m0g85wnfymqj63x5nbbd";
+ type = "gem";
+ };
+ version = "5.15.0";
+ };
+ multi_json = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0pb1g1y3dsiahavspyzkdy39j4q377009f6ix0bh1ag4nqw43l0z";
+ type = "gem";
+ };
+ version = "1.15.0";
+ };
+ mustermann = {
+ dependencies = ["ruby2_keywords"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0ccm54qgshr1lq3pr1dfh7gphkilc19dp63rw6fcx7460pjwy88a";
+ type = "gem";
+ };
+ version = "1.1.1";
+ };
+ rack = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0i5vs0dph9i5jn8dfc6aqd6njcafmb20rwqngrf759c9cvmyff16";
+ type = "gem";
+ };
+ version = "2.2.3";
+ };
+ rack-protection = {
+ dependencies = ["rack"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "159a4j4kragqh0z0z8vrpilpmaisnlz3n7kgiyf16bxkwlb3qlhz";
+ type = "gem";
+ };
+ version = "2.1.0";
+ };
+ rake = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "15whn7p9nrkxangbs9hh75q585yfn66lv0v2mhj6q6dl6x8bzr2w";
+ type = "gem";
+ };
+ version = "13.0.6";
+ };
+ ruby2_keywords = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "1vz322p8n39hz3b4a9gkmz9y7a5jaz41zrm2ywf31dvkqm03glgz";
+ type = "gem";
+ };
+ version = "0.0.5";
+ };
+ schleuder = {
+ dependencies = ["activerecord" "bcrypt" "charlock_holmes" "gpgme" "mail" "mail-gpg" "rake" "sinatra" "sinatra-contrib" "sqlite3" "thin" "thor"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "15j1rfkfvni82msamikynsg48s50hbsx1pxm3y967caq9s80ll6c";
+ type = "gem";
+ };
+ version = "4.0.2";
+ };
+ sinatra = {
+ dependencies = ["mustermann" "rack" "rack-protection" "tilt"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0dd53rzpkxgs697pycbhhgc9vcnxra4ly4xar8ni6aiydx2f88zk";
+ type = "gem";
+ };
+ version = "2.1.0";
+ };
+ sinatra-contrib = {
+ dependencies = ["multi_json" "mustermann" "rack-protection" "sinatra" "tilt"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "1rl1iiafz51yzjd0vchl2lni7lmwppjql6cn1fnfxbma707qlcja";
+ type = "gem";
+ };
+ version = "2.1.0";
+ };
+ sqlite3 = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0lja01cp9xd5m6vmx99zwn4r7s97r1w5cb76gqd8xhbm1wxyzf78";
+ type = "gem";
+ };
+ version = "1.4.2";
+ };
+ thin = {
+ dependencies = ["daemons" "eventmachine" "rack"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "123bh7qlv6shk8bg8cjc84ix8bhlfcilwnn3iy6zq3l57yaplm9l";
+ type = "gem";
+ };
+ version = "1.8.1";
+ };
+ thor = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "1yhrnp9x8qcy5vc7g438amd5j9sw83ih7c30dr6g6slgw9zj3g29";
+ type = "gem";
+ };
+ version = "0.20.3";
+ };
+ tilt = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0rn8z8hda4h41a64l0zhkiwz2vxw9b1nb70gl37h1dg2k874yrlv";
+ type = "gem";
+ };
+ version = "2.0.10";
+ };
+ tzinfo = {
+ dependencies = ["concurrent-ruby"];
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "10qp5x7f9hvlc0psv9gsfbxg4a7s0485wsbq1kljkxq94in91l4z";
+ type = "gem";
+ };
+ version = "2.0.4";
+ };
+ zeitwerk = {
+ groups = ["default"];
+ platforms = [];
+ source = {
+ remotes = ["https://rubygems.org"];
+ sha256 = "0lmg9x683gr9mkrbq9df2m0zb0650mdfxqna0bs10js44inv7znx";
+ type = "gem";
+ };
+ version = "2.5.3";
+ };
+}
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index ed9894e4516bd..2bc4abf5c4087 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -5490,6 +5490,10 @@ with pkgs;
conf = config.schildichat-web.conf or {};
};
+ schleuder = callPackage ../tools/security/schleuder { };
+
+ schleuder-cli = callPackage ../tools/security/schleuder/cli { };
+
tealdeer = callPackage ../tools/misc/tealdeer {
inherit (darwin.apple_sdk.frameworks) Security;
};