mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Move code from module to service (#24287)
The code should not be in `modules/` but `services/`. Reference: https://github.com/go-gitea/gitea/pull/24257#discussion_r1174578230
This commit is contained in:
		| @@ -1,194 +0,0 @@ | |||||||
| // Copyright 2014 The Gogs Authors. All rights reserved. |  | ||||||
| // Copyright 2019 The Gitea Authors. All rights reserved. |  | ||||||
| // SPDX-License-Identifier: MIT |  | ||||||
|  |  | ||||||
| package context |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models/auth" |  | ||||||
| 	"code.gitea.io/gitea/modules/log" |  | ||||||
| 	"code.gitea.io/gitea/modules/setting" |  | ||||||
| 	"code.gitea.io/gitea/modules/web/middleware" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // ToggleOptions contains required or check options |  | ||||||
| type ToggleOptions struct { |  | ||||||
| 	SignInRequired  bool |  | ||||||
| 	SignOutRequired bool |  | ||||||
| 	AdminRequired   bool |  | ||||||
| 	DisableCSRF     bool |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Toggle returns toggle options as middleware |  | ||||||
| func Toggle(options *ToggleOptions) func(ctx *Context) { |  | ||||||
| 	return func(ctx *Context) { |  | ||||||
| 		// Check prohibit login users. |  | ||||||
| 		if ctx.IsSigned { |  | ||||||
| 			if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm { |  | ||||||
| 				ctx.Data["Title"] = ctx.Tr("auth.active_your_account") |  | ||||||
| 				ctx.HTML(http.StatusOK, "user/auth/activate") |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 			if !ctx.Doer.IsActive || ctx.Doer.ProhibitLogin { |  | ||||||
| 				log.Info("Failed authentication attempt for %s from %s", ctx.Doer.Name, ctx.RemoteAddr()) |  | ||||||
| 				ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") |  | ||||||
| 				ctx.HTML(http.StatusOK, "user/auth/prohibit_login") |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if ctx.Doer.MustChangePassword { |  | ||||||
| 				if ctx.Req.URL.Path != "/user/settings/change_password" { |  | ||||||
| 					if strings.HasPrefix(ctx.Req.UserAgent(), "git") { |  | ||||||
| 						ctx.Error(http.StatusUnauthorized, ctx.Tr("auth.must_change_password")) |  | ||||||
| 						return |  | ||||||
| 					} |  | ||||||
| 					ctx.Data["Title"] = ctx.Tr("auth.must_change_password") |  | ||||||
| 					ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password" |  | ||||||
| 					if ctx.Req.URL.Path != "/user/events" { |  | ||||||
| 						middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI()) |  | ||||||
| 					} |  | ||||||
| 					ctx.Redirect(setting.AppSubURL + "/user/settings/change_password") |  | ||||||
| 					return |  | ||||||
| 				} |  | ||||||
| 			} else if ctx.Req.URL.Path == "/user/settings/change_password" { |  | ||||||
| 				// make sure that the form cannot be accessed by users who don't need this |  | ||||||
| 				ctx.Redirect(setting.AppSubURL + "/") |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Redirect to dashboard if user tries to visit any non-login page. |  | ||||||
| 		if options.SignOutRequired && ctx.IsSigned && ctx.Req.URL.RequestURI() != "/" { |  | ||||||
| 			ctx.Redirect(setting.AppSubURL + "/") |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if !options.SignOutRequired && !options.DisableCSRF && ctx.Req.Method == "POST" { |  | ||||||
| 			ctx.Csrf.Validate(ctx) |  | ||||||
| 			if ctx.Written() { |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if options.SignInRequired { |  | ||||||
| 			if !ctx.IsSigned { |  | ||||||
| 				if ctx.Req.URL.Path != "/user/events" { |  | ||||||
| 					middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI()) |  | ||||||
| 				} |  | ||||||
| 				ctx.Redirect(setting.AppSubURL + "/user/login") |  | ||||||
| 				return |  | ||||||
| 			} else if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm { |  | ||||||
| 				ctx.Data["Title"] = ctx.Tr("auth.active_your_account") |  | ||||||
| 				ctx.HTML(http.StatusOK, "user/auth/activate") |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Redirect to log in page if auto-signin info is provided and has not signed in. |  | ||||||
| 		if !options.SignOutRequired && !ctx.IsSigned && |  | ||||||
| 			len(ctx.GetSiteCookie(setting.CookieUserName)) > 0 { |  | ||||||
| 			if ctx.Req.URL.Path != "/user/events" { |  | ||||||
| 				middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI()) |  | ||||||
| 			} |  | ||||||
| 			ctx.Redirect(setting.AppSubURL + "/user/login") |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if options.AdminRequired { |  | ||||||
| 			if !ctx.Doer.IsAdmin { |  | ||||||
| 				ctx.Error(http.StatusForbidden) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 			ctx.Data["PageIsAdmin"] = true |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ToggleAPI returns toggle options as middleware |  | ||||||
| func ToggleAPI(options *ToggleOptions) func(ctx *APIContext) { |  | ||||||
| 	return func(ctx *APIContext) { |  | ||||||
| 		// Check prohibit login users. |  | ||||||
| 		if ctx.IsSigned { |  | ||||||
| 			if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm { |  | ||||||
| 				ctx.Data["Title"] = ctx.Tr("auth.active_your_account") |  | ||||||
| 				ctx.JSON(http.StatusForbidden, map[string]string{ |  | ||||||
| 					"message": "This account is not activated.", |  | ||||||
| 				}) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 			if !ctx.Doer.IsActive || ctx.Doer.ProhibitLogin { |  | ||||||
| 				log.Info("Failed authentication attempt for %s from %s", ctx.Doer.Name, ctx.RemoteAddr()) |  | ||||||
| 				ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") |  | ||||||
| 				ctx.JSON(http.StatusForbidden, map[string]string{ |  | ||||||
| 					"message": "This account is prohibited from signing in, please contact your site administrator.", |  | ||||||
| 				}) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if ctx.Doer.MustChangePassword { |  | ||||||
| 				ctx.JSON(http.StatusForbidden, map[string]string{ |  | ||||||
| 					"message": "You must change your password. Change it at: " + setting.AppURL + "/user/change_password", |  | ||||||
| 				}) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Redirect to dashboard if user tries to visit any non-login page. |  | ||||||
| 		if options.SignOutRequired && ctx.IsSigned && ctx.Req.URL.RequestURI() != "/" { |  | ||||||
| 			ctx.Redirect(setting.AppSubURL + "/") |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if options.SignInRequired { |  | ||||||
| 			if !ctx.IsSigned { |  | ||||||
| 				// Restrict API calls with error message. |  | ||||||
| 				ctx.JSON(http.StatusForbidden, map[string]string{ |  | ||||||
| 					"message": "Only signed in user is allowed to call APIs.", |  | ||||||
| 				}) |  | ||||||
| 				return |  | ||||||
| 			} else if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm { |  | ||||||
| 				ctx.Data["Title"] = ctx.Tr("auth.active_your_account") |  | ||||||
| 				ctx.HTML(http.StatusOK, "user/auth/activate") |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 			if ctx.IsSigned && ctx.IsBasicAuth { |  | ||||||
| 				if skip, ok := ctx.Data["SkipLocalTwoFA"]; ok && skip.(bool) { |  | ||||||
| 					return // Skip 2FA |  | ||||||
| 				} |  | ||||||
| 				twofa, err := auth.GetTwoFactorByUID(ctx.Doer.ID) |  | ||||||
| 				if err != nil { |  | ||||||
| 					if auth.IsErrTwoFactorNotEnrolled(err) { |  | ||||||
| 						return // No 2FA enrollment for this user |  | ||||||
| 					} |  | ||||||
| 					ctx.InternalServerError(err) |  | ||||||
| 					return |  | ||||||
| 				} |  | ||||||
| 				otpHeader := ctx.Req.Header.Get("X-Gitea-OTP") |  | ||||||
| 				ok, err := twofa.ValidateTOTP(otpHeader) |  | ||||||
| 				if err != nil { |  | ||||||
| 					ctx.InternalServerError(err) |  | ||||||
| 					return |  | ||||||
| 				} |  | ||||||
| 				if !ok { |  | ||||||
| 					ctx.JSON(http.StatusForbidden, map[string]string{ |  | ||||||
| 						"message": "Only signed in user is allowed to call APIs.", |  | ||||||
| 					}) |  | ||||||
| 					return |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if options.AdminRequired { |  | ||||||
| 			if !ctx.Doer.IsAdmin { |  | ||||||
| 				ctx.JSON(http.StatusForbidden, map[string]string{ |  | ||||||
| 					"message": "You have no permission to request for this.", |  | ||||||
| 				}) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 			ctx.Data["PageIsAdmin"] = true |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -689,7 +689,7 @@ func Routes(ctx gocontext.Context) *web.Route { | |||||||
| 	// Get user from session if logged in. | 	// Get user from session if logged in. | ||||||
| 	m.Use(auth.APIAuth(group)) | 	m.Use(auth.APIAuth(group)) | ||||||
|  |  | ||||||
| 	m.Use(context.ToggleAPI(&context.ToggleOptions{ | 	m.Use(auth.VerifyAuthWithOptionsAPI(&auth.VerifyOptions{ | ||||||
| 		SignInRequired: setting.Service.RequireSignInView, | 		SignInRequired: setting.Service.RequireSignInView, | ||||||
| 	})) | 	})) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -228,11 +228,11 @@ func Routes(ctx gocontext.Context) *web.Route { | |||||||
|  |  | ||||||
| // RegisterRoutes register routes | // RegisterRoutes register routes | ||||||
| func RegisterRoutes(m *web.Route) { | func RegisterRoutes(m *web.Route) { | ||||||
| 	reqSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: true}) | 	reqSignIn := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{SignInRequired: true}) | ||||||
| 	ignSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: setting.Service.RequireSignInView}) | 	ignSignIn := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{SignInRequired: setting.Service.RequireSignInView}) | ||||||
| 	ignExploreSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView}) | 	ignExploreSignIn := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{SignInRequired: setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView}) | ||||||
| 	ignSignInAndCsrf := context.Toggle(&context.ToggleOptions{DisableCSRF: true}) | 	ignSignInAndCsrf := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{DisableCSRF: true}) | ||||||
| 	reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequired: true}) | 	reqSignOut := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{SignOutRequired: true}) | ||||||
| 	validation.AddBindingRules() | 	validation.AddBindingRules() | ||||||
|  |  | ||||||
| 	linkAccountEnabled := func(ctx *context.Context) { | 	linkAccountEnabled := func(ctx *context.Context) { | ||||||
| @@ -551,7 +551,7 @@ func RegisterRoutes(m *web.Route) { | |||||||
|  |  | ||||||
| 	m.Get("/avatar/{hash}", user.AvatarByEmailHash) | 	m.Get("/avatar/{hash}", user.AvatarByEmailHash) | ||||||
|  |  | ||||||
| 	adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true}) | 	adminReq := auth_service.VerifyAuthWithOptions(&auth_service.VerifyOptions{SignInRequired: true, AdminRequired: true}) | ||||||
|  |  | ||||||
| 	// ***** START: Admin ***** | 	// ***** START: Admin ***** | ||||||
| 	m.Group("/admin", func() { | 	m.Group("/admin", func() { | ||||||
|   | |||||||
| @@ -5,9 +5,12 @@ package auth | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"code.gitea.io/gitea/models/auth" | ||||||
| 	"code.gitea.io/gitea/modules/context" | 	"code.gitea.io/gitea/modules/context" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
|  | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/web/middleware" | 	"code.gitea.io/gitea/modules/web/middleware" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -58,3 +61,182 @@ func authShared(ctx *context.Context, authMethod Method) error { | |||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // VerifyOptions contains required or check options | ||||||
|  | type VerifyOptions struct { | ||||||
|  | 	SignInRequired  bool | ||||||
|  | 	SignOutRequired bool | ||||||
|  | 	AdminRequired   bool | ||||||
|  | 	DisableCSRF     bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Checks authentication according to options | ||||||
|  | func VerifyAuthWithOptions(options *VerifyOptions) func(ctx *context.Context) { | ||||||
|  | 	return func(ctx *context.Context) { | ||||||
|  | 		// Check prohibit login users. | ||||||
|  | 		if ctx.IsSigned { | ||||||
|  | 			if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm { | ||||||
|  | 				ctx.Data["Title"] = ctx.Tr("auth.active_your_account") | ||||||
|  | 				ctx.HTML(http.StatusOK, "user/auth/activate") | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			if !ctx.Doer.IsActive || ctx.Doer.ProhibitLogin { | ||||||
|  | 				log.Info("Failed authentication attempt for %s from %s", ctx.Doer.Name, ctx.RemoteAddr()) | ||||||
|  | 				ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") | ||||||
|  | 				ctx.HTML(http.StatusOK, "user/auth/prohibit_login") | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if ctx.Doer.MustChangePassword { | ||||||
|  | 				if ctx.Req.URL.Path != "/user/settings/change_password" { | ||||||
|  | 					if strings.HasPrefix(ctx.Req.UserAgent(), "git") { | ||||||
|  | 						ctx.Error(http.StatusUnauthorized, ctx.Tr("auth.must_change_password")) | ||||||
|  | 						return | ||||||
|  | 					} | ||||||
|  | 					ctx.Data["Title"] = ctx.Tr("auth.must_change_password") | ||||||
|  | 					ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password" | ||||||
|  | 					if ctx.Req.URL.Path != "/user/events" { | ||||||
|  | 						middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI()) | ||||||
|  | 					} | ||||||
|  | 					ctx.Redirect(setting.AppSubURL + "/user/settings/change_password") | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
|  | 			} else if ctx.Req.URL.Path == "/user/settings/change_password" { | ||||||
|  | 				// make sure that the form cannot be accessed by users who don't need this | ||||||
|  | 				ctx.Redirect(setting.AppSubURL + "/") | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Redirect to dashboard if user tries to visit any non-login page. | ||||||
|  | 		if options.SignOutRequired && ctx.IsSigned && ctx.Req.URL.RequestURI() != "/" { | ||||||
|  | 			ctx.Redirect(setting.AppSubURL + "/") | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if !options.SignOutRequired && !options.DisableCSRF && ctx.Req.Method == "POST" { | ||||||
|  | 			ctx.Csrf.Validate(ctx) | ||||||
|  | 			if ctx.Written() { | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if options.SignInRequired { | ||||||
|  | 			if !ctx.IsSigned { | ||||||
|  | 				if ctx.Req.URL.Path != "/user/events" { | ||||||
|  | 					middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI()) | ||||||
|  | 				} | ||||||
|  | 				ctx.Redirect(setting.AppSubURL + "/user/login") | ||||||
|  | 				return | ||||||
|  | 			} else if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm { | ||||||
|  | 				ctx.Data["Title"] = ctx.Tr("auth.active_your_account") | ||||||
|  | 				ctx.HTML(http.StatusOK, "user/auth/activate") | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Redirect to log in page if auto-signin info is provided and has not signed in. | ||||||
|  | 		if !options.SignOutRequired && !ctx.IsSigned && | ||||||
|  | 			len(ctx.GetSiteCookie(setting.CookieUserName)) > 0 { | ||||||
|  | 			if ctx.Req.URL.Path != "/user/events" { | ||||||
|  | 				middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI()) | ||||||
|  | 			} | ||||||
|  | 			ctx.Redirect(setting.AppSubURL + "/user/login") | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if options.AdminRequired { | ||||||
|  | 			if !ctx.Doer.IsAdmin { | ||||||
|  | 				ctx.Error(http.StatusForbidden) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			ctx.Data["PageIsAdmin"] = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Checks authentication according to options | ||||||
|  | func VerifyAuthWithOptionsAPI(options *VerifyOptions) func(ctx *context.APIContext) { | ||||||
|  | 	return func(ctx *context.APIContext) { | ||||||
|  | 		// Check prohibit login users. | ||||||
|  | 		if ctx.IsSigned { | ||||||
|  | 			if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm { | ||||||
|  | 				ctx.Data["Title"] = ctx.Tr("auth.active_your_account") | ||||||
|  | 				ctx.JSON(http.StatusForbidden, map[string]string{ | ||||||
|  | 					"message": "This account is not activated.", | ||||||
|  | 				}) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			if !ctx.Doer.IsActive || ctx.Doer.ProhibitLogin { | ||||||
|  | 				log.Info("Failed authentication attempt for %s from %s", ctx.Doer.Name, ctx.RemoteAddr()) | ||||||
|  | 				ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") | ||||||
|  | 				ctx.JSON(http.StatusForbidden, map[string]string{ | ||||||
|  | 					"message": "This account is prohibited from signing in, please contact your site administrator.", | ||||||
|  | 				}) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if ctx.Doer.MustChangePassword { | ||||||
|  | 				ctx.JSON(http.StatusForbidden, map[string]string{ | ||||||
|  | 					"message": "You must change your password. Change it at: " + setting.AppURL + "/user/change_password", | ||||||
|  | 				}) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Redirect to dashboard if user tries to visit any non-login page. | ||||||
|  | 		if options.SignOutRequired && ctx.IsSigned && ctx.Req.URL.RequestURI() != "/" { | ||||||
|  | 			ctx.Redirect(setting.AppSubURL + "/") | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if options.SignInRequired { | ||||||
|  | 			if !ctx.IsSigned { | ||||||
|  | 				// Restrict API calls with error message. | ||||||
|  | 				ctx.JSON(http.StatusForbidden, map[string]string{ | ||||||
|  | 					"message": "Only signed in user is allowed to call APIs.", | ||||||
|  | 				}) | ||||||
|  | 				return | ||||||
|  | 			} else if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm { | ||||||
|  | 				ctx.Data["Title"] = ctx.Tr("auth.active_your_account") | ||||||
|  | 				ctx.HTML(http.StatusOK, "user/auth/activate") | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			if ctx.IsSigned && ctx.IsBasicAuth { | ||||||
|  | 				if skip, ok := ctx.Data["SkipLocalTwoFA"]; ok && skip.(bool) { | ||||||
|  | 					return // Skip 2FA | ||||||
|  | 				} | ||||||
|  | 				twofa, err := auth.GetTwoFactorByUID(ctx.Doer.ID) | ||||||
|  | 				if err != nil { | ||||||
|  | 					if auth.IsErrTwoFactorNotEnrolled(err) { | ||||||
|  | 						return // No 2FA enrollment for this user | ||||||
|  | 					} | ||||||
|  | 					ctx.InternalServerError(err) | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
|  | 				otpHeader := ctx.Req.Header.Get("X-Gitea-OTP") | ||||||
|  | 				ok, err := twofa.ValidateTOTP(otpHeader) | ||||||
|  | 				if err != nil { | ||||||
|  | 					ctx.InternalServerError(err) | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
|  | 				if !ok { | ||||||
|  | 					ctx.JSON(http.StatusForbidden, map[string]string{ | ||||||
|  | 						"message": "Only signed in user is allowed to call APIs.", | ||||||
|  | 					}) | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if options.AdminRequired { | ||||||
|  | 			if !ctx.Doer.IsAdmin { | ||||||
|  | 				ctx.JSON(http.StatusForbidden, map[string]string{ | ||||||
|  | 					"message": "You have no permission to request for this.", | ||||||
|  | 				}) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			ctx.Data["PageIsAdmin"] = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user