From 7f797a698f835e6744971c17d33abb5485729bd3 Mon Sep 17 00:00:00 2001
From: Pablo Ovelleiro Corral <mail@pablo.tools>
Date: Mon, 1 Apr 2024 02:55:15 +0200
Subject: [PATCH] wastebin: init at 2.4.3 (#287455)

* wastebin: init at 2.4.3

* nixos/wastebin: init

Add module and test for wastebin
---
 .../manual/release-notes/rl-2405.section.md   |   2 +
 nixos/modules/module-list.nix                 |   1 +
 nixos/modules/services/misc/wastebin.nix      | 158 ++++++++++++++++++
 nixos/tests/all-tests.nix                     |   1 +
 nixos/tests/wastebin.nix                      |  19 +++
 pkgs/by-name/wa/wastebin/package.nix          |  43 +++++
 6 files changed, 224 insertions(+)
 create mode 100644 nixos/modules/services/misc/wastebin.nix
 create mode 100644 nixos/tests/wastebin.nix
 create mode 100644 pkgs/by-name/wa/wastebin/package.nix

diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md
index 06d6ebbd2b0a..7afc14347f5c 100644
--- a/nixos/doc/manual/release-notes/rl-2405.section.md
+++ b/nixos/doc/manual/release-notes/rl-2405.section.md
@@ -140,6 +140,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - [systemd-lock-handler](https://git.sr.ht/~whynothugo/systemd-lock-handler/), a bridge between logind D-Bus events and systemd targets. Available as [services.systemd-lock-handler.enable](#opt-services.systemd-lock-handler.enable).
 
+- [wastebin](https://github.com/matze/wastebin), a pastebin server written in rust. Available as [services.wastebin](#opt-services.wastebin.enable).
+
 - [Mealie](https://nightly.mealie.io/), a self-hosted recipe manager and meal planner with a RestAPI backend and a reactive frontend application built in NuxtJS for a pleasant user experience for the whole family. Available as [services.mealie](#opt-services.mealie.enable)
 
 - [Uni-Sync](https://github.com/EightB1ts/uni-sync), a synchronization tool for Lian Li Uni Controllers. Available as [hardware.uni-sync](#opt-hardware.uni-sync.enable)
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 0a15360f6ea5..9cbc421239ba 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -799,6 +799,7 @@
   ./services/misc/transfer-sh.nix
   ./services/misc/tzupdate.nix
   ./services/misc/uhub.nix
+  ./services/misc/wastebin.nix
   ./services/misc/weechat.nix
   ./services/misc/workout-tracker.nix
   ./services/misc/xmr-stak.nix
diff --git a/nixos/modules/services/misc/wastebin.nix b/nixos/modules/services/misc/wastebin.nix
new file mode 100644
index 000000000000..3d0af2862683
--- /dev/null
+++ b/nixos/modules/services/misc/wastebin.nix
@@ -0,0 +1,158 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.services.wastebin;
+  inherit (lib)
+    mkEnableOption mkPackageOption mkIf mkOption
+    types mapAttrs isBool getExe boolToString optionalAttrs;
+in
+{
+
+  options.services.wastebin = {
+
+    enable = mkEnableOption "Wastenbin pastebin service";
+
+    package = mkPackageOption pkgs "wastebin" { };
+
+    stateDir = mkOption {
+      type = types.path;
+      default = "/var/lib/wastebin";
+      description = "State directory of the daemon.";
+    };
+
+    secretFile = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      example = "/run/secrets/wastebin.env";
+      description = ''
+        Path to file containing sensitive environment variables.
+        Some variables that can be considered secrets are:
+
+        - WASTEBIN_PASSWORD_SALT:
+          salt used to hash user passwords used for encrypting pastes.
+
+        - WASTEBIN_SIGNING_KEY:
+          sets the key to sign cookies. If not set, a random key will be
+          generated which means cookies will become invalid after restarts and
+          paste creators will not be able to delete their pastes anymore.
+      '';
+    };
+
+    settings = mkOption {
+
+      description = ''
+        Additional configuration for wastebin, see
+        <https://github.com/matze/wastebin#usage> for supported values.
+        For secrets use secretFile option instead.
+      '';
+
+      type = types.submodule {
+
+        freeformType = with types; attrsOf (oneOf [ bool int str ]);
+
+        options = {
+
+          WASTEBIN_ADDRESS_PORT = mkOption {
+            type = types.str;
+            default = "0.0.0.0:8088";
+            description = "Address and port to bind to";
+          };
+
+          WASTEBIN_BASE_URL = mkOption {
+            default = "http://localhost";
+            example = "https://myhost.tld";
+            type = types.str;
+            description = ''
+              Base URL for the QR code display. If not set, the user agent's Host
+              header field is used as an approximation.
+            '';
+          };
+
+          WASTEBIN_CACHE_SIZE = mkOption {
+            default = 128;
+            type = types.int;
+            description = "Number of rendered syntax highlight items to cache. Can be disabled by setting to 0.";
+          };
+
+          WASTEBIN_DATABASE_PATH = mkOption {
+            default = "/var/lib/wastebin/sqlite3.db"; # TODO make this default to stateDir/sqlite3.db
+            type = types.str;
+            description = "Path to the sqlite3 database file. If not set, an in-memory database is used.";
+          };
+
+          WASTEBIN_HTTP_TIMEOUT = mkOption {
+            default = 5;
+            type = types.int;
+            description = "Maximum number of seconds a request can be processed until wastebin responds with 408";
+          };
+
+          WASTEBIN_MAX_BODY_SIZE = mkOption {
+            default = 1024;
+            type = types.int;
+            description = "Number of bytes to accept for POST requests";
+          };
+
+          WASTEBIN_TITLE = mkOption {
+            default = "wastebin";
+            type = types.str;
+            description = "Overrides the HTML page title";
+          };
+
+          RUST_LOG = mkOption {
+            default = "info";
+            type = types.str;
+            description =
+              ''
+                Influences logging. Besides the typical trace, debug, info etc.
+                keys, you can also set the tower_http key to some log level to get
+                additional information request and response logs.
+              '';
+          };
+        };
+      };
+
+      default = { };
+
+      example = {
+        WASTEBIN_TITLE = "My awesome pastebin";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable
+    {
+      systemd.services.wastebin = {
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
+        environment = mapAttrs (_: v: if isBool v then boolToString v else toString v) cfg.settings;
+        serviceConfig = {
+          CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
+          DevicePolicy = "closed";
+          DynamicUser = true;
+          ExecStart = "${getExe cfg.package}";
+          LockPersonality = true;
+          MemoryDenyWriteExecute = true;
+          PrivateDevices = true;
+          PrivateUsers = true;
+          ProtectClock = true;
+          ProtectControlGroups = true;
+          ProtectHostname = true;
+          ProtectKernelLogs = true;
+          ProtectKernelModules = true;
+          ProtectKernelTunables = true;
+          ProtectProc = "invisible";
+          RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+          RestrictNamespaces = true;
+          RestrictRealtime = true;
+          SystemCallArchitectures = [ "native" ];
+          SystemCallFilter = [ "@system-service" ];
+          StateDirectory = baseNameOf cfg.stateDir;
+          ReadWritePaths = cfg.stateDir;
+        } // optionalAttrs (cfg.secretFile != null) {
+          EnvironmentFile = cfg.secretFile;
+        };
+      };
+    };
+
+  meta.maintainers = with lib.maintainers; [ pinpox ];
+}
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 6a6ef1f6f38b..c804ce9418cd 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -985,6 +985,7 @@ in {
   vsftpd = handleTest ./vsftpd.nix {};
   warzone2100 = handleTest ./warzone2100.nix {};
   wasabibackend = handleTest ./wasabibackend.nix {};
+  wastebin = handleTest ./wastebin.nix {};
   watchdogd = handleTest ./watchdogd.nix {};
   webhook = runTest ./webhook.nix;
   wiki-js = handleTest ./wiki-js.nix {};
diff --git a/nixos/tests/wastebin.nix b/nixos/tests/wastebin.nix
new file mode 100644
index 000000000000..1cf0ff80ae99
--- /dev/null
+++ b/nixos/tests/wastebin.nix
@@ -0,0 +1,19 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
+  name = "wastebin";
+
+  meta = {
+    maintainers = with lib.maintainers; [ pinpox ];
+  };
+
+  nodes.machine = { pkgs, ... }: {
+    services.wastebin = {
+      enable = true;
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("wastebin.service")
+    machine.wait_for_open_port(8088)
+    machine.succeed("curl --fail http://localhost:8088/")
+  '';
+})
diff --git a/pkgs/by-name/wa/wastebin/package.nix b/pkgs/by-name/wa/wastebin/package.nix
new file mode 100644
index 000000000000..596d1d075219
--- /dev/null
+++ b/pkgs/by-name/wa/wastebin/package.nix
@@ -0,0 +1,43 @@
+{ lib
+, rustPlatform
+, fetchFromGitHub
+, pkg-config
+, sqlite
+, zstd
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "wastebin";
+  version = "2.4.3";
+
+  src = fetchFromGitHub {
+    owner = "matze";
+    repo = "wastebin";
+    rev = version;
+    hash = "sha256-5L9ug/OOvobic3bYjz8KUkQdnaVmAb2ltXCCiZkVHOg=";
+  };
+
+  cargoHash = "sha256-KbYbsV3+xhGFgcKrdLMiQ5+1meePjXYMD9PltlO+QMA=";
+
+  nativeBuildInputs = [
+    pkg-config
+  ];
+
+  buildInputs = [
+    sqlite
+    zstd
+  ];
+
+  env = {
+    ZSTD_SYS_USE_PKG_CONFIG = true;
+  };
+
+  meta = with lib; {
+    description = "Wastebin is a pastebin";
+    homepage = "https://github.com/matze/wastebin";
+    changelog = "https://github.com/matze/wastebin/blob/${src.rev}/CHANGELOG.md";
+    license = licenses.mit;
+    maintainers = with maintainers; [ pinpox matthiasbeyer ];
+    mainProgram = "wastebin";
+  };
+}