feat: Add nginx module

Change-Id: I34fbb926c4b7eab344c1c14de4e4b5f82c6c30eb
Reviewed-on: https://git.clicks.codes/c/Infra/NixFiles/+/785
Reviewed-by: Samuel Shuert <coded@clicks.codes>
Tested-by: Skyler Grey <minion@clicks.codes>
diff --git a/lib/nginx/http/internal/lib.nginx.http.internal.http.spec.nix b/lib/nginx/http/internal/lib.nginx.http.internal.http.spec.nix
new file mode 100644
index 0000000..4f56d96
--- /dev/null
+++ b/lib/nginx/http/internal/lib.nginx.http.internal.http.spec.nix
@@ -0,0 +1,238 @@
+# SPDX-FileCopyrightText: 2024 Clicks Codes
+#
+# SPDX-License-Identifier: GPL-3.0-only
+
+{ lib, ... }: let
+  step0 = {
+    "calibre.clicks.codes" = {
+      service = lib.clicks.nginx.http.reverseProxy "generic" 1024;
+      www = true;
+      dnsProvider = "cloudflare";
+      routes = null;
+      authWith = "tailscale";
+      enableHttp = true;
+    };
+  };
+  step1 = {
+    "calibre.clicks.codes" = {
+      service = {
+        host = "generic";
+        port = 1024;
+        protocol = "http";
+        _type = "reverseProxy";
+        headers = null;
+      };
+      dnsProvider = "cloudflare";
+      routes = null;
+      authWith = "tailscale";
+      enableHttp = true;
+    };
+    "www.calibre.clicks.codes" = {
+      routes."~ ^/?([^\r\n]*)$" = lib.home-manager.hm.dag.entryAnywhere {
+        to = "https://calibre.clicks.codes/$1";
+        permanent = true;
+        _type = "redirect";
+        headers = null;
+      };
+      authWith = null;
+      service = null;
+      enableHttp = true;
+    };
+  };
+  step2 = {
+    "calibre.clicks.codes" = {
+      routes."/" = lib.home-manager.hm.dag.entryAnywhere {
+        host = "generic";
+        port = 1024;
+        protocol = "http";
+        _type = "reverseProxy";
+        headers = null;
+      };
+      dnsProvider = "cloudflare";
+      authWith = "tailscale";
+      enableHttp = true;
+    };
+    "www.calibre.clicks.codes" = {
+      routes."~ ^/?([^\r\n]*)$" = lib.home-manager.hm.dag.entryAnywhere {
+        to = "https://calibre.clicks.codes/$1";
+        permanent = true;
+        _type = "redirect";
+        headers = null;
+      };
+      authWith = null;
+      enableHttp = true;
+    };
+  };
+  step3 = {
+    "calibre.clicks.codes" = {
+      routes = [
+        {
+          name = "/";
+          value = {
+            host = "generic";
+            port = 1024;
+            protocol = "http";
+            _type = "reverseProxy";
+            headers = null;
+          };
+        }
+      ];
+      dnsProvider = "cloudflare";
+      authWith = "tailscale";
+      enableHttp = true;
+    };
+    "www.calibre.clicks.codes" = {
+      routes = [
+        {
+          name = "~ ^/?([^\r\n]*)$";
+          value = {
+            to = "https://calibre.clicks.codes/$1";
+            permanent = true;
+            _type = "redirect";
+            headers = null;
+          };
+        }
+      ];
+      authWith = null;
+      enableHttp = true;
+    };
+  };
+  step4 = {
+    "calibre.clicks.codes" = {
+      routes = [
+        {
+          name = "/";
+          value = {
+            host = "generic";
+            port = 1024;
+            protocol = "http";
+            _type = "reverseProxy";
+            headers = null;
+          };
+        }
+      ];
+      dnsProvider = "cloudflare";
+      authWith = "tailscale";
+      enableHttp = true;
+    };
+    "www.calibre.clicks.codes" = {
+      routes = [
+        {
+          name = "~ ^/?([^\r\n]*)$";
+          value = {
+            to = "https://calibre.clicks.codes/$1";
+            permanent = true;
+            _type = "redirect";
+            headers = null;
+          };
+        }
+      ];
+      authWith = null;
+      enableHttp = true;
+    };
+  };
+  step5 = {
+    "calibre.clicks.codes" = {
+      locations = [
+        {
+          name = "/";
+          value = {
+            proxyPass = "http://generic:1024";
+            proxyWebsockets = true;
+            recommendedProxySettings = true;
+          };
+        }
+      ];
+      dnsProvider = "cloudflare";
+      authWith = "tailscale";
+      enableHttp = true;
+    };
+    "www.calibre.clicks.codes" = {
+      locations = [
+        {
+          name = "~ ^/?([^\r\n]*)$";
+          value = {
+            return = "307 https://calibre.clicks.codes/$1";
+          };
+        }
+      ];
+      authWith = null;
+      enableHttp = true;
+    };
+  };
+  step6 = {
+    "calibre.clicks.codes" = {
+      locations."/" = {
+        priority = 100;
+        proxyPass = "http://generic:1024";
+        proxyWebsockets = true;
+        recommendedProxySettings = true;
+      };
+      dnsProvider = "cloudflare";
+      authWith = "tailscale";
+      enableHttp = true;
+    };
+    "www.calibre.clicks.codes" = {
+      locations."~ ^/?([^\r\n]*)$" = {
+        return = "307 https://calibre.clicks.codes/$1";
+        priority = 100;
+      };
+      authWith = null;
+      enableHttp = true;
+    };
+  };
+  step7 = {
+    "calibre.clicks.codes" = {
+      locations."/" = {
+        priority = 100;
+        proxyPass = "http://generic:1024";
+        proxyWebsockets = true;
+        recommendedProxySettings = true;
+      };
+      onlySSL = false;
+      addSSL = true;
+      useACMEHost = "calibre.clicks.codes";
+      dnsProvider = "cloudflare";
+      authWith = "tailscale";
+    };
+    "www.calibre.clicks.codes" = {
+      locations."~ ^/?([^\r\n]*)$" = {
+        return = "307 https://calibre.clicks.codes/$1";
+        priority = 100;
+      };
+      onlySSL = false;
+      addSSL = true;
+      useACMEHost = "www.calibre.clicks.codes";
+      authWith = null;
+    };
+  };
+in {
+  testGenerateWwwRedirects = {
+    expr = lib.clicks.nginx.http.internal.generateWwwRedirects step0;
+    expected = step1;
+  };
+  testTranslateServiceToRoutes = {
+    expr = lib.clicks.nginx.http.internal.translateServiceToRoutes step1;
+    expected = step2;
+  };
+  testTranslateRoutesDagToList = {
+    expr = lib.clicks.nginx.http.internal.translateRoutesDagToList step2;
+    expected = step3;
+  };
+  testUnwrapHeaderPassthrough = {
+    expr = lib.clicks.nginx.http.internal.unwrapHeaders step3;
+    expected = step4;
+  };
+  testTranslateRoutesToLocations = {
+    expr = lib.clicks.nginx.http.internal.translateRoutesToLocations step4;
+    expected = step5;
+  };
+  testSetLocationPriorities = {
+    expr = lib.clicks.nginx.http.internal.setLocationPriorities step5;
+    expected = step6;
+  };
+  testAddListenDefaults = {
+    expr = lib.clicks.nginx.http.internal.addListenDefaults step6;
+    expected = step7;
+  };
+}