this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

auth: whoami

Clément 23ff9d3d 698a555b

+104 -3
+11 -3
backend/cmd/api/main.go
··· 4 4 "database/sql" 5 5 6 6 "github.com/go-chi/chi/v5" 7 - "github.com/go-chi/chi/v5/middleware" 7 + chimiddleware "github.com/go-chi/chi/v5/middleware" 8 8 "github.com/syumai/workers" 9 9 _ "github.com/syumai/workers/cloudflare/d1" // register driver 10 10 "uiua.online/internal/handlers" 11 + "uiua.online/internal/middlewares" 11 12 "uiua.online/internal/services" 12 13 ) 13 14 ··· 21 22 userSvc := services.NewUserService(db) 22 23 authSvc := services.NewAuthService(db, userSvc, sessionSvc) 23 24 25 + auth := middlewares.NewAuthMiddleware(sessionSvc) 26 + 24 27 authHandler := handlers.NewAuthHandler(authSvc) 25 28 26 29 r := chi.NewRouter() 27 - r.Use(middleware.Logger) 28 - r.Use(middleware.Recoverer) 30 + r.Use(chimiddleware.Logger) 31 + r.Use(chimiddleware.Recoverer) 29 32 30 33 r.Get("/", handlers.Health) 31 34 32 35 r.Route("/auth", func(r chi.Router) { 33 36 r.Post("/login", authHandler.Login) 37 + 38 + r.Group(func(r chi.Router) { 39 + r.Use(auth.RequireAuth) 40 + r.Get("/whoami", authHandler.Whoami) 41 + }) 34 42 }) 35 43 36 44 workers.Serve(r)
+13
backend/internal/handlers/auth.go
··· 5 5 "fmt" 6 6 "net/http" 7 7 8 + "uiua.online/internal/middlewares" 8 9 "uiua.online/internal/models" 9 10 "uiua.online/internal/services" 10 11 ) ··· 33 34 w.Header().Set("Set-Cookie", fmt.Sprintf("token=%s; HttpOnly; Secure; SameSite=Strict", token)) 34 35 w.WriteHeader(http.StatusOK) 35 36 } 37 + 38 + func (h *AuthHandler) Whoami(w http.ResponseWriter, r *http.Request) { 39 + userID := middlewares.GetUserID(r.Context()) 40 + email, err := h.svc.Whoami(r.Context(), userID) 41 + if err != nil { 42 + http.Error(w, err.Error(), http.StatusInternalServerError) 43 + return 44 + } 45 + 46 + w.Write([]byte(email)) 47 + w.WriteHeader(http.StatusOK) 48 + }
+40
backend/internal/middlewares/auth.go
··· 1 + package middlewares 2 + 3 + import ( 4 + "context" 5 + "net/http" 6 + 7 + "uiua.online/internal/services" 8 + ) 9 + 10 + type contextKey string 11 + 12 + const UserIDKey contextKey = "user_id" 13 + 14 + type AuthMiddleware struct { 15 + session *services.SessionService 16 + } 17 + 18 + func NewAuthMiddleware(session *services.SessionService) *AuthMiddleware { 19 + return &AuthMiddleware{session: session} 20 + } 21 + 22 + func (m *AuthMiddleware) RequireAuth(next http.Handler) http.Handler { 23 + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 24 + token, err := r.Cookie("token") 25 + if err != nil { 26 + http.Error(w, "missing authorization header", http.StatusUnauthorized) 27 + return 28 + } 29 + 30 + userId, err := m.session.GetUserFromSession(token.Value) 31 + if err != nil { 32 + w.Header().Set("Set-Cookie", "id=token; Max-Age=0") 33 + http.Error(w, "invalid token", http.StatusUnauthorized) 34 + return 35 + } 36 + 37 + ctx := context.WithValue(r.Context(), UserIDKey, userId) 38 + next.ServeHTTP(w, r.WithContext(ctx)) 39 + }) 40 + }
+14
backend/internal/middlewares/context.go
··· 1 + package middlewares 2 + 3 + import ( 4 + "context" 5 + "errors" 6 + ) 7 + 8 + func GetUserID(ctx context.Context) string { 9 + userID, ok := ctx.Value(UserIDKey).(string) 10 + if !ok { 11 + panic(errors.New("user id not found")) 12 + } 13 + return userID 14 + }
+9
backend/internal/services/auth.go
··· 40 40 41 41 return token, nil 42 42 } 43 + 44 + func (s *AuthService) Whoami(context context.Context, userId string) (string, error) { 45 + user, err := s.user.GetFromID(userId) 46 + if err != nil { 47 + return "", err 48 + } 49 + 50 + return user.Email, nil 51 + }
+8
backend/internal/services/session.go
··· 17 17 return &SessionService{db: db} 18 18 } 19 19 20 + func (s *SessionService) GetUserFromSession(token string) (uuid.UUID, error) { 21 + var userID uuid.UUID 22 + if err := s.db.QueryRow("select user_id from \"session\" where token = ?", token).Scan(&userID); err != nil { 23 + return uuid.Nil, err 24 + } 25 + return userID, nil 26 + } 27 + 20 28 // creates a new session for the given user and returns the token 21 29 func (s *SessionService) CreateForUser(user *models.User) (string, error) { 22 30 token := make([]byte, 16)
+9
backend/internal/services/user.go
··· 39 39 40 40 return false, errors.New("invalid credentials") 41 41 } 42 + 43 + func (s *UserService) GetFromID(userId string) (*models.User, error) { 44 + row := s.db.QueryRow("select * from \"user\" where id = ?", userId) 45 + var user models.User 46 + if err := row.Scan(&user.ID, &user.Email, &user.PasswordHash); err != nil { 47 + return nil, err 48 + } 49 + return &user, nil 50 + }