117 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			117 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
| { config, pkgs, lib, ... }:
 | |
| let
 | |
|   cfg = config.environment.robots-txt;
 | |
| 
 | |
|   robots-txt-format = {
 | |
|     type = let
 | |
|       coercedStrToNonEmptyListOfStr = lib.types.coercedTo lib.types.str lib.singleton (lib.types.nonEmptyListOf lib.types.str);
 | |
|     in lib.types.listOf (lib.types.submodule {
 | |
|       freeformType = lib.types.attrsOf coercedStrToNonEmptyListOfStr;
 | |
|       options = {
 | |
|         pre_comment = lib.mkOption {
 | |
|           description = "Comment to add before the rule";
 | |
|           type = lib.types.lines;
 | |
|           default = "";
 | |
|         };
 | |
|         post_comment = lib.mkOption {
 | |
|           description = "Comment to add after the rule";
 | |
|           type = lib.types.lines;
 | |
|           default = "";
 | |
|         };
 | |
|       };
 | |
|     });
 | |
| 
 | |
|     generate = name: value: let
 | |
|       makeComment = comment: lib.pipe comment [
 | |
|         (lib.splitString "\n")
 | |
|         (lib.map (line: if line == "" then "#" else "# ${line}"))
 | |
|         (lib.concatStringsSep "\n")
 | |
|       ];
 | |
| 
 | |
|       ruleToString = rule: let
 | |
|         user_agent = rule.User-agent or [];
 | |
|         pre_comment = rule.pre_comment;
 | |
|         post_comment = rule.post_comment;
 | |
|         rest = builtins.removeAttrs rule [ "User-agent" "pre_comment" "post_comment" ];
 | |
|       in lib.concatStringsSep "\n" (lib.filter (x: x != null) [
 | |
|         (if (pre_comment != "") then makeComment pre_comment else null)
 | |
|         (let
 | |
|           user-agents = lib.concatMapStringsSep "\n" (value: "User-agent: ${value}") user_agent;
 | |
|         in
 | |
|           if user_agent == [] then null else user-agents
 | |
|         )
 | |
|         (lib.pipe rest [
 | |
|           (lib.mapAttrsToList (ruleName: map (value: "${ruleName}: ${value}")))
 | |
|           lib.concatLists
 | |
|           (lib.concatStringsSep "\n")
 | |
|         ])
 | |
|         (if (post_comment != "") then makeComment post_comment else null)
 | |
|       ]);
 | |
| 
 | |
|       content = lib.concatMapStringsSep "\n\n" ruleToString value;
 | |
|     in pkgs.writeText name content;
 | |
|   };
 | |
| in
 | |
| {
 | |
|   options.environment.robots-txt = lib.mkOption {
 | |
|     default = { };
 | |
|     description = ''
 | |
|       Different instances of robots.txt to use with web services.
 | |
|     '';
 | |
|     type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: {
 | |
|       options = {
 | |
|         enable = lib.mkEnableOption "this instance of robots.txt" // {
 | |
|           default = true;
 | |
|         };
 | |
| 
 | |
|         path = lib.mkOption {
 | |
|           description = "The resulting path of the dir containing the robots.txt file";
 | |
|           type = lib.types.path;
 | |
|           readOnly = true;
 | |
|           default = "/etc/robots-txt/${name}";
 | |
|         };
 | |
| 
 | |
|         rules = lib.mkOption {
 | |
|           description = "Rules to include in robots.txt";
 | |
|           default = [ ];
 | |
|           example = [
 | |
|             { User-agent = "Googlebot"; Disallow = "/no-googlebot"; }
 | |
|             { User-agent = "Bingbot"; Disallow = [ "/no-bingbot" "/no-bingbot2" ]; }
 | |
|           ];
 | |
|           type = robots-txt-format.type;
 | |
|         };
 | |
| 
 | |
|         virtualHost = lib.mkOption {
 | |
|           description = "An nginx virtual host to add the robots.txt to";
 | |
|           type = lib.types.nullOr lib.types.str;
 | |
|           default = null;
 | |
|         };
 | |
|       };
 | |
|     }));
 | |
|   };
 | |
| 
 | |
|   config = {
 | |
|     environment.etc = lib.mapAttrs' (name: value: {
 | |
|       name = "robots-txt/${name}/robots.txt";
 | |
|       value.source = robots-txt-format.generate name value.rules;
 | |
|     }) cfg;
 | |
| 
 | |
|     services.nginx.virtualHosts = lib.pipe cfg [
 | |
|       (lib.filterAttrs (_: value: value.virtualHost != null))
 | |
|       (lib.mapAttrs' (name: value: {
 | |
|         name = value.virtualHost;
 | |
|         value = {
 | |
|           locations = {
 | |
|             "= /robots.txt" = {
 | |
|               extraConfig = ''
 | |
|                 add_header Content-Type text/plain;
 | |
|               '';
 | |
|               root = cfg.${name}.path;
 | |
|             };
 | |
|           };
 | |
|         };
 | |
|       }))
 | |
|     ];
 | |
|   };
 | |
| }
 |