add clearer permissions

This commit is contained in:
Nathan Anderson 2025-10-26 21:52:50 -06:00
parent 877560a974
commit 2eadf8918d
2 changed files with 62 additions and 76 deletions

View File

@ -3,18 +3,34 @@
let let
cfg = config.services.dufs; cfg = config.services.dufs;
# Helper to create auth arguments from user list # User credential submodule
# Each user needs a separate -a flag userCredential = lib.types.submodule {
mkAuthArgs = users: readonlyUsers: 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 let
rwUsers = lib.concatMapStringsSep " " writers = lib.concatMapStringsSep " "
(user: "-a '${user.username}:${user.passwordHash}@/:rw'") (user: "-a '${user.username}:${user.passwordHash}@/:rw'")
users; rwUsers;
roUsers = lib.concatMapStringsSep " " readers = lib.concatMapStringsSep " "
(user: "-a '${user.username}:${user.passwordHash}@/:ro'") (user: "-a '${user.username}:${user.passwordHash}@/:ro'")
readonlyUsers; roUsers;
in in
"${rwUsers} ${roUsers}"; lib.concatStringsSep " " (lib.filter (s: s != "") [writers readers]);
in in
{ {
options.services.dufs = { options.services.dufs = {
@ -65,6 +81,12 @@ in
description = "Bind address for public instance"; description = "Bind address for public instance";
}; };
users = lib.mkOption {
type = lib.types.listOf userCredential;
default = [];
description = "Users with read-write access";
};
allowSearch = lib.mkOption { allowSearch = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
default = true; default = true;
@ -88,55 +110,15 @@ in
}; };
users = lib.mkOption { users = lib.mkOption {
type = lib.types.listOf (lib.types.submodule { type = lib.types.listOf userCredential;
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
'';
};
};
});
default = []; default = [];
description = "List of users with read-write access"; description = "Users with read-write access";
example = [
{
username = "admin";
passwordHash = "$6$rounds=656000$...";
}
];
}; };
readonlyUsers = lib.mkOption { guestUsers = lib.mkOption {
type = lib.types.listOf (lib.types.submodule { type = lib.types.listOf userCredential;
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
'';
};
};
});
default = []; default = [];
description = "List of users with read-only access"; description = "Guest users with read-only access";
example = [
{
username = "viewer";
passwordHash = "$6$rounds=656000$...";
}
];
}; };
allowUpload = lib.mkOption { allowUpload = lib.mkOption {
@ -192,10 +174,16 @@ in
Type = "simple"; Type = "simple";
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
ExecStart = '' 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} \ ${cfg.package}/bin/dufs ${cfg.servePathPublic} \
--bind ${cfg.publicInstance.bind} \ --bind ${cfg.publicInstance.bind} \
--port ${toString cfg.publicInstance.port} \ --port ${toString cfg.publicInstance.port} \
${authArgs} \
${lib.optionalString cfg.publicInstance.allowSearch "--allow-search"} ${lib.optionalString cfg.publicInstance.allowSearch "--allow-search"}
''; '';
Restart = "on-failure"; Restart = "on-failure";
@ -224,7 +212,7 @@ in
${cfg.package}/bin/dufs ${cfg.servePathPrivate} \ ${cfg.package}/bin/dufs ${cfg.servePathPrivate} \
--bind ${cfg.privateInstance.bind} \ --bind ${cfg.privateInstance.bind} \
--port ${toString cfg.privateInstance.port} \ --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.allowUpload "--allow-upload"} \
${lib.optionalString cfg.privateInstance.allowDelete "--allow-delete"} \ ${lib.optionalString cfg.privateInstance.allowDelete "--allow-delete"} \
${lib.optionalString cfg.privateInstance.allowSearch "--allow-search"} ${lib.optionalString cfg.privateInstance.allowSearch "--allow-search"}

View File

@ -182,39 +182,38 @@ in
user = "kage"; user = "kage";
group = "users"; group = "users";
# Public read-only instance # Public instance with admin/guest authentication
publicInstance = { publicInstance = {
enable = true; enable = true;
port = 5000; port = 5000;
allowSearch = true; 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 = { privateInstance = {
enable = true; enable = true;
port = 5001; port = 5001;
allowUpload = true; allowUpload = true;
allowDelete = true; allowDelete = false;
allowSearch = true; allowSearch = true;
# Read-write users
users = [ users = [
# Generate password hash with: mkpasswd -m sha-512
# These are temporary passwords and should be changed
{ {
username = "nate"; username = "user";
passwordHash = "$6$eIqVeCL9q5GlN.Em$xm7RxNcGfArYFBprmnggt1zzDf.HluKwXcG9LsJNCK6.vnKGmQDb5b7h7g81tWY7jIDdPsgLu0jiTzbz1lFIC0"; # password passwordHash = "$6$lJDBaW7zzlaAlzbV$u.mzsKCDOCWdUffPlXhx9dWRgJsxOUJRKj5Z5/NMEPC2WfPT9x9W145rThogzFLhynIT7UkYXd4zYdnsrGPRS0"; # open
} }
]; ];
# Read-only users guestUsers = [
readonlyUsers = [
{ {
username = "guest"; username = "guest";
passwordHash = "$6$.Ot.4AWNRpx0LJ1s$M01RpAJ.VZWJfDrTlali.P0Fhnn0Ji.uP/fIdgZP0ly64g8AzeGb6/2C9dbKmnARdVV9M12mLmU6ENmUbR/ym1"; # guest passwordHash = "$6$.Ot.4AWNRpx0LJ1s$M01RpAJ.VZWJfDrTlali.P0Fhnn0Ji.uP/fIdgZP0ly64g8AzeGb6/2C9dbKmnARdVV9M12mLmU6ENmUbR/ym1"; # guest
} }
{
username = "readonly";
passwordHash = "$6$3Z5KK8mIbxN2tZR4$eCOpbwAKAk6CKMZWgWddgJaQyTDUkYzB0T8tNXfSUQkUL2A/QEXoEONcPaZnF/jfem9qB..Snm2xR/7GTkyVg."; # readonly
}
]; ];
}; };
}; };
@ -235,7 +234,6 @@ in
listenAddresses = [ "*:631" ]; listenAddresses = [ "*:631" ];
allowFrom = [ "all" ]; allowFrom = [ "all" ];
browsing = true; browsing = true;
# browserAddress = "192.168.1.169:631";
defaultShared = true; defaultShared = true;
openFirewall = true; openFirewall = true;
}; };