diff options
Diffstat (limited to 'modules/by-name')
68 files changed, 0 insertions, 5508 deletions
diff --git a/modules/by-name/ba/back/module.nix b/modules/by-name/ba/back/module.nix deleted file mode 100644 index d47ffce..0000000 --- a/modules/by-name/ba/back/module.nix +++ /dev/null @@ -1,92 +0,0 @@ -{ - config, - lib, - vhackPackages, - pkgs, - ... -}: let - cfg = config.vhack.back; -in { - options.vhack.back = { - enable = lib.mkEnableOption "Back issue tracker (inspired by tvix's panettone)"; - - domain = lib.mkOption { - type = lib.types.str; - description = "The domain to host this `back` instance on."; - }; - - settings = { - scan_path = lib.mkOption { - type = lib.types.path; - description = "The path to the directory under which all the repositories reside"; - }; - project_list = lib.mkOption { - type = lib.types.path; - description = "The path to the `projects.list` file."; - }; - - source_code_repository_url = lib.mkOption { - description = "The url to the source code of this instance of back"; - default = "https://git.foss-syndicate.org/vhack.eu/nixos-server/tree/pkgs/by-name/ba/back"; - type = lib.types.str; - }; - - root_url = lib.mkOption { - type = lib.types.str; - description = "The url to this instance of back."; - default = "https://${cfg.domain}"; - }; - }; - }; - - config = lib.mkIf cfg.enable { - systemd.services."back" = { - description = "Back issue tracking system."; - requires = ["network-online.target"]; - after = ["network-online.target"]; - wantedBy = ["default.target"]; - - serviceConfig = { - ExecStart = "${lib.getExe vhackPackages.back} ${(pkgs.formats.json {}).generate "config.json" cfg.settings}"; - - # Ensure that the service can read the repository - # FIXME(@bpeetz): This has the implied assumption, that all the exposed git - # repositories are readable for the git group. This should not be necessary. <2024-12-23> - User = "git"; - Group = "git"; - - DynamicUser = true; - Restart = "always"; - - # Sandboxing - ProtectSystem = "strict"; - ProtectHome = true; - PrivateTmp = true; - PrivateDevices = true; - ProtectHostname = true; - ProtectClock = true; - ProtectKernelTunables = true; - ProtectKernelModules = true; - ProtectKernelLogs = true; - ProtectControlGroups = true; - RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"]; - RestrictNamespaces = true; - LockPersonality = true; - MemoryDenyWriteExecute = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - RemoveIPC = true; - PrivateMounts = true; - # System Call Filtering - SystemCallArchitectures = "native"; - SystemCallFilter = ["~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid"]; - }; - }; - services.nginx.virtualHosts."${cfg.domain}" = { - locations."/".proxyPass = "http://127.0.0.1:8000"; - - enableACME = true; - forceSSL = true; - }; - }; -} diff --git a/modules/by-name/ba/backup/module.nix b/modules/by-name/ba/backup/module.nix deleted file mode 100644 index 856a1c3..0000000 --- a/modules/by-name/ba/backup/module.nix +++ /dev/null @@ -1,91 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: let - cfg = config.vhack.backup; - snapshots = "/srv/snapshots"; - postgresUser = "postgres"; -in { - options.vhack.backup = { - enable = lib.mkEnableOption "backups with restic"; - user = lib.mkOption { - type = lib.types.str; - description = "The storagebox-user to use"; - example = "u384702-sub2"; - }; - privateSshKey = lib.mkOption { - type = lib.types.path; - description = "The age-encrypted ssh-key, passed to agenix"; - }; - privatePassword = lib.mkOption { - type = lib.types.path; - description = "The age-encrypted restic password, passed to agenix"; - }; - }; - config = lib.mkIf cfg.enable { - vhack.persist.directories = [ - { - directory = "/root/.ssh"; - user = "root"; - group = "root"; - mode = "0700"; - } - ]; - age.secrets = { - resticpass = { - file = cfg.privatePassword; - mode = "0700"; - owner = "root"; - group = "root"; - }; - resticssh = { - file = cfg.privateSshKey; - mode = "0700"; - owner = "root"; - group = "root"; - }; - }; - services.restic.backups = { - storagebox = { - initialize = true; - backupPrepareCommand = '' - ${pkgs.sudo}/bin/sudo -u ${postgresUser} ${pkgs.postgresql}/bin/pg_dumpall --clean --if-exists --quote-all-identifiers > /srv/db_backup.sql - - [ -d /srv/snapshots ] || ${pkgs.btrfs-progs}/bin/btrfs subvolume create /srv/snapshots; - [ -d /srv/snapshots/srv ] && ${pkgs.btrfs-progs}/bin/btrfs subvolume delete /srv/snapshots/srv; - ${pkgs.btrfs-progs}/bin/btrfs subvolume snapshot -r /srv /srv/snapshots/srv; - - # dump() { - # # compression: - # # pg_dump -F t -v "$1" | xz -z -9 -e -T0 > "db_$1.tar.xz" - # pg_dump -v "$1" > "db_$1.tar.xz" - # } - # # List all databases, and dump each of them in its own file - # # psql --list --csv | while read -r line; do echo "$line" | grep ','; done | while IFS=, read -r name _; do echo "$name"; done | sed '1d' | while read -r db_name; do dump "$db_name"; done - ''; - paths = [ - snapshots - ]; - exclude = [ - ".snapshots" - "/var/lib/postgresql" # included in the db dump - ]; - extraBackupArgs = [ - "--verbose" # spam log - ]; - passwordFile = config.age.secrets.resticpass.path; - extraOptions = [ - "rclone.program='ssh -p 23 ${cfg.user}@${cfg.user}.your-storagebox.de -i ${config.age.secrets.resticssh.path}'" - ]; - repository = "rclone: "; # There is only one repository served - timerConfig = { - Requires = "network-online.target"; - OnCalendar = "daily"; - Persistent = true; - }; - }; - }; - }; -} diff --git a/modules/by-name/co/constants/module.nix b/modules/by-name/co/constants/module.nix deleted file mode 100644 index 2115a37..0000000 --- a/modules/by-name/co/constants/module.nix +++ /dev/null @@ -1,96 +0,0 @@ -# This file is inspired by the `nixos/modules/misc/ids.nix` -# file in nixpkgs. -{ - lib, - config, - ... -}: { - options.vhack.constants = { - ids.uids = lib.mkOption { - internal = true; - description = '' - The user IDs used in the vhack.eu nixos config. - ''; - type = lib.types.attrsOf (lib.types.ints.between 0 400); - }; - ids.gids = lib.mkOption { - internal = true; - description = '' - The group IDs used in the vhack.eu nixos config. - ''; - type = lib.types.attrsOf (lib.types.ints.between 0 400); - }; - }; - - config.vhack.constants = { - ids.uids = { - # Keep this sorted with `!sort --numeric-sort --key=2 --field-separator="="` - systemd-coredump = 151; # GROUP - opendkim = 221; - mautrix-whatsapp = 222; - etebase-server = 223; - matrix-synapse = 224; - rspamd = 225; - knot-resolver = 226; - peertube = 231; - redis-mastodon = 232; - redis-peertube = 233; - redis-rspamd = 234; - redis-stalwart-mail = 235; - mastodon = 236; - stalwart-mail = 238; - acme = 328; - dhcpcd = 329; - nscd = 330; - sshd = 331; - systemd-oom = 332; - resolvconf = 333; # GROUP - nix-sync = 334; - nextcloud = 335; - redis-nextcloud = 336; - taskchampion = 337; - stalwart-mail-certificates = 338; # GROUP - sharkey = 339; - redis-sharkey = 340; - - # As per the NixOS file, the uids should not be greater or equal to 400; - }; - ids.gids = let - inherit (config.vhack.constants.ids) uids; - in { - # Please add your groups to the users and inherit them here. - # This avoids having an user/group id mismatch. - inherit - (uids) - acme - dhcpcd - etebase-server - knot-resolver - mastodon - matrix-synapse - mautrix-whatsapp - nextcloud - nix-sync - nscd - opendkim - peertube - redis-mastodon - redis-nextcloud - redis-peertube - redis-rspamd - redis-stalwart-mail - rspamd - sshd - stalwart-mail - systemd-oom - sharkey - redis-sharkey - systemd-coredump # matches systemd-coredump user - resolvconf # This group is not matched to an user? - stalwart-mail-certificates # This group is used to connect nginx and stalwart-mail - ; - - # The gid should match the uid. Thus should not be >= 400; - }; - }; -} diff --git a/modules/by-name/co/coredump/module.nix b/modules/by-name/co/coredump/module.nix deleted file mode 100644 index ce28ed9..0000000 --- a/modules/by-name/co/coredump/module.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.systemd.coredump; -in { - options.vhack.systemd.coredump = { - # NOTE(@bpeetz): Enabled by default, because that is what NixOS also does. <2024-12-25> - enable = (lib.mkEnableOption "oomd") // {default = true;}; - }; - - config = lib.mkIf cfg.enable { - users = { - groups.systemd-coredump.gid = config.vhack.constants.ids.gids.systemd-coredump; - }; - }; -} diff --git a/modules/by-name/dh/dhcpcd/module.nix b/modules/by-name/dh/dhcpcd/module.nix deleted file mode 100644 index 0e35af3..0000000 --- a/modules/by-name/dh/dhcpcd/module.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.dhcpcd; -in { - options.vhack.dhcpcd = { - enable = (lib.mkEnableOption "dhcpcd") // {default = config.networking.dhcpcd.enable;}; - }; - - config = lib.mkIf cfg.enable { - users = { - users.dhcpcd.uid = config.vhack.constants.ids.uids.dhcpcd; - groups.dhcpcd.gid = config.vhack.constants.ids.gids.dhcpcd; - }; - }; -} diff --git a/modules/by-name/di/disko/module.nix b/modules/by-name/di/disko/module.nix deleted file mode 100644 index b4fc3c8..0000000 --- a/modules/by-name/di/disko/module.nix +++ /dev/null @@ -1,78 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.disko; - - defaultMountOptions = ["compress-force=zstd:15" "noatime"]; -in { - options.vhack.disko = { - enable = lib.mkEnableOption "disk configuration via disko"; - - disk = lib.mkOption { - type = lib.types.path; - example = "/dev/disk/by-id/ata-WDC_WD10SDRW-11A0XS0_WD-WXP2A901KJN5"; - description = "Path to the main disk"; - }; - }; - - config = lib.mkIf cfg.enable { - disko.devices = { - disk.main = { - type = "disk"; - device = cfg.disk; - - content = { - type = "gpt"; - partitions = { - boot = { - size = "1M"; - type = "EF02"; # for grub MBR - }; - root = { - size = "100%"; - content = { - type = "btrfs"; - extraArgs = ["-f" "--label nixos"]; # f: Override existing partitions - - subvolumes = { - "/nix" = { - mountpoint = "/nix"; - mountOptions = defaultMountOptions; - }; - "/srv" = { - mountpoint = "/srv"; - mountOptions = defaultMountOptions; - }; - "/srv/.snapshots" = { - mountpoint = "/srv/.snapshots"; - mountOptions = defaultMountOptions; - }; - "/boot" = { - mountpoint = "/boot"; - mountOptions = defaultMountOptions; - }; - }; - }; - }; - }; - }; - }; - - nodev."/" = { - fsType = "tmpfs"; - mountOptions = ["defaults" "size=6G" "mode=755"]; - }; - }; - - fileSystems = { - "/srv" = { - neededForBoot = true; - }; - "/boot" = { - neededForBoot = true; - }; - }; - }; -} diff --git a/modules/by-name/dn/dns/dns/default.nix b/modules/by-name/dn/dns/dns/default.nix deleted file mode 100644 index 4ce07d8..0000000 --- a/modules/by-name/dn/dns/dns/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -{lib}: let - util = import ./util {inherit lib;}; - types = import ./types {inherit lib util;}; -in { - inherit - types - ; -} diff --git a/modules/by-name/dn/dns/dns/types/default.nix b/modules/by-name/dn/dns/dns/types/default.nix deleted file mode 100644 index ece315f..0000000 --- a/modules/by-name/dn/dns/dns/types/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -{ - lib, - util, -}: let - simple = {types = import ./simple.nix {inherit lib;};}; -in { - record = import ./record.nix {inherit lib util;}; - records = import ./records {inherit lib util simple;}; - - zone = import ./zone.nix {inherit lib util simple;}; -} diff --git a/modules/by-name/dn/dns/dns/types/record.nix b/modules/by-name/dn/dns/dns/types/record.nix deleted file mode 100644 index e992bf9..0000000 --- a/modules/by-name/dn/dns/dns/types/record.nix +++ /dev/null @@ -1,75 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# SPDX-FileCopyrightText: 2021 Naïm Favier <n@monade.li> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -{lib, ...}: let - inherit (lib) hasSuffix isString mkOption removeSuffix types; - - recordType = rsubt: let - submodule = types.submodule { - options = - { - class = mkOption { - type = types.enum ["IN"]; - default = "IN"; - example = "IN"; - description = "Resource record class. Only IN is supported"; - }; - ttl = mkOption { - type = types.nullOr types.ints.unsigned; # TODO: u32 - default = null; - example = 300; - description = "Record caching duration (in seconds)"; - }; - } - // rsubt.options; - }; - in - ( - if rsubt ? fromString - then types.either types.str - else lib.id - ) - submodule; - - # name == "@" : use unqualified domain name - writeRecord = name: rsubt: data: let - data' = - if isString data && rsubt ? fromString - then - # add default values for the record type - (recordType rsubt).merge [] [ - { - file = ""; - value = rsubt.fromString data; - } - ] - else data; - name' = let - fname = rsubt.nameFixup or (n: _: n) name data'; - in - if name == "@" - then name - else if (hasSuffix ".@" name) - then removeSuffix ".@" fname - else "${fname}."; - inherit (rsubt) rtype; - in - lib.concatStringsSep " " (with data'; - [ - name' - ] - ++ lib.optionals (ttl != null) [ - (toString ttl) - ] - ++ [ - class - rtype - (rsubt.dataToString data') - ]); -in { - inherit recordType; - inherit writeRecord; -} diff --git a/modules/by-name/dn/dns/dns/types/records/A.nix b/modules/by-name/dn/dns/dns/types/records/A.nix deleted file mode 100644 index 296943e..0000000 --- a/modules/by-name/dn/dns/dns/types/records/A.nix +++ /dev/null @@ -1,19 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -{lib, ...}: let - inherit (lib) mkOption types; -in { - rtype = "A"; - options = { - address = mkOption { - type = types.str; - example = "26.3.0.103"; - description = "IP address of the host"; - }; - }; - dataToString = {address, ...}: address; - fromString = address: {inherit address;}; -} diff --git a/modules/by-name/dn/dns/dns/types/records/AAAA.nix b/modules/by-name/dn/dns/dns/types/records/AAAA.nix deleted file mode 100644 index 4717176..0000000 --- a/modules/by-name/dn/dns/dns/types/records/AAAA.nix +++ /dev/null @@ -1,19 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -{lib, ...}: let - inherit (lib) mkOption types; -in { - rtype = "AAAA"; - options = { - address = mkOption { - type = types.str; - example = "4321:0:1:2:3:4:567:89ab"; - description = "IPv6 address of the host"; - }; - }; - dataToString = {address, ...}: address; - fromString = address: {inherit address;}; -} diff --git a/modules/by-name/dn/dns/dns/types/records/CAA.nix b/modules/by-name/dn/dns/dns/types/records/CAA.nix deleted file mode 100644 index 4b40510..0000000 --- a/modules/by-name/dn/dns/dns/types/records/CAA.nix +++ /dev/null @@ -1,42 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -# RFC 8659 -{lib, ...}: let - inherit (lib) mkOption types; -in { - rtype = "CAA"; - options = { - issuerCritical = mkOption { - type = types.bool; - example = true; - description = '' - If set to '1', indicates that the corresponding property tag - MUST be understood if the semantics of the CAA record are to be - correctly interpreted by an issuer - ''; - }; - tag = mkOption { - type = types.enum ["issue" "issuewild" "iodef"]; - example = "issue"; - description = "One of the defined property tags"; - }; - value = mkOption { - type = types.str; # section 4.1.1: not limited in length - example = "ca.example.net"; - description = "Value of the property"; - }; - }; - dataToString = { - issuerCritical, - tag, - value, - ... - }: ''${ - if issuerCritical - then "128" - else "0" - } ${tag} "${value}"''; -} diff --git a/modules/by-name/dn/dns/dns/types/records/CNAME.nix b/modules/by-name/dn/dns/dns/types/records/CNAME.nix deleted file mode 100644 index 095b078..0000000 --- a/modules/by-name/dn/dns/dns/types/records/CNAME.nix +++ /dev/null @@ -1,27 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -# RFC 1035, 3.3.1 -{ - lib, - simple, - ... -}: let - inherit (lib) mkOption; -in { - rtype = "CNAME"; - options = { - cname = mkOption { - type = simple.types.domain-name; - example = "www.test.com"; - description = '' - A <domain-name> which specifies the canonical or primary name - for the owner. The owner name is an alias. - ''; - }; - }; - dataToString = {cname, ...}: "${cname}"; - fromString = cname: {inherit cname;}; -} diff --git a/modules/by-name/dn/dns/dns/types/records/DKIM.nix b/modules/by-name/dn/dns/dns/types/records/DKIM.nix deleted file mode 100644 index 31b2f67..0000000 --- a/modules/by-name/dn/dns/dns/types/records/DKIM.nix +++ /dev/null @@ -1,75 +0,0 @@ -# -# SPDX-FileCopyrightText: 2020 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -# This is a “fake” record type, not actually part of DNS. -# It gets compiled down to a TXT record. -# RFC 6376 -{ - lib, - util, - ... -}: let - inherit (lib) mkOption types; -in rec { - rtype = "TXT"; - options = { - selector = mkOption { - type = types.str; - example = "mail"; - description = "DKIM selector name"; - }; - h = mkOption { - type = types.listOf types.str; - default = []; - example = ["sha1" "sha256"]; - description = "Acceptable hash algorithms. Empty means all of them"; - apply = lib.concatStringsSep ":"; - }; - k = mkOption { - type = types.nullOr types.str; - default = "rsa"; - example = "rsa"; - description = "Key type"; - }; - n = mkOption { - type = types.str; - default = ""; - example = "Just any kind of arbitrary notes."; - description = "Notes that might be of interest to a human"; - }; - p = mkOption { - type = types.str; - example = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkMoGeLnQg1fWn7/zYtIxN2SnFCjxOCKG9v3b4jYfcTNh5ijSsq631uBItLa7od+v/RtdC2UzJ1lWT947qR+Rcac2gbto/NMqJ0fzfVjH4OuKhitdY9tf6mcwGjaNBcWToIMmPSPDdQPNUYckcQ2QIDAQAB"; - description = "Public-key data (base64)"; - }; - s = mkOption { - type = types.listOf (types.enum ["*" "email"]); - default = ["*"]; - example = ["email"]; - description = "Service Type"; - apply = lib.concatStringsSep ":"; - }; - t = mkOption { - type = types.listOf (types.enum ["y" "s"]); - default = []; - example = ["y"]; - description = "Flags"; - apply = lib.concatStringsSep ":"; - }; - }; - dataToString = data: let - items = - ["v=DKIM1"] - ++ lib.pipe data [ - (builtins.intersectAttrs options) # remove garbage list `_module` - (lib.filterAttrs (_k: v: v != null && v != "")) - (lib.filterAttrs (k: _v: k != "selector")) - (lib.mapAttrsToList (k: v: "${k}=${v}")) - ]; - result = lib.concatStringsSep "; " items + ";"; - in - util.writeCharacterString result; - nameFixup = name: self: "${self.selector}._domainkey.${name}"; -} diff --git a/modules/by-name/dn/dns/dns/types/records/DMARC.nix b/modules/by-name/dn/dns/dns/types/records/DMARC.nix deleted file mode 100644 index 0f10f2c..0000000 --- a/modules/by-name/dn/dns/dns/types/records/DMARC.nix +++ /dev/null @@ -1,108 +0,0 @@ -# -# SPDX-FileCopyrightText: 2020 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -# This is a “fake” record type, not actually part of DNS. -# It gets compiled down to a TXT record. -# RFC 7489 -{ - lib, - util, - ... -}: let - inherit (lib) mkOption types; -in rec { - rtype = "TXT"; - options = { - adkim = mkOption { - type = types.enum ["relaxed" "strict"]; - default = "relaxed"; - example = "strict"; - description = "DKIM Identifier Alignment mode"; - apply = builtins.substring 0 1; - }; - aspf = mkOption { - type = types.enum ["relaxed" "strict"]; - default = "relaxed"; - example = "strict"; - description = "SPF Identifier Alignment mode"; - apply = builtins.substring 0 1; - }; - fo = mkOption { - type = types.listOf (types.enum ["0" "1" "d" "s"]); - default = ["0"]; - example = ["0" "1" "s"]; - description = "Failure reporting options"; - apply = lib.concatStringsSep ":"; - }; - p = mkOption { - type = types.enum ["none" "quarantine" "reject"]; - example = "quarantine"; - description = "Requested Mail Receiver policy"; - }; - pct = mkOption { - type = types.ints.between 0 100; - default = 100; - example = 30; - description = "Percentage of messages to which the DMARC policy is to be applied"; - apply = builtins.toString; - }; - rf = mkOption { - type = types.listOf (types.enum ["afrf"]); - default = ["afrf"]; - example = ["afrf"]; - description = "Format to be used for message-specific failure reports"; - apply = lib.concatStringsSep ":"; - }; - ri = mkOption { - type = types.ints.unsigned; # FIXME: u32 - default = 86400; - example = 12345; - description = "Interval requested between aggregate reports"; - apply = builtins.toString; - }; - rua = mkOption { - type = types.oneOf [types.str (types.listOf types.str)]; - default = []; - example = "mailto:dmarc+rua@example.com"; - description = "Addresses to which aggregate feedback is to be sent"; - apply = val: - # FIXME: need to encode commas in URIs - if builtins.isList val - then lib.concatStringsSep "," val - else val; - }; - ruf = mkOption { - type = types.listOf types.str; - default = []; - example = ["mailto:dmarc+ruf@example.com" "mailto:another+ruf@example.com"]; - description = "Addresses to which message-specific failure information is to be reported"; - apply = val: - # FIXME: need to encode commas in URIs - if builtins.isList val - then lib.concatStringsSep "," val - else val; - }; - sp = mkOption { - type = types.nullOr (types.enum ["none" "quarantine" "reject"]); - default = null; - example = "quarantine"; - description = "Requested Mail Receiver policy for all subdomains"; - }; - }; - dataToString = data: let - # The specification could be more clear on this, but `v` and `p` MUST - # be the first two tags in the record. - items = - ["v=DMARC1; p=${data.p}"] - ++ lib.pipe data [ - (builtins.intersectAttrs options) # remove garbage list `_module` - (lib.filterAttrs (k: v: v != null && v != "" && k != "p")) - (lib.mapAttrsToList (k: v: "${k}=${v}")) - ]; - result = lib.concatStringsSep "; " items + ";"; - in - util.writeCharacterString result; - nameFixup = name: _self: "_dmarc.${name}"; -} diff --git a/modules/by-name/dn/dns/dns/types/records/DNAME.nix b/modules/by-name/dn/dns/dns/types/records/DNAME.nix deleted file mode 100644 index 042ce95..0000000 --- a/modules/by-name/dn/dns/dns/types/records/DNAME.nix +++ /dev/null @@ -1,15 +0,0 @@ -# RFC 6672 -{lib, ...}: let - inherit (lib) dns mkOption; -in { - rtype = "DNAME"; - options = { - dname = mkOption { - type = dns.types.domain-name; - example = "www.test.com"; - description = "A <domain-name> which provides redirection from a part of the DNS name tree to another part of the DNS name tree"; - }; - }; - dataToString = {dname, ...}: "${dname}"; - fromString = dname: {inherit dname;}; -} diff --git a/modules/by-name/dn/dns/dns/types/records/DNSKEY.nix b/modules/by-name/dn/dns/dns/types/records/DNSKEY.nix deleted file mode 100644 index 86ce3a1..0000000 --- a/modules/by-name/dn/dns/dns/types/records/DNSKEY.nix +++ /dev/null @@ -1,63 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Aluísio Augusto Silva Gonçalves <https://aasg.name> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# RFC 4034, 2 -{lib, ...}: let - inherit (builtins) isInt split; - inherit (lib) concatStrings flatten mkOption types; - - dnssecOptions = import ./dnssec.nix {inherit lib;}; - inherit (dnssecOptions) mkDNSSECAlgorithmOption; -in { - rtype = "DNSKEY"; - options = { - flags = mkOption { - description = "Flags pertaining to this RR."; - type = types.either types.ints.u16 (types.submodule { - options = { - zoneSigningKey = mkOption { - description = "Whether this RR holds a zone signing key (ZSK)."; - type = types.bool; - default = false; - }; - secureEntryPoint = mkOption { - type = types.bool; - description = '' - Whether this RR holds a secure entry point. - In general, this means the key is a key-signing key (KSK), as opposed to a zone-signing key. - ''; - default = false; - }; - }; - }); - apply = value: - if isInt value - then value - else - ( - if value.zoneSigningKey - then 256 - else 0 - ) - + ( - if value.secureEntryPoint - then 1 - else 0 - ); - }; - algorithm = mkDNSSECAlgorithmOption { - description = "Algorithm of the key referenced by this RR."; - }; - publicKey = mkOption { - type = types.str; - description = "Base64-encoded public key."; - apply = value: concatStrings (flatten (split "[[:space:]]" value)); - }; - }; - dataToString = { - flags, - algorithm, - publicKey, - ... - }: "${toString flags} 3 ${toString algorithm} ${publicKey}"; -} diff --git a/modules/by-name/dn/dns/dns/types/records/DS.nix b/modules/by-name/dn/dns/dns/types/records/DS.nix deleted file mode 100644 index 76fac9a..0000000 --- a/modules/by-name/dn/dns/dns/types/records/DS.nix +++ /dev/null @@ -1,48 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Aluísio Augusto Silva Gonçalves <https://aasg.name> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# RFC 4034, 5 -{lib, ...}: let - inherit (lib) mkOption types; - - dnssecOptions = import ./dnssec.nix {inherit lib;}; - inherit (dnssecOptions) mkRegisteredNumberOption mkDNSSECAlgorithmOption; - - mkDSDigestTypeOption = args: - mkRegisteredNumberOption { - registryName = "Delegation Signer (DS) Resource Record (RR) Type Digest Algorithms"; - numberType = types.ints.u8; - # These mnemonics are unofficial, unlike the DNSSEC algorithm ones. - mnemonics = { - "sha-1" = 1; - "sha-256" = 2; - "gost" = 3; - "sha-384" = 4; - }; - }; -in { - rtype = "DS"; - options = { - keyTag = mkOption { - description = "Tag computed over the DNSKEY referenced by this RR to identify it."; - type = types.ints.u16; - }; - algorithm = mkDNSSECAlgorithmOption { - description = "Algorithm of the key referenced by this RR."; - }; - digestType = mkDSDigestTypeOption { - description = "Type of the digest given in the `digest` attribute."; - }; - digest = mkOption { - description = "Digest of the DNSKEY referenced by this RR."; - type = types.strMatching "[[:xdigit:]]+"; - }; - }; - dataToString = { - keyTag, - algorithm, - digestType, - digest, - ... - }: "${toString keyTag} ${toString algorithm} ${toString digestType} ${digest}"; -} diff --git a/modules/by-name/dn/dns/dns/types/records/HTTPS.nix b/modules/by-name/dn/dns/dns/types/records/HTTPS.nix deleted file mode 100644 index 6e2ef3d..0000000 --- a/modules/by-name/dn/dns/dns/types/records/HTTPS.nix +++ /dev/null @@ -1,5 +0,0 @@ -args: -import ./SVCB.nix args -// { - rtype = "HTTPS"; -} diff --git a/modules/by-name/dn/dns/dns/types/records/MTA-STS.nix b/modules/by-name/dn/dns/dns/types/records/MTA-STS.nix deleted file mode 100644 index 030490e..0000000 --- a/modules/by-name/dn/dns/dns/types/records/MTA-STS.nix +++ /dev/null @@ -1,42 +0,0 @@ -# -# SPDX-FileCopyrightText: 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -# This is a “fake” record type, not actually part of DNS. -# It gets compiled down to a TXT record. -# RFC 8461 -{ - lib, - util, - ... -}: let - inherit (lib) mkOption types; -in rec { - rtype = "TXT"; - options = { - id = mkOption { - type = types.str; - example = "20160831085700Z"; - description = '' - A short string used to track policy updates. This string MUST - uniquely identify a given instance of a policy, such that senders - can determine when the policy has been updated by comparing to the - "id" of a previously seen policy. There is no implied ordering of - "id" fields between revisions. - ''; - }; - }; - dataToString = data: let - items = - ["v=STSv1"] - ++ lib.pipe data [ - (builtins.intersectAttrs options) # remove garbage list `_module` - (lib.filterAttrs (k: v: v != null && v != "")) - (lib.mapAttrsToList (k: v: "${k}=${v}")) - ]; - result = lib.concatStringsSep "; " items + ";"; - in - util.writeCharacterString result; - nameFixup = name: _self: "_mta-sts.${name}"; -} diff --git a/modules/by-name/dn/dns/dns/types/records/MX.nix b/modules/by-name/dn/dns/dns/types/records/MX.nix deleted file mode 100644 index c25b89c..0000000 --- a/modules/by-name/dn/dns/dns/types/records/MX.nix +++ /dev/null @@ -1,32 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -# RFC 1035, 3.3.9 -{ - lib, - simple, - ... -}: let - inherit (lib) mkOption types; -in { - rtype = "MX"; - options = { - preference = mkOption { - type = types.ints.u16; - example = 10; - description = "The preference given to this RR among others at the same owner. Lower values are preferred"; - }; - exchange = mkOption { - type = simple.types.domain-name; - example = "smtp.example.com."; - description = "A <domain-name> which specifies a host willing to act as a mail exchange for the owner name"; - }; - }; - dataToString = { - preference, - exchange, - ... - }: "${toString preference} ${exchange}"; -} diff --git a/modules/by-name/dn/dns/dns/types/records/NS.nix b/modules/by-name/dn/dns/dns/types/records/NS.nix deleted file mode 100644 index ea60a91..0000000 --- a/modules/by-name/dn/dns/dns/types/records/NS.nix +++ /dev/null @@ -1,24 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -# RFC 1035, 3.3.11 -{ - lib, - simple, - ... -}: let - inherit (lib) mkOption; -in { - rtype = "NS"; - options = { - nsdname = mkOption { - type = simple.types.domain-name; - example = "ns2.example.com"; - description = "A <domain-name> which specifies a host which should be authoritative for the specified class and domain"; - }; - }; - dataToString = {nsdname, ...}: "${nsdname}"; - fromString = nsdname: {inherit nsdname;}; -} diff --git a/modules/by-name/dn/dns/dns/types/records/OPENPGPKEY.nix b/modules/by-name/dn/dns/dns/types/records/OPENPGPKEY.nix deleted file mode 100644 index 1f39cb9..0000000 --- a/modules/by-name/dn/dns/dns/types/records/OPENPGPKEY.nix +++ /dev/null @@ -1,18 +0,0 @@ -# RFC7929 -{ - lib, - util, - ... -}: let - inherit (lib) mkOption types; -in { - rtype = "OPENPGPKEY"; - options = { - data = mkOption { - type = types.str; - }; - }; - - dataToString = {data, ...}: util.writeCharacterString data; - fromString = data: {inherit data;}; -} diff --git a/modules/by-name/dn/dns/dns/types/records/PTR.nix b/modules/by-name/dn/dns/dns/types/records/PTR.nix deleted file mode 100644 index 075f82e..0000000 --- a/modules/by-name/dn/dns/dns/types/records/PTR.nix +++ /dev/null @@ -1,92 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -# RFC 1035, 3.3.12 -{ - lib, - simple, - ... -}: let - inherit (lib) mkOption; - - inherit (lib.strings) stringToCharacters splitString; - - reverseIpv4 = input: - builtins.concatStringsSep "." (lib.lists.reverseList (splitString "." - input)); - - reverseIpv6 = input: let - split = splitString ":" input; - elementLength = builtins.length split; - - reverseString = string: - builtins.concatStringsSep "" (lib.lists.reverseList - (stringToCharacters string)); - in - reverseString (builtins.concatStringsSep "." (stringToCharacters (builtins.concatStringsSep - "" (builtins.map ( - part: let - c = stringToCharacters part; - in - if builtins.length c == 4 - then - # valid part - part - else if builtins.length c < 4 && builtins.length c > 0 - then - # leading zeros were elided - (builtins.concatStringsSep "" ( - builtins.map builtins.toString ( - builtins.genList (_: 0) (4 - (builtins.length c)) - ) - )) - + part - else if builtins.length c == 0 - then - # Multiple full blocks were elided. Only one of these can be in an - # IPv6 address, as such we can simply add (8 - (elementLength - 1)) `0000` - # blocks. We need to substract one from `elementLength` because - # this empty part is included in the `elementLength`. - builtins.concatStringsSep "" (builtins.genList (_: "0000") (8 - (elementLength - 1))) - else builtins.throw "Impossible" - ) - split)))); -in { - rtype = "PTR"; - options = { - name = mkOption { - type = simple.types.domain-name; - example = "mail2.server.com"; - description = "The <domain-name> which is defined by the IP."; - }; - ip = { - v4 = mkOption { - type = lib.types.nullOr lib.types.str; - example = "192.168.1.4"; - description = "The IPv4 address of the host."; - default = null; - apply = v: - if v != null - then reverseIpv4 v - else v; - }; - v6 = mkOption { - type = lib.types.nullOr lib.types.str; - example = "192.168.1.4"; - description = "The IPv6 address of the host."; - default = null; - apply = v: - if v != null - then reverseIpv6 v - else v; - }; - }; - }; - dataToString = {name, ...}: "${name}."; - nameFixup = name: self: - if self.ip.v6 == null - then "${self.ip.v4}.in-addr.arpa" - else "${self.ip.v6}.ip6.arpa"; -} diff --git a/modules/by-name/dn/dns/dns/types/records/SOA.nix b/modules/by-name/dn/dns/dns/types/records/SOA.nix deleted file mode 100644 index db7436e..0000000 --- a/modules/by-name/dn/dns/dns/types/records/SOA.nix +++ /dev/null @@ -1,65 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -# RFC 1035, 3.3.13 -{ - lib, - simple, - ... -}: let - inherit (lib) concatStringsSep removeSuffix replaceStrings; - inherit (lib) mkOption types; -in { - rtype = "SOA"; - options = { - nameServer = mkOption { - type = simple.types.domain-name; - example = "ns1.example.com"; - description = "The <domain-name> of the name server that was the original or primary source of data for this zone. Don't forget the dot at the end!"; - }; - adminEmail = mkOption { - type = simple.types.domain-name; - example = "admin@example.com"; - description = "An email address of the person responsible for this zone. (Note: in traditional zone files you are supposed to put a dot instead of `@` in your address; you can use `@` with this module and it is recommended to do so. Also don't put the dot at the end!)"; - apply = s: replaceStrings ["@"] ["."] (removeSuffix "." s); - }; - serial = mkOption { - type = types.ints.unsigned; # TODO: u32 - example = 20; - description = "Version number of the original copy of the zone"; - }; - refresh = mkOption { - type = types.ints.unsigned; # TODO: u32 - default = 24 * 60 * 60; - example = 7200; - description = "Time interval before the zone should be refreshed"; - }; - retry = mkOption { - type = types.ints.unsigned; # TODO: u32 - default = 10 * 60; - example = 600; - description = "Time interval that should elapse before a failed refresh should be retried"; - }; - expire = mkOption { - type = types.ints.unsigned; # TODO: u32 - default = 10 * 24 * 60 * 60; - example = 3600000; - description = "Time value that specifies the upper limit on the time interval that can elapse before the zone is no longer authoritative"; - }; - minimum = mkOption { - type = types.ints.unsigned; # TODO: u32 - default = 60; - example = 60; - description = "Minimum TTL field that should be exported with any RR from this zone"; - }; - }; - dataToString = data @ { - nameServer, - adminEmail, - ... - }: let - numbers = map toString (with data; [serial refresh retry expire minimum]); - in "${nameServer} ${adminEmail}. (${concatStringsSep " " numbers})"; -} diff --git a/modules/by-name/dn/dns/dns/types/records/SRV.nix b/modules/by-name/dn/dns/dns/types/records/SRV.nix deleted file mode 100644 index 5f558ed..0000000 --- a/modules/by-name/dn/dns/dns/types/records/SRV.nix +++ /dev/null @@ -1,51 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -# RFC 2782 -{ - lib, - simple, - ... -}: let - inherit (lib) mkOption types; -in { - rtype = "SRV"; - options = { - service = mkOption { - type = types.str; - example = "foobar"; - description = "The symbolic name of the desired service. Do not add the underscore!"; - }; - proto = mkOption { - type = types.str; - example = "tcp"; - description = "The symbolic name of the desired protocol. Do not add the underscore!"; - }; - priority = mkOption { - type = types.ints.u16; - default = 0; - example = 0; - description = "The priority of this target host"; - }; - weight = mkOption { - type = types.ints.u16; - default = 100; - example = 20; - description = "The weight field specifies a relative weight for entries with the same priority. Larger weights SHOULD be given a proportionately higher probability of being selected"; - }; - port = mkOption { - type = types.ints.u16; - example = 9; - description = "The port on this target host of this service"; - }; - target = mkOption { - type = simple.types.domain-name; - example = ""; - description = "The domain name of the target host"; - }; - }; - dataToString = data: with data; "${toString priority} ${toString weight} ${toString port} ${target}"; - nameFixup = name: self: "_${self.service}._${self.proto}.${name}"; -} diff --git a/modules/by-name/dn/dns/dns/types/records/SSHFP.nix b/modules/by-name/dn/dns/dns/types/records/SSHFP.nix deleted file mode 100644 index 1409860..0000000 --- a/modules/by-name/dn/dns/dns/types/records/SSHFP.nix +++ /dev/null @@ -1,39 +0,0 @@ -# RFC 4255 -{lib, ...}: let - inherit (lib) mkOption types; - inherit (builtins) attrNames; - algorithm = { - "rsa" = 1; - "dsa" = 2; - "ecdsa" = 3; # RFC 6594 - "ed25519" = 4; # RFC 7479 / RFC 8709 - "ed448" = 6; # RFC 8709 - }; - mode = { - "sha1" = 1; - "sha256" = 2; # RFC 6594 - }; -in { - rtype = "SSHFP"; - options = { - algorithm = mkOption { - example = "ed25519"; - type = types.enum (attrNames algorithm); - apply = value: algorithm.${value}; - }; - fingerprintType = mkOption { - example = "sha256"; - type = types.enum (attrNames mode); - apply = value: mode.${value}; - }; - fingerprint = mkOption { - type = types.str; - }; - }; - dataToString = { - algorithm, - fingerprintType, - fingerprint, - ... - }: "${toString algorithm} ${toString fingerprintType} ${fingerprint}"; -} diff --git a/modules/by-name/dn/dns/dns/types/records/SVCB.nix b/modules/by-name/dn/dns/dns/types/records/SVCB.nix deleted file mode 100644 index 62cbc3d..0000000 --- a/modules/by-name/dn/dns/dns/types/records/SVCB.nix +++ /dev/null @@ -1,100 +0,0 @@ -# rfc9460 -{lib, ...}: let - inherit - (lib) - concatStringsSep - filter - isInt - isList - mapAttrsToList - mkOption - types - ; - - mkSvcParams = params: - concatStringsSep " " ( - filter (s: s != "") ( - mapAttrsToList ( - name: value: - if value - then name - else if isList value - then "${name}=${concatStringsSep "," value}" - else if isInt value - then "${name}=${builtins.toString value}" - else "" - ) - params - ) - ); -in { - rtype = "SVCB"; - options = { - svcPriority = mkOption { - example = 1; - type = types.ints.u16; - }; - targetName = mkOption { - example = "."; - type = types.str; - }; - mandatory = mkOption { - example = ["ipv4hint"]; - default = null; - type = types.nullOr (types.nonEmptyListOf types.str); - }; - alpn = mkOption { - example = ["h2"]; - default = null; - type = types.nullOr (types.nonEmptyListOf types.str); - }; - no-default-alpn = mkOption { - example = true; - default = false; - type = types.bool; - }; - port = mkOption { - example = 443; - default = null; - type = types.nullOr types.port; - }; - ipv4hint = mkOption { - example = ["127.0.0.1"]; - default = null; - type = types.nullOr (types.nonEmptyListOf types.str); - }; - ipv6hint = mkOption { - example = ["::1"]; - default = null; - type = types.nullOr (types.nonEmptyListOf types.str); - }; - ech = mkOption { - type = types.nullOr types.str; - default = null; - }; - }; - dataToString = { - svcPriority, - targetName, - mandatory ? null, - alpn ? null, - no-default-alpn ? null, - port ? null, - ipv4hint ? null, - ipv6hint ? null, - ech ? null, - ... - }: "${toString svcPriority} ${targetName} ${ - mkSvcParams { - inherit - alpn - ech - ipv4hint - ipv6hint - mandatory - no-default-alpn - port - ; - } - }"; -} diff --git a/modules/by-name/dn/dns/dns/types/records/TLSA.nix b/modules/by-name/dn/dns/dns/types/records/TLSA.nix deleted file mode 100644 index d92a29b..0000000 --- a/modules/by-name/dn/dns/dns/types/records/TLSA.nix +++ /dev/null @@ -1,50 +0,0 @@ -# RFC 6698 -{lib, ...}: let - inherit (lib) mkOption types; - inherit (builtins) attrNames; - - certUsage = { - "pkix-ta" = 0; - "pkix-ee" = 1; - "dane-ta" = 2; - "dane-ee" = 3; - }; - selectors = { - "cert" = 0; - "spki" = 1; - }; - match = { - "exact" = 0; - "sha256" = 1; - "sha512" = 2; - }; -in { - rtype = "TLSA"; - options = { - certUsage = mkOption { - example = "dane-ee"; - type = types.enum (attrNames certUsage); - apply = value: certUsage.${value}; - }; - selector = mkOption { - example = "spki"; - type = types.enum (attrNames selectors); - apply = value: selectors.${value}; - }; - matchingType = mkOption { - example = "sha256"; - type = types.enum (attrNames match); - apply = value: match.${value}; - }; - certificate = mkOption { - type = types.str; - }; - }; - dataToString = { - certUsage, - selector, - matchingType, - certificate, - ... - }: "${toString certUsage} ${toString selector} ${toString matchingType} ${certificate}"; -} diff --git a/modules/by-name/dn/dns/dns/types/records/TXT.nix b/modules/by-name/dn/dns/dns/types/records/TXT.nix deleted file mode 100644 index d605ce8..0000000 --- a/modules/by-name/dn/dns/dns/types/records/TXT.nix +++ /dev/null @@ -1,24 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -# RFC 1035, 3.3.14 -{ - lib, - util, - ... -}: let - inherit (lib) mkOption types; -in { - rtype = "TXT"; - options = { - data = mkOption { - type = types.str; - example = "favorite drink=orange juice"; - description = "Arbitrary information"; - }; - }; - dataToString = {data, ...}: util.writeCharacterString data; - fromString = data: {inherit data;}; -} diff --git a/modules/by-name/dn/dns/dns/types/records/default.nix b/modules/by-name/dn/dns/dns/types/records/default.nix deleted file mode 100644 index 76a86cd..0000000 --- a/modules/by-name/dn/dns/dns/types/records/default.nix +++ /dev/null @@ -1,43 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -{ - lib, - util, - simple, -}: let - inherit (lib.attrsets) genAttrs; - - types = [ - "A" - "AAAA" - "CAA" - "CNAME" - "DNAME" - "MX" - "NS" - "SOA" - "SRV" - "TXT" - "PTR" - - # DNSSEC types - "DNSKEY" - "DS" - - # DANE types - "SSHFP" - "TLSA" - "OPENPGPKEY" - "SVCB" - "HTTPS" - - # Pseudo types - "DKIM" - "DMARC" - "MTA-STS" - ]; -in - genAttrs types (t: import (./. + "/${t}.nix") {inherit lib simple util;}) diff --git a/modules/by-name/dn/dns/dns/types/records/dnssec.nix b/modules/by-name/dn/dns/dns/types/records/dnssec.nix deleted file mode 100644 index 648f676..0000000 --- a/modules/by-name/dn/dns/dns/types/records/dnssec.nix +++ /dev/null @@ -1,48 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Aluísio Augusto Silva Gonçalves <https://aasg.name> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -{lib}: let - inherit (builtins) attrNames isInt removeAttrs; - inherit (lib) mkOption types; -in rec { - mkRegisteredNumberOption = { - registryName, - numberType, - mnemonics, - } @ args: - mkOption - { - type = - types.either numberType (types.enum (attrNames mnemonics)) - // { - name = "registeredNumber"; - description = "number in IANA registry '${registryName}'"; - }; - apply = value: - if isInt value - then value - else mnemonics.${value}; - } - // removeAttrs args ["registryName" "numberType" "mnemonics"]; - - mkDNSSECAlgorithmOption = args: - mkRegisteredNumberOption { - registryName = "Domain Name System Security (DNSSEC) Algorithm Numbers"; - numberType = types.ints.u8; - mnemonics = { - "dsa" = 3; - "rsasha1" = 5; - "dsa-nsec3-sha1" = 6; - "rsasha1-nsec3-sha1" = 7; - "rsasha256" = 8; - "rsasha512" = 10; - "ecc-gost" = 12; - "ecdsap256sha256" = 13; - "ecdsap384sha384" = 14; - "ed25519" = 15; - "ed448" = 16; - "privatedns" = 253; - "privateoid" = 254; - }; - }; -} diff --git a/modules/by-name/dn/dns/dns/types/simple.nix b/modules/by-name/dn/dns/dns/types/simple.nix deleted file mode 100644 index fece2c9..0000000 --- a/modules/by-name/dn/dns/dns/types/simple.nix +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-FileCopyrightText: 2021 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -{lib}: let - inherit (builtins) stringLength; -in { - # RFC 1035, 3.1 - domain-name = lib.types.addCheck lib.types.str (s: stringLength s <= 255); -} diff --git a/modules/by-name/dn/dns/dns/types/zone.nix b/modules/by-name/dn/dns/dns/types/zone.nix deleted file mode 100644 index 44ccb15..0000000 --- a/modules/by-name/dn/dns/dns/types/zone.nix +++ /dev/null @@ -1,119 +0,0 @@ -# -# SPDX-FileCopyrightText: 2019 Kirill Elagin <https://kir.elagin.me/> -# SPDX-FileCopyrightText: 2021 Naïm Favier <n@monade.li> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -# -{ - lib, - util, - simple, -}: let - inherit (builtins) filter removeAttrs; - inherit - (lib) - concatMapStringsSep - concatStringsSep - mapAttrs - mapAttrsToList - optionalString - ; - inherit (lib) mkOption literalExample types; - - inherit (import ./record.nix {inherit lib;}) recordType writeRecord; - - rsubtypes = import ./records {inherit lib util simple;}; - rsubtypes' = removeAttrs rsubtypes ["SOA"]; - - subzoneOptions = - { - subdomains = mkOption { - type = types.attrsOf subzone; - default = {}; - example = { - www = { - A = [{address = "1.1.1.1";}]; - }; - staging = { - A = [{address = "1.0.0.1";}]; - }; - }; - description = "Records for subdomains of the domain"; - }; - } - // mapAttrs (n: t: - mkOption { - type = types.listOf (recordType t); - default = []; - # example = [ t.example ]; # TODO: any way to auto-generate an example for submodule? - description = "List of ${n} records for this zone/subzone"; - }) - rsubtypes'; - - subzone = types.submodule { - options = subzoneOptions; - }; - - writeSubzone = name: zone: let - groupToString = pseudo: subt: - concatMapStringsSep "\n" (writeRecord name subt) zone."${pseudo}"; - groups = mapAttrsToList groupToString rsubtypes'; - groups' = filter (s: s != "") groups; - - writeSubzone' = subname: writeSubzone "${subname}.${name}"; - sub = concatStringsSep "\n\n" (mapAttrsToList writeSubzone' zone.subdomains); - in - concatStringsSep "\n\n" groups' - + optionalString (sub != "") ("\n\n" + sub); - zone = types.submodule ({name, ...}: { - options = - { - useOrigin = mkOption { - type = types.bool; - default = false; - description = "Wether to use $ORIGIN and unqualified name or fqdn when exporting the zone."; - }; - - TTL = mkOption { - type = types.ints.unsigned; - default = 24 * 60 * 60; - example = literalExample "60 * 60"; - description = "Default record caching duration. Sets the $TTL variable"; - }; - SOA = mkOption rec { - type = recordType rsubtypes.SOA; - example = - { - ttl = 24 * 60 * 60; - } - // type.example; - description = "SOA record"; - }; - } - // subzoneOptions; - }); - renderToString = name: { - useOrigin, - TTL, - SOA, - ... - } @ zone: - if useOrigin - then '' - $ORIGIN ${name}. - $TTL ${toString TTL} - - ${writeRecord "@" rsubtypes.SOA SOA} - - ${writeSubzone "@" zone} - '' - else '' - $TTL ${toString TTL} - - ${writeRecord name rsubtypes.SOA SOA} - - ${writeSubzone name zone} - ''; -in { - inherit zone subzone renderToString; -} diff --git a/modules/by-name/dn/dns/dns/util/default.nix b/modules/by-name/dn/dns/dns/util/default.nix deleted file mode 100644 index 59e661d..0000000 --- a/modules/by-name/dn/dns/dns/util/default.nix +++ /dev/null @@ -1,76 +0,0 @@ -# SPDX-FileCopyrightText: 2021 Kirill Elagin <https://kir.elagin.me/> -# -# SPDX-License-Identifier: MPL-2.0 or MIT -{lib}: let - inherit - (builtins) - concatStringsSep - genList - stringLength - substring - ; - inherit - (lib.strings) - concatMapStrings - concatMapStringsSep - fixedWidthString - splitString - stringToCharacters - ; - inherit (lib.lists) filter reverseList; - - /* - Split a string into byte chunks, such that each output String is less then or equal to - `n` bytes. - - # Type - - splitInGroupsOf :: Integer -> String -> [String] - - # Arguments - - n - : The number of bytes to put into each String. - - s - : The String to split. - */ - splitInGroupsOf = n: s: let - groupCount = (stringLength s - 1) / n + 1; - in - genList (i: substring (i * n) n s) groupCount; - - # : str -> str - # Prepares a Nix string to be written to a zone file as a character-string - # literal: breaks it into chunks of 255 (per RFC 1035, 3.3) and encloses - # each chunk in quotation marks. - writeCharacterString = s: - if stringLength s <= 255 - then ''"${s}"'' - else concatMapStringsSep " " (x: ''"${x}"'') (splitInGroupsOf 255 s); - - # : str -> str, with length 4 (zeros are padded to the left) - align4Bytes = fixedWidthString 4 "0"; - - # : int -> str -> str - # Expands "" to 4n zeros and aligns the rest on 4 bytes - align4BytesOrExpand = n: v: - if v == "" - then (fixedWidthString (4 * n) "0" "") - else align4Bytes v; - - # : str -> [ str ] - # Returns the record of the ipv6 as a list - mkRecordAux = v6: let - splitted = splitString ":" v6; - n = 8 - builtins.length (filter (x: x != "") splitted); - in - stringToCharacters (concatMapStrings (align4BytesOrExpand n) splitted); - - # : str -> str - # Returns the reversed record of the ipv6 - mkReverseRecord = v6: - concatStringsSep "." (reverseList (mkRecordAux v6)) + ".ip6.arpa"; -in { - inherit writeCharacterString mkReverseRecord; -} diff --git a/modules/by-name/dn/dns/module.nix b/modules/by-name/dn/dns/module.nix deleted file mode 100644 index 8f4ad37..0000000 --- a/modules/by-name/dn/dns/module.nix +++ /dev/null @@ -1,86 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.dns; - - zones = - builtins.mapAttrs (name: value: { - data = - dns.types.zone.renderToString name value; - }) - cfg.zones; - - dns = import ./dns {inherit lib;}; - - ports = let - parsePorts = listeners: let - splitAddress = addr: lib.splitString "@" addr; - - extractPort = addr: let - split = splitAddress addr; - in - lib.toInt ( - if (builtins.length split) == 2 - then builtins.elemAt split 1 - else "53" - ); - in - builtins.map extractPort listeners; - in - lib.unique (parsePorts cfg.interfaces); -in { - options.vhack.dns = { - enable = lib.mkEnableOption "custom dns server"; - - openFirewall = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Open the following ports: - TCP (${lib.concatStringsSep ", " (map toString ports)}) - UDP (${lib.concatStringsSep ", " (map toString ports)}) - ''; - }; - - interfaces = lib.mkOption { - type = lib.types.listOf lib.types.str; - description = '' - A list of the interfaces to bind to. To select the port add `@` to the end of the - interface. The default port is 53. - ''; - example = [ - "192.168.1.3" - "2001:db8:1::3" - ]; - }; - - zones = lib.mkOption { - type = lib.types.attrsOf dns.types.zone.zone; - description = "DNS zones"; - }; - }; - - config = lib.mkIf cfg.enable { - services.nsd = { - enable = true; - verbosity = 4; - inherit (cfg) interfaces; - inherit zones; - }; - - networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall ports; - networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall ports; - - systemd.services.nsd = { - requires = [ - "network-online.target" - ]; - after = [ - "network.target" - "network-online.target" - ]; - }; - }; -} diff --git a/modules/by-name/et/etesync/module.nix b/modules/by-name/et/etesync/module.nix deleted file mode 100644 index bcabc8a..0000000 --- a/modules/by-name/et/etesync/module.nix +++ /dev/null @@ -1,80 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.etesync; -in { - options.vhack.etesync = { - enable = lib.mkEnableOption '' - a secure, end-to-end encrypted, and privacy respecting sync for your contacts, calendars, tasks and notes. - ''; - secretFile = lib.mkOption { - type = lib.types.path; - description = "The age encrypted globale etebase secretfile passed to agenix"; - }; - }; - - config = lib.mkIf cfg.enable { - services.etebase-server = { - enable = true; - port = 8001; - settings = { - global.secret_file = "${config.age.secrets.etebase-server.path}"; - allowed_hosts = { - allowed_host1 = "etebase.vhack.eu"; - allowed_host2 = "dav.vhack.eu"; - }; - }; - }; - - age.secrets.etebase-server = { - file = cfg.secretFile; - mode = "700"; - owner = "etebase-server"; - group = "etebase-server"; - }; - - vhack.persist.directories = [ - { - directory = "/var/lib/etebase-server"; - user = "etebase-server"; - group = "etebase-server"; - mode = "0700"; - } - ]; - - services.nginx = { - enable = true; - recommendedTlsSettings = true; - recommendedOptimisation = true; - recommendedGzipSettings = true; - recommendedProxySettings = true; - - virtualHosts = { - "etebase.vhack.eu" = { - enableACME = true; - forceSSL = true; - - locations = { - # TODO: Maybe fix permissions to use pregenerated static files which would - # improve performance. - #"/static" = { - # root = config.services.etebase-server.settings.global.static_root; - #}; - "/" = { - proxyPass = "http://127.0.0.1:${builtins.toString config.services.etebase-server.port}"; - }; - }; - serverAliases = [ - "dav.vhack.eu" - ]; - }; - }; - }; - users = { - users.etebase-server.uid = config.vhack.constants.ids.uids.etebase-server; - groups.etebase-server.gid = config.vhack.constants.ids.gids.etebase-server; - }; - }; -} diff --git a/modules/by-name/fa/fail2ban/module.nix b/modules/by-name/fa/fail2ban/module.nix deleted file mode 100644 index c619ef9..0000000 --- a/modules/by-name/fa/fail2ban/module.nix +++ /dev/null @@ -1,58 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.fail2ban; -in { - options.vhack.fail2ban = { - enable = lib.mkEnableOption "fail2ban"; - }; - - config = lib.mkIf cfg.enable { - vhack.persist.directories = [ - { - directory = "/var/lib/fail2ban"; - # TODO: Fail2ban should probably run under a dedicated `fail2ban` user. <2024-12-25> - user = "root"; - group = "root"; - mode = "0700"; - } - ]; - - services.fail2ban = { - enable = true; - maxretry = 7; # ban after 7 failures - daemonSettings = { - Definition = { - logtarget = "SYSLOG"; - socket = "/run/fail2ban/fail2ban.sock"; - pidfile = "/run/fail2ban/fail2ban.pid"; - dbfile = "/var/lib/fail2ban/db.sqlite3"; - }; - }; - bantime-increment = { - enable = true; - rndtime = "8m"; - overalljails = true; - multipliers = "2 4 16 128 256"; - maxtime = "72h"; - }; - jails = { - dovecot = '' - # block IPs which failed to log-in - # aggressive mode add blocking for aborted connections - enabled = true - filter = dovecot[mode=aggressive] - maxretry = 2 - ''; - postfix = '' - enabled = true - filter = postfix[mode=aggressive] - findtime = 600 - maxretry = 3 - ''; - }; - }; - }; -} diff --git a/modules/by-name/ga/gallery/module.nix b/modules/by-name/ga/gallery/module.nix deleted file mode 100644 index a5237e6..0000000 --- a/modules/by-name/ga/gallery/module.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.sils.gallery; -in { - options.sils.gallery = { - enable = lib.mkEnableOption "a stateful static gallery site"; - domain = lib.mkOption { - type = lib.types.str; - }; - }; - config = lib.mkIf cfg.enable { - vhack.nginx.enable = true; - services.nginx.virtualHosts."${cfg.domain}" = { - forceSSL = true; - enableACME = true; - root = "/srv/${cfg.domain}"; - }; - }; -} diff --git a/modules/by-name/gi/git-server/css.nix b/modules/by-name/gi/git-server/css.nix deleted file mode 100644 index 7d0ad06..0000000 --- a/modules/by-name/gi/git-server/css.nix +++ /dev/null @@ -1,119 +0,0 @@ -{ - cgitPkg, - pkgs, -}: let - /* - Adapted from `https://git.qyliss.net/nixlib/sys/atuin.nix`, originally distributed under - the MIT license. - */ - cgitCss = - pkgs.runCommand "cgit-extra.css" { - licenseHeader = '' - /* - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License v2 as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * See <https://www.gnu.org/licenses/>. - */ - - ''; - - # Adapted from - # <https://git.causal.agency/src/plain/www/git.causal.agency/custom.css>, - # distributed as a Larger Work under a Secondary License, - # as permitted by the terms of the - # Mozilla Public License Version 2.0. - extraCss = '' - * { line-height: 1.25em; } - - article { - font-family: sans-serif; - max-width: 70ch; - margin-left: auto; - margin-right: auto; - } - - div#cgit { - margin: auto; - font-family: monospace; - -moz-tab-size: 4; - tab-size: 4; - display: table; - } - - div#cgit table#header { - margin-left: auto; - margin-right: auto; - } - div#cgit table#header td.logo { - display: none; - } - div#cgit table#header td.main { - font-size: 1em; - font-weight: bold; - } - div#cgit table#header td.sub { - border-top: none; - } - div#cgit table.tabs { - margin-left: auto; - margin-right: auto; - border-bottom: none; - } - div#cgit div.content { - border-bottom: none; - min-width: 108ch; - } - div#cgit div.content div#summary { - display: table; - margin-left: auto; - margin-right: auto; - } - div#cgit div.notes { - border: none; - background: transparent; - padding: 0; - } - div#cgit table.list { - margin-left: auto; - margin-right: auto; - } - div#cgit table.list th a { - color: inherit; - } - div#cgit table.list tr:nth-child(even) { - background: inherit; - } - div#cgit table.list tr:hover { - background: inherit; - } - div#cgit table.list tr.nohover-highlight:hover:nth-child(even) { - background: inherit; - } - div#cgit div.footer { - font-size: 1em; - margin-top: 0; - } - - div#cgit table.blob td.linenumbers:nth-last-child(3) { - display: none; - } - - div#cgit table.blob td.linenumbers a:target { - color: goldenrod; - text-decoration: underline; - outline: none; - } - ''; - passAsFile = ["licenseHeader" "extraCss"]; - } '' - cat $licenseHeaderPath ${cgitPkg}/cgit/cgit.css $extraCssPath > $out - ''; -in - cgitCss diff --git a/modules/by-name/gi/git-server/module.nix b/modules/by-name/gi/git-server/module.nix deleted file mode 100644 index db35897..0000000 --- a/modules/by-name/gi/git-server/module.nix +++ /dev/null @@ -1,188 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - cfg = config.vhack.git-server; - - cgitCss = import ./css.nix { - inherit pkgs; - cgitPkg = - config.services.cgit."${cfg.domain}".package; - }; -in { - options.vhack.git-server = { - enable = lib.mkEnableOption '' - a lightweight git-server, realised with cgit and gitolite. - ''; - - domain = lib.mkOption { - type = lib.types.str; - default = "git.vhack.eu"; - description = '' - The domain this git instance will run under. - ''; - }; - - gitolite = { - adminPubkey = lib.mkOption { - description = '' - The initial key to use for gitolite. This will only be used for the initial - clone of the `gitolite-admin` repository. - ''; - type = lib.types.str; - default = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAe4o1PM6VasT3KZNl5NYvgkkBrPOg36dqsywd10FztS openpgp:0x21D20D6A"; - }; - }; - }; - - config = lib.mkIf cfg.enable { - programs.git = { - enable = true; - config = { - init = { - defaultBranch = "main"; - }; - }; - }; - - # Needed for the nginx proxy and the virtual host - vhack = { - nginx.enable = true; - persist.directories = [ - { - directory = "/var/lib/gitolite"; - user = "git"; - group = "git"; - mode = "0755"; - } - ]; - }; - - services = { - gitolite = { - inherit (cfg.gitolite) adminPubkey; - enable = true; - dataDir = "/var/lib/gitolite"; - user = "git"; - group = "git"; - extraGitoliteRc = '' - $RC{UMASK} = 0027; # Enable group access, important for cgit. - - # Enable modifing git variables (for cgit.owner and such things) - # These must be enable in the gitolite-admin repo (option user-configs = ...) - push( @{$RC{ENABLE}}, 'config' ); - push( @{$RC{ENABLE}}, 'git-config' ); - - push( @{$RC{ENABLE}}, 'expand-deny-messages' ); - push( @{$RC{ENABLE}}, 'Motd' ); - - push( @{$RC{ENABLE}}, 'cgit' ); - ''; - }; - - cgit."${cfg.domain}" = { - enable = true; - package = pkgs.cgit-pink; - scanPath = "${config.services.gitolite.dataDir}/repositories"; - user = "git"; - group = "git"; - settings = { - branch-sort = "age"; - - # Allow users to download a repo checkout with these compression formats - snapshots = ["tar.gz" "zip"]; - # The template used to generate the clone url for https clone. - clone-url = [ - "https://${cfg.domain}/$CGIT_REPO_URL" - "ssh://git@${cfg.domain}/$CGIT_REPO_URL" - ]; - enable-http-clone = true; - - # TODO: We might want to add an logo and readme here <2024-07-31> - # logo = "<url>"; - # root-readme = "/some/readme/file" - root-desc = "The cgit instance of ${cfg.domain}!"; - root-title = "${ - lib.strings.toUpper (builtins.substring 0 1 cfg.domain) + builtins.substring 1 (builtins.stringLength cfg.domain) cfg.domain - } cgit instace"; - - # Set the default maximum statistics period. Valid values are "week", - # "month", "quarter" and "year". - max-stats = "week"; - - readme = [ - ":README.md" - ":readme.md" - ":README.mkd" - ":readme.mkd" - ":README.rst" - ":readme.rst" - ":README.html" - ":readme.html" - ":README.htm" - ":readme.htm" - ":README.txt" - ":readme.txt" - ":README" - ":readme" - ":INSTALL.md" - ":install.md" - ":INSTALL.mkd" - ":install.mkd" - ":INSTALL.rst" - ":install.rst" - ":INSTALL.html" - ":install.html" - ":INSTALL.htm" - ":install.htm" - ":INSTALL.txt" - ":install.txt" - ":INSTALL" - ":install" - ]; - - enable-blame = true; - enable-commit-graph = true; - enable-subject-links = true; - enable-follow-links = true; - enable-index-links = true; - enable-index-owner = true; - - # NOTE: This allows cgit to take configuration from the bare git repositories: - # All `repo.<key>` can be set by setting `cgit.<key>` in the git config. E.g.: - # setting the owner (i.e. `repo.owner`) would be done by setting the - # `cgit.owner` config. All repo options are outline in the cgitrc (5) man page. - enable-git-config = true; - - # Remove the `.git` suffix from scanned repositories (this must be set _before_ `scan-path`) - remove-suffix = true; - - css = "/custom_cgit.css"; - - # This is a number of path elements to treat as section. - # `-1` means that we treat the last element as name, all others as sections - section-from-path = -1; - - project-list = "${config.services.gitolite.dataDir}/projects.list"; - - # TODO: We might want to use the kernel.org `libravatar.lua` email-filter <2024-07-31> - source-filter = "${config.services.cgit."${cfg.domain}".package}/lib/cgit/filters/syntax-highlighting.py"; - about-filter = "${config.services.cgit."${cfg.domain}".package}/lib/cgit/filters/about-formatting.sh"; - }; - }; - - nginx.virtualHosts."${cfg.domain}" = { - enableACME = true; - forceSSL = true; - - locations = { - "= /custom_cgit.css" = { - alias = cgitCss.outPath; - }; - }; - }; - }; - }; -} diff --git a/modules/by-name/im/impermanence/module.nix b/modules/by-name/im/impermanence/module.nix deleted file mode 100644 index 1c916e2..0000000 --- a/modules/by-name/im/impermanence/module.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.persist; -in { - options.vhack.persist = { - enable = lib.mkEnableOption "impermanence"; - - directories = lib.mkOption { - description = "The list of directories to persist"; - type = lib.types.listOf (lib.types.coercedTo lib.types.str (d: {directory = d;}) (lib.types.attrsOf lib.types.anything)); - }; - }; - - config = lib.mkIf cfg.enable { - environment.persistence."/srv" = { - hideMounts = true; - directories = - [ - "/etc/nixos" - ] - ++ cfg.directories; - files = [ - "/etc/machine-id" - ]; - }; - }; -} diff --git a/modules/by-name/in/invidious-router/module.nix b/modules/by-name/in/invidious-router/module.nix deleted file mode 100644 index f85a06c..0000000 --- a/modules/by-name/in/invidious-router/module.nix +++ /dev/null @@ -1,70 +0,0 @@ -{ - config, - lib, - pkgsUnstable, - ... -}: let - cfg = config.vhack.invidious-router; -in { - options.vhack.invidious-router = { - enable = lib.mkEnableOption "invidious-router"; - domain = lib.mkOption { - type = lib.types.str; - description = "The domain invidious-router should be served on"; - }; - extraDomains = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = []; - description = "Addtional domains invidious-router should be served on"; - }; - }; - config = lib.mkIf cfg.enable { - services.invidious-router = { - enable = true; - package = pkgsUnstable.invidious-router; - settings = { - app = { - listen = "127.0.0.1:8050"; - enable_youtube_fallback = false; - reload_instance_list_interval = "60s"; - not_available_message = '' - No available invidious instance found! - [link]View this video on YouTube[/link], a proprietary - platform that collects and uses your data without respecting - your privacy. - ''; - }; - api = { - enabled = true; - url = "https://api.invidious.io/instances.json"; - filter_regions = false; - allowed_regions = [ - "AT" - "DE" - "CH" - ]; - }; - healthcheck = { - path = "/watch?v=uSvJaYxRoB4"; - allowed_status_codes = [ - 200 - ]; - timeout = "1s"; - interval = "10s"; - filter_by_response_time = { - enabled = true; - qty_of_top_results = 4; - }; - minimum_ratio = 0.2; - remove_no_ratio = false; - text_not_present = "YouTube is currently trying to block Invidious instances"; - }; - }; - nginx = { - enable = true; - inherit (cfg) domain extraDomains; - }; - }; - vhack.nginx.enable = true; - }; -} diff --git a/modules/by-name/ma/mail/module.nix b/modules/by-name/ma/mail/module.nix deleted file mode 100644 index 55f2fb8..0000000 --- a/modules/by-name/ma/mail/module.nix +++ /dev/null @@ -1,167 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.mail; - all_admins = [ - "sils@vhack.eu" - "soispha@vhack.eu" - "nightingale@vhack.eu" - ]; -in { - options.vhack.mail = { - enable = lib.mkEnableOption "sophisticated mail setup with simple-nixos-mailserver"; - fqdn = lib.mkOption { - type = lib.types.str; - description = "The fqdn mailserver should be served on."; - }; - }; - - config = lib.mkIf cfg.enable { - vhack.persist.directories = [ - { - directory = "/var/lib/mail/backup"; - user = "virtualMail"; - group = "virtualMail"; - mode = "0700"; - } - { - directory = "/var/lib/mail/sieve"; - user = "virtualMail"; - group = "virtualMail"; - mode = "0700"; - } - { - directory = "/var/lib/mail/vmail"; - user = "virtualMail"; - group = "virtualMail"; - mode = "0700"; - } - { - directory = "/var/lib/mail/dkim"; - user = "opendkim"; - group = "opendkim"; - mode = "0700"; - } - { - directory = "/var/lib/postfix/data"; - user = "postfix"; - group = "postfix"; - mode = "0700"; - } - { - directory = "/var/lib/postfix/queue"; - user = "postfix"; - group = "postfix"; - mode = "0700"; - } - { - directory = "/var/lib/rspamd"; - user = "rspamd"; - group = "rspamd"; - mode = "0700"; - } - ]; - vhack.nginx.enable = true; - security.acme.certs = { - "${cfg.fqdn}" = { - domain = cfg.fqdn; - }; - }; - mailserver = { - enable = true; - inherit (cfg) fqdn; - - useFsLayout = true; - - extraVirtualAliases = { - "abuse@vhack.eu" = all_admins; - "postmaster@vhack.eu" = all_admins; - "admin@vhack.eu" = all_admins; - }; - - mailDirectory = "/var/lib/mail/vmail"; - dkimKeyDirectory = "/var/lib/mail/dkim"; - sieveDirectory = "/var/lib/mail/sieve"; - backup.snapshotRoot = "/var/lib/mail/backup"; - - enableImap = false; - enableImapSsl = true; - enablePop3 = false; - enablePop3Ssl = true; - # SMTP - enableSubmission = false; - enableSubmissionSsl = true; - openFirewall = true; - - keyFile = "/var/lib/acme/${cfg.fqdn}/key.pem"; - certificateScheme = "acme"; - certificateFile = "/var/lib/acme/${cfg.fqdn}/fullchain.pem"; - - domains = [ - "vhack.eu" - - "s-schoeffel.de" - "b-peetz.de" - - "sils.li" - "nightingale.sils.li" - "sils.sils.li" - ]; - - loginAccounts = { - "sils@vhack.eu" = { - hashedPassword = "$2b$05$RW/Svgk7iGxvP5W7ZwUZ1e.a3fj4fteevb2MtfFYYD0d1DQ17y9Fm"; - }; - "soispha@vhack.eu" = { - hashedPassword = "$2b$05$XX36sJuHNbTFvi8DFldscOeQBHahluSkiUqD9QGzQaET7NJusSuQW"; - }; - - "benedikt.peetz@b-peetz.de" = { - hashedPassword = "$2b$05$MfET8utot2OolPZNASqoDe4VXNoG2chnEWhdfQ2E92mit0TvI2gBy"; - aliases = ["@b-peetz.de"]; - }; - "silas.schoeffel@s-schoeffel.de" = { - hashedPassword = "$2b$05$Qb8rl7ncpCcTbsSdsduJBuOITp8RTD6sfOTjuxJsVtD9vjAYY9n8e"; - aliases = ["@s-schoeffel.de"]; - }; - - "nightingale@vhack.eu" = { - hashedPassword = "$2b$05$nDKVVq1EktKXWqGFhnOLP.plLovXFyvWSuptK9GIkxA5DScKFx6YS"; - aliases = [ - "@nightingale.sils.li" - ]; - }; - "sils@sils.li" = { - hashedPassword = "$2b$05$Ebzh2ZhuWkz1p4tqJ172IejNZg10FtCxPDY4k6umYrpirXg7ezIRq"; - aliases = [ - "@sils.sils.li" - "@sils.li" - ]; - }; - - # Mail-Account used by hosted software - "mastodon@vhack.eu" = { - hashedPassword = "$2b$05$pSby3x2p3cHg0FyAE8IiJ.nYUqtAIR10JA8HNpHwMAiLXqc.ltSK."; - }; - "peertube@vhack.eu" = { - hashedPassword = "$y$j9T$hyWQ8Awd2Xrc6qsK.2hwE1$LxACfaeW.yHGbkQL95dWtID9.zXL/aMwT6lp.yU/0g0"; - }; - }; - }; - - users = { - users = { - knot-resolver.uid = config.vhack.constants.ids.uids.knot-resolver; - redis-rspamd.uid = config.vhack.constants.ids.uids.redis-rspamd; - rspamd.uid = config.vhack.constants.ids.uids.rspamd; - }; - groups = { - knot-resolver.gid = lib.mkForce config.vhack.constants.ids.gids.knot-resolver; - redis-rspamd.gid = config.vhack.constants.ids.gids.redis-rspamd; - rspamd.gid = config.vhack.constants.ids.gids.rspamd; - }; - }; - }; -} diff --git a/modules/by-name/ma/mastodon/module.nix b/modules/by-name/ma/mastodon/module.nix deleted file mode 100644 index 84f3ec8..0000000 --- a/modules/by-name/ma/mastodon/module.nix +++ /dev/null @@ -1,128 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: let - emailAddress = "mastodon@vhack.eu"; - applyPatches = pkg: - pkg.overrideAttrs (attrs: { - patches = (attrs.patches or []) ++ [./patches/0001-feat-treewide-Increase-character-limit-to-5000-in-me.patch]; - }); - cfg = config.vhack.mastodon; -in { - options.vhack.mastodon = { - enable = lib.mkEnableOption "a mastodon instance"; - domain = lib.mkOption { - type = lib.types.str; - description = "The Domain mastodon should be served on"; - example = "mastodon.vhack.eu"; - }; - enableTLD = lib.mkEnableOption "using the tld as handle, configured via - webfinger (note: this requires the tld to point to the same server as domain)"; - tld = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - example = "vhack.eu"; - }; - mailPwFile = lib.mkOption { - type = lib.types.path; - description = "The age encrypted mail password file passed to agenix"; - }; - }; - config = lib.mkIf cfg.enable { - age.secrets.mastodonMail = { - file = cfg.mailPwFile; - mode = "700"; - owner = "mastodon"; - group = "mastodon"; - }; - - vhack = { - persist.directories = [ - { - directory = "/var/lib/mastodon"; - user = "mastodon"; - group = "mastodon"; - mode = "0700"; - } - ]; - - postgresql.enable = true; - - nginx.enable = true; - }; - - services.mastodon = { - enable = true; - - package = applyPatches pkgs.mastodon; - - # Unstable Mastodon package, used if - # security updates aren't backported. - #package = applyPatches pkgsUnstable.mastodon; - - localDomain = - if cfg.enableTLD - then cfg.tld - else cfg.domain; - smtp = { - authenticate = true; - createLocally = false; - fromAddress = emailAddress; - user = emailAddress; - host = "mail.foss-syndicate.org"; - passwordFile = config.age.secrets.mastodonMail.path; - }; - streamingProcesses = 3; # Number of Cores - 1 - extraConfig = { - WEB_DOMAIN = cfg.domain; - EMAIL_DOMAIN_ALLOWLIST = "vhack.eu|sils.li"; - }; - }; - - services.nginx = { - enable = true; - recommendedProxySettings = true; # required for redirections to work - virtualHosts = { - "${cfg.domain}" = { - root = "${config.services.mastodon.package}/public/"; - # mastodon only supports https, but you can override this if you offload tls elsewhere. - forceSSL = true; - enableACME = true; - - locations = { - "/system/".alias = "/var/lib/mastodon/public-system/"; - "/".tryFiles = "$uri @proxy"; - "@proxy" = { - proxyPass = "http://unix:/run/mastodon-web/web.socket"; - proxyWebsockets = true; - }; - "/api/v1/streaming/" = { - proxyPass = "http://unix:/run/mastodon-streaming/streaming.socket"; - proxyWebsockets = true; - }; - }; - }; - "${cfg.tld}" = - if cfg.enableTLD - then { - locations."/.well-known/webfinger".return = "301 https://${cfg.domain}$request_uri"; - } - else {}; - }; - }; - - users = { - users.mastodon.uid = config.vhack.constants.ids.uids.mastodon; - users.redis-mastodon.uid = config.vhack.constants.ids.uids.redis-mastodon; - groups.redis-mastodon.gid = config.vhack.constants.ids.gids.redis-mastodon; - groups.mastodon = { - gid = config.vhack.constants.ids.gids.mastodon; - members = [ - config.services.nginx.user - ]; - }; - }; - }; -} diff --git a/modules/by-name/ma/mastodon/patches/0001-feat-treewide-Increase-character-limit-to-5000-in-me.patch b/modules/by-name/ma/mastodon/patches/0001-feat-treewide-Increase-character-limit-to-5000-in-me.patch deleted file mode 100644 index 35dc809..0000000 --- a/modules/by-name/ma/mastodon/patches/0001-feat-treewide-Increase-character-limit-to-5000-in-me.patch +++ /dev/null @@ -1,40 +0,0 @@ -From ab67426c53d343eee349de501767ecbbf5d211ad Mon Sep 17 00:00:00 2001 -From: Benedikt Peetz <benedikt.peetz@b-peetz.de> -Date: Sat, 21 Dec 2024 20:07:11 +0100 -Subject: [PATCH] feat(treewide): Increase character limit to 5000 in messages - -The default of 500 was just not enough. ---- - .../features/compose/containers/compose_form_container.js | 2 +- - app/validators/status_length_validator.rb | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/app/javascript/mastodon/features/compose/containers/compose_form_container.js b/app/javascript/mastodon/features/compose/containers/compose_form_container.js -index bda2edba6..76ac65bf3 100644 ---- a/app/javascript/mastodon/features/compose/containers/compose_form_container.js -+++ b/app/javascript/mastodon/features/compose/containers/compose_form_container.js -@@ -28,7 +28,7 @@ const mapStateToProps = state => ({ - anyMedia: state.getIn(['compose', 'media_attachments']).size > 0, - isInReply: state.getIn(['compose', 'in_reply_to']) !== null, - lang: state.getIn(['compose', 'language']), -- maxChars: state.getIn(['server', 'server', 'configuration', 'statuses', 'max_characters'], 500), -+ maxChars: state.getIn(['server', 'server', 'configuration', 'statuses', 'max_characters'], 5000), - }); - - const mapDispatchToProps = (dispatch) => ({ -diff --git a/app/validators/status_length_validator.rb b/app/validators/status_length_validator.rb -index dc841ded3..9cb1ec94b 100644 ---- a/app/validators/status_length_validator.rb -+++ b/app/validators/status_length_validator.rb -@@ -1,7 +1,7 @@ - # frozen_string_literal: true - - class StatusLengthValidator < ActiveModel::Validator -- MAX_CHARS = 500 -+ MAX_CHARS = 5000 - URL_PLACEHOLDER_CHARS = 23 - URL_PLACEHOLDER = 'x' * 23 - --- -2.47.0 - diff --git a/modules/by-name/ma/matrix/module.nix b/modules/by-name/ma/matrix/module.nix deleted file mode 100644 index f34ecf4..0000000 --- a/modules/by-name/ma/matrix/module.nix +++ /dev/null @@ -1,179 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.matrix; - clientConfig."m.homeserver".base_url = "https://${cfg.fqdn}"; - serverConfig."m.server" = "${cfg.fqdn}:443"; - mkWellKnown = data: '' - add_header Content-Type application/json; - add_header Access-Control-Allow-Origin *; - return 200 '${builtins.toJSON data}'; - ''; -in { - options.vhack.matrix = { - enable = lib.mkEnableOption "matrix setup based on synapse"; - fqdn = lib.mkOption { - type = lib.types.str; - description = "The FQDN on which matrix-synapse should be served."; - example = "matrix.vhack.eu"; - }; - url = lib.mkOption { - type = lib.types.str; - description = "The url the matrix-server should be known under."; - }; - sharedSecretFile = lib.mkOption { - type = lib.types.path; - description = "The age encrypted shared secret file for synapse, passed to agenix"; - }; - }; - - config = lib.mkIf cfg.enable { - age.secrets.matrix-synapse_registration_shared_secret = { - file = cfg.sharedSecretFile; - mode = "700"; - owner = "matrix-synapse"; - group = "matrix-synapse"; - }; - networking.firewall.allowedTCPPorts = [80 443]; - - vhack = { - persist.directories = [ - { - directory = "/var/lib/matrix"; - user = "matrix-synapse"; - group = "matrix-synapse"; - mode = "0700"; - } - { - directory = "/var/lib/mautrix-whatsapp"; - user = "mautrix-whatsapp"; - group = "matrix-synapse"; - mode = "0750"; - } - ]; - - postgresql.enable = true; - nginx.enable = true; - }; - - systemd = { - tmpfiles.rules = [ - "d /etc/matrix 0755 matrix-synapse matrix-synapse" - ]; - services.postgresql.postStart = '' - $PSQL -tAc "ALTER ROLE matrix-synapse WITH ENCRYPTED PASSWORD 'synapse';" - $PSQL -tAc "ALTER ROLE mautrix-whatsapp WITH ENCRYPTED PASSWORD 'whatsapp';" - ''; - }; - - services = { - postgresql = { - enable = true; - ensureUsers = [ - { - name = "matrix-synapse"; - ensureDBOwnership = true; - } - { - name = "mautrix-whatsapp"; - ensureDBOwnership = true; - } - ]; - ensureDatabases = [ - "matrix-synapse" - "mautrix-whatsapp" - ]; - }; - - nginx = { - enable = true; - recommendedTlsSettings = true; - recommendedOptimisation = true; - recommendedGzipSettings = true; - recommendedProxySettings = true; - virtualHosts = { - "${cfg.url}" = { - enableACME = true; - forceSSL = true; - locations = { - "/.well-known/matrix/server".extraConfig = mkWellKnown serverConfig; - "/.well-known/matrix/client".extraConfig = mkWellKnown clientConfig; - }; - }; - "${cfg.fqdn}" = { - enableACME = true; - forceSSL = true; - locations = { - "/".return = "404"; - "/_matrix".proxyPass = "http://[::1]:8008"; - "/_synapse/client".proxyPass = "http://[::1]:8008"; - }; - }; - }; - }; - - mautrix-whatsapp = { - # FIXME(@bpeetz): This was disabled because `mautrix-whatsapp` dependends on libolm. - # Re-enable it, when this has changed. <2024-09-06> - enable = false; - settings = { - appservice = { - database = { - type = "postgres"; - uri = "postgres:///mautrix-whatsapp?host=/run/postgresql"; - }; - whatsapp = { - # TODO: See https://github.com/tulir/whatsmeow/blob/efc632c008604016ddde63bfcfca8de4e5304da9/binary/proto/def.proto#L43-L64 for a list. - # This also determines the WhatsApp icon - browser_name = "unknown"; - }; - }; - homeserver.address = "https://${cfg.fqdn}"; - bridge.permissions = { - "@soispha:vhack.eu" = "admin"; - "@sils:vhack.eu" = "admin"; - "@nightingale:vhack.eu" = "admin"; - }; - }; - }; - - matrix-synapse = { - enable = true; - dataDir = "/var/lib/matrix"; - configFile = "/etc/matrix/matrix.conf"; - settings = { - media_store_path = "/var/lib/matrix/media_store"; - registration_shared_secret_path = "${config.age.secrets.matrix-synapse_registration_shared_secret.path}"; - server_name = cfg.url; - listeners = [ - { - port = 8008; - bind_addresses = ["::1"]; - type = "http"; - tls = false; - x_forwarded = true; - resources = [ - { - names = ["client" "federation"]; - compress = true; - } - ]; - } - ]; - }; - }; - }; - users = { - users = { - matrix-synapse.uid = config.vhack.constants.ids.uids.matrix-synapse; - mautrix-whatsapp = { - uid = config.vhack.constants.ids.uids.mautrix-whatsapp; - group = "matrix-synapse"; - }; - }; - groups.matrix-synapse.gid = config.vhack.constants.ids.gids.matrix-synapse; - }; - }; -} diff --git a/modules/by-name/mi/miniflux/module.nix b/modules/by-name/mi/miniflux/module.nix deleted file mode 100644 index 0075bca..0000000 --- a/modules/by-name/mi/miniflux/module.nix +++ /dev/null @@ -1,55 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.miniflux; -in { - options.vhack.miniflux = { - enable = lib.mkEnableOption "miniflux, an simple web rss reading software"; - domain = lib.mkOption { - type = lib.types.str; - description = "The primary domain miniflux should be served on"; - }; - extraDomains = lib.mkOption { - type = lib.types.listOf lib.types.str; - description = "Additional domains to serve miniflux on"; - default = []; - }; - adminCredentialsFile = lib.mkOption { - type = lib.types.path; - description = "The age encrypted admin credentials file passed to agenix"; - }; - }; - config = lib.mkIf cfg.enable { - age.secrets = { - minifluxAdmin = { - file = cfg.adminCredentialsFile; - mode = "700"; - owner = "root"; - group = "root"; - }; - }; - services.miniflux = { - enable = true; - config = { - LISTEN_ADDR = "127.0.0.1:5892"; - }; - adminCredentialsFile = config.age.secrets.minifluxAdmin.path; - }; - - vhack = { - nginx.enable = true; - postgresql.enable = true; - }; - services.nginx = { - virtualHosts.${cfg.domain} = { - locations."/".proxyPass = "http://${config.services.miniflux.config.LISTEN_ADDR}"; - - enableACME = true; - forceSSL = true; - serverAliases = cfg.extraDomains; - }; - }; - }; -} diff --git a/modules/by-name/mu/murmur/module.nix b/modules/by-name/mu/murmur/module.nix deleted file mode 100644 index 5cc6f7d..0000000 --- a/modules/by-name/mu/murmur/module.nix +++ /dev/null @@ -1,80 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.murmur; -in { - options.vhack.murmur = { - enable = lib.mkEnableOption "murmur, a mumble server software"; - murmurStore = lib.mkOption { - type = lib.types.str; - default = "/var/lib/murmur"; - description = "The location of murmurs data dir."; - }; - host = lib.mkOption { - type = lib.types.str; - description = "The domain murmur should be served on."; - example = "mumble.vhack.eu"; - }; - url = lib.mkOption { - type = lib.types.str; - description = "The url this instance should be registered under. Note that - this is not the domain mumur is served on"; - example = "vhack.eu"; - }; - name = lib.mkOption { - type = lib.types.str; - description = "The name this instance should be registered under."; - example = "vhack"; - }; - }; - config = lib.mkIf cfg.enable { - vhack.persist.directories = [ - { - directory = cfg.murmurStore; - user = "murmur"; - group = "murmur"; - mode = "0700"; - } - ]; - - services.murmur = { - enable = true; - openFirewall = true; - welcometext = '' - <b>You never get a second chance to make a first impression</b><br> - - The entire team of [name of the company] is thrilled to welcome you on board. We hope you’ll do some amazing work here! - ''; - sslKey = "${cfg.murmurStore}/key.pem"; - sslCert = "${cfg.murmurStore}/fullchain.pem"; - - registerUrl = cfg.url; - registerName = cfg.name; - registerHostname = cfg.host; - hostName = cfg.host; - clientCertRequired = true; - bandwidth = 7200000; - }; - - security.acme.certs.murmur = { - domain = cfg.host; - postRun = - /* - bash - */ - '' - set -x - rm "${cfg.murmurStore}/key.pem" - rm "${cfg.murmurStore}/fullchain.pem" - - cp key.pem "${cfg.murmurStore}"; - cp fullchain.pem "${cfg.murmurStore}"; - - chown murmur:murmur "${cfg.murmurStore}/key.pem" - chown murmur:murmur "${cfg.murmurStore}/fullchain.pem" - ''; - }; - }; -} diff --git a/modules/by-name/ne/nextcloud/module.nix b/modules/by-name/ne/nextcloud/module.nix deleted file mode 100644 index 2e40970..0000000 --- a/modules/by-name/ne/nextcloud/module.nix +++ /dev/null @@ -1,78 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: let - cfg = config.vhack.nextcloud; -in { - options.vhack.nextcloud = { - enable = lib.mkEnableOption "a sophisticated nextcloud setup"; - package = lib.mkOption { - type = lib.types.package; - default = pkgs.nextcloud31; - description = "The nextcloud package to use"; - }; - hostname = lib.mkOption { - type = lib.types.str; - description = "The nextcloud hostname (fqdn)"; - }; - adminpassFile = lib.mkOption { - type = lib.types.path; - description = "The age encrypted admin password file"; - }; - }; - config = lib.mkIf cfg.enable { - vhack = { - nginx.enable = true; - postgresql.enable = true; - persist.directories = [ - "/var/lib/nextcloud" - ]; - }; - age.secrets = { - adminpassFile = { - file = cfg.adminpassFile; - mode = "0700"; - owner = "nextcloud"; - group = "nextcloud"; - }; - }; - - services = { - nextcloud = { - enable = true; - configureRedis = true; - config = { - adminuser = "admin"; - adminpassFile = config.age.secrets.adminpassFile.path; - dbname = "nextcloud"; - dbuser = "nextcloud"; - dbtype = "pgsql"; - }; - database.createLocally = true; - hostName = cfg.hostname; - https = true; - maxUploadSize = "5G"; - package = cfg.package; - settings = { - default_phone_region = "DE"; - }; - }; - nginx.virtualHosts.${cfg.hostname} = { - forceSSL = true; - enableACME = true; - }; - }; - users = { - users = { - "nextcloud".uid = config.vhack.constants.ids.uids.nextcloud; - "redis-nextcloud".uid = config.vhack.constants.ids.uids.redis-nextcloud; - }; - groups = { - "nextcloud".gid = config.vhack.constants.ids.gids.nextcloud; - "redis-nextcloud".gid = config.vhack.constants.ids.gids.redis-nextcloud; - }; - }; - }; -} diff --git a/modules/by-name/ng/nginx/module.nix b/modules/by-name/ng/nginx/module.nix deleted file mode 100644 index fa3337d..0000000 --- a/modules/by-name/ng/nginx/module.nix +++ /dev/null @@ -1,74 +0,0 @@ -{ - lib, - config, - ... -}: let - mkRedirect = _: value: { - forceSSL = true; - enableACME = true; - locations."/".return = "301 ${value}$request_uri"; - }; - - redirects = builtins.mapAttrs mkRedirect cfg.redirects; - - cfg = config.vhack.nginx; -in { - options.vhack.nginx = { - enable = lib.mkEnableOption '' - a default nginx config. - ''; - - selfsign = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Whether to selfsign the acme certificates. This should only - really be useful for tests. - ''; - }; - - redirects = lib.mkOption { - type = lib.types.attrsOf lib.types.str; - default = {}; - description = '' - An attrset of redirects to add. - The keys are the domain that should than be redirected to the url specified as - value. - ''; - }; - }; - - config = lib.mkIf cfg.enable { - vhack.persist.directories = [ - "/var/lib/acme" - ]; - - users = { - users.acme = { - uid = config.vhack.constants.ids.uids.acme; - group = "acme"; - }; - groups.acme.gid = config.vhack.constants.ids.gids.acme; - }; - - security.acme = { - acceptTerms = true; - defaults = { - email = "admin@vhack.eu"; - webroot = "/var/lib/acme/acme-challenge"; - - # Avoid spamming the acme server, if we run in a test, and only really want self-signed - # certificates - server = lib.mkIf cfg.selfsign "https://127.0.0.1"; - }; - }; - - networking.firewall = { - allowedTCPPorts = [80 443]; - }; - services.nginx = { - enable = true; - virtualHosts = redirects; - }; - }; -} diff --git a/modules/by-name/ni/nix-sync/internal_module.nix b/modules/by-name/ni/nix-sync/internal_module.nix deleted file mode 100644 index 4e28586..0000000 --- a/modules/by-name/ni/nix-sync/internal_module.nix +++ /dev/null @@ -1,299 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - cfg = config.services.nix-sync; - esa = lib.strings.escapeShellArg; - - mkTimer = name: repo: { - description = "Nix sync ${name} timer"; - wantedBy = ["timers.target"]; - timerConfig = { - OnUnitActiveSec = repo.interval; - }; - wants = ["network-online.target"]; - after = ["network-online.target"]; - }; - - parents = path: let - split_path = builtins.split "/" path; - filename = builtins.elemAt split_path (builtins.length split_path - 1); - path_build = - lib.strings.removeSuffix "/" (builtins.replaceStrings [filename] [""] path); - final_path = - if filename == "" - then parents path_build - else path_build; - in - final_path; - - mkUnit = name: repo: let - optionalPathSeparator = - if lib.strings.hasPrefix "/" repo.path - then "" - else "/"; - /* - * `ln` tries to create a symlink in the directory, if the target ends with a '/', - * thus remove it. - */ - repoPath = lib.strings.removeSuffix "/" repo.path; - - repoCachePath = cfg.cachePath + optionalPathSeparator + repo.path; - execStartScript = pkgs.writeScript "nix-sync-exec" '' - #! /usr/bin/env dash - export XDG_CACHE_HOME="$CACHE_DIRECTORY"; - cd ${esa repoCachePath}; - - git fetch - origin="$(git rev-parse @{u})"; - branch="$(git rev-parse @)"; - - if ! [ "$origin" = "$branch" ]; then - git pull --rebase; - - out_paths=$(mktemp); - nix build . --print-out-paths --experimental-features 'nix-command flakes' > "$out_paths"; - [ "$(wc -l < "$out_paths")" -gt 1 ] && { echo "To many out-paths"; exit 1; } - out_path="$(cat "$out_paths")"; - rm ${esa repoPath}; - ln -s "$out_path" ${esa repoPath}; - rm "$out_paths"; - fi - ''; - execStartPreScript = '' - export XDG_CACHE_HOME="$CACHE_DIRECTORY"; - - if ! [ -d ${esa repoCachePath}/.git ]; then - mkdir --parents ${esa repoCachePath}; - git clone ${esa repo.uri} ${esa repoCachePath}; - - out_paths=$(mktemp); - nix build ${esa repoCachePath} --print-out-paths --experimental-features 'nix-command flakes' > "$out_paths"; - [ "$(wc -l < "$out_paths")" -gt 1 ] && { echo "To many out-paths"; exit 1; } - out_path="$(cat "$out_paths")"; - ln -s "$out_path" ${esa repoPath}; - rm "$out_paths"; - fi - - if ! [ -L ${esa repoPath} ]; then - cd ${esa repoCachePath}; - - git pull --rebase; - - out_paths=$(mktemp); - nix build . --print-out-paths --experimental-features 'nix-command flakes' > "$out_paths"; - [ "$(wc -l < "$out_paths")" -gt 1 ] && { echo "To many out-paths"; exit 1; } - out_path="$(cat "$out_paths")"; - - if [ -d ${esa repoPath} ]; then - rm -d ${esa repoPath}; - else - mkdir --parents "$(dirname ${esa repoPath})"; - fi - [ -e ${esa repoPath} ] && rm ${esa repoPath}; - - ln -s "$out_path" ${esa repoPath}; - rm "$out_paths"; - fi - ''; - in { - description = "Nix Sync ${name}"; - wantedBy = ["default.target"]; - after = ["network.target"]; - path = with pkgs; [openssh git nix mktemp coreutils dash]; - preStart = execStartPreScript; - - serviceConfig = { - TimeoutSec = 0; - ExecStart = execStartScript; - Restart = "on-abort"; - # User and group - User = cfg.user; - Group = cfg.group; - # Runtime directory and mode - RuntimeDirectory = "nix-sync"; - RuntimeDirectoryMode = "0750"; - # Cache directory and mode - CacheDirectory = "nix-sync"; - CacheDirectoryMode = "0750"; - # Logs directory and mode - LogsDirectory = "nix-sync"; - LogsDirectoryMode = "0750"; - # Proc filesystem - ProcSubset = "all"; - ProtectProc = "invisible"; - # New file permissions - UMask = "0027"; # 0640 / 0750 - # Capabilities - AmbientCapabilities = ["CAP_CHOWN"]; - CapabilityBoundingSet = ["CAP_CHOWN"]; - # Security - NoNewPrivileges = true; - # Sandboxing (sorted by occurrence in https://www.freedesktop.org/software/systemd/man/systemd.exec.html) - ReadWritePaths = ["${esa (parents repo.path)}" "-${esa (parents repoCachePath)}" "-${esa cfg.cachePath}"]; - ReadOnlyPaths = ["/nix"]; # TODO: Should be irrelevant, as we have ProtectSystem=Strict <2024-06-01> - ProtectSystem = "strict"; - ProtectHome = true; - PrivateTmp = true; - PrivateDevices = true; - ProtectHostname = true; - ProtectClock = true; - ProtectKernelTunables = true; - ProtectKernelModules = true; - ProtectKernelLogs = true; - ProtectControlGroups = true; - RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"]; - RestrictNamespaces = true; - LockPersonality = true; - MemoryDenyWriteExecute = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - RemoveIPC = true; - PrivateMounts = true; - # System Call Filtering - SystemCallArchitectures = "native"; - SystemCallFilter = ["~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid"]; - }; - }; - - services = - lib.mapAttrs' (name: repo: { - name = "nix-sync-${name}"; - value = mkUnit name repo; - }) - cfg.repositories; - timers = - lib.mapAttrs' (name: repo: { - name = "nix-sync-${name}"; - value = mkTimer name repo; - }) - cfg.repositories; - - # generate the websites directory, so systemd can mount it read write - generatedDirectories = - lib.mapAttrsToList ( - _: repo: "d ${esa (parents repo.path)} 0755 ${cfg.user} ${cfg.group}" - ) - cfg.repositories; - - repositoryType = lib.types.submodule ({name, ...}: { - options = { - name = lib.mkOption { - internal = true; - default = name; - type = lib.types.str; - description = "The name that should be given to this unit."; - }; - - path = lib.mkOption { - type = lib.types.str; - description = "The path at which to sync the repository"; - }; - - uri = lib.mkOption { - type = lib.types.str; - example = "ssh://user@example.com:/~[user]/path/to/repo.git"; - description = '' - The URI of the remote to be synchronized. This is only used in the - event that the directory does not already exist. See - <link xlink:href="https://git-scm.com/docs/git-clone#_git_urls"/> - for the supported URIs. - ''; - }; - - extraSettings = lib.mkOption { - type = lib.types.attrsOf lib.types.anything; - example = lib.literalExpression '' - { - locations."/.well-known/openpgpkey/hu/" = { - extraConfig = \'\' - default_type application/octet-stream; - - add_header Access-Control-Allow-Origin * always; - \'\'; - }; - } - ''; - description = '' - Extra config to add the the nginx virtual host. - ''; - }; - - interval = lib.mkOption { - type = lib.types.int; - default = 500; - description = '' - The interval, specified in seconds, at which the synchronization will - be triggered. - ''; - }; - }; - }); -in { - options = { - services.nix-sync = { - enable = lib.mkEnableOption "nix-sync services"; - - user = lib.mkOption { - type = lib.types.str; - default = "nix-sync"; - description = lib.mdDoc "User account under which nix-sync units runs."; - }; - - group = lib.mkOption { - type = lib.types.str; - default = "nix-sync"; - description = lib.mdDoc "Group account under which nix-sync units runs."; - }; - - cachePath = lib.mkOption { - type = lib.types.str; - default = "/var/lib/nix-sync"; - description = lib.mdDoc '' - Where to cache git directories. Should not end with a slash ("/") - ''; - }; - - repositories = lib.mkOption { - type = with lib.types; attrsOf repositoryType; - description = '' - The repositories that should be synchronized. - ''; - }; - }; - }; - - config = lib.mkIf cfg.enable { - assertions = [ - { - assertion = !lib.strings.hasSuffix "/" cfg.cachePath; - message = "Your cachePath ('${cfg.cachePath}') ends with a slash ('/'), please use: '${lib.strings.removeSuffix "/" cfg.cachePath}'."; - } - ]; - systemd = { - tmpfiles.rules = - generatedDirectories; - - inherit services timers; - }; - users.users = - if cfg.user == "nix-sync" - then { - nix-sync = { - group = "${cfg.group}"; - isSystemUser = true; - }; - } - else lib.warnIf (cfg.user != "nix-sync") "The user (${cfg.user}) is not \"nix-sync\", thus you are responible for generating it."; - users.groups = - if cfg.group == "nix-sync" - then { - nix-sync = { - members = ["${cfg.user}"]; - }; - } - else lib.warnIf (cfg.group != "nix-sync") "The group (${cfg.group}) is not \"nix-sync\", thus you are responible for generating it."; - }; -} diff --git a/modules/by-name/ni/nix-sync/module.nix b/modules/by-name/ni/nix-sync/module.nix deleted file mode 100644 index 9ddd210..0000000 --- a/modules/by-name/ni/nix-sync/module.nix +++ /dev/null @@ -1,108 +0,0 @@ -{ - config, - lib, - modulesPath, - nixLib, - ... -}: let - cfg = config.vhack.nix-sync; - - mkNixSyncRepository = { - domain, - repositoryUrl, - extraSettings, - }: { - name = "${domain}"; - value = { - path = "/etc/nginx/websites/${domain}"; - uri = "${repositoryUrl}"; - inherit extraSettings; - }; - }; - nixSyncRepositories = builtins.listToAttrs (builtins.map mkNixSyncRepository cfg.domains); - - mkVirtHost = { - domain, - repositoryUrl, - extraSettings, - }: { - name = "${domain}"; - value = - # FIXME(@bpeetz): We cannot use something like `lib.recursiveUpdate` because the - # `extraSettings` are instantiated from the “real” nginx type. As such the - # `extaSettings` would override our values here. Therefore, the direct merge. <2025-02-07> - extraSettings - // { - forceSSL = true; - enableACME = true; - root = "/etc/nginx/websites/${domain}"; - }; - }; - virtHosts = builtins.listToAttrs (builtins.map mkVirtHost cfg.domains); -in { - imports = [ - ./internal_module.nix - ]; - - options.vhack.nix-sync = { - enable = lib.mkEnableOption '' - a website git ops solution. - ''; - - domains = lib.mkOption { - type = lib.types.listOf (lib.types.submodule { - options = { - domain = lib.mkOption { - type = lib.types.str; - example = "b-peetz.de"; - description = '' - The fully qualified domain to use as base of this website. - ''; - }; - repositoryUrl = lib.mkOption { - type = lib.types.str; - example = "b-peetz.de"; - description = '' - The url used for the source git repository, which is deployed at this domain. - ''; - }; - extraSettings = lib.mkOption { - type = - lib.types.submodule (import (modulesPath + "/services/web-servers/nginx/vhost-options.nix") {inherit config lib;}); - example = { - locations."/.well-known/openpgpkey/".extraConfig = "default_type application/octet-stream"; - }; - default = {}; - description = '' - Extra configuration to add to the nginx virtual host. - ''; - }; - }; - }); - }; - }; - - config = lib.mkIf cfg.enable { - vhack.persist.directories = [ - { - directory = "/var/lib/nix-sync"; - user = "nix-sync"; - group = "nix-sync"; - mode = "0700"; - } - ]; - - services.nix-sync = { - enable = true; - repositories = nixSyncRepositories; - }; - - vhack.nginx.enable = true; - services.nginx.virtualHosts = virtHosts; - - users = { - users.nix-sync.uid = config.vhack.constants.ids.uids.nix-sync; - groups.nix-sync.gid = config.vhack.constants.ids.gids.nix-sync; - }; - }; -} diff --git a/modules/by-name/ni/nixconfig/module.nix b/modules/by-name/ni/nixconfig/module.nix deleted file mode 100644 index a5bf950..0000000 --- a/modules/by-name/ni/nixconfig/module.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.nixconfig; -in { - options.vhack.nixconfig = { - enable = lib.mkEnableOption "sophisticated nix settings"; - }; - config = lib.mkIf cfg.enable { - nix = { - # gc = { - # automatic = true; - # dates = "daily"; - # options = "--delete-older-than 3"; - # }; - settings = { - auto-optimise-store = true; - experimental-features = ["nix-command" "flakes"]; - trusted-users = [ - "root" - "@wheel" - ]; - }; - }; - }; -} diff --git a/modules/by-name/ns/nscd/module.nix b/modules/by-name/ns/nscd/module.nix deleted file mode 100644 index 428ae3b..0000000 --- a/modules/by-name/ns/nscd/module.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.nscd; -in { - options.vhack.nscd = { - # NOTE(@bpeetz): This is enabled by default in NixOS. - # Because of this reason: - # > Whether to enable the Name Service Cache Daemon. Disabling this is - # > strongly discouraged, as this effectively disables NSS Lookups from - # > all non-glibc NSS modules, including the ones provided by systemd. - # - # As such we should also always enable it. <2024-12-25> - enable = (lib.mkEnableOption "nscd") // {default = true;}; - }; - - config = lib.mkIf cfg.enable { - users = { - users.nscd.uid = config.vhack.constants.ids.uids.nscd; - groups.nscd.gid = config.vhack.constants.ids.gids.nscd; - }; - }; -} diff --git a/modules/by-name/oo/oomd/module.nix b/modules/by-name/oo/oomd/module.nix deleted file mode 100644 index 3b39236..0000000 --- a/modules/by-name/oo/oomd/module.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.systemd.oomd; -in { - options.vhack.systemd.oomd = { - # NOTE(@bpeetz): Enabled by default, because that is what NixOS also does. <2024-12-25> - enable = (lib.mkEnableOption "oomd") // {default = true;}; - }; - - config = lib.mkIf cfg.enable { - users = { - users.systemd-oom.uid = config.vhack.constants.ids.uids.systemd-oom; - groups.systemd-oom.gid = config.vhack.constants.ids.gids.systemd-oom; - }; - }; -} diff --git a/modules/by-name/op/openssh/module.nix b/modules/by-name/op/openssh/module.nix deleted file mode 100644 index 83aeadf..0000000 --- a/modules/by-name/op/openssh/module.nix +++ /dev/null @@ -1,60 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.openssh; -in { - options.vhack.openssh = { - enable = lib.mkEnableOption '' - a sane openssh implementation. - ''; - }; - - config = lib.mkIf cfg.enable { - /* - FIXME(@bpeetz): - This results in a boot error, as the `/var/lib/sshd` directory - is only mounted _after_ the stage 2 init and with it the system - activation. `agenix` needs the sshd hostkey however to decrypt the - secrets and thus we have to ensure that this directory is mounted - _before_ the system activation. Alas the only way I see to achieve - that is to store the ssh hostkey directly on /srv, which is mounted - before (it's marked as 'neededForBoot' after all). - - It should be possible to achieve this with impermanence however, - as `/var/log` is mounted in the stage 1 init; The problem is that - I have no idea _why_ only this is mounted and nothing else. - - - vhack.persist.directories = [ - { - directory = "/var/lib/sshd"; - user = "root"; - group = "root"; - mode = "0755"; - } - ]; - */ - - users = { - users.sshd.uid = config.vhack.constants.ids.uids.sshd; - groups.sshd.gid = config.vhack.constants.ids.gids.sshd; - }; - - services.openssh = { - enable = true; - settings.PasswordAuthentication = false; - hostKeys = [ - { - # FIXME: Remove the dependency on `/srv` this workaround. - # See the explanation for using `/srv` above. - path = "/srv/var/lib/sshd/ssh_host_ed25519_key"; - - rounds = 1000; - type = "ed25519"; - } - ]; - }; - }; -} diff --git a/modules/by-name/pe/peertube/module.nix b/modules/by-name/pe/peertube/module.nix deleted file mode 100644 index e65e0b5..0000000 --- a/modules/by-name/pe/peertube/module.nix +++ /dev/null @@ -1,124 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.peertube; -in { - options.vhack.peertube = { - enable = lib.mkEnableOption '' - the peertube video platform. - ''; - peertubeGeneral = lib.mkOption { - type = lib.types.path; - description = "The age encrypted general secret file passed to agenix"; - }; - smtpPasswordFile = lib.mkOption { - type = lib.types.path; - description = "The age encrypted smtp password file passed to agenix"; - }; - }; - - config = lib.mkIf cfg.enable { - services.peertube = { - enable = true; - - configureNginx = true; - localDomain = "peertube.vhack.eu"; - enableWebHttps = true; - listenWeb = 443; - - smtp = { - createLocally = false; - passwordFile = "${config.age.secrets.peertubeSmtp.path}"; - }; - database = { - createLocally = true; - }; - redis = { - enableUnixSocket = true; - createLocally = true; - }; - - secrets.secretsFile = "${config.age.secrets.peertubeGeneral.path}"; - - settings = { - signup = { - enabled = true; - - limit = 10; # When the limit is reached, registrations are disabled. -1 == unlimited - - minimum_age = 18; # Used to configure the signup form - - # Users fill a form to register so moderators can accept/reject the registration - requires_approval = true; - requires_email_verification = true; - }; - user = { - video_quota = "10GB"; - video_quota_daily = "2GB"; - }; - auto_blacklist = { - videos = { - of_users = { - enabled = true; - }; - }; - }; - listen.hostname = "127.0.0.1"; - instance.name = "PeerTube at Vhack.eu"; - - admin.email = "admin@vhack.eu"; - - smtp = let - emailAddress = "peertube@vhack.eu"; - in { - transport = "smtp"; - hostname = "mail.foss-syndicate.org"; - port = 587; - username = emailAddress; - tls = true; - disable_starttls = true; - from_address = emailAddress; - }; - }; - }; - - # The `configureNginx` option does not do this for some reason - # TODO(@bpeetz): Find out why <2024-06-27> - services.nginx.virtualHosts."${config.services.peertube.localDomain}" = { - enableACME = true; - forceSSL = true; - }; - - age.secrets = { - peertubeGeneral = { - file = cfg.peertubeGeneral; - mode = "700"; - owner = "peertube"; - group = "peertube"; - }; - peertubeSmtp = { - file = cfg.smtpPasswordFile; - mode = "700"; - owner = "peertube"; - group = "peertube"; - }; - }; - - vhack.persist.directories = [ - { - directory = "/var/lib/peertube"; - user = "peertube"; - group = "peertube"; - mode = "0700"; - } - ]; - users = { - users.peertube.uid = config.vhack.constants.ids.uids.peertube; - groups.peertube.gid = config.vhack.constants.ids.gids.peertube; - users.redis-peertube.uid = config.vhack.constants.ids.uids.redis-peertube; - groups.redis-peertube.gid = config.vhack.constants.ids.gids.redis-peertube; - }; - }; -} diff --git a/modules/by-name/po/postgresql/module.nix b/modules/by-name/po/postgresql/module.nix deleted file mode 100644 index 319c3ac..0000000 --- a/modules/by-name/po/postgresql/module.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.postgresql; -in { - options.vhack.postgresql = { - enable = lib.mkEnableOption "postgresql"; - }; - - config = lib.mkIf cfg.enable { - vhack.persist.directories = [ - "/var/lib/postgresql" - ]; - - services.postgresql.enable = true; - }; -} diff --git a/modules/by-name/re/redlib/module.nix b/modules/by-name/re/redlib/module.nix deleted file mode 100644 index eb5edba..0000000 --- a/modules/by-name/re/redlib/module.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ - config, - pkgsUnstable, - lib, - ... -}: let - domain = "redlib.vhack.eu"; - - cfg = config.vhack.redlib; -in { - options.vhack.redlib = { - enable = lib.mkEnableOption '' - the redlib reddit frontend - ''; - }; - - config = lib.mkIf cfg.enable { - services.redlib = { - enable = true; - package = pkgsUnstable.redlib; - port = 8080; - address = "127.0.0.1"; - openFirewall = false; - }; - - services.nginx = { - enable = true; - virtualHosts.${domain} = { - locations."/".proxyPass = "http://127.0.0.1:${toString config.services.redlib.port}"; - - enableACME = true; - forceSSL = true; - }; - }; - - # TODO(@bpeetz): Remove this at some point. <2025-02-04> - vhack.nginx.redirects = { - "libreddit.vhack.eu" = "${domain}"; - }; - }; -} diff --git a/modules/by-name/re/resolvconf/module.nix b/modules/by-name/re/resolvconf/module.nix deleted file mode 100644 index ff99696..0000000 --- a/modules/by-name/re/resolvconf/module.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.resolvconf; -in { - options.vhack.resolvconf = { - # NOTE(@bpeetz): This condition is taken directly from NixOS. <2024-12-25> - enable = lib.mkEnableOption "resolvconf" // {default = !(config.environment.etc ? "resolv.conf");}; - }; - - config = lib.mkIf cfg.enable { - users.groups.resolvconf.gid = config.vhack.constants.ids.gids.resolvconf; - }; -} diff --git a/modules/by-name/ru/rust-motd/module.nix b/modules/by-name/ru/rust-motd/module.nix deleted file mode 100644 index a6998f4..0000000 --- a/modules/by-name/ru/rust-motd/module.nix +++ /dev/null @@ -1,92 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - cfg = config.vhack.rust-motd; - - # List all users that can login - pred = n: v: ( - false # <- just here for neat formatting - || v.initialHashedPassword != null - || v.initialPassword != null - || v.hashedPassword != null - || v.hashedPasswordFile != null - || v.password != null - || v.passwordFile != null - || v.openssh.authorizedKeys.keys != [] - || v.openssh.authorizedKeys.keyFiles != [] - ); - userList = builtins.mapAttrs (n: v: 2) (lib.filterAttrs pred config.users.users); -in { - options.vhack.rust-motd = { - enable = lib.mkEnableOption "rust-motd"; - }; - - config = lib.mkIf cfg.enable { - systemd.services.rust-motd = { - path = with pkgs; [ - bash - fail2ban # Needed for rust-motd fail2ban integration - ]; - }; - - programs.rust-motd = { - enable = true; - enableMotdInSSHD = true; - refreshInterval = "*:0/5"; # 0/5 means: hour 0 AND all hour wich match (0 + 5 * x) (is the same as: 0, 5, 10, 15, 20) - - # An example is here: https://raw.githubusercontent.com/rust-motd/rust-motd/refs/heads/main/example_config.toml - settings = { - global = { - progress_full_character = "="; - progress_empty_character = "-"; - progress_prefix = "["; - progress_suffix = "]"; - time_format = "%Y-%m-%d %H:%M:%S"; - }; - - banner = { - color = "red"; - command = "${pkgs.hostname}/bin/hostname | ${pkgs.figlet}/bin/figlet -f slant"; - # if you don't want a dependency on figlet, you can generate your - # banner however you want, put it in a file, and then use something like: - # command = "cat banner.txt" - }; - - uptime = { - prefix = "Uptime:"; - }; - - # ssl_certificates = { - # sort_method = "manual"; - # - # certs = { - # "server1.vhack.eu" = "/var/lib/acme/server1.vhack.eu/cert.pem"; - # "vhack.eu" = "/var/lib/acme/vhack.eu/cert.pem"; - # }; - # }; - - filesystems = { - root = "/"; - persistent = "/srv"; - store = "/nix"; - boot = "/boot"; - }; - - memory = { - swap_pos = "beside"; # or "below" or "none" - }; - - fail2_ban = { - jails = ["sshd"]; #, "anotherjail"] - }; - - last_login = userList; - - last_run = {}; - }; - }; - }; -} diff --git a/modules/by-name/sh/sharkey/module.nix b/modules/by-name/sh/sharkey/module.nix deleted file mode 100644 index 2b50cf0..0000000 --- a/modules/by-name/sh/sharkey/module.nix +++ /dev/null @@ -1,298 +0,0 @@ -# Source: https://github.com/sodiboo/system/blob/b63c7b27f49043e8701b3ff5e1441cd27d5a2fff/sharkey/module.nix -{ - config, - lib, - pkgs, - vhackPackages, - ... -}: let - cfg = config.vhack.sharkey; - - createDB = cfg.database.host == "127.0.0.1" && cfg.database.createLocally; - - settingsFormat = pkgs.formats.yaml {}; - configFile = settingsFormat.generate "sharkey-config.yml" cfg.settings; -in { - options.vhack.sharkey = { - enable = lib.mkEnableOption "sharkey"; - - fqdn = lib.mkOption { - description = "The fully qualified domain name of this instance."; - type = lib.types.str; - example = "sharkey.shonk.social"; - }; - - package = lib.mkOption { - type = lib.types.package; - default = vhackPackages.sharkey; - defaultText = lib.literalExpression "vhackPackages.sharkey"; - description = "Sharkey package to use."; - }; - - dataDirectory = lib.mkOption { - type = lib.types.path; - default = "/var/lib/sharkey"; - description = "The directory where sharkey stores it's data."; - - # This is already set in the package. - readOnly = true; - }; - - database = { - createLocally = lib.mkOption { - description = "Whether to enable local db creation."; - type = lib.types.bool; - default = true; - }; - - host = lib.mkOption { - type = lib.types.str; - default = "127.0.0.1"; - description = "The database host."; - }; - - port = lib.mkOption { - type = lib.types.port; - default = 5432; - description = "The database port."; - }; - - name = lib.mkOption { - type = lib.types.str; - default = "sharkey"; - description = "The database name in postgresql."; - }; - }; - - settings = lib.mkOption { - inherit (settingsFormat) type; - default = {}; - description = '' - Configuration for Sharkey, see - <link xlink:href="https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/.config/example.yml"/> - for supported settings. - ''; - }; - }; - - config = lib.mkIf cfg.enable { - environment.systemPackages = [cfg.package]; - - vhack = { - nginx.enable = true; - - sharkey.settings = { - id = "aidx"; - - url = "https://${cfg.fqdn}/"; - port = 5312; - - db = { - inherit (cfg.database) host port; - db = cfg.database.name; - user = cfg.database.name; - pass = "sharkey-password"; - }; - redis = { - path = config.services.redis.servers."sharkey".unixSocket; - }; - }; - - persist.directories = [ - { - directory = "${config.services.redis.servers."sharkey".settings.dir}"; - user = "sharkey"; - group = "redis-sharey"; - mode = "0770"; - } - { - directory = "${cfg.dataDirectory}"; - user = "sharkey"; - group = "sharkey"; - mode = "0770"; - } - ]; - }; - - services = { - nginx.virtualHosts."${cfg.fqdn}" = { - locations."/" = { - proxyPass = "http://127.0.0.1:${toString cfg.settings.port}"; - proxyWebsockets = true; - }; - - # proxy_set_header Host $host; - # proxy_http_version 1.1; - # proxy_redirect off; - # - # # If it's behind another reverse proxy or CDN, remove the following. - # proxy_set_header X-Real-IP $remote_addr; - # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - # proxy_set_header X-Forwarded-Proto https; - # - # # For WebSocket - # proxy_set_header Upgrade $http_upgrade; - # proxy_set_header Connection $connection_upgrade; - # - # # Cache settings - # proxy_cache cache1; - # proxy_cache_lock on; - # proxy_cache_use_stale updating; - # proxy_force_ranges on; - # add_header X-Cache $upstream_cache_status; - - enableACME = true; - forceSSL = true; - }; - - postgresql = lib.mkIf createDB { - enable = true; - settings.port = cfg.database.port; - ensureUsers = [ - { - inherit (cfg.database) name; - ensureDBOwnership = true; - } - ]; - ensureDatabases = [cfg.database.name]; - }; - - redis = { - servers."sharkey" = { - enable = true; - - user = "sharkey"; - - # Disable TCP listening. (We have a UNIX socket) - port = 0; - bind = null; - - settings = { - protected-mode = true; - enable-protected-configs = false; - enable-debug-command = false; - enable-module-command = false; - - supervised = "systemd"; - stop-writes-on-bgsave-error = true; - sanitize-dump-payload = "clients"; - }; - }; - }; - }; - - systemd.services.postgresql.postStart = '' - $PSQL -tAc "ALTER ROLE ${cfg.database.name} WITH ENCRYPTED PASSWORD 'sharkey-password';" - ''; - - systemd.services.sharkey = { - requires = - [ - "redis-sharkey.service" - "network-online.target" - ] - ++ lib.optionals createDB ["postgresql.service"]; - - after = - [ - "redis-sharkey.service" - "network-online.target" - ] - ++ lib.optionals createDB ["postgresql.service"]; - - wantedBy = ["multi-user.target"]; - - environment = { - MISSKEY_CONFIG_YML = "${configFile}"; - NODE_ENV = "production"; - }; - - serviceConfig = { - Type = "simple"; - - StateDirectory = "sharkey"; - StateDirectoryMode = "0700"; - CacheDirectory = "sharkey"; - RuntimeDirectory = "sharkey"; - RuntimeDirectoryMode = "0700"; - ExecStart = "${lib.getExe cfg.package} migrateandstart"; - - TimeoutSec = 60; - Restart = "no"; - - StandardOutput = "journal"; - StandardError = "journal"; - SyslogIdentifier = "sharkey"; - - User = "sharkey"; - Group = "sharkey"; - - # Bind standard privileged ports - AmbientCapabilities = []; - CapabilityBoundingSet = []; - - ReadWritePaths = [ - "${cfg.dataDirectory}" - ]; - - # Hardening - DeviceAllow = [""]; - LockPersonality = true; - # Probably needed for v8's JIT (crashes with it on). - MemoryDenyWriteExecute = false; - PrivateDevices = true; - PrivateUsers = true; - # Sharkey needs access to the hosts CPUs - ProcSubset = "all"; - PrivateTmp = true; - ProtectClock = true; - ProtectControlGroups = true; - ProtectHome = true; - ProtectHostname = true; - ProtectKernelLogs = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectProc = "invisible"; - ProtectSystem = "strict"; - RestrictAddressFamilies = [ - "AF_UNIX" # Local communication unix(7) - "AF_INET" # IPv4 Internet protocols ip(7) - "AF_INET6" # IPv6 Internet protocols ipv6(7) - # Needed for nodes `os.networkInterfaces()` function. - "AF_NETLINK" # Kernel user interface device netlink(7) - ]; - RestrictNamespaces = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - SystemCallArchitectures = "native"; - SystemCallFilter = [ - "@system-service" - "@chown" - "~@mount" - ]; - UMask = "0077"; - }; - }; - - users = { - groups.sharkey = { - gid = config.vhack.constants.ids.gids.sharkey; - }; - users.sharkey = { - isSystemUser = true; - group = "sharkey"; - uid = config.vhack.constants.ids.uids.sharkey; - home = cfg.package; - packages = [cfg.package]; - }; - - groups.redis-sharkey = { - gid = config.vhack.constants.ids.gids.redis-sharkey; - }; - users.redis-sharkey = { - group = "redis-sharkey"; - uid = config.vhack.constants.ids.uids.redis-sharkey; - }; - }; - }; -} diff --git a/modules/by-name/st/stalwart-mail/module.nix b/modules/by-name/st/stalwart-mail/module.nix deleted file mode 100644 index 7bd985f..0000000 --- a/modules/by-name/st/stalwart-mail/module.nix +++ /dev/null @@ -1,428 +0,0 @@ -{ - lib, - config, - pkgs, - vhackPackages, - ... -}: let - cfg = config.vhack.stalwart-mail; - topCfg = config.services.stalwart-mail; - - configFormat = pkgs.formats.toml {}; - configFile = configFormat.generate "stalwart-mail.toml" topCfg.settings; -in { - imports = [ - ./settings.nix - ]; - - options.vhack.stalwart-mail = { - enable = lib.mkEnableOption "starwart-mail"; - - package = lib.mkPackageOption vhackPackages "stalwart-mail-free" {}; - - admin = lib.mkOption { - description = '' - Email address to advertise as administrator. This is the address, where dkim, spv - etc. refusal reports are sent to. - - The format should be: `mailto:<name>@<domain>` - ''; - type = lib.types.str; - example = "mailto:dmarc+rua@example.com"; - default = ""; - }; - - fqdn = lib.mkOption { - type = lib.types.str; - example = "mail.foss-syndicate.org"; - description = '' - The fully qualified domain name for this mail server. - ''; - }; - - principals = lib.mkOption { - default = null; - type = lib.types.nullOr (lib.types.listOf (lib.types.submodule { - options = { - name = lib.mkOption { - type = lib.types.str; - description = "Specifies the username of the account"; - }; - - class = lib.mkOption { - type = lib.types.enum ["individual" "admin"]; - description = "Specifies the account type"; - }; - - description = lib.mkOption { - type = lib.types.str; - description = "Provides a description or full name for the user"; - default = ""; - }; - - secret = lib.mkOption { - type = let - prefix = pre: lib.types.strMatching "^${lib.strings.escapeRegex pre}.*"; - in - lib.types.oneOf [ - (prefix "$argon2") - (prefix "$pbkdf2") - (prefix "$scrypt") - (prefix "$2") # bcrypt - (prefix "$6$") # sha-512 - (prefix "$5$") # sha-256 - (prefix "$sha1") - (prefix "$1") # md5 - (prefix "_") # BSDi crypt - (prefix "{SHA}") # base64 sha - (prefix "{SSHA}") # base64 salted sha - - # unix crypt - (prefix "{CRYPT}") - (prefix "{crypt}") - - # Plain text - (prefix "{PLAIN}") - (prefix "{plain}") - (prefix "{CLEAR}") - (prefix "{clear}") - ]; - description = '' - Sets the password for the user account. - Passwords can be stored hashed or in plain text (not recommended). - See <https://stalw.art/docs/auth/authentication/password/> for a description - of password encoding. - ''; - }; - email = lib.mkOption { - type = lib.types.listOf lib.types.str; - description = '' - A list of email addresses associated with the user. - The first address in the list is considered the primary address. - ''; - }; - }; - })); - }; - - dataDirectory = lib.mkOption { - description = '' - The directory in which to store all storage things. - ''; - default = "/var/lib/stalwart-mail"; - type = lib.types.path; - readOnly = true; - }; - - openFirewall = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Whether to open TCP firewall ports, which are specified in - {option}`services.stalwart-mail.settings.listener` on all interfaces. - ''; - }; - - security = lib.mkOption { - type = lib.types.nullOr (lib.types.submodule { - options = { - verificationMode = lib.mkOption { - type = lib.types.enum ["relaxed" "strict"]; - description = '' - Whether to allow invalid signatures/checks or not. - ''; - default = "relaxed"; - }; - - dkimKeys = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule { - options = { - dkimPublicKey = lib.mkOption { - type = lib.types.str; - description = '' - The base 64 encoded representation of the public dkim key. - ''; - }; - dkimPrivateKeyPath = lib.mkOption { - type = lib.types.path; - description = '' - The path to the dkim private key agenix file. - Generate it via the `./gen_key` script: - ''; - }; - keyAlgorithm = lib.mkOption { - type = lib.types.enum ["ed25519-sha256" "rsa-sha-256" "rsa-sha-1"]; - description = "The algorithm of the used key"; - }; - }; - }); - description = '' - Which key to use for which domain. The attr keys are the domains - ''; - default = {}; - }; - }; - }); - description = '' - Security options. This should only be set to `null` when testing. - ''; - }; - }; - - config = lib.mkIf cfg.enable { - assertions = [ - { - assertion = cfg.admin != ""; - message = "You need to specify an admin address."; - } - ]; - - vhack.nginx.enable = true; - services = { - stalwart-mail = { - # NOTE(@bpeetz): We do not use the NixOS service, as it comes with too much - # bothersome default configuration and not really any useful configuration. - # However, this decision could obviously be reversed in the future. <2025-02-08> - enable = false; - inherit (cfg) package; - }; - - nginx.virtualHosts."${cfg.fqdn}" = { - locations."/" = { - proxyPass = "http://${builtins.elemAt config.services.stalwart-mail.settings.server.listener.http.bind 0}"; - recommendedProxySettings = true; - }; - - useACMEHost = "${cfg.fqdn}"; - forceSSL = true; - }; - - redis = { - servers = { - "stalwart-mail" = { - enable = true; - - user = "stalwart-mail"; - - # Disable TCP listening. (We have a UNIX socket) - port = 0; - bind = null; - - settings = { - protected-mode = true; - enable-protected-configs = false; - enable-debug-command = false; - enable-module-command = false; - - supervised = "systemd"; - stop-writes-on-bgsave-error = true; - sanitize-dump-payload = "clients"; - }; - }; - }; - }; - }; - security.acme.certs = { - "${cfg.fqdn}" = { - domain = cfg.fqdn; - group = "stalwart-mail-certificates"; - }; - }; - - age.secrets = let - keys = - lib.mapAttrs' ( - keyDomain: keyConfig: - lib.nameValuePair "stalwartMail${keyDomain}" - { - file = keyConfig.dkimPrivateKeyPath; - mode = "600"; - owner = "stalwart-mail"; - group = "stalwart-mail"; - } - ) - cfg.security.dkimKeys; - in - lib.mkIf (cfg.security != null) keys; - - vhack.persist.directories = [ - { - directory = "${cfg.dataDirectory}"; - user = "stalwart-mail"; - group = "stalwart-mail"; - mode = "0700"; - } - { - directory = "${config.services.redis.servers."stalwart-mail".settings.dir}"; - user = "stalwart-mail"; - group = "redis-stalwart-mail"; - mode = "0770"; - } - ]; - - # This service stores a potentially large amount of data. - # Running it as a dynamic user would force chown to be run every time the - # service is restarted on a potentially large number of files. - # That would cause unnecessary and unwanted delays. - users = { - groups = { - stalwart-mail = { - gid = config.vhack.constants.ids.gids.stalwart-mail; - }; - stalwart-mail-certificates = { - gid = config.vhack.constants.ids.gids.stalwart-mail-certificates; - }; - redis-stalwart-mail = { - gid = config.vhack.constants.ids.gids.redis-stalwart-mail; - }; - }; - users = { - nginx = { - extraGroups = ["stalwart-mail-certificates"]; - }; - stalwart-mail = { - isSystemUser = true; - group = "stalwart-mail"; - uid = config.vhack.constants.ids.uids.stalwart-mail; - extraGroups = ["stalwart-mail-certificates"]; - }; - redis-stalwart-mail = { - group = "redis-stalwart-mail"; - uid = config.vhack.constants.ids.uids.redis-stalwart-mail; - }; - }; - }; - - systemd.tmpfiles.rules = [ - "d '${cfg.dataDirectory}' - stalwart-mail stalwart-mail - -" - ]; - - systemd = { - services.stalwart-mail = { - wantedBy = ["multi-user.target"]; - requires = - [ - "redis-stalwart-mail.service" - "network-online.target" - ] - ++ (lib.optional (cfg.security != null) "acme-${cfg.fqdn}.service"); - after = [ - "local-fs.target" - "network.target" - "network-online.target" - "redis-stalwart-mail.service" - "acme-${cfg.fqdn}.service" - ]; - conflicts = [ - "postfix.service" - "sendmail.service" - "exim4.service" - ]; - description = "Stalwart Mail Server"; - - environment = { - SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; - NIX_SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; - }; - - preStart = let - esa = lib.strings.escapeShellArg; - mkTmpFile = path: "[ -d ${esa path} ] || mkdir --parents ${esa path}"; - - # Create the directories for stalwart - storageDirectories = lib.lists.filter (v: v != null) (lib.attrsets.mapAttrsToList (_: {path ? null, ...}: - if (path != null) - then mkTmpFile path - else null) - topCfg.settings.store); - in - '' - # Stalwart actually wants to store _data_ (e.g., blocked ips) in it's own config file. - # Thus we need to make it writable. - cat ${esa configFile} >$CACHE_DIRECTORY/mutable_config_file.toml - '' - + (builtins.concatStringsSep "\n" storageDirectories); - - serviceConfig = { - ExecStart = pkgs.writers.writeDash "start-stalwart-mail" '' - ${lib.getExe cfg.package} --config="$CACHE_DIRECTORY/mutable_config_file.toml" - ''; - - Restart = "no"; - - KillMode = "process"; - KillSignal = "SIGINT"; - - Type = "simple"; - LimitNOFILE = 65536; - - StandardOutput = "journal"; - StandardError = "journal"; - - ReadWritePaths = [ - cfg.dataDirectory - ]; - CacheDirectory = "stalwart-mail"; - StateDirectory = "stalwart-mail"; - - User = "stalwart-mail"; - Group = "stalwart-mail"; - - SyslogIdentifier = "stalwart-mail"; - - # Bind standard privileged ports - AmbientCapabilities = ["CAP_NET_BIND_SERVICE"]; - CapabilityBoundingSet = ["CAP_NET_BIND_SERVICE"]; - - # Hardening - DeviceAllow = [""]; - LockPersonality = true; - MemoryDenyWriteExecute = true; - PrivateDevices = true; - PrivateUsers = false; # incompatible with CAP_NET_BIND_SERVICE - ProcSubset = "pid"; - PrivateTmp = true; - ProtectClock = true; - ProtectControlGroups = true; - ProtectHome = true; - ProtectHostname = true; - ProtectKernelLogs = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectProc = "invisible"; - ProtectSystem = "strict"; - RestrictAddressFamilies = [ - "AF_INET" - "AF_INET6" - "AF_UNIX" - ]; - RestrictNamespaces = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - SystemCallArchitectures = "native"; - SystemCallFilter = [ - "@system-service" - "~@privileged" - ]; - UMask = "0077"; - }; - }; - }; - - # Make admin commands available in the shell - environment.systemPackages = [cfg.package]; - - networking.firewall = let - parsePorts = listeners: let - parseAddresses = listeners: lib.flatten (lib.mapAttrsToList (name: value: value.bind) listeners); - splitAddress = addr: lib.splitString ":" addr; - extractPort = addr: lib.toInt (builtins.foldl' (a: b: b) "" (splitAddress addr)); - in - builtins.map extractPort (parseAddresses listeners); - in - lib.mkIf (cfg.openFirewall && (builtins.hasAttr "listener" topCfg.settings.server)) - { - allowedTCPPorts = parsePorts topCfg.settings.server.listener; - }; - }; -} diff --git a/modules/by-name/st/stalwart-mail/settings.nix b/modules/by-name/st/stalwart-mail/settings.nix deleted file mode 100644 index 907cea9..0000000 --- a/modules/by-name/st/stalwart-mail/settings.nix +++ /dev/null @@ -1,552 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - cfg = config.vhack.stalwart-mail; - - signaturesByDomain = - (builtins.map ({name, ...}: { - "if" = "sender_domain = '${name}'"; - "then" = "'${name}'"; - }) - (lib.attrsToList cfg.security.dkimKeys)) - ++ [{"else" = false;}]; - - maybeVerificationMode = - if cfg.security != null - then cfg.security.verificationMode - else "disable"; - - directory = - if cfg.principals == null - then "internal" - else "in-memory"; -in { - config.services.stalwart-mail.settings = lib.mkIf cfg.enable { - # https://www.rfc-editor.org/rfc/rfc6376.html#section-3.3 - signature = let - signatures = - lib.mapAttrs (keyDomain: keyConfig: { - private-key = "%{file:${config.age.secrets."stalwartMail${keyDomain}".path}}%"; - - domain = keyDomain; - - selector = "mail"; - headers = ["From" "To" "Cc" "Date" "Subject" "Message-ID" "Organization" "MIME-Version" "Content-Type" "In-Reply-To" "References" "List-Id" "User-Agent" "Thread-Topic" "Thread-Index"]; - algorithm = keyConfig.keyAlgorithm; - - # How do we canonicalize the headers/body? - # https://www.rfc-editor.org/rfc/rfc6376.html#section-3.4 - canonicalization = "simple/simple"; - - expire = "50d"; - report = true; - }) - cfg.security.dkimKeys; - in - lib.mkIf (cfg.security != null) signatures; - - auth = let - # NOTE(@bpeetz): We disable all the checks if the `listener` is submissions, because the - # user's email client will obviously not have the right IP address to pass SPF or - # IPREV. It will also not be able to sign the message with DKIM (as we has to key). <2025-02-25> - ifNotSmpt = valueTrue: valueFalse: [ - { - "if" = "listener != 'submissions'"; - "then" = valueTrue; - } - {"else" = valueFalse;} - ]; - in { - iprev = { - verify = ifNotSmpt maybeVerificationMode "disable"; - }; - spf = { - verify = { - ehlo = ifNotSmpt maybeVerificationMode "disable"; - - mail-from = ifNotSmpt maybeVerificationMode "disable"; - }; - }; - dmarc = { - verify = ifNotSmpt maybeVerificationMode "disable"; - }; - arc = { - seal = lib.mkIf (cfg.security != null) signaturesByDomain; - verify = ifNotSmpt maybeVerificationMode "disable"; - }; - dkim = { - verify = ifNotSmpt maybeVerificationMode "disable"; - - # Ignore insecure dkim signed messages (i.e., messages containing both - # signed and appended not-signed content.) - strict = true; - - sign = - lib.mkIf (cfg.security != null) signaturesByDomain; - }; - }; - report = { - domain = "${cfg.fqdn}"; - submitter = "'${cfg.fqdn}'"; - analysis = { - addresses = ["dmarc@*" "abuse@*"]; - forward = true; - store = "30d"; - }; - tls.aggregate = { - from-name = "'TLS Report'"; - from-address = "'noreply-tls@${cfg.fqdn}'"; - org-name = "'Foss Syndicate Mail Handling'"; - contact-info = "'${cfg.admin}'"; - send = "daily"; - max-size = 26214400; # 25 MiB - sign = lib.mkIf (cfg.security != null) "'${cfg.fqdn}'"; - }; - dmarc = { - aggregate = { - from-name = "'DMARC Report'"; - from-address = "'noreply-dmarc@${cfg.fqdn}'"; - org-name = "'Foss Syndicate Mail Handling'"; - contact-info = "'${cfg.admin}'"; - send = "weekly"; - max-size = 26214400; # 25MiB - sign = lib.mkIf (cfg.security != null) "'${cfg.fqdn}'"; - }; - from-name = "'Report Subsystem'"; - from-address = "'noreply-dmarc@${cfg.fqdn}'"; - subject = "'DMARC Authentication Failure Report'"; - send = "1/1d"; - sign = lib.mkIf (cfg.security != null) signaturesByDomain; - }; - spf = { - from-name = "'Report Subsystem'"; - from-address = "'noreply-spf@${cfg.fqdn}'"; - subject = "'SPF Authentication Failure Report'"; - send = "1/1d"; - sign = lib.mkIf (cfg.security != null) signaturesByDomain; - }; - dkim = { - from-name = "'Report Subsystem'"; - from-address = "'noreply-dkim@${cfg.fqdn}'"; - subject = "'DKIM Authentication Failure Report'"; - send = "1/1d"; - sign = lib.mkIf (cfg.security != null) signaturesByDomain; - }; - dsn = { - from-name = "'Mail Delivery Subsystem'"; - from-address = "'MAILER-DAEMON@${cfg.fqdn}'"; - sign = lib.mkIf (cfg.security != null) signaturesByDomain; - }; - }; - queue = { - schedule = { - retry = "[2m, 5m, 10m, 15m, 30m, 1h, 2h]"; - notify = "[2h, 7h, 1d, 3d]"; - expire = "5d"; - }; - outbound = { - tls = { - starttls = - if maybeVerificationMode == "strict" - then "require" - else "optional"; - allow-invalid-certs = false; - ip-strategy = "ipv6_then_ipv4"; - mta-sts = - if maybeVerificationMode == "strict" - then "require" - else "optional"; - }; - }; - }; - resolver = { - type = "system"; - preserve-intermediates = true; - concurrency = 2; - timeout = "5s"; - attempts = 2; - try-tcp-on-error = true; - public-suffix = [ - "file://${pkgs.publicsuffix-list}/share/publicsuffix/public_suffix_list.dat" - ]; - }; - - spam-filter = { - enable = true; - header = { - status = { - enable = true; - name = "X-Spam-Status"; - }; - result = { - enable = true; - name = "X-Spam-Result"; - }; - }; - bayes = { - enable = true; - - # Learn from users putting mail into JUNK or taking mail out of it. - account = { - enable = true; - }; - }; - - # Fetch the newest spam-filter rules not from github, but from the nix - # package. - resource = "file://${cfg.package.passthru.spamfilter}/spam-filter.toml"; - auto-update = false; - }; - - webadmin = { - # Fetch the newest webadmin bundle not from github, but from the nix - # package. - resource = "file://${cfg.package.passthru.webadmin}/webadmin.zip"; - auto-update = false; - path = "/var/cache/stalwart-mail"; - }; - - session = { - milter = { - # TODO: Add this <2025-02-07> - # "clamav" = { - # enable = true; - # hostname = "127.0.0.1"; - # port = 15112; - # tls = false; - # allow-invalid-certs = false; - # }; - }; - ehlo = { - require = true; - }; - rcpt = { - directory = "'${directory}'"; - catch-all = true; - subaddressing = true; - }; - data = { - spam-filter = true; - add-headers = { - received = true; - received-spf = true; - auth-results = true; - message-id = true; - date = true; - return-path = true; - delivered-to = true; - }; - auth = { - mechanisms = ["LOGIN" "PLAIN"]; - directory = "'${directory}'"; - require = true; - must-match-sender = true; - errors = { - total = 3; - wait = "5s"; - }; - }; - }; - extensions = { - pipelining = true; - chunking = true; - requiretls = true; - no-soliciting = ""; - dsn = [ - { - "if" = "!is_empty(authenticated_as)"; - "then" = true; - } - {"else" = false;} - ]; - future-release = [ - { - "if" = "!is_empty(authenticated_as)"; - "then" = "7d"; - } - {"else" = false;} - ]; - deliver-by = [ - { - "if" = "!is_empty(authenticated_as)"; - "then" = "15d"; - } - {"else" = false;} - ]; - mt-priority = [ - { - "if" = "!is_empty(authenticated_as)"; - "then" = "mixer"; - } - {"else" = false;} - ]; - vrfy = [ - { - "if" = "!is_empty(authenticated_as)"; - "then" = true; - } - {"else" = false;} - ]; - expn = [ - { - "if" = "!is_empty(authenticated_as)"; - "then" = true; - } - {"else" = false;} - ]; - }; - }; - - jmap = { - account = { - purge.frequency = "0 0 *"; - }; - protocol = { - changes.max-history = "14d"; - }; - email = { - # NOTE(@bpeetz): We probably want to enable the auto-deletion of emails in - # the "Junk" and "Deleted" items mail folders, but this should be - # communicated to the users. <2025-02-07> - auto-expunge = false; - }; - mailbox = { - max-depth = 50; - max-name-length = 255; - }; - folders = let - mkFolder = name: { - inherit name; - create = true; - subscribe = true; - }; - in { - inbox = mkFolder "INBOX"; - drafts = mkFolder "DRAFTS"; - sent = mkFolder "SENT"; - trash = mkFolder "TRASH"; - archive = mkFolder "ARCHIVE"; - junk = mkFolder "JUNK"; - shared = {name = "SHARED";}; - }; - }; - imap = { - auth = { - # Allow password login over non tls connection - allow-plain-text = false; - }; - }; - - server = { - hostname = cfg.fqdn; - - listener = { - # HTTP (used for jmap) - "http" = { - bind = ["127.0.0.1:8112"]; - protocol = "http"; - # handled by ngnix - tls.implicit = false; - }; - - # IMAP - "imap" = { - bind = ["[::]:993"]; - protocol = "imap"; - tls.implicit = true; - }; - - # SMTP - "submissions" = { - bind = ["[::]:465"]; - protocol = "smtp"; - tls.implicit = true; - }; - "input" = { - bind = ["[::]:25"]; - protocol = "smtp"; - tls = { - enable = true; - # Require an explicit `STARTTLS` - implicit = false; - }; - }; - - # # POP3 (should be disabled, unless there is a real reason to use it) - # "pop3" = { - # bind = ["[::]:995"]; - # protocol = "pop3"; - # tls.implicit = true; - # }; - - # # LMTP - # "lmtp" = { - # bind = ["[::]:24"]; - # protocol = "lmtp"; - # }; - - # ManageSieve - "managesieve" = { - bind = ["[::]:4190"]; - protocol = "managesieve"; - tls.implicit = true; - }; - }; - - tls = { - enable = true; - - # Expect the client connection to be encrypted from the start (i.e., - # without STARTTLS) - implicit = true; - - certificate = "default"; - }; - - http = { - url = "protocol + '://' + config_get('server.hostname') + ':' + local_port"; - - # We are behind a nginx proxy, and can thus trust this header. - use-x-forwarded = true; - }; - - auto-ban = { - # Ban if the same IP fails to login 10 times in a day - rate = "10/1d"; - - # Ban the login for an user account, if different IP-Addresses tried and - # failed to login 100 times in single day - auth.rate = "100/1d"; - - abuse.rate = "35/1d"; - - loiter.rate = "150/1d"; - - scan.rate = "150/1d"; - }; - - cache = let - MiB = 1024 * 1024; - in { - access-token.size = 10 * MiB; - http-auth.size = 1 * MiB; - permission.size = 5 * MiB; - account.size = 10 * MiB; - mailbox.size = 10 * MiB; - thread.size = 10 * MiB; - bayes.size = 10 * MiB; - dns = { - txt.size = 5 * MiB; - mx.size = 5 * MiB; - ptr.size = 1 * MiB; - ipv4.size = 5 * MiB; - ipv6.size = 5 * MiB; - tlsa.size = 1 * MiB; - mta-sts.size = 1 * MiB; - rbl.size = 5 * MiB; - }; - }; - }; - - tracer = { - # NOTE(@bpeetz): - # We are using the console logger, because that has nice color output. - # Simply using the console should be fine, as systemd pipes that to the journal - # either way. <2025-02-08> - console = { - enable = true; - ansi = true; - level = "info"; - type = "console"; - }; - }; - - store = { - "rocksdb-data" = { - type = "rocksdb"; - path = "${cfg.dataDirectory}/storage/data"; - compression = "lz4"; - - # Perform “maintenance” every day at 3 am local time. - purge.frequency = "0 3 *"; - }; - "rocksdb-directory" = lib.mkIf (cfg.principals == null) { - type = "rocksdb"; - path = "${cfg.dataDirectory}/storage/directory"; - compression = "lz4"; - - # Perform “maintenance” every day at 1 am local time. - purge.frequency = "0 1 *"; - }; - "rocksdb-full-text-search" = { - type = "rocksdb"; - path = "${cfg.dataDirectory}/storage/full-text-search"; - compression = "lz4"; - - # Perform “maintenance” every day at 2 am local time. - purge.frequency = "0 2 *"; - }; - "file-system" = { - type = "fs"; - path = "${cfg.dataDirectory}/storage/blobs"; - depth = 2; - compression = "lz4"; - - # Perform “maintenance” every day at 5:30 am local time. - purge.frequency = "30 5 *"; - }; - "redis" = { - type = "redis"; - redis-type = "single"; - urls = "unix://${config.services.redis.servers."stalwart-mail".unixSocket}"; - timeout = "10s"; - - # Perform “maintenance” every day at 2:30 am local time. - purge.frequency = "30 2 *"; - }; - }; - storage = { - # PostgreSQL is an option, but this is recommended for single node - # configurations. - data = "rocksdb-data"; - - # We could also re-use the data storage backend for that. - blob = "file-system"; - - full-text.default-language = "en"; - fts = "rocksdb-full-text-search"; - - directory = "${directory}"; - - lookup = "redis"; - - # NOTE(@bpeetz): This will encrypt all emails with the users pgp key (if it - # can be determined.) This is a wonderful feature, but quite tiresome, if - # the user intends to read their email without a their pgp key present (for - # example via their smartphone.) <2025-02-07> - encryption.enable = false; - }; - - directory = { - "in-memory" = lib.mkIf (cfg.principals != null) { - type = "memory"; - inherit (cfg) principals; - }; - "internal" = lib.mkIf (cfg.principals == null) { - type = "internal"; - store = "rocksdb-directory"; - }; - }; - - certificate = { - "default" = { - cert = "%{file:${config.security.acme.certs.${cfg.fqdn}.directory}/fullchain.pem}%"; - private-key = "%{file:${config.security.acme.certs.${cfg.fqdn}.directory}/key.pem}%"; - default = true; - }; - }; - }; -} diff --git a/modules/by-name/sy/system-info/module.nix b/modules/by-name/sy/system-info/module.nix deleted file mode 100644 index 8136ae5..0000000 --- a/modules/by-name/sy/system-info/module.nix +++ /dev/null @@ -1,79 +0,0 @@ -{ - lib, - config, - pkgs, - ... -}: let - mkVirtualHostDisplay = name: value: let - aliases = - if value.serverAliases != [] - then - ": " - + builtins.concatStringsSep " " value.serverAliases - else ""; - in '' - ${name}${aliases} - ''; - vHosts = builtins.concatStringsSep "" (builtins.attrValues (builtins.mapAttrs mkVirtualHostDisplay config.services.nginx.virtualHosts)); - - mkOpenPortDisplay = mode: port: let - checkEnabled = service: name: - if config.vhack.${service}.enable - then name - else "<port is '${name}' but service 'vhack.${service}' is not enabled.>"; - mappings = { - "22" = checkEnabled "openssh" "ssh"; - "80" = checkEnabled "nginx" "http"; - "443" = checkEnabled "nginx" "https"; - - "53" = checkEnabled "dns" "dns"; - - "24" = checkEnabled "mail" "mail-lmtp"; - "465" = checkEnabled "mail" "mail-smtp-tls"; - "25" = checkEnabled "mail" "mail-smtp"; - "993" = checkEnabled "mail" "mail-imap-tls"; - "995" = checkEnabled "mail" "mail-pop3-tls"; - - "10222" = checkEnabled "taskchampion-sync" "taskchampion-sync"; - - # TODO(@bpeetz): Check which service opens these ports: <2025-01-28> - "64738" = "???"; - "4190" = "???"; - }; - in '' - ${mode} ${builtins.toString port}: ${ - if (builtins.hasAttr "${builtins.toString port}" mappings) - then mappings.${builtins.toString port} - else - builtins.throw - "'${builtins.toString port}' is still missing from the system info port -> name map. Maybe add it?" - } - ''; - - # TODO(@bpeetz): This should probably also include the allowed TCP/UDP port ranges. <2025-01-28> - openTCPPorts = builtins.concatStringsSep "" (builtins.map (mkOpenPortDisplay "TCP") config.networking.firewall.allowedTCPPorts); - openUDPPorts = builtins.concatStringsSep "" (builtins.map (mkOpenPortDisplay "UDP") config.networking.firewall.allowedUDPPorts); - - markdown = pkgs.writeText "${config.networking.hostName}-system-info.md" '' - ## Virtual Hosts - ${vHosts} - ## Open ports - ${openTCPPorts} - ${openUDPPorts} - ''; -in { - options.vhack.system-info = { - markdown = lib.mkOption { - type = lib.types.package; - description = '' - A derivation, that builds a markdown file, showing relevant system - information for this host. - ''; - readOnly = true; - }; - }; - - config.vhack.system-info = { - inherit markdown; - }; -} diff --git a/modules/by-name/ta/taskchampion-sync/module.nix b/modules/by-name/ta/taskchampion-sync/module.nix deleted file mode 100644 index 1870186..0000000 --- a/modules/by-name/ta/taskchampion-sync/module.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ - config, - lib, - ... -}: let - cfg = config.vhack.taskchampion-sync; - dataDirectory = "/var/lib/taskchampion-sync-server"; -in { - options.vhack.taskchampion-sync = { - enable = lib.mkEnableOption "taskchampion-sync"; - }; - - config = lib.mkIf cfg.enable { - users = { - users.taskchampion.uid = config.vhack.constants.ids.uids.taskchampion; - groups.taskchampion.gid = config.vhack.constants.ids.uids.taskchampion; - }; - - vhack.persist.directories = [ - { - directory = dataDirectory; - user = "taskchampion"; - group = "taskchampion"; - mode = "0700"; - } - ]; - - services.taskchampion-sync-server = { - enable = true; - openFirewall = true; - dataDir = dataDirectory; - }; - }; -} diff --git a/modules/by-name/us/users/module.nix b/modules/by-name/us/users/module.nix deleted file mode 100644 index a197b13..0000000 --- a/modules/by-name/us/users/module.nix +++ /dev/null @@ -1,82 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - cfg = config.vhack.users; - - mkUser = { - name, - password, - uid, - sshKey, - }: { - inherit name; - value = { - inherit name uid; - isNormalUser = true; - home = "/home/${name}"; - hashedPassword = password; - extraGroups = [ - "wheel" - ]; - openssh.authorizedKeys.keys = [ - sshKey - ]; - }; - }; - - extraUsers = lib.listToAttrs (builtins.map mkUser [ - { - name = "soispha"; - password = "$y$jFT$3.8XmUyukZvpExMUxDZkI.$IVrJgm8ysNDF/0vDD2kF6w73ozXgr1LMVRNN4Bq7pv1"; - sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIME4ZVa+IoZf6T3U08JG93i6QIAJ4amm7mkBzO14JSkz cardno:000F_18F83532"; - uid = 1000; - } - { - name = "sils"; - password = "$y$jFT$KpFnahVCE9JbE.5P3us8o.$ZzSxCusWqe3sL7b6DLgOXNNUf114tiiptM6T8lDxtKC"; - sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAe4o1PM6VasT3KZNl5NYvgkkBrPOg36dqsywd10FztS openpgp:0x21D20D6A"; - uid = 1001; - } - ]); -in { - options.vhack.users = { - enable = lib.mkEnableOption "user setup"; - }; - - config = lib.mkIf cfg.enable { - users = { - mutableUsers = false; - defaultUserShell = pkgs.bashInteractive; - - users = - { - root = { - hashedPassword = lib.mkForce null; # to lock root - openssh.authorizedKeys.keys = lib.mkForce []; - }; - } - // extraUsers; - - # TODO(@bpeetz): Is this still relevant? - # If it is, it should be moved to a separate module. <2024-12-24> - # nixremote = { - # name = "nixremote"; - # isNormalUser = true; - # createHome = true; - # home = "/home/nixremote"; - # uid = 1003; - # group = "nixremote"; - # openssh.authorizedKeys.keys = [ - # "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCbSWqFzb+WTq2JVoRGoTkCkP7AM3bNY91bsUBeoQQc8gKAWuqCrpAOmr2Q2QMaTTGEOM0CsWfWLs3ZYtynHmc7wIFc4T/sUloV+dB9oSCmOk5ePxtj8+gpPK35Ja+ug5zmXsaI4s+n9mEbuuEjn33MxDYCUzAI+aWvWe68u/j+FM3u9c3Ta009rotajjSZ/cmIltgNLsG1rnAZRpwmLVg5UL4cb9um54o/NLYFd2KAekQFVbwUQDzzqriZhWmzkfhnznBMDblf9R1xvZ18Lqv3JF21shdaR43NW1wtuntBvAdsVYK2VUEbj+3MxTkK0aQ/E9SHMtH8MRE4oxU74TeTWfIhuSZk9/wekzSNMkHP3ReFC6B9xCMYa+ZqaTaGSWLQi78AQDeM2F9rAfp3hQzyRa7T7qKlgbae/hEb07xZglqmG7eml9vPSt4AHv5Y176Q95NiiWduGoLQOmjvSBMU9/KEGrGKyLfGH1Wa2EOfPxKKcvcHW0Xi9PlPiuP0nYk= root@thinklappi" - # ]; - # }; - # }; - # groups.nixremote = { - # gid = 1004; - # }; - }; - }; -} |
