From ad648f0484f27a23b33359ae74e49865ade6f797 Mon Sep 17 00:00:00 2001 From: Abhishek Shroff Date: Sat, 19 Jul 2025 13:48:43 +0530 Subject: [PATCH] [server][api][auth] Split out functions into various files --- server/internal/api/v1/auth/oauth.go | 49 +++++++++ server/internal/api/v1/auth/password.go | 54 +++++++++- server/internal/api/v1/auth/routes.go | 136 +----------------------- server/internal/api/v1/auth/token.go | 51 +++++++++ 4 files changed, 157 insertions(+), 133 deletions(-) create mode 100644 server/internal/api/v1/auth/oauth.go create mode 100644 server/internal/api/v1/auth/token.go diff --git a/server/internal/api/v1/auth/oauth.go b/server/internal/api/v1/auth/oauth.go new file mode 100644 index 00000000..6165d28d --- /dev/null +++ b/server/internal/api/v1/auth/oauth.go @@ -0,0 +1,49 @@ +package auth + +import ( + "net/http" + "net/url" + + "codeberg.org/shroff/phylum/server/internal/auth" + "codeberg.org/shroff/phylum/server/internal/db" + "github.com/gin-gonic/gin" +) + +func handleOAuthStart(c *gin.Context) { + provider := c.Query("provider") + clientType := auth.OpenIDClientWeb + if c.Query("client_type") == "native" { + clientType = auth.OpenIDClientNative + } + db := db.Get(c.Request.Context()) + if authURL, err := auth.OpenIDStart(db, provider, getInstanceURL(c.Request, "/api/v1/auth/oauth/redirect"), clientType); err != nil { + panic(err) + } else { + c.Redirect(http.StatusFound, authURL) + } +} + +func handleOAuthRedirect(c *gin.Context) { + db := db.Get(c.Request.Context()) + + authCode := c.Query("code") + state := c.Query("state") + + if clientType, err := auth.OpenIDValidateAuthCode(db, state, authCode, getInstanceURL(c.Request, "/api/v1/auth/oauth/redirect")); err != nil { + panic(err) + } else { + var clientURI url.URL + if clientType == auth.OpenIDClientWeb { + clientURI = *c.Request.URL + clientURI.RawQuery = "" + } else { + clientURI = url.URL{Scheme: "cloud.phylum.drive"} + } + clientURI.Path = "/login/token" + q := url.Values{} + q.Add("token", state) + q.Add("instance", getInstanceURL(c.Request, "")) + clientURI.RawQuery = q.Encode() + c.Redirect(http.StatusFound, clientURI.String()) + } +} diff --git a/server/internal/api/v1/auth/password.go b/server/internal/api/v1/auth/password.go index 01038e95..9383f8a6 100644 --- a/server/internal/api/v1/auth/password.go +++ b/server/internal/api/v1/auth/password.go @@ -7,6 +7,7 @@ import ( "codeberg.org/shroff/phylum/server/internal/auth" "codeberg.org/shroff/phylum/server/internal/core" "codeberg.org/shroff/phylum/server/internal/db" + "codeberg.org/shroff/phylum/server/internal/mail" "github.com/gin-gonic/gin" ) @@ -16,7 +17,19 @@ type passwordUpdateParams struct { NewPassword string `json:"new_password" form:"new_password"` } -func handlePasswordChangeRoute(c *gin.Context) { +func handlePasswordLogin(c *gin.Context) { + var params passwordParams + err := c.ShouldBind(¶ms) + if err != nil { + panic(core.NewError(http.StatusBadRequest, "missing_params", "Email or password not specified")) + } + + loginAndSendResponse(c, func(db db.TxHandler) (auth.Auth, string, error) { + return auth.PerformPasswordLogin(db, params.Email, params.Password) + }) +} + +func handlePasswordChange(c *gin.Context) { var params passwordUpdateParams err := c.Bind(¶ms) if err != nil { @@ -35,3 +48,42 @@ func handlePasswordChangeRoute(c *gin.Context) { c.JSON(200, gin.H{}) } + +func handlePasswordRequestReset(c *gin.Context) { + var params emailParams + err := c.ShouldBind(¶ms) + if err != nil { + panic(core.NewError(http.StatusBadRequest, "missing_params", "Missing Parameters")) + } + + if err := db.RunInTx(c.Request.Context(), func(db db.TxHandler) error { + if user, token, err := auth.CreateResetToken(db, params.Email); err != nil { + // Do not indicate that there was an error if no user was found + if !errors.Is(err, core.ErrUserNotFound) { + return err + } + } else { + // TODO: #jobs #mail #error + go func() { + mail.SendPasswordResetEmail(user, token) + }() + } + return nil + }); err != nil { + panic(err) + } else { + c.JSON(http.StatusOK, gin.H{}) + } +} + +func handlePasswordReset(c *gin.Context) { + var params resetPasswordParams + err := c.ShouldBind(¶ms) + if err != nil { + panic(core.NewError(http.StatusBadRequest, "missing_params", "Missing Parameters")) + } + + loginAndSendResponse(c, func(db db.TxHandler) (auth.Auth, string, error) { + return auth.ResetUserPassword(db, params.Email, params.Token, params.Password) + }) +} diff --git a/server/internal/api/v1/auth/routes.go b/server/internal/api/v1/auth/routes.go index 97cb7a96..5de2d18a 100644 --- a/server/internal/api/v1/auth/routes.go +++ b/server/internal/api/v1/auth/routes.go @@ -51,14 +51,14 @@ func SetupRoutes(r *gin.RouterGroup, logger *zerolog.Logger) { if auth.PasswordAuthEnabled() { passwordConfigResponse.Password = true - group.POST("/password/login", handlePasswordAuth) - group.POST("/password/change", handlePasswordChangeRoute) + group.POST("/password/login", handlePasswordLogin) + group.POST("/password/change", handlePasswordChange) } if auth.PasswordResetEnabled() { if mail.Configured() { passwordConfigResponse.PasswordReset = true - group.POST("/password/request-reset", handleRequestPasswordReset) - group.POST("/password/reset", handleResetPassword) + group.POST("/password/request-reset", handlePasswordRequestReset) + group.POST("/password/reset", handlePasswordReset) } else { logger.Warn().Msg("Password reset enabled but mail not configured") } @@ -85,44 +85,6 @@ func handleConfig(c *gin.Context) { c.JSON(http.StatusOK, passwordConfigResponse) } -func handleOAuthStart(c *gin.Context) { - provider := c.Query("provider") - clientType := auth.OpenIDClientWeb - if c.Query("client_type") == "native" { - clientType = auth.OpenIDClientNative - } - db := db.Get(c.Request.Context()) - if authURL, err := auth.OpenIDStart(db, provider, getInstanceURL(c.Request, "/api/v1/auth/oauth/redirect"), clientType); err != nil { - panic(err) - } else { - c.Redirect(http.StatusFound, authURL) - } -} - -func handleOAuthRedirect(c *gin.Context) { - db := db.Get(c.Request.Context()) - - authCode := c.Query("code") - state := c.Query("state") - - if clientType, err := auth.OpenIDValidateAuthCode(db, state, authCode, getInstanceURL(c.Request, "/api/v1/auth/oauth/redirect")); err != nil { - panic(err) - } else { - var clientURI url.URL - if clientType == auth.OpenIDClientWeb { - clientURI = *c.Request.URL - clientURI.RawQuery = "" - } else { - clientURI = url.URL{Scheme: "cloud.phylum.drive"} - } - clientURI.Path = "/login/token" - q := url.Values{} - q.Add("token", state) - q.Add("instance", getInstanceURL(c.Request, "")) - clientURI.RawQuery = q.Encode() - c.Redirect(http.StatusFound, clientURI.String()) - } -} func getInstanceURL(req *http.Request, path string) string { uri := url.URL{ Scheme: "https", @@ -138,96 +100,6 @@ func getInstanceURL(req *http.Request, path string) string { return uri.String() } -func handleTokenLogin(c *gin.Context) { - var params tokenLoginParams - err := c.ShouldBind(¶ms) - if err != nil { - panic(core.NewError(http.StatusBadRequest, "missing_params", "login token not specified")) - } - - loginAndSendResponse(c, func(db db.TxHandler) (auth.Auth, string, error) { - return auth.PerformTokenLogin(db, params.Token) - }) -} - -func handleTokenRequest(c *gin.Context) { - var params emailParams - err := c.ShouldBind(¶ms) - if err != nil { - panic(core.NewError(http.StatusBadRequest, "missing_params", "Missing Parameters")) - } - - if err := db.RunInTx(c.Request.Context(), func(db db.TxHandler) error { - if user, token, err := auth.CreateLoginToken(db, params.Email); err != nil { - // Do not indicate that there was an error if no user was found - if !errors.Is(err, core.ErrUserNotFound) { - return err - } - } else { - // TODO: #jobs #mail #error - go func() { - mail.SendTokenLoginEmail(user, token) - }() - } - return nil - }); err != nil { - panic(err) - } else { - c.JSON(http.StatusOK, gin.H{}) - } -} - -func handlePasswordAuth(c *gin.Context) { - var params passwordParams - err := c.ShouldBind(¶ms) - if err != nil { - panic(core.NewError(http.StatusBadRequest, "missing_params", "Email or password not specified")) - } - - loginAndSendResponse(c, func(db db.TxHandler) (auth.Auth, string, error) { - return auth.PerformPasswordLogin(db, params.Email, params.Password) - }) -} - -func handleRequestPasswordReset(c *gin.Context) { - var params emailParams - err := c.ShouldBind(¶ms) - if err != nil { - panic(core.NewError(http.StatusBadRequest, "missing_params", "Missing Parameters")) - } - - if err := db.RunInTx(c.Request.Context(), func(db db.TxHandler) error { - if user, token, err := auth.CreateResetToken(db, params.Email); err != nil { - // Do not indicate that there was an error if no user was found - if !errors.Is(err, core.ErrUserNotFound) { - return err - } - } else { - // TODO: #jobs #mail #error - go func() { - mail.SendPasswordResetEmail(user, token) - }() - } - return nil - }); err != nil { - panic(err) - } else { - c.JSON(http.StatusOK, gin.H{}) - } -} - -func handleResetPassword(c *gin.Context) { - var params resetPasswordParams - err := c.ShouldBind(¶ms) - if err != nil { - panic(core.NewError(http.StatusBadRequest, "missing_params", "Missing Parameters")) - } - - loginAndSendResponse(c, func(db db.TxHandler) (auth.Auth, string, error) { - return auth.ResetUserPassword(db, params.Email, params.Token, params.Password) - }) -} - func loginAndSendResponse(c *gin.Context, loginFn func(db.TxHandler) (auth.Auth, string, error)) { var err error var key string diff --git a/server/internal/api/v1/auth/token.go b/server/internal/api/v1/auth/token.go new file mode 100644 index 00000000..bdc7ce52 --- /dev/null +++ b/server/internal/api/v1/auth/token.go @@ -0,0 +1,51 @@ +package auth + +import ( + "errors" + "net/http" + + "codeberg.org/shroff/phylum/server/internal/auth" + "codeberg.org/shroff/phylum/server/internal/core" + "codeberg.org/shroff/phylum/server/internal/db" + "codeberg.org/shroff/phylum/server/internal/mail" + "github.com/gin-gonic/gin" +) + +func handleTokenLogin(c *gin.Context) { + var params tokenLoginParams + err := c.ShouldBind(¶ms) + if err != nil { + panic(core.NewError(http.StatusBadRequest, "missing_params", "login token not specified")) + } + + loginAndSendResponse(c, func(db db.TxHandler) (auth.Auth, string, error) { + return auth.PerformTokenLogin(db, params.Token) + }) +} + +func handleTokenRequest(c *gin.Context) { + var params emailParams + err := c.ShouldBind(¶ms) + if err != nil { + panic(core.NewError(http.StatusBadRequest, "missing_params", "Missing Parameters")) + } + + if err := db.RunInTx(c.Request.Context(), func(db db.TxHandler) error { + if user, token, err := auth.CreateLoginToken(db, params.Email); err != nil { + // Do not indicate that there was an error if no user was found + if !errors.Is(err, core.ErrUserNotFound) { + return err + } + } else { + // TODO: #jobs #mail #error + go func() { + mail.SendTokenLoginEmail(user, token) + }() + } + return nil + }); err != nil { + panic(err) + } else { + c.JSON(http.StatusOK, gin.H{}) + } +}