diff --git a/openflare_agent/internal/nginx/manager_test.go b/openflare_agent/internal/nginx/manager_test.go index 5562f9f3..3a5bf367 100644 --- a/openflare_agent/internal/nginx/manager_test.go +++ b/openflare_agent/internal/nginx/manager_test.go @@ -1003,6 +1003,18 @@ func TestManagedPowLuaFilesUseInternalChallengeFlow(t *testing.T) { if !strings.Contains(openRestyPowChallengeLua, ``) { t.Fatal("expected challenge html to force Anubis frontend to reuse the current URL as redir target") } + if !strings.Contains(openRestyPowCheckLua, `pow_sessions:set(session_key, "1", session_ttl)`) { + t.Fatal("expected check.lua to refresh the PoW session TTL on each valid request") + } + if !strings.Contains(openRestyPowCheckLua, `ngx.header["Set-Cookie"] = session_cookie(cookie_val, session_ttl)`) { + t.Fatal("expected check.lua to refresh the browser session cookie on each valid request") + } + if !strings.Contains(openRestyPowChallengeLua, `local session_ttl = config.session_ttl or 600`) { + t.Fatal("expected challenge.lua to default session TTL to 10 minutes") + } + if !strings.Contains(openRestyPowVerifyLua, `local session_ttl = challenge_info.session_ttl or 600`) { + t.Fatal("expected verify.lua to default session TTL to 10 minutes") + } if !strings.Contains(openRestyPowVerifyLua, `if ngx.var.scheme == "https" then`) { t.Fatal("expected verify.lua to only mark the session cookie as Secure for HTTPS requests") } diff --git a/openflare_agent/internal/nginx/pow_assets.go b/openflare_agent/internal/nginx/pow_assets.go index df1d497d..b41d16aa 100644 --- a/openflare_agent/internal/nginx/pow_assets.go +++ b/openflare_agent/internal/nginx/pow_assets.go @@ -25,6 +25,14 @@ local policy = require "pow.policy" local pow_config_dict = ngx.shared.openflare_pow_config local pow_sessions = ngx.shared.openflare_pow_sessions +local function session_cookie(value, ttl) + local cookie = "__openflare_pow=" .. value .. "; Path=/; HttpOnly; SameSite=Lax; Max-Age=" .. tostring(ttl) + if ngx.var.scheme == "https" then + cookie = cookie .. "; Secure" + end + return cookie +end + -- Lazy-load pow_config from file; reload when content changes local function load_pow_config() local config_paths = { @@ -95,6 +103,7 @@ if not route_config.enabled then end local config = route_config.config or {} +local session_ttl = config.session_ttl or 600 local uri = ngx.var.uri or "" local ua = ngx.var.http_user_agent or "" local remote_ip = ngx.var.remote_addr or "" @@ -123,8 +132,11 @@ end -- Check valid session cookie local cookie_val = ngx.var["cookie___openflare_pow"] if cookie_val and cookie_val ~= "" then - local session_data = pow_sessions:get(host .. ":" .. cookie_val) + local session_key = host .. ":" .. cookie_val + local session_data = pow_sessions:get(session_key) if session_data then + pow_sessions:set(session_key, "1", session_ttl) + ngx.header["Set-Cookie"] = session_cookie(cookie_val, session_ttl) return end end @@ -187,7 +199,7 @@ local config = route_config.config or {} local difficulty = config.difficulty or 4 local algorithm = config.algorithm or "fast" local challenge_ttl = config.challenge_ttl or 300 -local session_ttl = config.session_ttl or 86400 +local session_ttl = config.session_ttl or 600 -- Generate challenge data without depending on ngx.random_bytes, which is not -- available in every OpenResty runtime build. @@ -307,7 +319,7 @@ end local challenge_data = challenge_info.data or "" local difficulty = challenge_info.difficulty or 4 local host = challenge_info.host or ngx.var.host or "" -local session_ttl = challenge_info.session_ttl or 86400 +local session_ttl = challenge_info.session_ttl or 600 -- Compute SHA-256(challenge_data + nonce) local calc_string = challenge_data .. tostring(math.floor(nonce)) diff --git a/openflare_server/service/agent_test.go b/openflare_server/service/agent_test.go index f1796eaf..f021673b 100644 --- a/openflare_server/service/agent_test.go +++ b/openflare_server/service/agent_test.go @@ -1,6 +1,9 @@ package service -import "testing" +import ( + "strings" + "testing" +) func TestGetActiveConfigForAgentIncludesPoWConfig(t *testing.T) { setupServiceTestDB(t) @@ -39,3 +42,37 @@ func TestGetActiveConfigForAgentIncludesPoWConfig(t *testing.T) { t.Fatal("expected agent config to include pow_config.json support file") } } + +func TestGetActiveConfigForAgentUsesTenMinutePoWSessionDefault(t *testing.T) { + setupServiceTestDB(t) + + _, err := CreateProxyRoute(ProxyRouteInput{ + Domain: "pow-default.example.com", + OriginURL: "https://origin.internal", + Enabled: true, + PoWEnabled: true, + PoWConfig: `{}`, + }) + if err != nil { + t.Fatalf("CreateProxyRoute failed: %v", err) + } + + if _, err := PublishConfigVersion("root"); err != nil { + t.Fatalf("PublishConfigVersion failed: %v", err) + } + + activeConfig, err := GetActiveConfigForAgent() + if err != nil { + t.Fatalf("GetActiveConfigForAgent failed: %v", err) + } + + for _, file := range activeConfig.SupportFiles { + if file.Path == "pow_config.json" { + if !strings.Contains(file.Content, `"session_ttl":600`) { + t.Fatalf("expected default PoW session TTL to be 600 seconds, got %s", file.Content) + } + return + } + } + t.Fatal("expected agent config to include pow_config.json support file") +} diff --git a/openflare_server/service/proxy_route.go b/openflare_server/service/proxy_route.go index 6ea9f704..3ff9ad32 100644 --- a/openflare_server/service/proxy_route.go +++ b/openflare_server/service/proxy_route.go @@ -1097,7 +1097,7 @@ func defaultPoWConfig() ProxyRoutePoWConfig { return ProxyRoutePoWConfig{ Difficulty: 4, Algorithm: "fast", - SessionTTL: 86400, + SessionTTL: 600, ChallengeTTL: 300, Whitelist: ProxyRoutePoWListConfig{IPs: []string{}, IPCidrs: []string{}, Paths: []string{}, PathRegexes: []string{}, UserAgents: []string{}}, Blacklist: ProxyRoutePoWListConfig{IPs: []string{}, IPCidrs: []string{}, Paths: []string{}, PathRegexes: []string{}, UserAgents: []string{}}, diff --git a/openflare_server/web/features/proxy-routes/components/proxy-route-config-page.tsx b/openflare_server/web/features/proxy-routes/components/proxy-route-config-page.tsx index eb3ededd..5314cc57 100644 --- a/openflare_server/web/features/proxy-routes/components/proxy-route-config-page.tsx +++ b/openflare_server/web/features/proxy-routes/components/proxy-route-config-page.tsx @@ -806,7 +806,7 @@ function PowSection({ pow_enabled: route.pow_enabled, difficulty: powConfig?.difficulty ?? 4, algorithm: powConfig?.algorithm ?? 'fast', - session_ttl: powConfig?.session_ttl ?? 86400, + session_ttl: powConfig?.session_ttl ?? 600, challenge_ttl: powConfig?.challenge_ttl ?? 300, whitelist: buildPowListFromConfig(powConfig?.whitelist), blacklist: buildPowListFromConfig(powConfig?.blacklist), @@ -818,7 +818,7 @@ function PowSection({ pow_enabled: route.pow_enabled, difficulty: powConfig?.difficulty ?? 4, algorithm: powConfig?.algorithm ?? 'fast', - session_ttl: powConfig?.session_ttl ?? 86400, + session_ttl: powConfig?.session_ttl ?? 600, challenge_ttl: powConfig?.challenge_ttl ?? 300, whitelist: buildPowListFromConfig(powConfig?.whitelist), blacklist: buildPowListFromConfig(powConfig?.blacklist), @@ -904,8 +904,8 @@ function PowSection({