forked from hinterland/hearth
feat: vendor gitea 1.16.2
This commit is contained in:
@@ -15,10 +15,10 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/metrics"
|
||||
"code.gitea.io/gitea/modules/public"
|
||||
"code.gitea.io/gitea/modules/reqctx"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
@@ -33,7 +33,6 @@ import (
|
||||
"code.gitea.io/gitea/routers/web/healthcheck"
|
||||
"code.gitea.io/gitea/routers/web/misc"
|
||||
"code.gitea.io/gitea/routers/web/org"
|
||||
org_setting "code.gitea.io/gitea/routers/web/org/setting"
|
||||
"code.gitea.io/gitea/routers/web/repo"
|
||||
"code.gitea.io/gitea/routers/web/repo/actions"
|
||||
repo_setting "code.gitea.io/gitea/routers/web/repo/setting"
|
||||
@@ -91,32 +90,64 @@ func optionsCorsHandler() func(next http.Handler) http.Handler {
|
||||
}
|
||||
}
|
||||
|
||||
// The OAuth2 plugin is expected to be executed first, as it must ignore the user id stored
|
||||
// in the session (if there is a user id stored in session other plugins might return the user
|
||||
// object for that id).
|
||||
//
|
||||
// The Session plugin is expected to be executed second, in order to skip authentication
|
||||
// for users that have already signed in.
|
||||
func buildAuthGroup() *auth_service.Group {
|
||||
group := auth_service.NewGroup()
|
||||
group.Add(&auth_service.OAuth2{}) // FIXME: this should be removed and only applied in download and oauth related routers
|
||||
group.Add(&auth_service.Basic{}) // FIXME: this should be removed and only applied in download and git/lfs routers
|
||||
|
||||
if setting.Service.EnableReverseProxyAuth {
|
||||
group.Add(&auth_service.ReverseProxy{}) // reverse-proxy should before Session, otherwise the header will be ignored if user has login
|
||||
}
|
||||
group.Add(&auth_service.Session{})
|
||||
|
||||
if setting.IsWindows && auth_model.IsSSPIEnabled(graceful.GetManager().ShutdownContext()) {
|
||||
group.Add(&auth_service.SSPI{}) // it MUST be the last, see the comment of SSPI
|
||||
}
|
||||
|
||||
return group
|
||||
type AuthMiddleware struct {
|
||||
AllowOAuth2 web.PreMiddlewareProvider
|
||||
AllowBasic web.PreMiddlewareProvider
|
||||
MiddlewareHandler func(*context.Context)
|
||||
}
|
||||
|
||||
func webAuth(authMethod auth_service.Method) func(*context.Context) {
|
||||
return func(ctx *context.Context) {
|
||||
ar, err := common.AuthShared(ctx.Base, ctx.Session, authMethod)
|
||||
func newWebAuthMiddleware() *AuthMiddleware {
|
||||
type keyAllowOAuth2 struct{}
|
||||
type keyAllowBasic struct{}
|
||||
webAuth := &AuthMiddleware{}
|
||||
|
||||
middlewareSetContextValue := func(key, val any) web.PreMiddlewareProvider {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
dataStore := reqctx.GetRequestDataStore(r.Context())
|
||||
dataStore.SetContextValue(key, val)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
webAuth.AllowBasic = middlewareSetContextValue(keyAllowBasic{}, true)
|
||||
webAuth.AllowOAuth2 = middlewareSetContextValue(keyAllowOAuth2{}, true)
|
||||
|
||||
enableSSPI := setting.IsWindows && auth_model.IsSSPIEnabled(graceful.GetManager().ShutdownContext())
|
||||
webAuth.MiddlewareHandler = func(ctx *context.Context) {
|
||||
allowBasic := ctx.GetContextValue(keyAllowBasic{}) == true
|
||||
allowOAuth2 := ctx.GetContextValue(keyAllowOAuth2{}) == true
|
||||
|
||||
group := auth_service.NewGroup()
|
||||
|
||||
// Most auth methods should ignore the user id stored in the session.
|
||||
// If the auth succeeds, it must use the user id from the auth method to make sure the new login succeeds.
|
||||
if allowOAuth2 {
|
||||
group.Add(&auth_service.OAuth2{})
|
||||
}
|
||||
if allowBasic {
|
||||
group.Add(&auth_service.Basic{})
|
||||
}
|
||||
|
||||
// Sessionless means the route's auth can be done without web ui, then it doesn't need to create a session
|
||||
// For example: accessing git via http, access rss feeds, downloading attachments, etc
|
||||
isSessionless := allowOAuth2 || allowBasic
|
||||
|
||||
if setting.Service.EnableReverseProxyAuth {
|
||||
// reverse-proxy should before Session, otherwise the header will be ignored if user has login
|
||||
group.Add(&auth_service.ReverseProxy{CreateSession: !isSessionless})
|
||||
}
|
||||
|
||||
// The Session plugin will skip authentication for users that have already signed in.
|
||||
group.Add(&auth_service.Session{})
|
||||
|
||||
if enableSSPI {
|
||||
// it MUST be the last, see the comment of SSPI
|
||||
group.Add(&auth_service.SSPI{CreateSession: !isSessionless})
|
||||
}
|
||||
|
||||
ar, err := common.AuthShared(ctx.Base, ctx.Session, group)
|
||||
if err != nil {
|
||||
log.Error("Failed to verify user: %v", err)
|
||||
ctx.HTTPError(http.StatusUnauthorized, "Failed to authenticate user")
|
||||
@@ -129,13 +160,14 @@ func webAuth(authMethod auth_service.Method) func(*context.Context) {
|
||||
// ensure the session uid is deleted
|
||||
_ = ctx.Session.Delete("uid")
|
||||
}
|
||||
|
||||
ctx.Csrf.PrepareForSessionUser(ctx)
|
||||
}
|
||||
return webAuth
|
||||
}
|
||||
|
||||
// verifyAuthWithOptions checks authentication according to options
|
||||
func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.Context) {
|
||||
crossOriginProtection := http.NewCrossOriginProtection()
|
||||
|
||||
return func(ctx *context.Context) {
|
||||
// Check prohibit login users.
|
||||
if ctx.IsSigned {
|
||||
@@ -159,9 +191,7 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.Cont
|
||||
}
|
||||
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())
|
||||
}
|
||||
middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI())
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/change_password")
|
||||
return
|
||||
}
|
||||
@@ -172,25 +202,22 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.Cont
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect to dashboard (or alternate location) if user tries to visit any non-login page.
|
||||
// When a signed-in user visits a page that requires sign-out (e.g.: "/user/login"), redirect to home (or alternate location)
|
||||
if options.SignOutRequired && ctx.IsSigned && ctx.Req.URL.RequestURI() != "/" {
|
||||
ctx.RedirectToCurrentSite(ctx.FormString("redirect_to"))
|
||||
return
|
||||
}
|
||||
|
||||
if !options.SignOutRequired && !options.DisableCSRF && ctx.Req.Method == http.MethodPost {
|
||||
ctx.Csrf.Validate(ctx)
|
||||
if ctx.Written() {
|
||||
if !options.SignOutRequired && !options.DisableCrossOriginProtection {
|
||||
if err := crossOriginProtection.Check(ctx.Req); err != nil {
|
||||
http.Error(ctx.Resp, err.Error(), http.StatusForbidden)
|
||||
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")
|
||||
ctx.Redirect(middleware.RedirectLinkUserLogin(ctx.Req))
|
||||
return
|
||||
} else if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm {
|
||||
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
|
||||
@@ -200,12 +227,8 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.Cont
|
||||
}
|
||||
|
||||
// Redirect to log in page if auto-signin info is provided and has not signed in.
|
||||
if !options.SignOutRequired && !ctx.IsSigned &&
|
||||
ctx.GetSiteCookie(setting.CookieRememberName) != "" {
|
||||
if ctx.Req.URL.Path != "/user/events" {
|
||||
middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI())
|
||||
}
|
||||
ctx.Redirect(setting.AppSubURL + "/user/login")
|
||||
if !options.SignOutRequired && !ctx.IsSigned && ctx.GetSiteCookie(setting.CookieRememberName) != "" {
|
||||
ctx.Redirect(middleware.RedirectLinkUserLogin(ctx.Req))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -233,16 +256,17 @@ const RouterMockPointBeforeWebRoutes = "before-web-routes"
|
||||
func Routes() *web.Router {
|
||||
routes := web.NewRouter()
|
||||
|
||||
// GetHead allows a HEAD request redirect to GET if HEAD method is not defined for that route
|
||||
routes.BeforeRouting(chi_middleware.GetHead)
|
||||
|
||||
routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler
|
||||
routes.Methods("GET, HEAD, OPTIONS", "/assets/*", optionsCorsHandler(), public.FileHandlerFunc())
|
||||
routes.Methods("GET, HEAD, OPTIONS", "/assets/*", routing.MarkLogLevelTrace, public.AssetsCors(), public.FileHandlerFunc())
|
||||
routes.Methods("GET, HEAD", "/avatars/*", avatarStorageHandler(setting.Avatar.Storage, "avatars", storage.Avatars))
|
||||
routes.Methods("GET, HEAD", "/repo-avatars/*", avatarStorageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars))
|
||||
routes.Methods("GET, HEAD", "/apple-touch-icon.png", misc.StaticRedirect("/assets/img/apple-touch-icon.png"))
|
||||
routes.Methods("GET, HEAD", "/apple-touch-icon-precomposed.png", misc.StaticRedirect("/assets/img/apple-touch-icon.png"))
|
||||
routes.Methods("GET, HEAD", "/favicon.ico", misc.StaticRedirect("/assets/img/favicon.png"))
|
||||
|
||||
_ = templates.HTMLRenderer()
|
||||
|
||||
var mid []any
|
||||
|
||||
if setting.EnableGzip {
|
||||
@@ -269,13 +293,11 @@ func Routes() *web.Router {
|
||||
routes.Get("/ssh_info", misc.SSHInfo)
|
||||
routes.Get("/api/healthz", healthcheck.Check)
|
||||
|
||||
mid = append(mid, common.Sessioner(), context.Contexter())
|
||||
mid = append(mid, common.MustInitSessioner(), context.Contexter())
|
||||
|
||||
// Get user from session if logged in.
|
||||
mid = append(mid, webAuth(buildAuthGroup()))
|
||||
|
||||
// GetHead allows a HEAD request redirect to GET if HEAD method is not defined for that route
|
||||
mid = append(mid, chi_middleware.GetHead)
|
||||
webAuth := newWebAuthMiddleware()
|
||||
mid = append(mid, webAuth.MiddlewareHandler)
|
||||
|
||||
if setting.API.EnableSwagger {
|
||||
// Note: The route is here but no in API routes because it renders a web page
|
||||
@@ -284,18 +306,25 @@ func Routes() *web.Router {
|
||||
|
||||
mid = append(mid, goGet)
|
||||
mid = append(mid, common.PageGlobalData)
|
||||
mid = append(mid, common.BlockExpensive(), common.QoS(), web.RouterMockPoint(RouterMockPointBeforeWebRoutes))
|
||||
|
||||
webRoutes := web.NewRouter()
|
||||
webRoutes.Use(mid...)
|
||||
webRoutes.Group("", func() { registerWebRoutes(webRoutes) }, common.BlockExpensive(), common.QoS(), web.RouterMockPoint(RouterMockPointBeforeWebRoutes))
|
||||
webRoutes.AfterRouting(mid...)
|
||||
registerWebRoutes(webRoutes, webAuth)
|
||||
|
||||
routes.Mount("", webRoutes)
|
||||
return routes
|
||||
}
|
||||
|
||||
var optSignInIgnoreCsrf = verifyAuthWithOptions(&common.VerifyOptions{DisableCSRF: true})
|
||||
// optSignInFromAnyOrigin means that the user can (optionally) be signed in from any origin (no cross-origin protection)
|
||||
// - With CORS middleware: CORS middleware does the preflight request handling, the requests has Sec-Fetch-Site header.
|
||||
// The CORS mechanism already protects cross-origin requests, and the CrossOriginProtection has no "allowed origin" list, so disable CrossOriginProtection.
|
||||
// - For non-browser client requests: git clone via http, no Sec-Fetch-Site header.
|
||||
// Such requests are not cross-origin requests, so disable CrossOriginProtection.
|
||||
var optSignInFromAnyOrigin = verifyAuthWithOptions(&common.VerifyOptions{DisableCrossOriginProtection: true})
|
||||
|
||||
// registerWebRoutes register routes
|
||||
func registerWebRoutes(m *web.Router) {
|
||||
func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) {
|
||||
// required to be signed in or signed out
|
||||
reqSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: true})
|
||||
reqSignOut := verifyAuthWithOptions(&common.VerifyOptions{SignOutRequired: true})
|
||||
@@ -463,6 +492,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Get("", shared_actions.Runners)
|
||||
m.Combo("/{runnerid}").Get(shared_actions.RunnersEdit).
|
||||
Post(web.Bind(forms.EditRunnerForm{}), shared_actions.RunnersEditPost)
|
||||
m.Post("/{runnerid}/update-runner", shared_actions.RunnerUpdatePost)
|
||||
m.Post("/{runnerid}/delete", shared_actions.RunnerDeletePost)
|
||||
m.Post("/reset_registration_token", shared_actions.ResetRunnerRegistrationToken)
|
||||
})
|
||||
@@ -487,6 +517,9 @@ func registerWebRoutes(m *web.Router) {
|
||||
}, optionsCorsHandler())
|
||||
|
||||
m.Post("/-/markup", reqSignIn, web.Bind(structs.MarkupOption{}), misc.Markup)
|
||||
m.Post("/-/web-banner/dismiss", misc.WebBannerDismiss)
|
||||
m.Get("/-/web-theme/list", misc.WebThemeList)
|
||||
m.Post("/-/web-theme/apply", optSignIn, misc.WebThemeApply)
|
||||
|
||||
m.Group("/explore", func() {
|
||||
m.Get("", func(ctx *context.Context) {
|
||||
@@ -562,12 +595,14 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Post("/grant", web.Bind(forms.GrantApplicationForm{}), auth.GrantApplicationOAuth)
|
||||
// TODO manage redirection
|
||||
m.Post("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth)
|
||||
}, optSignInIgnoreCsrf, reqSignIn)
|
||||
}, reqSignIn)
|
||||
|
||||
m.Methods("GET, POST, OPTIONS", "/userinfo", optionsCorsHandler(), optSignInIgnoreCsrf, auth.InfoOAuth)
|
||||
m.Methods("POST, OPTIONS", "/access_token", optionsCorsHandler(), web.Bind(forms.AccessTokenForm{}), optSignInIgnoreCsrf, auth.AccessTokenOAuth)
|
||||
m.Methods("GET, OPTIONS", "/keys", optionsCorsHandler(), optSignInIgnoreCsrf, auth.OIDCKeys)
|
||||
m.Methods("POST, OPTIONS", "/introspect", optionsCorsHandler(), web.Bind(forms.IntrospectTokenForm{}), optSignInIgnoreCsrf, auth.IntrospectOAuth)
|
||||
m.Group("", func() {
|
||||
m.Methods("GET, POST, OPTIONS", "/userinfo", auth.InfoOAuth)
|
||||
m.Methods("POST, OPTIONS", "/access_token", web.Bind(forms.AccessTokenForm{}), auth.AccessTokenOAuth)
|
||||
m.Methods("GET, OPTIONS", "/keys", auth.OIDCKeys)
|
||||
m.Methods("POST, OPTIONS", "/introspect", web.Bind(forms.IntrospectTokenForm{}), auth.IntrospectOAuth)
|
||||
}, optionsCorsHandler(), webAuth.AllowOAuth2, optSignInFromAnyOrigin)
|
||||
}, oauth2Enabled)
|
||||
|
||||
m.Group("/user/settings", func() {
|
||||
@@ -657,7 +692,11 @@ func registerWebRoutes(m *web.Router) {
|
||||
}, packagesEnabled)
|
||||
|
||||
m.Group("/actions", func() {
|
||||
m.Get("", user_setting.RedirectToDefaultSetting)
|
||||
m.Get("", misc.LocationRedirect("./actions/general"))
|
||||
m.Group("/general", func() {
|
||||
m.Get("", shared_actions.GeneralSettings)
|
||||
m.Post("", shared_actions.UpdateGeneralSettings)
|
||||
})
|
||||
addSettingsRunnersRoutes()
|
||||
addSettingsSecretsRoutes()
|
||||
addSettingsVariablesRoutes()
|
||||
@@ -682,7 +721,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Get("", user_setting.BlockedUsers)
|
||||
m.Post("", web.Bind(forms.BlockUserForm{}), user_setting.BlockedUsersPost)
|
||||
})
|
||||
}, reqSignIn, ctxDataSet("PageIsUserSettings", true, "EnablePackages", setting.Packages.Enabled, "EnableNotifyMail", setting.Service.EnableNotifyMail))
|
||||
}, reqSignIn, user_setting.SettingsCtxData)
|
||||
|
||||
m.Group("/user", func() {
|
||||
m.Get("/activate", auth.Activate)
|
||||
@@ -693,7 +732,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Post("/recover_account", auth.ResetPasswdPost)
|
||||
m.Get("/forgot_password", auth.ForgotPasswd)
|
||||
m.Post("/forgot_password", auth.ForgotPasswdPost)
|
||||
m.Post("/logout", auth.SignOut)
|
||||
m.Get("/logout", auth.SignOut)
|
||||
m.Get("/stopwatches", reqSignIn, user.GetStopwatches)
|
||||
m.Get("/search_candidates", optExploreSignIn, user.SearchCandidates)
|
||||
m.Group("/oauth2", func() {
|
||||
@@ -749,6 +788,16 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Post("/{userid}/avatar/delete", admin.DeleteAvatar)
|
||||
})
|
||||
|
||||
m.Group("/badges", func() {
|
||||
m.Get("", admin.Badges)
|
||||
m.Combo("/new").Get(admin.NewBadge).Post(web.Bind(forms.AdminCreateBadgeForm{}), admin.NewBadgePost)
|
||||
m.Get("/slug/{badge_slug}", admin.ViewBadge)
|
||||
m.Combo("/slug/{badge_slug}/edit").Get(admin.EditBadge).Post(web.Bind(forms.AdminEditBadgeForm{}), admin.EditBadgePost)
|
||||
m.Post("/slug/{badge_slug}/delete", admin.DeleteBadge)
|
||||
m.Combo("/slug/{badge_slug}/users").Get(admin.BadgeUsers).Post(admin.BadgeUsersPost)
|
||||
m.Post("/slug/{badge_slug}/users/delete", admin.DeleteBadgeUser)
|
||||
})
|
||||
|
||||
m.Group("/emails", func() {
|
||||
m.Get("", admin.Emails)
|
||||
m.Post("/activate", admin.ActivateEmail)
|
||||
@@ -810,7 +859,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
}, oauth2Enabled)
|
||||
|
||||
m.Group("/actions", func() {
|
||||
m.Get("", admin.RedirectToDefaultSetting)
|
||||
m.Get("", misc.LocationRedirect("./actions/runners"))
|
||||
addSettingsRunnersRoutes()
|
||||
addSettingsVariablesRoutes()
|
||||
})
|
||||
@@ -818,8 +867,9 @@ func registerWebRoutes(m *web.Router) {
|
||||
// ***** END: Admin *****
|
||||
|
||||
m.Group("", func() {
|
||||
m.Get("/{username}", user.UsernameSubRoute)
|
||||
m.Methods("GET, OPTIONS", "/attachments/{uuid}", optionsCorsHandler(), repo.GetAttachment)
|
||||
// it handles "username.rss" in the handler, so allow basic auth as other rss/atom routes
|
||||
m.Get("/{username}", webAuth.AllowBasic, user.UsernameSubRoute)
|
||||
m.Methods("GET, OPTIONS", "/attachments/{uuid}", optionsCorsHandler(), webAuth.AllowBasic, webAuth.AllowOAuth2, repo.GetAttachment)
|
||||
}, optSignIn)
|
||||
|
||||
m.Post("/{username}", reqSignIn, context.UserAssignmentWeb(), user.ActionUserFollow)
|
||||
@@ -837,6 +887,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
|
||||
// the legacy names "reqRepoXxx" should be renamed to the correct name "reqUnitXxx", these permissions are for units, not repos
|
||||
reqUnitsWithMarkdown := context.RequireUnitReader(unit.TypeCode, unit.TypeIssues, unit.TypePullRequests, unit.TypeReleases, unit.TypeWiki)
|
||||
reqUnitsWithMentions := context.RequireUnitReader(unit.TypeIssues, unit.TypePullRequests, unit.TypeReleases, unit.TypeWiki, unit.TypeProjects)
|
||||
reqUnitCodeReader := context.RequireUnitReader(unit.TypeCode)
|
||||
reqUnitIssuesReader := context.RequireUnitReader(unit.TypeIssues)
|
||||
reqUnitPullsReader := context.RequireUnitReader(unit.TypePullRequests)
|
||||
@@ -890,6 +941,8 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Group("/{org}", func() {
|
||||
m.Get("/dashboard", user.Dashboard)
|
||||
m.Get("/dashboard/{team}", user.Dashboard)
|
||||
m.Get("/dashboard/-/heatmap", user.DashboardHeatmap)
|
||||
m.Get("/dashboard/-/heatmap/{team}", user.DashboardHeatmap)
|
||||
m.Get("/issues", user.Issues)
|
||||
m.Get("/issues/{team}", user.Issues)
|
||||
m.Get("/pulls", user.Pulls)
|
||||
@@ -958,7 +1011,11 @@ func registerWebRoutes(m *web.Router) {
|
||||
})
|
||||
|
||||
m.Group("/actions", func() {
|
||||
m.Get("", org_setting.RedirectToDefaultSetting)
|
||||
m.Get("", misc.LocationRedirect("./actions/general"))
|
||||
m.Group("/general", func() {
|
||||
m.Get("", shared_actions.GeneralSettings)
|
||||
m.Post("", shared_actions.UpdateGeneralSettings)
|
||||
})
|
||||
addSettingsRunnersRoutes()
|
||||
addSettingsSecretsRoutes()
|
||||
addSettingsVariablesRoutes()
|
||||
@@ -1014,18 +1071,27 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Get("/versions", user.ListPackageVersions)
|
||||
m.Group("/{version}", func() {
|
||||
m.Get("", user.ViewPackageVersion)
|
||||
m.Post("", reqPackageAccess(perm.AccessModeWrite), user.PackageVersionDelete)
|
||||
m.Get("/{version_sub}", user.ViewPackageVersion)
|
||||
m.Get("/files/{fileid}", user.DownloadPackageFile)
|
||||
m.Group("/settings", func() {
|
||||
m.Get("", user.PackageSettings)
|
||||
m.Post("", web.Bind(forms.PackageSettingForm{}), user.PackageSettingsPost)
|
||||
m.Group("/terraform", func() {
|
||||
m.Post("/lock", user.ActionPackageTerraformLock)
|
||||
m.Post("/unlock", user.ActionPackageTerraformUnlock)
|
||||
}, reqPackageAccess(perm.AccessModeWrite))
|
||||
m.Get("/files/{fileid}", user.DownloadPackageFile)
|
||||
})
|
||||
})
|
||||
m.Group("/settings/{type}/{name}", func() {
|
||||
m.Get("", user.PackageSettings)
|
||||
m.Post("", web.Bind(forms.PackageSettingForm{}), user.PackageSettingsPost)
|
||||
}, reqPackageAccess(perm.AccessModeWrite))
|
||||
}, context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
|
||||
}
|
||||
|
||||
// at the moment, only editing "owner-level projects" need to "mention", maybe in the future we can relax the permission check
|
||||
m.Get("/mentions-in-owner", reqUnitAccess(unit.TypeProjects, perm.AccessModeWrite, true), org.GetMentionsInOwner)
|
||||
|
||||
m.Get("/repositories", org.Repositories)
|
||||
m.Get("/heatmap", user.DashboardHeatmap)
|
||||
|
||||
m.Group("/projects", func() {
|
||||
m.Group("", func() {
|
||||
@@ -1073,6 +1139,11 @@ func registerWebRoutes(m *web.Router) {
|
||||
}, optSignIn, context.RepoAssignment, reqUnitCodeReader)
|
||||
// end "/{username}/{reponame}/-": migrate
|
||||
|
||||
m.Group("/{username}/{reponame}/-", func() {
|
||||
m.Get("/mentions-in-repo", repo.GetMentionsInRepo)
|
||||
}, optSignIn, context.RepoAssignment, reqUnitsWithMentions)
|
||||
// end "/{username}/{reponame}/-": mentions
|
||||
|
||||
m.Group("/{username}/{reponame}/settings", func() {
|
||||
m.Group("", func() {
|
||||
m.Combo("").Get(repo_setting.Settings).
|
||||
@@ -1102,7 +1173,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Combo("/edit").Get(repo_setting.SettingsProtectedBranch).
|
||||
Post(web.Bind(forms.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo_setting.SettingsProtectedBranchPost)
|
||||
m.Post("/{id}/delete", repo_setting.DeleteProtectedBranchRulePost)
|
||||
m.Post("/priority", web.Bind(forms.ProtectBranchPriorityForm{}), context.RepoMustNotBeArchived(), repo_setting.UpdateBranchProtectionPriories)
|
||||
m.Post("/priority", context.RepoMustNotBeArchived(), repo_setting.UpdateBranchProtectionPriories)
|
||||
})
|
||||
|
||||
m.Group("/tags", func() {
|
||||
@@ -1150,11 +1221,22 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Post("/{lid}/unlock", repo_setting.LFSUnlock)
|
||||
})
|
||||
})
|
||||
m.Group("/actions/general", func() {
|
||||
m.Get("", repo_setting.ActionsGeneralSettings)
|
||||
m.Post("/actions_unit", repo_setting.ActionsUnitPost)
|
||||
}) // doesn't require actions enabled
|
||||
m.Group("/actions", func() {
|
||||
m.Get("", shared_actions.RedirectToDefaultSetting)
|
||||
m.Get("", misc.LocationRedirect("./actions/general"))
|
||||
addSettingsRunnersRoutes()
|
||||
addSettingsSecretsRoutes()
|
||||
addSettingsVariablesRoutes()
|
||||
m.Group("/general", func() {
|
||||
m.Group("/collaborative_owner", func() {
|
||||
m.Post("/add", repo_setting.AddCollaborativeOwner)
|
||||
m.Post("/delete", repo_setting.DeleteCollaborativeOwner)
|
||||
})
|
||||
m.Post("/token_permissions", repo_setting.UpdateTokenPermissions)
|
||||
})
|
||||
}, actions.MustEnableActions)
|
||||
// the follow handler must be under "settings", otherwise this incomplete repo can't be accessed
|
||||
m.Group("/migrate", func() {
|
||||
@@ -1168,12 +1250,11 @@ func registerWebRoutes(m *web.Router) {
|
||||
// end "/{username}/{reponame}/settings"
|
||||
|
||||
// user/org home, including rss feeds like "/{username}/{reponame}.rss"
|
||||
m.Get("/{username}/{reponame}", optSignIn, context.RepoAssignment, context.RepoRefByType(git.RefTypeBranch), repo.SetEditorconfigIfExists, repo.Home)
|
||||
m.Get("/{username}/{reponame}", optSignIn, webAuth.AllowBasic, context.RepoAssignment, context.RepoRefByType(git.RefTypeBranch), repo.SetEditorconfigIfExists, repo.Home)
|
||||
|
||||
m.Post("/{username}/{reponame}/markup", optSignIn, context.RepoAssignment, reqUnitsWithMarkdown, web.Bind(structs.MarkupOption{}), misc.Markup)
|
||||
|
||||
m.Group("/{username}/{reponame}", func() {
|
||||
m.Get("/find/*", repo.FindFiles)
|
||||
m.Group("/tree-list", func() {
|
||||
m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.TreeList)
|
||||
m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.TreeList)
|
||||
@@ -1370,8 +1451,8 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Group("/{username}/{reponame}", func() { // repo tags
|
||||
m.Group("/tags", func() {
|
||||
m.Get("", context.RepoRefByDefaultBranch() /* for the "commits" tab */, repo.TagsList)
|
||||
m.Get(".rss", feedEnabled, repo.TagsListFeedRSS)
|
||||
m.Get(".atom", feedEnabled, repo.TagsListFeedAtom)
|
||||
m.Get(".rss", webAuth.AllowBasic, feedEnabled, repo.TagsListFeedRSS)
|
||||
m.Get(".atom", webAuth.AllowBasic, feedEnabled, repo.TagsListFeedAtom)
|
||||
m.Get("/list", repo.GetTagList)
|
||||
}, ctxDataSet("EnableFeed", setting.Other.EnableFeed))
|
||||
m.Post("/tags/delete", reqSignIn, reqRepoCodeWriter, context.RepoMustNotBeArchived(), repo.DeleteTag)
|
||||
@@ -1381,16 +1462,17 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Group("/{username}/{reponame}", func() { // repo releases
|
||||
m.Group("/releases", func() {
|
||||
m.Get("", repo.Releases)
|
||||
m.Get(".rss", feedEnabled, repo.ReleasesFeedRSS)
|
||||
m.Get(".atom", feedEnabled, repo.ReleasesFeedAtom)
|
||||
m.Get(".rss", webAuth.AllowBasic, feedEnabled, repo.ReleasesFeedRSS)
|
||||
m.Get(".atom", webAuth.AllowBasic, feedEnabled, repo.ReleasesFeedAtom)
|
||||
m.Get("/tag/*", repo.SingleRelease)
|
||||
m.Get("/latest", repo.LatestRelease)
|
||||
}, ctxDataSet("EnableFeed", setting.Other.EnableFeed))
|
||||
m.Get("/releases/attachments/{uuid}", repo.GetAttachment)
|
||||
m.Get("/releases/download/{vTag}/{fileName}", repo.RedirectDownload)
|
||||
m.Get("/releases/attachments/{uuid}", webAuth.AllowBasic, webAuth.AllowOAuth2, repo.GetAttachment)
|
||||
m.Get("/releases/download/{vTag}/{fileName}", webAuth.AllowBasic, webAuth.AllowOAuth2, repo.RedirectDownload)
|
||||
m.Group("/releases", func() {
|
||||
m.Get("/new", repo.NewRelease)
|
||||
m.Post("/new", web.Bind(forms.NewReleaseForm{}), repo.NewReleasePost)
|
||||
m.Post("/generate-notes", web.Bind(forms.GenerateReleaseNotesForm{}), repo.GenerateReleaseNotes)
|
||||
m.Post("/delete", repo.DeleteRelease)
|
||||
m.Post("/attachments", repo.UploadReleaseAttachment)
|
||||
m.Post("/attachments/remove", repo.DeleteAttachment)
|
||||
@@ -1403,7 +1485,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
// end "/{username}/{reponame}": repo releases
|
||||
|
||||
m.Group("/{username}/{reponame}", func() { // to maintain compatibility with old attachments
|
||||
m.Get("/attachments/{uuid}", repo.GetAttachment)
|
||||
m.Get("/attachments/{uuid}", webAuth.AllowBasic, webAuth.AllowOAuth2, repo.GetAttachment)
|
||||
}, optSignIn, context.RepoAssignment)
|
||||
// end "/{username}/{reponame}": compatibility with old attachments
|
||||
|
||||
@@ -1450,6 +1532,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Post("/enable", reqRepoAdmin, actions.EnableWorkflowFile)
|
||||
m.Post("/run", reqRepoActionsWriter, actions.Run)
|
||||
m.Get("/workflow-dispatch-inputs", reqRepoActionsWriter, actions.WorkflowDispatchInputs)
|
||||
m.Post("/approve-all-checks", reqRepoActionsWriter, actions.ApproveAllChecks)
|
||||
|
||||
m.Group("/runs/{run}", func() {
|
||||
m.Combo("").
|
||||
@@ -1469,9 +1552,10 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView)
|
||||
m.Delete("/artifacts/{artifact_name}", reqRepoActionsWriter, actions.ArtifactsDeleteView)
|
||||
m.Post("/rerun", reqRepoActionsWriter, actions.Rerun)
|
||||
m.Post("/rerun-failed", reqRepoActionsWriter, actions.RerunFailed)
|
||||
})
|
||||
m.Group("/workflows/{workflow_name}", func() {
|
||||
m.Get("/badge.svg", actions.GetWorkflowBadge)
|
||||
m.Get("/badge.svg", webAuth.AllowBasic, webAuth.AllowOAuth2, actions.GetWorkflowBadge)
|
||||
})
|
||||
}, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqRepoActionsReader, actions.MustEnableActions)
|
||||
// end "/{username}/{reponame}/actions"
|
||||
@@ -1521,7 +1605,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Group("/{username}/{reponame}", func() {
|
||||
m.Get("/{type:pulls}", repo.Issues)
|
||||
m.Group("/{type:pulls}/{index}", func() {
|
||||
m.Get("", repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue)
|
||||
m.Get("", repo.SetEditorconfigIfExists, repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue)
|
||||
m.Get(".diff", repo.DownloadPullDiff)
|
||||
m.Get(".patch", repo.DownloadPullPatch)
|
||||
m.Get("/merge_box", repo.ViewPullMergeBox)
|
||||
@@ -1557,7 +1641,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Group("/archive", func() {
|
||||
m.Get("/*", repo.Download)
|
||||
m.Post("/*", repo.InitiateDownload)
|
||||
}, repo.MustBeNotEmpty, dlSourceEnabled)
|
||||
}, webAuth.AllowBasic, webAuth.AllowOAuth2, repo.MustBeNotEmpty, dlSourceEnabled)
|
||||
|
||||
m.Group("/branches", func() {
|
||||
m.Get("/list", repo.GetBranchesList)
|
||||
@@ -1570,7 +1654,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.SingleDownloadOrLFS)
|
||||
m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.SingleDownloadOrLFS)
|
||||
m.Get("/*", context.RepoRefByType(""), repo.SingleDownloadOrLFS) // "/*" route is deprecated, and kept for backward compatibility
|
||||
}, repo.MustBeNotEmpty)
|
||||
}, webAuth.AllowBasic, webAuth.AllowOAuth2, repo.MustBeNotEmpty)
|
||||
|
||||
m.Group("/raw", func() {
|
||||
m.Get("/blob/{sha}", repo.DownloadByID)
|
||||
@@ -1578,7 +1662,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.SingleDownload)
|
||||
m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.SingleDownload)
|
||||
m.Get("/*", context.RepoRefByType(""), repo.SingleDownload) // "/*" route is deprecated, and kept for backward compatibility
|
||||
}, repo.MustBeNotEmpty)
|
||||
}, webAuth.AllowBasic, webAuth.AllowOAuth2, repo.MustBeNotEmpty)
|
||||
|
||||
m.Group("/render", func() {
|
||||
m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.RenderFile)
|
||||
@@ -1611,8 +1695,8 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Get("/cherry-pick/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, context.RepoRefByDefaultBranch(), repo.CherryPick)
|
||||
}, repo.MustBeNotEmpty)
|
||||
|
||||
m.Get("/rss/branch/*", context.RepoRefByType(git.RefTypeBranch), feedEnabled, feed.RenderBranchFeedRSS)
|
||||
m.Get("/atom/branch/*", context.RepoRefByType(git.RefTypeBranch), feedEnabled, feed.RenderBranchFeedAtom)
|
||||
m.Get("/rss/branch/*", context.RepoRefByType(git.RefTypeBranch), webAuth.AllowBasic, feedEnabled, feed.RenderBranchFeedRSS)
|
||||
m.Get("/atom/branch/*", context.RepoRefByType(git.RefTypeBranch), webAuth.AllowBasic, feedEnabled, feed.RenderBranchFeedAtom)
|
||||
|
||||
m.Group("/src", func() {
|
||||
m.Get("", func(ctx *context.Context) { ctx.Redirect(ctx.Repo.RepoLink) }) // there is no "{owner}/{repo}/src" page, so redirect to "{owner}/{repo}" to avoid 404
|
||||
@@ -1639,9 +1723,14 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Post("/action/{action:accept_transfer|reject_transfer}", reqSignIn, repo.ActionTransfer)
|
||||
}, optSignIn, context.RepoAssignment)
|
||||
|
||||
common.AddOwnerRepoGitLFSRoutes(m, optSignInIgnoreCsrf, lfsServerEnabled) // "/{username}/{reponame}/{lfs-paths}": git-lfs support
|
||||
// git lfs uses its own jwt key, and it handles the token & auth by itself, it conflicts with the general "OAuth2" auth method
|
||||
// pattern: "/{username}/{reponame}/{lfs-paths}": git-lfs support, see also addOwnerRepoGitHTTPRouters
|
||||
common.AddOwnerRepoGitLFSRoutes(m, lfsServerEnabled, webAuth.AllowBasic, repo.CorsHandler(), optSignInFromAnyOrigin)
|
||||
|
||||
addOwnerRepoGitHTTPRouters(m) // "/{username}/{reponame}/{git-paths}": git http support
|
||||
// Some users want to use "web-based git client" to access Gitea's repositories,
|
||||
// so the CORS handler and OPTIONS method are used.
|
||||
// pattern: "/{username}/{reponame}/{git-paths}": git http support
|
||||
addOwnerRepoGitHTTPRouters(m, repo.HTTPGitEnabledHandler, webAuth.AllowBasic, webAuth.AllowOAuth2, repo.CorsHandler(), optSignInFromAnyOrigin, context.UserAssignmentWeb())
|
||||
|
||||
m.Group("/notifications", func() {
|
||||
m.Get("", user.Notifications)
|
||||
@@ -1656,15 +1745,17 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Get("/swagger.v1.json", SwaggerV1Json)
|
||||
}
|
||||
|
||||
if !setting.IsProd {
|
||||
if !setting.IsProd || setting.IsInE2eTesting() {
|
||||
m.Group("/devtest", func() {
|
||||
m.Any("", devtest.List)
|
||||
m.Any("/fetch-action-test", devtest.FetchActionTest)
|
||||
m.Any("/mail-preview", devtest.MailPreview)
|
||||
m.Any("/mail-preview/*", devtest.MailPreviewRender)
|
||||
m.Any("/{sub}", devtest.TmplCommon)
|
||||
m.Get("/repo-action-view/{run}/{job}", devtest.MockActionsView)
|
||||
m.Post("/actions-mock/runs/{run}/jobs/{job}", web.Bind(actions.ViewRequest{}), devtest.MockActionsRunsJobs)
|
||||
m.Get("/repo-action-view/runs/{run}", devtest.MockActionsView)
|
||||
m.Get("/repo-action-view/runs/{run}/jobs/{job}", devtest.MockActionsView)
|
||||
m.Post("/repo-action-view/runs/{run}", web.Bind(actions.ViewRequest{}), devtest.MockActionsRunsJobs)
|
||||
m.Post("/repo-action-view/runs/{run}/jobs/{job}", web.Bind(actions.ViewRequest{}), devtest.MockActionsRunsJobs)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user