Skip to content

Commit 95ddcdd

Browse files
authored
refactor: share secure request detection helper (#23)
1 parent 2ee13be commit 95ddcdd

File tree

4 files changed

+55
-23
lines changed

4 files changed

+55
-23
lines changed

internal/handlers/auth_handler.go

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (h *AuthHandler) Login(c echo.Context) error {
7979
cookie.Path = "/"
8080
cookie.HttpOnly = true
8181
cookie.SameSite = http.SameSiteStrictMode
82-
cookie.Secure = requestIsSecure(c)
82+
cookie.Secure = utils.IsSecureRequest(c.Request())
8383
c.SetCookie(cookie)
8484

8585
// 4. Redirect (HTMX handles 200 OK with HX-Redirect)
@@ -96,20 +96,11 @@ func (h *AuthHandler) Logout(c echo.Context) error {
9696
cookie.Path = "/"
9797
cookie.HttpOnly = true
9898
cookie.SameSite = http.SameSiteStrictMode
99-
cookie.Secure = requestIsSecure(c)
99+
cookie.Secure = utils.IsSecureRequest(c.Request())
100100
c.SetCookie(cookie)
101101
return c.Redirect(http.StatusSeeOther, "/login")
102102
}
103103

104-
func requestIsSecure(c echo.Context) bool {
105-
req := c.Request()
106-
if req.TLS != nil {
107-
return true
108-
}
109-
110-
return req.Header.Get("X-Forwarded-Proto") == "https"
111-
}
112-
113104
// LoginOIDC initiates the OIDC flow
114105
func (h *AuthHandler) LoginOIDC(c echo.Context) error {
115106
// TODO: Generate state, store in cookie, redirect to OIDC provider

internal/middleware/security_headers.go

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package middleware
22

33
import (
4-
"strings"
5-
4+
"github.com/damacus/iron-buckets/internal/utils"
65
"github.com/labstack/echo/v4"
76
)
87

@@ -26,20 +25,11 @@ func SecurityHeaders() echo.MiddlewareFunc {
2625
headers.Set("Permissions-Policy", "geolocation=(), microphone=(), camera=()")
2726
headers.Set("Content-Security-Policy", contentSecurityPolicy)
2827

29-
if isSecureRequest(c) {
28+
if utils.IsSecureRequest(c.Request()) {
3029
headers.Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
3130
}
3231

3332
return next(c)
3433
}
3534
}
3635
}
37-
38-
func isSecureRequest(c echo.Context) bool {
39-
req := c.Request()
40-
if req.TLS != nil {
41-
return true
42-
}
43-
44-
return strings.EqualFold(req.Header.Get("X-Forwarded-Proto"), "https")
45-
}

internal/utils/request_security.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package utils
2+
3+
import (
4+
"net/http"
5+
"strings"
6+
)
7+
8+
func IsSecureRequest(req *http.Request) bool {
9+
if req == nil {
10+
return false
11+
}
12+
13+
if req.TLS != nil {
14+
return true
15+
}
16+
17+
return strings.EqualFold(req.Header.Get("X-Forwarded-Proto"), "https")
18+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package utils
2+
3+
import (
4+
"crypto/tls"
5+
"net/http/httptest"
6+
"testing"
7+
)
8+
9+
func TestIsSecureRequest_UsesTLSState(t *testing.T) {
10+
req := httptest.NewRequest("GET", "/health", nil)
11+
req.TLS = &tls.ConnectionState{}
12+
13+
if !IsSecureRequest(req) {
14+
t.Fatal("expected request with TLS state to be secure")
15+
}
16+
}
17+
18+
func TestIsSecureRequest_UsesForwardedProtoCaseInsensitive(t *testing.T) {
19+
req := httptest.NewRequest("GET", "/health", nil)
20+
req.Header.Set("X-Forwarded-Proto", "HTTPS")
21+
22+
if !IsSecureRequest(req) {
23+
t.Fatal("expected X-Forwarded-Proto=HTTPS to be secure")
24+
}
25+
}
26+
27+
func TestIsSecureRequest_ReturnsFalseForNonSecureRequest(t *testing.T) {
28+
req := httptest.NewRequest("GET", "/health", nil)
29+
30+
if IsSecureRequest(req) {
31+
t.Fatal("expected plain HTTP request to be non-secure")
32+
}
33+
}

0 commit comments

Comments
 (0)