diff options
| -rw-r--r-- | src/server/router.go | 14 | ||||
| -rw-r--r-- | src/sessions/middleware.go | 13 | ||||
| -rw-r--r-- | src/sessions/sessions.go | 38 | ||||
| -rw-r--r-- | src/user/routes.go | 48 | ||||
| -rw-r--r-- | ui/pages/user/create.tmpl.html | 2 | ||||
| -rw-r--r-- | ui/pages/user/login.tmpl.html | 4 |
6 files changed, 80 insertions, 39 deletions
diff --git a/src/server/router.go b/src/server/router.go index 6b33a7d..3b43119 100644 --- a/src/server/router.go +++ b/src/server/router.go @@ -12,12 +12,11 @@ import ( type HandlerFunc func(s *Server) http.HandlerFunc type Route struct { - Name string - Method string - Path string - AuthRequired bool - HandlerFunc HandlerFunc - Middlewares []func(http.Handler) http.Handler + Name string + Method string + Path string + HandlerFunc HandlerFunc + Middlewares []func(http.Handler) http.Handler } type Routes []Route @@ -25,6 +24,7 @@ type Routes []Route func NewRouter(config *conf.Conf) *chi.Mux { r := chi.NewRouter() r.Use(middleware.Logger) - r.Use(sessions.SetSession) + sessions.InitStore() + r.Use(sessions.StartSession) return r } diff --git a/src/sessions/middleware.go b/src/sessions/middleware.go index 6bb3b15..6ae34ac 100644 --- a/src/sessions/middleware.go +++ b/src/sessions/middleware.go @@ -5,22 +5,25 @@ import ( "net/http" ) -func SetSession(next http.Handler) http.Handler { +func StartSession(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // is there a session_token cookie? scookie, err := r.Cookie("session_token") if err != nil || scookie.Value == "" { // no session value or cookie next.ServeHTTP(w, r) + return } + // check for existing session cvalue := scookie.Value vsession, ok := GetSession(cvalue) if !ok { // no session next.ServeHTTP(w, r) + return } // set session - ctx := context.WithValue(r.Context(), SessionCtxKey("session"), vsession.Id()) + ctx := context.WithValue(r.Context(), SessionCtxKey("session"), vsession) next.ServeHTTP(w, r.WithContext(ctx)) }) } @@ -30,6 +33,7 @@ func GuestSession(next http.Handler) http.Handler { // if SessionKey does exist then redirect to `/u/me` as this is an auth session if v := r.Context().Value(SessionCtxKey("session")); v != nil { http.Redirect(w, r, "/u/me", http.StatusSeeOther) + return } // else this is a valid guest request next.ServeHTTP(w, r) @@ -40,10 +44,11 @@ func AuthSession(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // if session key exists then this is a valid auth request if v := r.Context().Value(SessionCtxKey("session")); v != nil { - http.Redirect(w, r, "/login", http.StatusSeeOther) + next.ServeHTTP(w, r) + return } // else this is a guest session request, redirect to login - http.Redirect(w, r, "/login", http.StatusSeeOther) + http.Redirect(w, r, "/u/auth", http.StatusSeeOther) }) } diff --git a/src/sessions/sessions.go b/src/sessions/sessions.go index 34fe91c..0124c51 100644 --- a/src/sessions/sessions.go +++ b/src/sessions/sessions.go @@ -7,19 +7,23 @@ import ( "github.com/google/uuid" ) -type sessionvalues map[string]any +type SessionValues map[string]any type Session struct { id string - values sessionvalues - mu *sync.Mutex + values SessionValues + lock *sync.Mutex } type SessionCtxKey string -var _sessions map[string]Session +var _sessions map[string]*Session -func NewSession(w http.ResponseWriter, values map[string]any) Session { +func InitStore() { + _sessions = map[string]*Session{} +} + +func NewSession(w http.ResponseWriter, values map[string]any) *Session { token := uuid.NewString() // set secure cookie in http.ResponseWriter @@ -30,15 +34,16 @@ func NewSession(w http.ResponseWriter, values map[string]any) Session { }) // create session and store - s := Session{ + s := &Session{ id: token, - values: sessionvalues(values), + values: SessionValues(values), + lock: &sync.Mutex{}, } _sessions[token] = s return s } -func GetSession(id string) (Session, bool) { +func GetSession(id string) (*Session, bool) { s, ok := _sessions[id] return s, ok } @@ -48,14 +53,23 @@ func (s *Session) Id() string { } func (s *Session) Get(key string) interface{} { - s.mu.Lock() - defer s.mu.Unlock() + s.lock.Lock() + defer s.lock.Unlock() return s.values[key] } func (s *Session) Set(key string, value interface{}) bool { - s.mu.Lock() - defer s.mu.Unlock() + s.lock.Lock() + defer s.lock.Unlock() s.values[key] = value + _sessions[s.id] = s return true } + +func (s *Session) Destroy(w http.ResponseWriter) { + delete(_sessions, s.id) + http.SetCookie(w, &http.Cookie{ + Name: "session_token", + Value: "", + }) +} diff --git a/src/user/routes.go b/src/user/routes.go index d3db728..3bcab06 100644 --- a/src/user/routes.go +++ b/src/user/routes.go @@ -20,28 +20,37 @@ var Routes = server.Routes{ server.Route{ Name: "Store", Method: "POST", - Path: "/user", + Path: "/u", HandlerFunc: Store, + Middlewares: server.NewMiddlewares(sessions.GuestSession), }, server.Route{ Name: "LoginForm", Method: "GET", - Path: "/u/login", + Path: "/u/auth", HandlerFunc: LoginForm, + Middlewares: server.NewMiddlewares(sessions.GuestSession), }, server.Route{ Name: "Authenticate", Method: "POST", Path: "/u/auth", - HandlerFunc: Authenticate, + HandlerFunc: Login, + Middlewares: server.NewMiddlewares(sessions.GuestSession), + }, + server.Route{ + Name: "Logout", + Method: "GET", + Path: "/u/logout", + HandlerFunc: Logout, + Middlewares: server.NewMiddlewares(sessions.AuthSession), }, server.Route{ - Name: "Me", - Method: "GET", - Path: "/u/me", - AuthRequired: true, - HandlerFunc: Show, - Middlewares: server.NewMiddlewares(sessions.AuthSession), + Name: "Me", + Method: "GET", + Path: "/u/me", + HandlerFunc: Show, + Middlewares: server.NewMiddlewares(sessions.AuthSession), }, } @@ -81,7 +90,7 @@ func Store(s *server.Server) http.HandlerFunc { } // Send email validation // Create cookie session - sessions.NewSession(w, map[string]interface{}{"uid": user.Id, "username": user.Username}) + sessions.NewSession(w, sessions.SessionValues{"uid": user.Id, "username": user.Username}) // Redirect to user profile http.Redirect(w, r, "/u/me", http.StatusSeeOther) } @@ -93,13 +102,26 @@ func LoginForm(s *server.Server) http.HandlerFunc { } } -func Authenticate(s *server.Server) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) {} +func Login(s *server.Server) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + // look up the user from the db + // hash the form secret + // compare form hash to db hash + // login or dont + } +} + +func Logout(s *server.Server) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + session := r.Context().Value("session").(*sessions.Session) + session.Destroy(w) + http.Redirect(w, r, "/u/auth", http.StatusSeeOther) + } } func Show(s *server.Server) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - session := r.Context().Value(sessions.SessionCtxKey("session")).(sessions.Session) + session := r.Context().Value(sessions.SessionCtxKey("session")).(*sessions.Session) username := session.Get("username").(string) s.Ui.Render(w, "user/me", &struct{ Message, Username string }{"Congrats on getting this far!", username}) } diff --git a/ui/pages/user/create.tmpl.html b/ui/pages/user/create.tmpl.html index 47143c6..68a9e93 100644 --- a/ui/pages/user/create.tmpl.html +++ b/ui/pages/user/create.tmpl.html @@ -2,7 +2,7 @@ {{define "main"}} <h1>Create User</h1> - <form action="/user" method="POST"> + <form action="/u" method="POST"> <label> Email <input type="email" placeholder="email" name="email" /> diff --git a/ui/pages/user/login.tmpl.html b/ui/pages/user/login.tmpl.html index 5c42f97..d56f61a 100644 --- a/ui/pages/user/login.tmpl.html +++ b/ui/pages/user/login.tmpl.html @@ -2,7 +2,7 @@ {{define "main"}} <h1>Login</h1> - <form hx-post="/user" action="/user/auth" method="POST" hx-target="#messages" hx-swap="outerHTML"> + <form action="/u/auth" method="POST"> <label> Username <input type="text" placeholder="username" name="username" /> @@ -11,6 +11,6 @@ Password <input type="password" placeholder="password" name="password" /> </label> - <button type="submit" hx-disabled-elt="this">Login</button> + <button type="submit">Login</button> </form> {{end}} |
