209 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			209 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
{ config, lib, pkgs, ... }:
 | 
						|
 | 
						|
let
 | 
						|
  cfg = config.services.dufs;
 | 
						|
 | 
						|
  # Helper to create auth string from user list
 | 
						|
  mkAuthString = users: lib.concatMapStringsSep "|"
 | 
						|
    (user: "${user.username}:${user.passwordHash}@/:rw")
 | 
						|
    users;
 | 
						|
in
 | 
						|
{
 | 
						|
  options.services.dufs = {
 | 
						|
    enable = lib.mkEnableOption "dufs file server";
 | 
						|
 | 
						|
    package = lib.mkOption {
 | 
						|
      type = lib.types.package;
 | 
						|
      default = pkgs.dufs;
 | 
						|
      description = "The dufs package to use";
 | 
						|
    };
 | 
						|
 | 
						|
    servePathPublic = lib.mkOption {
 | 
						|
      type = lib.types.str;
 | 
						|
      default = "/nfs_export/kage/dufs/public";
 | 
						|
      description = "Directory path to serve files from";
 | 
						|
    };
 | 
						|
 | 
						|
    servePathPrivate = lib.mkOption {
 | 
						|
      type = lib.types.str;
 | 
						|
      default = "/nfs_export/kage/dufs/private";
 | 
						|
      description = "Directory path to serve files from";
 | 
						|
    };
 | 
						|
 | 
						|
    user = lib.mkOption {
 | 
						|
      type = lib.types.str;
 | 
						|
      default = "dufs";
 | 
						|
      description = "User to run dufs service as";
 | 
						|
    };
 | 
						|
 | 
						|
    group = lib.mkOption {
 | 
						|
      type = lib.types.str;
 | 
						|
      default = "dufs";
 | 
						|
      description = "Group to run dufs service as";
 | 
						|
    };
 | 
						|
 | 
						|
    publicInstance = {
 | 
						|
      enable = lib.mkEnableOption "public read-only instance";
 | 
						|
 | 
						|
      port = lib.mkOption {
 | 
						|
        type = lib.types.port;
 | 
						|
        default = 5000;
 | 
						|
        description = "Port for public read-only instance";
 | 
						|
      };
 | 
						|
 | 
						|
      bind = lib.mkOption {
 | 
						|
        type = lib.types.str;
 | 
						|
        default = "0.0.0.0";
 | 
						|
        description = "Bind address for public instance";
 | 
						|
      };
 | 
						|
 | 
						|
      allowSearch = lib.mkOption {
 | 
						|
        type = lib.types.bool;
 | 
						|
        default = true;
 | 
						|
        description = "Allow searching in public instance";
 | 
						|
      };
 | 
						|
    };
 | 
						|
 | 
						|
    privateInstance = {
 | 
						|
      enable = lib.mkEnableOption "private read-write instance";
 | 
						|
 | 
						|
      port = lib.mkOption {
 | 
						|
        type = lib.types.port;
 | 
						|
        default = 5001;
 | 
						|
        description = "Port for private authenticated instance";
 | 
						|
      };
 | 
						|
 | 
						|
      bind = lib.mkOption {
 | 
						|
        type = lib.types.str;
 | 
						|
        default = "0.0.0.0";
 | 
						|
        description = "Bind address for private instance";
 | 
						|
      };
 | 
						|
 | 
						|
      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: openssl passwd -6)";
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = [];
 | 
						|
        description = "List of users with read-write access";
 | 
						|
        example = [
 | 
						|
          {
 | 
						|
            username = "admin";
 | 
						|
            passwordHash = "$6$rounds=656000$...";
 | 
						|
          }
 | 
						|
        ];
 | 
						|
      };
 | 
						|
 | 
						|
      allowUpload = lib.mkOption {
 | 
						|
        type = lib.types.bool;
 | 
						|
        default = true;
 | 
						|
        description = "Allow file uploads";
 | 
						|
      };
 | 
						|
 | 
						|
      allowDelete = lib.mkOption {
 | 
						|
        type = lib.types.bool;
 | 
						|
        default = true;
 | 
						|
        description = "Allow file deletion";
 | 
						|
      };
 | 
						|
 | 
						|
      allowSearch = lib.mkOption {
 | 
						|
        type = lib.types.bool;
 | 
						|
        default = true;
 | 
						|
        description = "Allow searching";
 | 
						|
      };
 | 
						|
    };
 | 
						|
 | 
						|
    openFirewall = lib.mkOption {
 | 
						|
      type = lib.types.bool;
 | 
						|
      default = false;
 | 
						|
      description = "Open firewall ports for enabled instances";
 | 
						|
    };
 | 
						|
  };
 | 
						|
 | 
						|
  config = lib.mkIf cfg.enable {
 | 
						|
    # Create dufs user and group
 | 
						|
    users.users.${cfg.user} = {
 | 
						|
      isSystemUser = true;
 | 
						|
      group = cfg.group;
 | 
						|
      description = "dufs file server user";
 | 
						|
    };
 | 
						|
 | 
						|
    users.groups.${cfg.group} = {};
 | 
						|
 | 
						|
    # Public read-only instance
 | 
						|
    systemd.services.dufs-public = lib.mkIf cfg.publicInstance.enable {
 | 
						|
      description = "dufs public read-only file server";
 | 
						|
      wantedBy = [ "multi-user.target" ];
 | 
						|
      after = [ "network.target" ];
 | 
						|
 | 
						|
      serviceConfig = {
 | 
						|
        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"} \
 | 
						|
            --render-index
 | 
						|
        '';
 | 
						|
        Restart = "on-failure";
 | 
						|
        RestartSec = "10s";
 | 
						|
 | 
						|
        # Hardening
 | 
						|
        NoNewPrivileges = true;
 | 
						|
        PrivateTmp = true;
 | 
						|
        ProtectSystem = "strict";
 | 
						|
        ProtectHome = true;
 | 
						|
        ReadOnlyPaths = [ cfg.servePathPublic ];
 | 
						|
      };
 | 
						|
    };
 | 
						|
 | 
						|
    # Private read-write instance
 | 
						|
    systemd.services.dufs-private = lib.mkIf cfg.privateInstance.enable {
 | 
						|
      description = "dufs private read-write file server";
 | 
						|
      wantedBy = [ "multi-user.target" ];
 | 
						|
      after = [ "network.target" ];
 | 
						|
 | 
						|
      serviceConfig = {
 | 
						|
        Type = "simple";
 | 
						|
        User = cfg.user;
 | 
						|
        Group = cfg.group;
 | 
						|
        ExecStart = ''
 | 
						|
          ${cfg.package}/bin/dufs ${cfg.servePathPrivate} \
 | 
						|
            --bind ${cfg.privateInstance.bind} \
 | 
						|
            --port ${toString cfg.privateInstance.port} \
 | 
						|
            --auth '${mkAuthString cfg.privateInstance.users}' \
 | 
						|
            ${lib.optionalString cfg.privateInstance.allowUpload "--allow-upload"} \
 | 
						|
            ${lib.optionalString cfg.privateInstance.allowDelete "--allow-delete"} \
 | 
						|
            ${lib.optionalString cfg.privateInstance.allowSearch "--allow-search"} \
 | 
						|
            --render-index
 | 
						|
        '';
 | 
						|
        Restart = "on-failure";
 | 
						|
        RestartSec = "10s";
 | 
						|
 | 
						|
        # Hardening
 | 
						|
        NoNewPrivileges = true;
 | 
						|
        PrivateTmp = true;
 | 
						|
        ProtectSystem = "strict";
 | 
						|
        ProtectHome = true;
 | 
						|
        ReadWritePaths = [ cfg.servePathPrivate ];
 | 
						|
      };
 | 
						|
    };
 | 
						|
 | 
						|
    # Firewall configuration
 | 
						|
    networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall (
 | 
						|
      (lib.optional cfg.publicInstance.enable cfg.publicInstance.port) ++
 | 
						|
      (lib.optional cfg.privateInstance.enable cfg.privateInstance.port)
 | 
						|
    );
 | 
						|
  };
 | 
						|
}
 |