providers/session: Provide option for insecure session cookie

Closes #28. Also increase security of secure session cookie.
This commit is contained in:
Sasha Koshka 2024-12-27 01:10:28 -05:00
parent 851931d518
commit b6e4c719ca

View File

@ -1,5 +1,6 @@
package session
import "log"
import "time"
import "net/http"
import "html/template"
@ -10,6 +11,7 @@ import "git.tebibyte.media/sashakoshka/go-util/container"
import shttp "git.tebibyte.media/sashakoshka/step/http"
const sessionIDCookieName = "step-session-id"
const secureSessionIDCookieName = "__Host-step-session-id"
const defaultLifetime = 48 * time.Hour
var _ step.FuncProviderFor = new(Provider)
@ -19,7 +21,8 @@ var _ step.Trimmer = new(Provider)
// Provider provides session functions.
type Provider struct {
Lifetime time.Duration
Lifetime time.Duration
InsecureCookie bool
sessions usync.RWLocker[sessionMap]
}
@ -53,6 +56,15 @@ func (this *Provider) Configure (config step.Meta) error {
if err != nil { return err }
this.Lifetime = lifetime
}
if insecureCookieStr := config.Get("session.insecure-cookie"); insecureCookieStr != "" {
if insecureCookieStr != "true" && insecureCookieStr != "false" {
return step.ErrTypeMismatch
}
this.InsecureCookie = insecureCookieStr == "true"
if this.InsecureCookie {
log.Println("!!! session.insecure-cookie is active, this is not recommended")
}
}
return nil
}
@ -61,6 +73,7 @@ func (this *Provider) FuncMapFor (document *step.Document) template.FuncMap {
stat := &state {
document: document,
sessions: &this.sessions,
insecureCookie: this.InsecureCookie,
}
return template.FuncMap {
"sessionHTTP": stat.funcSessionHTTP,
@ -72,6 +85,7 @@ type state struct {
document *step.Document
sessions *usync.RWLocker[sessionMap]
lifetime time.Duration
insecureCookie bool
}
func (this *state) funcSessionHTTP (
@ -81,8 +95,10 @@ func (this *state) funcSessionHTTP (
*Session,
error,
) {
cookieName := sessionIDCookieName
if !this.insecureCookie { cookieName = secureSessionIDCookieName }
var id uuid.UUID
if cookie, err := req.Cookie(sessionIDCookieName); err == nil {
if cookie, err := req.Cookie(cookieName); err == nil {
if parsed, err := uuid.Parse(cookie.Value); err == nil {
id = parsed
}
@ -108,14 +124,16 @@ func (this *state) funcSessionHTTP (
result = session
}
cookie := &http.Cookie {
Name: sessionIDCookieName,
Name: cookieName,
Value: result.ID().String(),
Expires: expiration,
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteStrictMode,
Path: "/",
}
if !this.insecureCookie {
cookie.Secure = true
cookie.HttpOnly = true
}
underlyingRes := shttp.UnderlyingResponseWriter(res)
http.SetCookie(underlyingRes, cookie)
return result, nil