diff --git a/api/handlers/v1/auth.go b/api/handlers/v1/auth.go new file mode 100644 index 0000000..86f6b6b --- /dev/null +++ b/api/handlers/v1/auth.go @@ -0,0 +1,99 @@ +package v1 + +import ( + "go-cook/api/models" + "go-cook/api/repositories" + "net/http" + "time" + + "github.com/golang-jwt/jwt/v5" + "github.com/labstack/echo/v4" +) + +type JwtToken struct { + Exp time.Time `json:"exp"` + Authorized bool `json:"authorized"` + UserName string `json:"username"` + Token string `json:"token"` + jwt.RegisteredClaims +} + +func generateJwt() (string, error) { + //TODO use env here + secret := []byte("ThisIsABadSecretDontReallyUseThis") + + token := jwt.New(jwt.SigningMethodEdDSA) + claims := token.Claims.(jwt.MapClaims) + claims["exp"] = time.Now().Add(10 * time.Minute) + claims["authorized"] = true + claims["username"] = "someone" + + tokenString, err := token.SignedString(secret) + if err != nil { + return "", err + } + + return tokenString, nil +} + +func (h *Handler) AuthRegister(c echo.Context) error { + username := c.QueryParam("username") + _, err := h.userRepo.GetByName(username) + if err != nil { + // if we have an err, validate that if its not user not found. + // if the user is not found, we can use that name + if err.Error() != repositories.ErrUserNotFound { + return c.JSON(http.StatusInternalServerError, models.ErrorResponse{ + HttpCode: http.StatusInternalServerError, + Message: err.Error(), + }) + } + } + + password := c.QueryParam("password") + err = h.UserService.CheckPasswordForRequirements(password) + if err != nil { + return c.JSON(http.StatusInternalServerError, models.ErrorResponse{ + HttpCode: http.StatusInternalServerError, + Message: err.Error(), + }) + } + + _, err = h.userRepo.Create(username, password) + if err != nil { + return c.JSON(http.StatusInternalServerError, models.ErrorResponse{ + HttpCode: http.StatusInternalServerError, + Message: err.Error(), + }) + } + + return nil +} + +func (h *Handler) AuthLogin(c echo.Context) error { + username := c.QueryParam("username") + password := c.QueryParam("password") + + // check if the user exists + err := h.UserService.DoesUserExist(username) + if err != nil { + return c.JSON(http.StatusInternalServerError, err) + } + + // make sure the hash matches + err = h.UserService.DoesPasswordMatchHash(username, password) + if err != nil { + return c.JSON(http.StatusInternalServerError, err) + } + + token, err := generateJwt() + if err != nil { + return c.JSON(http.StatusInternalServerError, err) + } + + return c.JSON(http.StatusOK, token) +} + +func (h *Handler) RefreshJwtToken(c echo.Context) error { + return nil +} diff --git a/api/handlers/v1/demo.go b/api/handlers/v1/demo.go index bbab75e..2b5503d 100644 --- a/api/handlers/v1/demo.go +++ b/api/handlers/v1/demo.go @@ -47,3 +47,8 @@ func (h *Handler) HelloBody(c echo.Context) error { Message: fmt.Sprintf("Hello, %s", request.Name), }) } + + +func (h *Handler) ProtectedRoute(c echo.Context)error { + return nil +} \ No newline at end of file diff --git a/api/handlers/v1/handler.go b/api/handlers/v1/handler.go index 1788678..201d4f2 100644 --- a/api/handlers/v1/handler.go +++ b/api/handlers/v1/handler.go @@ -3,26 +3,52 @@ package v1 import ( "database/sql" "go-cook/api/repositories" + "go-cook/api/services" + "github.com/golang-jwt/jwt/v5" + echojwt "github.com/labstack/echo-jwt/v4" "github.com/labstack/echo/v4" ) type Handler struct { - userRepo repositories.UserRepository + UserService services.UserService + userRepo repositories.IUserTable + recipeRepo repositories.IRecipeTable } func NewHandler(conn *sql.DB) *Handler { return &Handler{ - userRepo: repositories.NewUserRepository(conn), + UserService: services.NewUserService(conn), + userRepo: repositories.NewUserRepository(conn), + recipeRepo: repositories.NewRecipeRepository(conn), } } func (h *Handler) Register(v1 *echo.Group) { + jwtConfig := echojwt.Config{ + NewClaimsFunc: func(c echo.Context) jwt.Claims { + return new(JwtToken) + }, + SigningKey: []byte("ThisIsABadSecretDontReallyUseThis"), + } + + v1.POST("/login", h.AuthLogin) + v1.POST("/register", h.AuthRegister) demo := v1.Group("/demo") - demo.GET("/hello", h.DemoHello) + + demo.GET("/hello", h.DemoHello) demo.GET("/hello/:who", h.HelloWho) + + demo.Use(echojwt.WithConfig(jwtConfig)) demo.GET("/hello/body", h.HelloBody) - users := v1.Group("/users") - users.POST("/new", h.NewUser) + protected := v1.Group("/demo/protected") + protected.GET("/", h.ProtectedRoute) + + //recipes := v1.Group("/recipe") + + //users := v1.Group("/users") + //users.POST("/register", h.RegisterUser) + //users.POST("/login", h.LoginUser) + //users.POST("/update/password", h.UpdatePassword) } diff --git a/api/handlers/v1/users.go b/api/handlers/v1/users.go index 3f3ed84..e2dcc37 100644 --- a/api/handlers/v1/users.go +++ b/api/handlers/v1/users.go @@ -6,6 +6,10 @@ import ( "github.com/labstack/echo/v4" ) -func (h *Handler) NewUser(c echo.Context) error { - return c.JSON(http.StatusOK, "not implemented yet") +type newUserResponse struct { + +} + +func (h *Handler) RegisterUser(c echo.Context) error { + return c.JSON(http.StatusOK, newUserResponse{}) }