package handlers import ( "context" "database/sql" "html/template" "log" "net/http" "github.com/gorilla/sessions" ) type PageData struct { Title string Navbar string LoggedIn bool ShowCookieBanner bool BasePath string StaticPath string CurrentURL string } type Config struct { DomainName string `json:"domain_name"` ThreadrDir string `json:"threadr_dir"` DBUsername string `json:"db_username"` DBPassword string `json:"db_password"` DBDatabase string `json:"db_database"` DBServerHost string `json:"db_svr_host"` FileStorageDir string `json:"file_storage_dir"` SessionSecret string `json:"session_secret"` SessionSecure bool `json:"session_secure"` } type App struct { DB *sql.DB Store *sessions.CookieStore Config *Config Tmpl *template.Template } func (app *App) SessionMW(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session, err := app.Store.Get(r, "session-name") if err != nil { session = sessions.NewSession(app.Store, "session-name") } // Enforce secure cookie options on every request. session.Options = app.cookieOptions(r) ctx := context.WithValue(r.Context(), "session", session) r = r.WithContext(ctx) next(w, r) if err := session.Save(r, w); err != nil { /* Ok, so here's the thing Errors coming from this function here "can" be ignored. They mostly come from errors while setting cookies, so in some environments this will trigger a lot, but they are harmless. */ log.Printf("Error saving session in SessionMW: %v", err) } } } func (app *App) RequireLoginMW(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { session := r.Context().Value("session").(*sessions.Session) if _, ok := session.Values["user_id"].(int); !ok { http.Redirect(w, r, app.Config.ThreadrDir+"/login/?error=session", http.StatusFound) return } next(w, r) } } func (app *App) cookieOptions(r *http.Request) *sessions.Options { secure := app.Config.SessionSecure if r.TLS != nil { secure = true } // I dunno what I am doing honestly options := &sessions.Options{ Path: app.Config.ThreadrDir + "/", MaxAge: 86400 * 30, HttpOnly: true, Secure: secure, SameSite: http.SameSiteLaxMode, } if app.Config.DomainName != "" { options.Domain = app.Config.DomainName } return options }