-
-
Notifications
You must be signed in to change notification settings - Fork 14.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
filebrowser: 2.23.0 -> 2.28.0, add service module #289750
base: master
Are you sure you want to change the base?
Changes from all commits
6599a79
7358a59
a101a33
eb40383
7336e46
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14394,12 +14394,6 @@ | |
fingerprint = "E576 BFB2 CF6E B13D F571 33B9 E315 A758 4613 1564"; | ||
}]; | ||
}; | ||
nielsegberts = { | ||
email = "[email protected]"; | ||
github = "nielsegberts"; | ||
githubId = 368712; | ||
name = "Niels Egberts"; | ||
}; | ||
nigelgbanks = { | ||
name = "Nigel Banks"; | ||
email = "[email protected]"; | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -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; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a module level assertion |
||||||
cfg.tlsCertificate != null; | ||||||
|
||||||
configFile = pkgs.writeText "filebrowser-config.json" (generators.toJSON {} ({ | ||||||
database = "/var/lib/filebrowser/filebrowser.db"; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We use 2 spaces to intend nix code
Suggested change
|
||||||
root = cfg.rootDir; | ||||||
inherit (cfg) address port; | ||||||
} // (optionalAttrs enableTls { | ||||||
cert = cfg.tlsCertificate; | ||||||
key = cfg.tlsCertificateKey; | ||||||
}) | ||||||
// (optionalAttrs (cfg.baseUrl != null) { baseurl = cfg.baseUrl; }) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. optionalAttrs doesn't require sourounding brackets |
||||||
// (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; }) | ||||||
Comment on lines
+24
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use an rfc 42 freeform setting type for this? |
||||||
)); | ||||||
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; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this default to / ? |
||||||
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."; | ||||||
Comment on lines
+108
to
+112
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The description of those will be prefixed with |
||||||
|
||||||
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 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't we create the default user? |
||||||
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"; | ||||||
Comment on lines
+153
to
+167
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In nixpkgs we mostly use true instead of "yes" |
||||||
|
||||||
ExecStartPre = '' | ||||||
${pkgs.coreutils}/bin/mkdir -p ${toString cfg.rootDir} | ||||||
''; | ||||||
|
||||||
ExecStart = "${cfg.package}/bin/filebrowser --config ${configFile}"; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
}; | ||||||
}; | ||||||
|
||||||
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; | ||||||
}; | ||||||
|
||||||
meta.maintainers = with lib.maintainers; [ christoph-heiss ]; | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 '<!doctype html>'") | ||
|
||
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 '<!doctype html>'") | ||
''; | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find it kinda strange and unexpected that DynamicUser gets disabled when the user and group settings are changed.