From 2eadf8918dd36421b975e2511a7253e5123c34c6 Mon Sep 17 00:00:00 2001 From: Nathan Anderson Date: Sun, 26 Oct 2025 21:52:50 -0600 Subject: [PATCH] add clearer permissions --- shared/modules/services/dufs.nix | 108 ++++++++++++++----------------- shared/server-configuration.nix | 30 ++++----- 2 files changed, 62 insertions(+), 76 deletions(-) diff --git a/shared/modules/services/dufs.nix b/shared/modules/services/dufs.nix index f48b9ce..599a610 100644 --- a/shared/modules/services/dufs.nix +++ b/shared/modules/services/dufs.nix @@ -3,18 +3,34 @@ let cfg = config.services.dufs; - # Helper to create auth arguments from user list - # Each user needs a separate -a flag - mkAuthArgs = users: readonlyUsers: + # User credential submodule + userCredential = lib.types.submodule { + options = { + username = lib.mkOption { + type = lib.types.str; + description = "Username for authentication"; + }; + passwordHash = lib.mkOption { + type = lib.types.str; + description = '' + SHA-512 password hash (generate with: mkpasswd -m sha-512) + Note: Must start with $6$ for dufs compatibility + ''; + }; + }; + }; + + # Helper to create auth arguments for different permission levels + mkAuthArgs = rwUsers: roUsers: let - rwUsers = lib.concatMapStringsSep " " + writers = lib.concatMapStringsSep " " (user: "-a '${user.username}:${user.passwordHash}@/:rw'") - users; - roUsers = lib.concatMapStringsSep " " + rwUsers; + readers = lib.concatMapStringsSep " " (user: "-a '${user.username}:${user.passwordHash}@/:ro'") - readonlyUsers; + roUsers; in - "${rwUsers} ${roUsers}"; + lib.concatStringsSep " " (lib.filter (s: s != "") [writers readers]); in { options.services.dufs = { @@ -65,6 +81,12 @@ in description = "Bind address for public instance"; }; + users = lib.mkOption { + type = lib.types.listOf userCredential; + default = []; + description = "Users with read-write access"; + }; + allowSearch = lib.mkOption { type = lib.types.bool; default = true; @@ -88,55 +110,15 @@ in }; users = lib.mkOption { - type = lib.types.listOf (lib.types.submodule { - options = { - username = lib.mkOption { - type = lib.types.str; - description = "Username for authentication"; - }; - passwordHash = lib.mkOption { - type = lib.types.str; - description = '' - SHA-512 password hash (generate with: mkpasswd -m sha-512) - Note: Must start with $6$ for dufs compatibility - ''; - }; - }; - }); + type = lib.types.listOf userCredential; default = []; - description = "List of users with read-write access"; - example = [ - { - username = "admin"; - passwordHash = "$6$rounds=656000$..."; - } - ]; + description = "Users with read-write access"; }; - readonlyUsers = lib.mkOption { - type = lib.types.listOf (lib.types.submodule { - options = { - username = lib.mkOption { - type = lib.types.str; - description = "Username for authentication"; - }; - passwordHash = lib.mkOption { - type = lib.types.str; - description = '' - SHA-512 password hash (generate with: mkpasswd -m sha-512) - Note: Must start with $6$ for dufs compatibility - ''; - }; - }; - }); + guestUsers = lib.mkOption { + type = lib.types.listOf userCredential; default = []; - description = "List of users with read-only access"; - example = [ - { - username = "viewer"; - passwordHash = "$6$rounds=656000$..."; - } - ]; + description = "Guest users with read-only access"; }; allowUpload = lib.mkOption { @@ -192,12 +174,18 @@ in Type = "simple"; User = cfg.user; Group = cfg.group; - ExecStart = '' - ${cfg.package}/bin/dufs ${cfg.servePathPublic} \ - --bind ${cfg.publicInstance.bind} \ - --port ${toString cfg.publicInstance.port} \ - ${lib.optionalString cfg.publicInstance.allowSearch "--allow-search"} - ''; + ExecStart = + let + hasAuth = (cfg.publicInstance.users != []); + authArgs = lib.optionalString hasAuth + (mkAuthArgs cfg.publicInstance.users []) + " -a @/"; # allows read only on all paths (public) + in '' + ${cfg.package}/bin/dufs ${cfg.servePathPublic} \ + --bind ${cfg.publicInstance.bind} \ + --port ${toString cfg.publicInstance.port} \ + ${authArgs} \ + ${lib.optionalString cfg.publicInstance.allowSearch "--allow-search"} + ''; Restart = "on-failure"; RestartSec = "10s"; @@ -224,7 +212,7 @@ in ${cfg.package}/bin/dufs ${cfg.servePathPrivate} \ --bind ${cfg.privateInstance.bind} \ --port ${toString cfg.privateInstance.port} \ - ${mkAuthArgs cfg.privateInstance.users cfg.privateInstance.readonlyUsers} \ + ${mkAuthArgs cfg.privateInstance.users cfg.privateInstance.guestUsers} \ ${lib.optionalString cfg.privateInstance.allowUpload "--allow-upload"} \ ${lib.optionalString cfg.privateInstance.allowDelete "--allow-delete"} \ ${lib.optionalString cfg.privateInstance.allowSearch "--allow-search"} diff --git a/shared/server-configuration.nix b/shared/server-configuration.nix index 66919aa..ccac88f 100644 --- a/shared/server-configuration.nix +++ b/shared/server-configuration.nix @@ -182,38 +182,37 @@ in user = "kage"; group = "users"; - # Public read-only instance + # Public instance with admin/guest authentication publicInstance = { enable = true; port = 5000; allowSearch = true; + # Admin users can upload/modify on public instance + users = [ + { + username = "nate"; + passwordHash = "$6$lJDBaW7zzlaAlzbV$u.mzsKCDOCWdUffPlXhx9dWRgJsxOUJRKj5Z5/NMEPC2WfPT9x9W145rThogzFLhynIT7UkYXd4zYdnsrGPRS0"; # open + } + ]; }; - # Private read-write instance with authentication + # Private instance with admin/user/guest authentication privateInstance = { enable = true; port = 5001; allowUpload = true; - allowDelete = true; + allowDelete = false; allowSearch = true; - # Read-write users users = [ - # Generate password hash with: mkpasswd -m sha-512 - # These are temporary passwords and should be changed { - username = "nate"; - passwordHash = "$6$eIqVeCL9q5GlN.Em$xm7RxNcGfArYFBprmnggt1zzDf.HluKwXcG9LsJNCK6.vnKGmQDb5b7h7g81tWY7jIDdPsgLu0jiTzbz1lFIC0"; # password + username = "user"; + passwordHash = "$6$lJDBaW7zzlaAlzbV$u.mzsKCDOCWdUffPlXhx9dWRgJsxOUJRKj5Z5/NMEPC2WfPT9x9W145rThogzFLhynIT7UkYXd4zYdnsrGPRS0"; # open } ]; - # Read-only users - readonlyUsers = [ + guestUsers = [ { username = "guest"; - passwordHash = "$6$.Ot.4AWNRpx0LJ1s$M01RpAJ.VZWJfDrTlali.P0Fhnn0Ji.uP/fIdgZP0ly64g8AzeGb6/2C9dbKmnARdVV9M12mLmU6ENmUbR/ym1"; # guest - } - { - username = "readonly"; - passwordHash = "$6$3Z5KK8mIbxN2tZR4$eCOpbwAKAk6CKMZWgWddgJaQyTDUkYzB0T8tNXfSUQkUL2A/QEXoEONcPaZnF/jfem9qB..Snm2xR/7GTkyVg."; # readonly + passwordHash = "$6$.Ot.4AWNRpx0LJ1s$M01RpAJ.VZWJfDrTlali.P0Fhnn0Ji.uP/fIdgZP0ly64g8AzeGb6/2C9dbKmnARdVV9M12mLmU6ENmUbR/ym1"; # guest } ]; }; @@ -235,7 +234,6 @@ in listenAddresses = [ "*:631" ]; allowFrom = [ "all" ]; browsing = true; - # browserAddress = "192.168.1.169:631"; defaultShared = true; openFirewall = true; };