From 6599a79a8bd916fc5b99140ac2e268cfc14291ec Mon Sep 17 00:00:00 2001 From: Christoph Heiss Date: Sat, 17 Feb 2024 19:01:49 +0100 Subject: [PATCH 1/5] filebrowser: 2.23.0 -> 2.28.0 Signed-off-by: Christoph Heiss --- .../networking/filebrowser/default.nix | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/pkgs/applications/networking/filebrowser/default.nix b/pkgs/applications/networking/filebrowser/default.nix index 334302cae0089..439cdbb9acb92 100644 --- a/pkgs/applications/networking/filebrowser/default.nix +++ b/pkgs/applications/networking/filebrowser/default.nix @@ -1,20 +1,21 @@ { buildGoModule, buildNpmPackage, fetchFromGitHub, lib }: let + version = "2.28.0"; + src = fetchFromGitHub { + owner = "filebrowser"; + repo = "filebrowser"; + rev = "v${version}"; + hash = "sha256-ubfNGsVClMIq7u0DQVrR4Hdr8NNf76QXqLxnRVJHaCM="; + }; + frontend = buildNpmPackage rec { pname = "filebrowser-frontend"; - version = "2.23.0"; - - src = fetchFromGitHub { - owner = "filebrowser"; - repo = "filebrowser"; - rev = "v${version}"; - hash = "sha256-xhBIJcEtxDdMXSgQtLAV0UWzPtrvKEil0WV76K5ycBc="; - }; + inherit version src; sourceRoot = "${src.name}/frontend"; - npmDepsHash = "sha256-acNIMKHc4q7eiFLPBtKZBNweEsrt+//0VR6dqwXHTvA="; + npmDepsHash = "sha256-h2Sqco7NHLnaMNgh9Ykggarv6cS0NrA6M9/2nv2RU28="; NODE_OPTIONS = "--openssl-legacy-provider"; @@ -30,16 +31,9 @@ let in buildGoModule rec { pname = "filebrowser"; - version = "2.23.0"; - - src = fetchFromGitHub { - owner = "filebrowser"; - repo = "filebrowser"; - rev = "v${version}"; - hash = "sha256-xhBIJcEtxDdMXSgQtLAV0UWzPtrvKEil0WV76K5ycBc="; - }; + inherit version src; - vendorHash = "sha256-MR0ju2Nomb3j78Z+1YcJY+jPd40MZpuOTuQJM94AM8A="; + vendorHash = "sha256-pDQyJ0F6gCkJtUnaoSe+lWpgNbk/2GDGQ67S3G+VudE="; excludedPackages = [ "tools" ]; From 7358a59991c7f496c30ad188d4e67c2a4f076495 Mon Sep 17 00:00:00 2001 From: Christoph Heiss Date: Sat, 17 Feb 2024 19:02:06 +0100 Subject: [PATCH 2/5] filebrowser: add myself as maintainer Signed-off-by: Christoph Heiss --- pkgs/applications/networking/filebrowser/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/applications/networking/filebrowser/default.nix b/pkgs/applications/networking/filebrowser/default.nix index 439cdbb9acb92..f652273fd4d9e 100644 --- a/pkgs/applications/networking/filebrowser/default.nix +++ b/pkgs/applications/networking/filebrowser/default.nix @@ -49,7 +49,7 @@ buildGoModule rec { description = "Filebrowser is a web application for managing files and directories"; homepage = "https://filebrowser.org"; license = licenses.asl20; - maintainers = with maintainers; [ nielsegberts ]; + maintainers = with maintainers; [ nielsegberts christoph-heiss ]; mainProgram = "filebrowser"; }; } From a101a33444fbeee022bbd035870f74f633245efb Mon Sep 17 00:00:00 2001 From: Christoph Heiss Date: Fri, 22 Mar 2024 22:59:55 +0100 Subject: [PATCH 3/5] filebrowser: drop nielsegberts from maintainers This package hasn't been updated in ~1.5 years and the maintainer does not seem to respond. Signed-off-by: Christoph Heiss --- maintainers/maintainer-list.nix | 6 ------ pkgs/applications/networking/filebrowser/default.nix | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index a26b96ce3ea0d..d24166d2a504b 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -14394,12 +14394,6 @@ fingerprint = "E576 BFB2 CF6E B13D F571 33B9 E315 A758 4613 1564"; }]; }; - nielsegberts = { - email = "nix@nielsegberts.nl"; - github = "nielsegberts"; - githubId = 368712; - name = "Niels Egberts"; - }; nigelgbanks = { name = "Nigel Banks"; email = "nigel.g.banks@gmail.com"; diff --git a/pkgs/applications/networking/filebrowser/default.nix b/pkgs/applications/networking/filebrowser/default.nix index f652273fd4d9e..d778b2e7915e4 100644 --- a/pkgs/applications/networking/filebrowser/default.nix +++ b/pkgs/applications/networking/filebrowser/default.nix @@ -49,7 +49,7 @@ buildGoModule rec { description = "Filebrowser is a web application for managing files and directories"; homepage = "https://filebrowser.org"; license = licenses.asl20; - maintainers = with maintainers; [ nielsegberts christoph-heiss ]; + maintainers = with maintainers; [ christoph-heiss ]; mainProgram = "filebrowser"; }; } From eb40383d2637eeaf9cb2f2c9686216d700191766 Mon Sep 17 00:00:00 2001 From: Christoph Heiss Date: Sat, 17 Feb 2024 21:51:32 +0100 Subject: [PATCH 4/5] nixos/filebrowser: init module Signed-off-by: Christoph Heiss --- .../manual/release-notes/rl-2405.section.md | 2 + nixos/modules/module-list.nix | 1 + .../modules/services/web-apps/filebrowser.nix | 181 ++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 nixos/modules/services/web-apps/filebrowser.nix diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index 0fd44f0673315..b997f0648b5c3 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -181,6 +181,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). +- [filebrowser](https://github.com/filebrowser/filebrowser), a web application for managing files and directories. Available as [services.filebrowser.enable](#opt-services.filebrowser.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) diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 29c373788c1fe..eaac43ddd6529 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1338,6 +1338,7 @@ ./services/web-apps/engelsystem.nix ./services/web-apps/ethercalc.nix ./services/web-apps/firefly-iii.nix + ./services/web-apps/filebrowser.nix ./services/web-apps/fluidd.nix ./services/web-apps/freshrss.nix ./services/web-apps/galene.nix diff --git a/nixos/modules/services/web-apps/filebrowser.nix b/nixos/modules/services/web-apps/filebrowser.nix new file mode 100644 index 0000000000000..4813a8ce9848e --- /dev/null +++ b/nixos/modules/services/web-apps/filebrowser.nix @@ -0,0 +1,181 @@ +{ config, lib, pkgs, ... }: + +let + inherit (lib) generators types hasPrefix literalExpression mkEnableOption mkIf + mkOption mkPackageOption optional optionalAttrs; + + cfg = config.services.filebrowser; + enableDynamicUser = + assert cfg.user != "filebrowser" -> cfg.group != "filebrowser"; + cfg.user == "filebrowser"; + enableTls = + assert cfg.tlsCertificate != null -> cfg.tlsCertificateKey != null; + cfg.tlsCertificate != null; + + configFile = pkgs.writeText "filebrowser-config.json" (generators.toJSON {} ({ + database = "/var/lib/filebrowser/filebrowser.db"; + root = cfg.rootDir; + inherit (cfg) address port; + } // (optionalAttrs enableTls { + cert = cfg.tlsCertificate; + key = cfg.tlsCertificateKey; + }) + // (optionalAttrs (cfg.baseUrl != null) { baseurl = cfg.baseUrl; }) + // (optionalAttrs (cfg.cacheDir != null) { cache-dir = cfg.cacheDir; }) + // (optionalAttrs cfg.disableThumbnails { disable-thumbnails = true; }) + // (optionalAttrs cfg.disablePreviewResize { disable-preview-resize = true; }) + // (optionalAttrs cfg.disableCommandRunner { disable-exec = true; }) + // (optionalAttrs cfg.disableTypeDetectionByHeader { disable-type-detection-by-header = true; }) + )); +in +{ + options.services.filebrowser = { + enable = mkEnableOption + "File Browser is a web application for managing files and directories"; + + package = mkPackageOption pkgs "filebrowser" { }; + + # https://github.com/filebrowser/filebrowser/blob/bd3c1941ff8289a5dae877e08f7e25fa9b2a92c5/cmd/root.go#L56 + address = mkOption { + type = types.str; + default = "127.0.0.1"; + example = literalExpression "0.0.0.0"; + description = '' + Address the service should listen on. + ''; + }; + + port = mkOption { + type = types.port; + default = 8080; + description = "Port the service should listen on."; + }; + + tlsCertificate = mkOption { + type = types.nullOr types.path; + default = null; + description = "Optional TLS certificate"; + }; + + tlsCertificateKey = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Key for TLS certificate. Must be set if `services.filebrowser.tlsCertficate` + is used. + ''; + }; + + rootDir = mkOption { + type = types.path; + default = "/var/lib/filebrowser/files"; + description = '' + Path to the directory that should be exposed by File Browser. + ''; + }; + + baseUrl = mkOption { + type = types.nullOr types.str; + default = null; + example = "/files"; + description = '' + Subpath to serve the web interface at. Useful in combination with a + reverse proxy. + ''; + }; + + cacheDir = mkOption { + type = types.nullOr types.path; + default = null; + example = literalExpression "/var/cache/filebrowser"; + description = "File cache directory. Disabled by default."; + }; + + tokenExpirationTime = mkOption { + type = types.str; + default = "2h"; + example = "12h"; + description = "User session timeout"; + }; + + imageProcessors = mkOption { + type = types.int; + default = 4; + example = 2; + description = "Number of image processes."; + }; + + disableThumbnails = mkEnableOption "Disable image thumbnails."; + disablePreviewResize = mkEnableOption "Disable resize of image previews."; + disableCommandRunner = mkEnableOption "Disable the Command Runner feature."; + disableTypeDetectionByHeader = mkEnableOption + "Disable file type detection by reading file headers."; + + user = mkOption { + type = types.str; + default = "filebrowser"; + description = '' + If `services.filebrowser.group` is set, this must be set as well. Must + already exist. + ''; + }; + + group = mkOption { + type = types.str; + default = "filebrowser"; + description = '' + If `services.filebrowser.user` is set, this must be set as well. Must + already exist. + ''; + }; + + openFirewall = mkEnableOption "Open the port in the firewall."; + }; + + config = mkIf cfg.enable { + systemd.services.filebrowser = { + description = "File Browser service"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + environment.HOME = "/var/lib/filebrowser"; + + serviceConfig = { + Type = "simple"; + Restart = "on-failure"; + User = cfg.user; + Group = cfg.group; + StateDirectory = "filebrowser"; + BindPaths = optional (!(hasPrefix "/var/lib/filebrowser" cfg.rootDir)) cfg.rootDir; + + DynamicUser = enableDynamicUser; + + # Basic hardening + NoNewPrivileges = "yes"; + PrivateTmp = "yes"; + PrivateDevices = "yes"; + DevicePolicy = "closed"; + ProtectSystem = "strict"; + ProtectHome = "tmpfs"; + ProtectControlGroups = "yes"; + ProtectKernelModules = "yes"; + ProtectKernelTunables = "yes"; + RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6"; + RestrictNamespaces = "yes"; + RestrictRealtime = "yes"; + RestrictSUIDSGID = "yes"; + MemoryDenyWriteExecute = "yes"; + LockPersonality = "yes"; + + ExecStartPre = '' + ${pkgs.coreutils}/bin/mkdir -p ${toString cfg.rootDir} + ''; + + ExecStart = "${cfg.package}/bin/filebrowser --config ${configFile}"; + }; + }; + + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; + }; + + meta.maintainers = with lib.maintainers; [ christoph-heiss ]; +} From 7336e463b7080b42a41fe551e201ed82e3307979 Mon Sep 17 00:00:00 2001 From: Christoph Heiss Date: Sat, 17 Feb 2024 21:51:55 +0100 Subject: [PATCH 5/5] nixos/tests/filebrowser: init test module Signed-off-by: Christoph Heiss --- nixos/tests/all-tests.nix | 1 + nixos/tests/filebrowser.nix | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 nixos/tests/filebrowser.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 232f10d7c24dd..457620f638224 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -307,6 +307,7 @@ in { fenics = handleTest ./fenics.nix {}; ferm = handleTest ./ferm.nix {}; ferretdb = handleTest ./ferretdb.nix {}; + filebrowser = handleTest ./filebrowser.nix { }; filesystems-overlayfs = runTest ./filesystems-overlayfs.nix; firefly-iii = handleTest ./firefly-iii.nix {}; firefox = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox; }; diff --git a/nixos/tests/filebrowser.nix b/nixos/tests/filebrowser.nix new file mode 100644 index 0000000000000..67cc8b3731fbb --- /dev/null +++ b/nixos/tests/filebrowser.nix @@ -0,0 +1,46 @@ +import ./make-test-python.nix ({ pkgs, lib, ... }: + let + tls-cert = pkgs.runCommand "selfSignedCerts" { + buildInputs = [ pkgs.openssl ]; + } '' + mkdir -p $out + openssl req -x509 \ + -subj '/CN=localhost/' -days 365 \ + -addext 'subjectAltName = DNS:localhost' \ + -keyout "$out/cert.key" -newkey ed25519 \ + -out "$out/cert.pem" -noenc + ''; + in { + name = "filebrowser"; + meta.maintainers = with lib.maintainers; [ christoph-heiss ]; + + nodes = { + http = { + services.filebrowser = { + enable = true; + }; + }; + https = { + security.pki.certificateFiles = [ "${tls-cert}/cert.pem" ]; + services.filebrowser = { + enable = true; + tlsCertificate = "${tls-cert}/cert.pem"; + tlsCertificateKey = "${tls-cert}/cert.key"; + }; + }; + }; + + testScript = '' + start_all() + + with subtest("check if http works"): + http.wait_for_unit("filebrowser.service") + http.wait_for_open_port(8080) + http.succeed("curl -sSf http://localhost:8080 | grep ''") + + with subtest("check if https works"): + https.wait_for_unit("filebrowser.service") + https.wait_for_open_port(8080) + https.succeed("curl -sSf https://localhost:8080 | grep ''") + ''; + })