From 467df9395eec2fd62a0b04d4d3db5d7c8fd459bb Mon Sep 17 00:00:00 2001 From: arcnmx Date: Sat, 23 Mar 2024 13:32:59 -0700 Subject: [PATCH] fix(grocy): access --- modules/nixos/barcodebuddy.nix | 1 + nixos/access/grocy.nix | 98 +++++++++++++++++++++++++-------- nixos/grocy.nix | 79 +++++++++++++------------- nixos/secrets/barcodebuddy.yaml | 6 +- systems/tei/nixos.nix | 1 + 5 files changed, 120 insertions(+), 65 deletions(-) diff --git a/modules/nixos/barcodebuddy.nix b/modules/nixos/barcodebuddy.nix index a55652e7..e0b4fb35 100644 --- a/modules/nixos/barcodebuddy.nix +++ b/modules/nixos/barcodebuddy.nix @@ -147,6 +147,7 @@ in { all.sockets all.gettext all.session + all.filter all.redis ]); diff --git a/nixos/access/grocy.nix b/nixos/access/grocy.nix index 52742ac1..8a05fa7f 100644 --- a/nixos/access/grocy.nix +++ b/nixos/access/grocy.nix @@ -3,35 +3,87 @@ lib, ... }: let - inherit (lib.modules) mkIf mkDefault; + inherit (lib.modules) mkIf mkMerge mkDefault; + inherit (lib.strings) escapeRegex; inherit (config.services) grocy nginx; + inherit (config) networking; name.shortServer = mkDefault "grocy"; -in { - config.services.nginx.virtualHosts = { - grocy = { - inherit name; - locations."/" = mkIf (!grocy.enable) { - proxy.headers.enableRecommended = true; - extraConfig = '' - set $x_proxy_host ${nginx.virtualHosts.grocy.serverName}; - ''; - }; + serverName = "@grocy_internal"; + serverName'local = "@grocy_internal_local"; + extraConfig = '' + set $x_proxy_host ${serverName}; + set $grocy_user ""; + ''; + location = { + vouch.setProxyHeader = true; + proxy.headers.enableRecommended = true; + extraConfig = '' + proxy_set_header X-Grocy-User $grocy_user; + ''; + }; + luaAuthHost = { config, ... }: { + vouch.auth.lua = { + enable = true; + accessRequest = '' + local grocy_apikey = ngx.var["http_grocy_api_key"] + if grocy_apikey ~= nil and ngx.re.match(ngx.var["request_uri"], "^/api(/|$)") then + -- bypass authentication and let grocy decide... + -- if the API key is valid, the middleware will use its user instead + -- if the API key is invalid, the middleware will fall back to asking for a password + ngx.ctx.auth_res = { + status = ngx.HTTP_OK, + header = { }, + } + -- elseif ngx.re.match(ngx.var["x_forwarded_host"], [[grocy\.(local|tail)\.${escapeRegex networking.domain}$]]) then + -- ngx.ctx.auth_res = { + -- status = ngx.HTTP_OK, + -- header = { }, + -- } + -- ngx.var["grocy_user"] = "guest" + else + ngx.ctx.auth_res = ngx.location.capture("${config.vouch.auth.requestLocation}") + end + ''; }; - grocy'local = { - inherit name; - ssl.cert.copyFromVhost = "grocy"; - local.enable = mkDefault true; - locations."/" = mkIf (!grocy.enable) { - proxyPass = mkDefault (if grocy.enable - then "http://localhost:${toString nginx.defaultHTTPListenPort}" - else nginx.virtualHosts.grocy.locations."/".proxyPass - ); - proxy.headers.enableRecommended = true; + }; +in { + config.services.nginx = { + lua.http.enable = true; + virtualHosts = { + grocy'php = mkIf grocy.enable { + inherit serverName; + }; + grocy = mkMerge [ luaAuthHost { + inherit name extraConfig; + vouch.enable = true; + locations."/" = mkMerge [ location { + proxyPass = mkIf (grocy.enable) (mkDefault + "http://localhost:${toString nginx.defaultHTTPListenPort}" + ); + } ]; + } ]; + grocy'local = { + inherit name; + local.enable = mkDefault true; + ssl.cert.copyFromVhost = "grocy"; + locations."/" = { + proxy.headers.enableRecommended = true; + proxyPass = mkDefault "http://localhost:${toString nginx.defaultHTTPListenPort}"; + }; extraConfig = '' - set $x_proxy_host ${nginx.virtualHosts.grocy.serverName}; - proxy_redirect $x_scheme://${nginx.virtualHosts.grocy.serverName}/ $x_scheme://$x_host/; + set $x_proxy_host ${serverName'local}; ''; }; + grocy'local'int = mkMerge [ luaAuthHost { + # internal proxy workaround for http2 lua compat issues + serverName = serverName'local; + inherit name extraConfig; + proxied.enable = true; + vouch.enable = true; + locations."/" = mkMerge [ location { + proxyPass = mkDefault nginx.virtualHosts.grocy.locations."/".proxyPass; + } ]; + } ]; }; }; } diff --git a/nixos/grocy.nix b/nixos/grocy.nix index 5ce8ca15..473c67c8 100644 --- a/nixos/grocy.nix +++ b/nixos/grocy.nix @@ -8,62 +8,63 @@ in { config = { services.grocy = { enable = mkDefault true; - hostName = "grocy"; + hostName = "grocy'php"; nginx.enableSSL = false; settings = { currency = mkDefault "CAD"; }; }; services.nginx = let - name.shortServer = mkDefault "grocy"; - lua.access.block = '' - local grocy_user_pat = "^([^@]+)@.*$" - if ngx.re.match(ngx.var.auth_resp_x_vouch_user, grocy_user_pat) then - ngx.var["grocy_user"] = ngx.re.sub(ngx.var.auth_resp_x_vouch_user, grocy_user_pat, "$1", "o") or "guest" - end - ''; extraConfig = mkAfter '' set $grocy_user guest; set $grocy_middleware Grocy\Middleware\ReverseProxyAuthMiddleware; + set $grocy_auth_header GENSO_GROCY_USER; + set $grocy_auth_env true; - fastcgi_param GENSO_GROCY_USER $grocy_user; - fastcgi_param GROCY_REVERSE_PROXY_AUTH_HEADER GENSO_GROCY_USER; - fastcgi_param GROCY_REVERSE_PROXY_AUTH_USE_ENV true; + if ($http_grocy_api_key) { + set $grocy_user ""; + } + if ($request_uri ~ "^/api(/.*|)$") { + set $grocy_user ""; + } + if ($http_x_vouch_user ~ "^([^@]+)@.*$") { + set $grocy_user $1; + } + if ($http_x_grocy_user) { + #set $grocy_auth_header X-Grocy-User; + #set $grocy_auth_env false; + set $grocy_user $http_x_grocy_user; + } + if ($grocy_user = "") { + set $grocy_middleware Grocy\Middleware\DefaultAuthMiddleware; + } fastcgi_param GROCY_AUTH_CLASS $grocy_middleware; + fastcgi_param GROCY_REVERSE_PROXY_AUTH_USE_ENV $grocy_auth_env; + fastcgi_param GROCY_REVERSE_PROXY_AUTH_HEADER $grocy_auth_header; + fastcgi_param GENSO_GROCY_USER $grocy_user; + + set $grocy_https ""; + if ($x_scheme = https) { + set $grocy_https 1; + } + fastcgi_param HTTP_HOST $x_forwarded_host; + fastcgi_param REQUEST_SCHEME $x_scheme; + fastcgi_param HTTPS $grocy_https if_not_empty; ''; - in mkIf cfg.enable { - lua.http.enable = true; + in { virtualHosts = { - grocy = {config, ...}: { - inherit name; - vouch = { + grocy'php = mkIf cfg.enable ({config, ...}: { + name.shortServer = mkDefault "grocy"; + proxied = { enable = true; - requireAuth = false; - auth.lua = { - enable = true; - accessRequest = '' - local grocy_apikey = ngx.var["http_grocy_api_key"] - if grocy_apikey ~= nil and ngx.re.match(ngx.var.request_uri, "^/api(/|$)") then - -- bypass authentication and let grocy decide... - -- if the API key is valid, the middleware will use its user instead - -- if the API key is invalid, the middleware will fall back to the (invalid/empty) user string - ngx.ctx.auth_res = { - status = ngx.HTTP_OK, - header = { }, - } - ngx.var["grocy_user"] = "" - else - ngx.ctx.auth_res = ngx.location.capture("${config.vouch.auth.requestLocation}") - end - ''; - }; + xvars.enable = true; }; - locations."~ \\.php$" = mkIf nginx.virtualHosts.grocy.vouch.enable { - vouch.requireAuth = true; - inherit extraConfig lua; + local.denyGlobal = true; + locations."~ \\.php$" = { + inherit extraConfig; }; - }; + }); }; }; users.users.grocy = mkIf cfg.enable { diff --git a/nixos/secrets/barcodebuddy.yaml b/nixos/secrets/barcodebuddy.yaml index 8ac13ca8..e6f83d2c 100644 --- a/nixos/secrets/barcodebuddy.yaml +++ b/nixos/secrets/barcodebuddy.yaml @@ -1,4 +1,4 @@ -barcodebuddy-fastcgi-params: ENC[AES256_GCM,data:Ja1gkFypwLgdQyJWQljtkcmlJ4nKw8CACXIe9CXQduwv2wZdiAZcoulX6+kjPxHLMsdTuvWFbVY4GfBVWh6LmySLgR6tIwmNiNg7ncgVEQbeTK75HQFWviVDu13GjYQU7YCBB438gX2X2aPHb25EcLU6UQgzHyCetO6nG9/T9OhKmmS0UUXCG1JykWQqfHPpjddydRYw08ZseZHhcyPzXAwdoJZsgVs1KhbvCUuMJctCfFEwCesYXcGM6eTPg9N8+hqAa13ijkQ8NzmamUau45pmrRbUJOm+OXi0TjO8KYIkQg7bua64oO3DegzFmeFeqnSAmlIcvZw=,iv:tI+RtXAWKbx3jQ1QfuCcoEoXPq9oze0QjrwQ5mcDe0U=,tag:Fa8fODz6hQu09yaf3HyqXg==,type:str] +barcodebuddy-fastcgi-params: ENC[AES256_GCM,data:82HrXLAfR/vH7QtqaKOq/1B5/h0Qd0PRTK7W+DBtBLmaXMkGkV41vyohqnPblNJiIZHzkWPcmhdqcf2hhAKRxf3fn8LfMMk2FLKSVOqqQBlyFU/ZjNQymlTrr0ltmFDGskW5gsTMJUIAp6oILCfcIYKSYVDqjab6Gd7IG/mf95Pj9Moj5seft8wSoTd0lOajHn4dJ3Y4ZzcVZzaFrumxhxvLZpN7Rr0X7fnWtlpyTTnhPZ58fRvLlV+md5oQRz2h5KJ3HSlibWCm4yiDhUERNQ==,iv:vJ/afsq1FesiLdBDCe+nDvt4MjJ2ZofnV/+FeurNnrM=,tag:4DwuLh8CrPo8CK5zxsA2gA==,type:str] sops: shamir_threshold: 1 kms: [] @@ -78,8 +78,8 @@ sops: YVp2UnlUeVVuMjE1L0VsdEJQdmtlQWcKwuFHmj4KpUk/LGxKu2sHOmN8QsuiZat+ p4FswX4i4PDPmZAHYLt69MJIKUDlm3iN/A5Hfa6mX6R4NZjryNdD2w== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-03-22T15:15:33Z" - mac: ENC[AES256_GCM,data:N4NB3pSZsh8HTSp14/rj4kZ1dGvJzlP9j6uk9ZciCtNFsEmPLSSojdJfzULUvpbZv+emJHHgXCKORCtJ6xZ0Zn+8u2q/nvEiWQITMl00yeRz2SNanCumtXmT+YdMI0PEK6WnLJSyiq/qr5GQIzYKWZgJRaj7hiu/eTdpglTfZUo=,iv:ybOhB5ZFvdSEyewqVBtXAW5b5i9tUJBAk1GdycRwkMY=,tag:Pl7jQhHmKj8yhQDUyoZHFg==,type:str] + lastmodified: "2024-03-23T19:16:11Z" + mac: ENC[AES256_GCM,data:Jtbmq/04a6ar1D07UIb+xEbRmbBKCEY9G2UEmE3JX/xjnpFj10qFRHB1DX+sVtltjYDhWdtyVx/rWNg/QDcsC7aBelyUH2GamHSIHXFfQ+C5C0KySv+Fqur/px86wIn9jIzyohzQa0Vd4wiODrCtMpwnFx1PCaRk3/BSnrvkoOE=,iv:WAKYsjRuhpSK8ZdI60bU4mDjn80CMynnR/81Z5iILuI=,tag:wn4RMpLnKj0funHp//GGQg==,type:str] pgp: - created_at: "2024-03-22T14:22:11Z" enc: |- diff --git a/systems/tei/nixos.nix b/systems/tei/nixos.nix index b15c4793..7e56b686 100644 --- a/systems/tei/nixos.nix +++ b/systems/tei/nixos.nix @@ -17,6 +17,7 @@ in { nixos.postgres nixos.nginx nixos.access.zigbee2mqtt + nixos.access.grocy nixos.access.barcodebuddy nixos.mosquitto nixos.home-assistant