diff --git a/api/account/account.go b/api/account/account.go index 9893599..d9b41fd 100644 --- a/api/account/account.go +++ b/api/account/account.go @@ -3,6 +3,9 @@ package account import ( "context" "crypto/ed25519" + "net/http" + + "go.uber.org/zap" "github.com/julienschmidt/httprouter" @@ -19,26 +22,26 @@ var ( ) type AccountAPI struct { - config *viper.Viper - accounts *account.AccountServiceDefault - httpHandler *HttpHandler - identity ed25519.PrivateKey + config *viper.Viper + accounts *account.AccountServiceDefault + identity ed25519.PrivateKey + logger *zap.Logger } type AccountAPIParams struct { fx.In - Config *viper.Viper - Accounts *account.AccountServiceDefault - HttpHandler *HttpHandler - Identity ed25519.PrivateKey + Config *viper.Viper + Accounts *account.AccountServiceDefault + Identity ed25519.PrivateKey + Logger *zap.Logger } func NewS5(params AccountAPIParams) AccountApiResult { api := &AccountAPI{ - config: params.Config, - accounts: params.Accounts, - httpHandler: params.HttpHandler, - identity: params.Identity, + config: params.Config, + accounts: params.Accounts, + identity: params.Identity, + logger: params.Logger, } return AccountApiResult{ @@ -49,7 +52,6 @@ func NewS5(params AccountAPIParams) AccountApiResult { var Module = fx.Module("s5_api", fx.Provide(NewS5), - fx.Provide(NewHttpHandler), ) type AccountApiResult struct { @@ -74,6 +76,123 @@ func (a AccountAPI) Stop(ctx context.Context) error { return nil } +func (a AccountAPI) login(jc jape.Context) { + var request LoginRequest + + if jc.Decode(&request) != nil { + return + } + + exists, _, err := a.accounts.EmailExists(request.Email) + + if !exists { + _ = jc.Error(account.NewAccountError(account.ErrKeyInvalidLogin, nil), http.StatusUnauthorized) + if err != nil { + a.logger.Error("failed to check if email exists", zap.Error(err)) + } + return + } + + jwt, _, err := a.accounts.LoginPassword(request.Email, request.Password, jc.Request.RemoteAddr) + if err != nil { + return + } + + jc.ResponseWriter.Header().Set("Authorization", "Bearer "+jwt) + jc.ResponseWriter.WriteHeader(http.StatusOK) +} + +func (a AccountAPI) register(jc jape.Context) { + var request RegisterRequest + + if jc.Decode(&request) != nil { + return + } + + user, err := a.accounts.CreateAccount(request.Email, request.Password) + if err != nil { + _ = jc.Error(err, http.StatusUnauthorized) + a.logger.Error("failed to update account name", zap.Error(err)) + return + } + + err = a.accounts.UpdateAccountName(user.ID, request.FirstName, request.LastName) + + if err != nil { + _ = jc.Error(account.NewAccountError(account.ErrKeyAccountCreationFailed, err), http.StatusBadRequest) + a.logger.Error("failed to update account name", zap.Error(err)) + return + } +} + +func (a AccountAPI) otpGenerate(jc jape.Context) { + user := middleware.GetUserFromContext(jc.Request.Context()) + + otp, err := a.accounts.OTPGenerate(user) + if jc.Check("failed to generate otp", err) != nil { + return + } + + jc.Encode(&OTPGenerateResponse{ + OTP: otp, + }) +} + +func (a AccountAPI) otpVerify(jc jape.Context) { + user := middleware.GetUserFromContext(jc.Request.Context()) + + var request OTPVerifyRequest + + if jc.Decode(&request) != nil { + return + } + + err := a.accounts.OTPEnable(user, request.OTP) + + if jc.Check("failed to verify otp", err) != nil { + return + } +} + +func (a AccountAPI) otpValidate(jc jape.Context) { + user := middleware.GetUserFromContext(jc.Request.Context()) + + var request OTPValidateRequest + + if jc.Decode(&request) != nil { + return + } + + jwt, err := a.accounts.LoginOTP(user, request.OTP) + if jc.Check("failed to validate otp", err) != nil { + return + } + + account.SendJWT(jc, jwt) +} + +func (a AccountAPI) otpDisable(jc jape.Context) { + user := middleware.GetUserFromContext(jc.Request.Context()) + + var request OTPDisableRequest + + if jc.Decode(&request) != nil { + return + } + + valid, _, err := a.accounts.ValidLoginByUserID(user, request.Password) + + if !valid { + _ = jc.Error(account.NewAccountError(account.ErrKeyInvalidLogin, nil), http.StatusUnauthorized) + return + } + + err = a.accounts.OTPDisable(user) + if jc.Check("failed to disable otp", err) != nil { + return + } +} + func (a AccountAPI) Routes() *httprouter.Router { authMw2fa := authMiddleware(middleware.AuthMiddlewareOptions{ Identity: a.identity, @@ -90,11 +209,11 @@ func (a AccountAPI) Routes() *httprouter.Router { }) return jape.Mux(map[string]jape.Handler{ - "/api/auth/login": middleware.ApplyMiddlewares(a.httpHandler.login, authMw2fa, middleware.ProxyMiddleware), - "/api/auth/register": a.httpHandler.register, - "/api/auth/otp/generate": middleware.ApplyMiddlewares(a.httpHandler.otpGenerate, authMw, middleware.ProxyMiddleware), - "/api/auth/otp/verify": middleware.ApplyMiddlewares(a.httpHandler.otpVerify, authMw, middleware.ProxyMiddleware), - "/api/auth/otp/validate": middleware.ApplyMiddlewares(a.httpHandler.otpValidate, authMw, middleware.ProxyMiddleware), - "/api/auth/otp/disable": middleware.ApplyMiddlewares(a.httpHandler.otpDisable, authMw, middleware.ProxyMiddleware), + "/api/auth/login": middleware.ApplyMiddlewares(a.login, authMw2fa, middleware.ProxyMiddleware), + "/api/auth/register": a.register, + "/api/auth/otp/generate": middleware.ApplyMiddlewares(a.otpGenerate, authMw, middleware.ProxyMiddleware), + "/api/auth/otp/verify": middleware.ApplyMiddlewares(a.otpVerify, authMw, middleware.ProxyMiddleware), + "/api/auth/otp/validate": middleware.ApplyMiddlewares(a.otpValidate, authMw, middleware.ProxyMiddleware), + "/api/auth/otp/disable": middleware.ApplyMiddlewares(a.otpDisable, authMw, middleware.ProxyMiddleware), }) } diff --git a/api/account/http.go b/api/account/http.go deleted file mode 100644 index a1ea70c..0000000 --- a/api/account/http.go +++ /dev/null @@ -1,146 +0,0 @@ -package account - -import ( - "net/http" - - "git.lumeweb.com/LumeWeb/portal/account" - "git.lumeweb.com/LumeWeb/portal/api/middleware" - "go.sia.tech/jape" - "go.uber.org/fx" - "go.uber.org/zap" -) - -type HttpHandler struct { - accounts *account.AccountServiceDefault - logger *zap.Logger -} - -type HttpHandlerParams struct { - fx.In - Accounts *account.AccountServiceDefault - Logger *zap.Logger -} - -func NewHttpHandler(params HttpHandlerParams) *HttpHandler { - return &HttpHandler{ - accounts: params.Accounts, - logger: params.Logger, - } -} - -func (h *HttpHandler) login(jc jape.Context) { - var request LoginRequest - - if jc.Decode(&request) != nil { - return - } - - exists, _, err := h.accounts.EmailExists(request.Email) - - if !exists { - _ = jc.Error(account.NewAccountError(account.ErrKeyInvalidLogin, nil), http.StatusUnauthorized) - if err != nil { - h.logger.Error("failed to check if email exists", zap.Error(err)) - } - return - } - - jwt, _, err := h.accounts.LoginPassword(request.Email, request.Password, jc.Request.RemoteAddr) - if err != nil { - return - } - - jc.ResponseWriter.Header().Set("Authorization", "Bearer "+jwt) - jc.ResponseWriter.WriteHeader(http.StatusOK) -} - -func (h *HttpHandler) register(jc jape.Context) { - var request RegisterRequest - - if jc.Decode(&request) != nil { - return - } - - user, err := h.accounts.CreateAccount(request.Email, request.Password) - if err != nil { - _ = jc.Error(err, http.StatusUnauthorized) - h.logger.Error("failed to update account name", zap.Error(err)) - return - } - - err = h.accounts.UpdateAccountName(user.ID, request.FirstName, request.LastName) - - if err != nil { - _ = jc.Error(account.NewAccountError(account.ErrKeyAccountCreationFailed, err), http.StatusBadRequest) - h.logger.Error("failed to update account name", zap.Error(err)) - return - } -} - -func (h *HttpHandler) otpGenerate(jc jape.Context) { - user := middleware.GetUserFromContext(jc.Request.Context()) - - otp, err := h.accounts.OTPGenerate(user) - if jc.Check("failed to generate otp", err) != nil { - return - } - - jc.Encode(&OTPGenerateResponse{ - OTP: otp, - }) -} - -func (h *HttpHandler) otpVerify(jc jape.Context) { - user := middleware.GetUserFromContext(jc.Request.Context()) - - var request OTPVerifyRequest - - if jc.Decode(&request) != nil { - return - } - - err := h.accounts.OTPEnable(user, request.OTP) - - if jc.Check("failed to verify otp", err) != nil { - return - } -} - -func (h *HttpHandler) otpValidate(jc jape.Context) { - user := middleware.GetUserFromContext(jc.Request.Context()) - - var request OTPValidateRequest - - if jc.Decode(&request) != nil { - return - } - - jwt, err := h.accounts.LoginOTP(user, request.OTP) - if jc.Check("failed to validate otp", err) != nil { - return - } - - account.SendJWT(jc, jwt) -} - -func (h *HttpHandler) otpDisable(jc jape.Context) { - user := middleware.GetUserFromContext(jc.Request.Context()) - - var request OTPDisableRequest - - if jc.Decode(&request) != nil { - return - } - - valid, _, err := h.accounts.ValidLoginByUserID(user, request.Password) - - if !valid { - _ = jc.Error(account.NewAccountError(account.ErrKeyInvalidLogin, nil), http.StatusUnauthorized) - return - } - - err = h.accounts.OTPDisable(user) - if jc.Check("failed to disable otp", err) != nil { - return - } -}