mirror of
https://github.com/go-gitea/gitea.git
synced 2025-04-08 17:05:45 +02:00
Backport #34024 since there are too many AI crawlers. The new code is covered by tests and it does nothing if users don't set it.
This commit is contained in:
parent
5a9b3bfa50
commit
15e93a751c
@ -774,6 +774,9 @@ LEVEL = Info
|
|||||||
;ALLOW_ONLY_EXTERNAL_REGISTRATION = false
|
;ALLOW_ONLY_EXTERNAL_REGISTRATION = false
|
||||||
;;
|
;;
|
||||||
;; User must sign in to view anything.
|
;; User must sign in to view anything.
|
||||||
|
;; After 1.23.7, it could be set to "expensive" to block anonymous users accessing some pages which consume a lot of resources,
|
||||||
|
;; for example: block anonymous AI crawlers from accessing repo code pages.
|
||||||
|
;; The "expensive" mode is experimental and subject to change.
|
||||||
;REQUIRE_SIGNIN_VIEW = false
|
;REQUIRE_SIGNIN_VIEW = false
|
||||||
;;
|
;;
|
||||||
;; Mail notification
|
;; Mail notification
|
||||||
|
@ -26,6 +26,7 @@ type ConfigKey interface {
|
|||||||
In(defaultVal string, candidates []string) string
|
In(defaultVal string, candidates []string) string
|
||||||
String() string
|
String() string
|
||||||
Strings(delim string) []string
|
Strings(delim string) []string
|
||||||
|
Bool() (bool, error)
|
||||||
|
|
||||||
MustString(defaultVal string) string
|
MustString(defaultVal string) string
|
||||||
MustBool(defaultVal ...bool) bool
|
MustBool(defaultVal ...bool) bool
|
||||||
|
@ -43,7 +43,8 @@ var Service = struct {
|
|||||||
ShowRegistrationButton bool
|
ShowRegistrationButton bool
|
||||||
EnablePasswordSignInForm bool
|
EnablePasswordSignInForm bool
|
||||||
ShowMilestonesDashboardPage bool
|
ShowMilestonesDashboardPage bool
|
||||||
RequireSignInView bool
|
RequireSignInViewStrict bool
|
||||||
|
BlockAnonymousAccessExpensive bool
|
||||||
EnableNotifyMail bool
|
EnableNotifyMail bool
|
||||||
EnableBasicAuth bool
|
EnableBasicAuth bool
|
||||||
EnablePasskeyAuth bool
|
EnablePasskeyAuth bool
|
||||||
@ -159,7 +160,18 @@ func loadServiceFrom(rootCfg ConfigProvider) {
|
|||||||
Service.EmailDomainBlockList = CompileEmailGlobList(sec, "EMAIL_DOMAIN_BLOCKLIST")
|
Service.EmailDomainBlockList = CompileEmailGlobList(sec, "EMAIL_DOMAIN_BLOCKLIST")
|
||||||
Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration))
|
Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration))
|
||||||
Service.ShowMilestonesDashboardPage = sec.Key("SHOW_MILESTONES_DASHBOARD_PAGE").MustBool(true)
|
Service.ShowMilestonesDashboardPage = sec.Key("SHOW_MILESTONES_DASHBOARD_PAGE").MustBool(true)
|
||||||
Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
|
|
||||||
|
// boolean values are considered as "strict"
|
||||||
|
var err error
|
||||||
|
Service.RequireSignInViewStrict, err = sec.Key("REQUIRE_SIGNIN_VIEW").Bool()
|
||||||
|
if s := sec.Key("REQUIRE_SIGNIN_VIEW").String(); err != nil && s != "" {
|
||||||
|
// non-boolean value only supports "expensive" at the moment
|
||||||
|
Service.BlockAnonymousAccessExpensive = s == "expensive"
|
||||||
|
if !Service.BlockAnonymousAccessExpensive {
|
||||||
|
log.Error("Invalid config option: REQUIRE_SIGNIN_VIEW = %s", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Service.EnableBasicAuth = sec.Key("ENABLE_BASIC_AUTHENTICATION").MustBool(true)
|
Service.EnableBasicAuth = sec.Key("ENABLE_BASIC_AUTHENTICATION").MustBool(true)
|
||||||
Service.EnablePasswordSignInForm = sec.Key("ENABLE_PASSWORD_SIGNIN_FORM").MustBool(true)
|
Service.EnablePasswordSignInForm = sec.Key("ENABLE_PASSWORD_SIGNIN_FORM").MustBool(true)
|
||||||
Service.EnablePasskeyAuth = sec.Key("ENABLE_PASSKEY_AUTHENTICATION").MustBool(true)
|
Service.EnablePasskeyAuth = sec.Key("ENABLE_PASSKEY_AUTHENTICATION").MustBool(true)
|
||||||
|
@ -7,16 +7,14 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
"github.com/gobwas/glob"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLoadServices(t *testing.T) {
|
func TestLoadServices(t *testing.T) {
|
||||||
oldService := Service
|
defer test.MockVariableValue(&Service)()
|
||||||
defer func() {
|
|
||||||
Service = oldService
|
|
||||||
}()
|
|
||||||
|
|
||||||
cfg, err := NewConfigProviderFromData(`
|
cfg, err := NewConfigProviderFromData(`
|
||||||
[service]
|
[service]
|
||||||
@ -48,10 +46,7 @@ EMAIL_DOMAIN_BLOCKLIST = d3, *.b
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadServiceVisibilityModes(t *testing.T) {
|
func TestLoadServiceVisibilityModes(t *testing.T) {
|
||||||
oldService := Service
|
defer test.MockVariableValue(&Service)()
|
||||||
defer func() {
|
|
||||||
Service = oldService
|
|
||||||
}()
|
|
||||||
|
|
||||||
kases := map[string]func(){
|
kases := map[string]func(){
|
||||||
`
|
`
|
||||||
@ -130,3 +125,33 @@ ALLOWED_USER_VISIBILITY_MODES = public, limit, privated
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadServiceRequireSignInView(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&Service)()
|
||||||
|
|
||||||
|
cfg, err := NewConfigProviderFromData(`
|
||||||
|
[service]
|
||||||
|
`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
loadServiceFrom(cfg)
|
||||||
|
assert.False(t, Service.RequireSignInViewStrict)
|
||||||
|
assert.False(t, Service.BlockAnonymousAccessExpensive)
|
||||||
|
|
||||||
|
cfg, err = NewConfigProviderFromData(`
|
||||||
|
[service]
|
||||||
|
REQUIRE_SIGNIN_VIEW = true
|
||||||
|
`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
loadServiceFrom(cfg)
|
||||||
|
assert.True(t, Service.RequireSignInViewStrict)
|
||||||
|
assert.False(t, Service.BlockAnonymousAccessExpensive)
|
||||||
|
|
||||||
|
cfg, err = NewConfigProviderFromData(`
|
||||||
|
[service]
|
||||||
|
REQUIRE_SIGNIN_VIEW = expensive
|
||||||
|
`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
loadServiceFrom(cfg)
|
||||||
|
assert.False(t, Service.RequireSignInViewStrict)
|
||||||
|
assert.True(t, Service.BlockAnonymousAccessExpensive)
|
||||||
|
}
|
||||||
|
@ -51,7 +51,7 @@ func apiError(ctx *context.Context, status int, obj any) {
|
|||||||
|
|
||||||
// https://rust-lang.github.io/rfcs/2789-sparse-index.html
|
// https://rust-lang.github.io/rfcs/2789-sparse-index.html
|
||||||
func RepositoryConfig(ctx *context.Context) {
|
func RepositoryConfig(ctx *context.Context) {
|
||||||
ctx.JSON(http.StatusOK, cargo_service.BuildConfig(ctx.Package.Owner, setting.Service.RequireSignInView || ctx.Package.Owner.Visibility != structs.VisibleTypePublic))
|
ctx.JSON(http.StatusOK, cargo_service.BuildConfig(ctx.Package.Owner, setting.Service.RequireSignInViewStrict || ctx.Package.Owner.Visibility != structs.VisibleTypePublic))
|
||||||
}
|
}
|
||||||
|
|
||||||
func EnumeratePackageVersions(ctx *context.Context) {
|
func EnumeratePackageVersions(ctx *context.Context) {
|
||||||
|
@ -126,7 +126,7 @@ func apiUnauthorizedError(ctx *context.Context) {
|
|||||||
|
|
||||||
// ReqContainerAccess is a middleware which checks the current user valid (real user or ghost if anonymous access is enabled)
|
// ReqContainerAccess is a middleware which checks the current user valid (real user or ghost if anonymous access is enabled)
|
||||||
func ReqContainerAccess(ctx *context.Context) {
|
func ReqContainerAccess(ctx *context.Context) {
|
||||||
if ctx.Doer == nil || (setting.Service.RequireSignInView && ctx.Doer.IsGhost()) {
|
if ctx.Doer == nil || (setting.Service.RequireSignInViewStrict && ctx.Doer.IsGhost()) {
|
||||||
apiUnauthorizedError(ctx)
|
apiUnauthorizedError(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,7 +152,7 @@ func Authenticate(ctx *context.Context) {
|
|||||||
u := ctx.Doer
|
u := ctx.Doer
|
||||||
packageScope := auth_service.GetAccessScope(ctx.Data)
|
packageScope := auth_service.GetAccessScope(ctx.Data)
|
||||||
if u == nil {
|
if u == nil {
|
||||||
if setting.Service.RequireSignInView {
|
if setting.Service.RequireSignInViewStrict {
|
||||||
apiUnauthorizedError(ctx)
|
apiUnauthorizedError(ctx)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ func reqToken() func(ctx *context.APIContext) {
|
|||||||
|
|
||||||
func reqExploreSignIn() func(ctx *context.APIContext) {
|
func reqExploreSignIn() func(ctx *context.APIContext) {
|
||||||
return func(ctx *context.APIContext) {
|
return func(ctx *context.APIContext) {
|
||||||
if (setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView) && !ctx.IsSigned {
|
if (setting.Service.RequireSignInViewStrict || setting.Service.Explore.RequireSigninView) && !ctx.IsSigned {
|
||||||
ctx.Error(http.StatusUnauthorized, "reqExploreSignIn", "you must be signed in to search for users")
|
ctx.Error(http.StatusUnauthorized, "reqExploreSignIn", "you must be signed in to search for users")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -874,7 +874,7 @@ func Routes() *web.Router {
|
|||||||
m.Use(apiAuth(buildAuthGroup()))
|
m.Use(apiAuth(buildAuthGroup()))
|
||||||
|
|
||||||
m.Use(verifyAuthWithOptions(&common.VerifyOptions{
|
m.Use(verifyAuthWithOptions(&common.VerifyOptions{
|
||||||
SignInRequired: setting.Service.RequireSignInView,
|
SignInRequired: setting.Service.RequireSignInViewStrict,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
addActionsRoutes := func(
|
addActionsRoutes := func(
|
||||||
|
91
routers/common/blockexpensive.go
Normal file
91
routers/common/blockexpensive.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/web/middleware"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BlockExpensive() func(next http.Handler) http.Handler {
|
||||||
|
if !setting.Service.BlockAnonymousAccessExpensive {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return func(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
ret := determineRequestPriority(req.Context())
|
||||||
|
if !ret.SignedIn {
|
||||||
|
if ret.Expensive || ret.LongPolling {
|
||||||
|
http.Redirect(w, req, setting.AppSubURL+"/user/login", http.StatusSeeOther)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next.ServeHTTP(w, req)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isRoutePathExpensive(routePattern string) bool {
|
||||||
|
if strings.HasPrefix(routePattern, "/user/") || strings.HasPrefix(routePattern, "/login/") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
expensivePaths := []string{
|
||||||
|
// code related
|
||||||
|
"/{username}/{reponame}/archive/",
|
||||||
|
"/{username}/{reponame}/blame/",
|
||||||
|
"/{username}/{reponame}/commit/",
|
||||||
|
"/{username}/{reponame}/commits/",
|
||||||
|
"/{username}/{reponame}/graph",
|
||||||
|
"/{username}/{reponame}/media/",
|
||||||
|
"/{username}/{reponame}/raw/",
|
||||||
|
"/{username}/{reponame}/src/",
|
||||||
|
|
||||||
|
// issue & PR related (no trailing slash)
|
||||||
|
"/{username}/{reponame}/issues",
|
||||||
|
"/{username}/{reponame}/{type:issues}",
|
||||||
|
"/{username}/{reponame}/pulls",
|
||||||
|
"/{username}/{reponame}/{type:pulls}",
|
||||||
|
|
||||||
|
// wiki
|
||||||
|
"/{username}/{reponame}/wiki/",
|
||||||
|
|
||||||
|
// activity
|
||||||
|
"/{username}/{reponame}/activity/",
|
||||||
|
}
|
||||||
|
for _, path := range expensivePaths {
|
||||||
|
if strings.HasPrefix(routePattern, path) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isRoutePathForLongPolling(routePattern string) bool {
|
||||||
|
return routePattern == "/user/events"
|
||||||
|
}
|
||||||
|
|
||||||
|
func determineRequestPriority(ctx context.Context) (ret struct {
|
||||||
|
SignedIn bool
|
||||||
|
Expensive bool
|
||||||
|
LongPolling bool
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
dataStore := middleware.GetContextData(ctx)
|
||||||
|
chiRoutePath := chi.RouteContext(ctx).RoutePattern()
|
||||||
|
if _, ok := dataStore[middleware.ContextDataKeySignedUser].(*user_model.User); ok {
|
||||||
|
ret.SignedIn = true
|
||||||
|
} else {
|
||||||
|
ret.Expensive = isRoutePathExpensive(chiRoutePath)
|
||||||
|
ret.LongPolling = isRoutePathForLongPolling(chiRoutePath)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
30
routers/common/blockexpensive_test.go
Normal file
30
routers/common/blockexpensive_test.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBlockExpensive(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
expensive bool
|
||||||
|
routePath string
|
||||||
|
}{
|
||||||
|
{false, "/user/xxx"},
|
||||||
|
{false, "/login/xxx"},
|
||||||
|
{true, "/{username}/{reponame}/archive/xxx"},
|
||||||
|
{true, "/{username}/{reponame}/graph"},
|
||||||
|
{true, "/{username}/{reponame}/src/xxx"},
|
||||||
|
{true, "/{username}/{reponame}/wiki/xxx"},
|
||||||
|
{true, "/{username}/{reponame}/activity/xxx"},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
assert.Equal(t, c.expensive, isRoutePathExpensive(c.routePath), "routePath: %s", c.routePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.True(t, isRoutePathForLongPolling("/user/events"))
|
||||||
|
}
|
@ -156,7 +156,7 @@ func Install(ctx *context.Context) {
|
|||||||
form.DisableRegistration = setting.Service.DisableRegistration
|
form.DisableRegistration = setting.Service.DisableRegistration
|
||||||
form.AllowOnlyExternalRegistration = setting.Service.AllowOnlyExternalRegistration
|
form.AllowOnlyExternalRegistration = setting.Service.AllowOnlyExternalRegistration
|
||||||
form.EnableCaptcha = setting.Service.EnableCaptcha
|
form.EnableCaptcha = setting.Service.EnableCaptcha
|
||||||
form.RequireSignInView = setting.Service.RequireSignInView
|
form.RequireSignInView = setting.Service.RequireSignInViewStrict
|
||||||
form.DefaultKeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate
|
form.DefaultKeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate
|
||||||
form.DefaultAllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization
|
form.DefaultAllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization
|
||||||
form.DefaultEnableTimetracking = setting.Service.DefaultEnableTimetracking
|
form.DefaultEnableTimetracking = setting.Service.DefaultEnableTimetracking
|
||||||
|
@ -286,7 +286,7 @@ func ServCommand(ctx *context.PrivateContext) {
|
|||||||
repo.IsPrivate ||
|
repo.IsPrivate ||
|
||||||
owner.Visibility.IsPrivate() ||
|
owner.Visibility.IsPrivate() ||
|
||||||
(user != nil && user.IsRestricted) || // user will be nil if the key is a deploykey
|
(user != nil && user.IsRestricted) || // user will be nil if the key is a deploykey
|
||||||
setting.Service.RequireSignInView) {
|
setting.Service.RequireSignInViewStrict) {
|
||||||
if key.Type == asymkey_model.KeyTypeDeploy {
|
if key.Type == asymkey_model.KeyTypeDeploy {
|
||||||
if deployKey.Mode < mode {
|
if deployKey.Mode < mode {
|
||||||
ctx.JSON(http.StatusUnauthorized, private.Response{
|
ctx.JSON(http.StatusUnauthorized, private.Response{
|
||||||
|
@ -127,7 +127,7 @@ func httpBase(ctx *context.Context) *serviceHandler {
|
|||||||
// Only public pull don't need auth.
|
// Only public pull don't need auth.
|
||||||
isPublicPull := repoExist && !repo.IsPrivate && isPull
|
isPublicPull := repoExist && !repo.IsPrivate && isPull
|
||||||
var (
|
var (
|
||||||
askAuth = !isPublicPull || setting.Service.RequireSignInView
|
askAuth = !isPublicPull || setting.Service.RequireSignInViewStrict
|
||||||
environ []string
|
environ []string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -285,23 +285,23 @@ func Routes() *web.Router {
|
|||||||
mid = append(mid, repo.GetActiveStopwatch)
|
mid = append(mid, repo.GetActiveStopwatch)
|
||||||
mid = append(mid, goGet)
|
mid = append(mid, goGet)
|
||||||
|
|
||||||
others := web.NewRouter()
|
webRoutes := web.NewRouter()
|
||||||
others.Use(mid...)
|
webRoutes.Use(mid...)
|
||||||
registerRoutes(others)
|
webRoutes.Group("", func() { registerWebRoutes(webRoutes) }, common.BlockExpensive())
|
||||||
routes.Mount("", others)
|
routes.Mount("", webRoutes)
|
||||||
return routes
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
var optSignInIgnoreCsrf = verifyAuthWithOptions(&common.VerifyOptions{DisableCSRF: true})
|
var optSignInIgnoreCsrf = verifyAuthWithOptions(&common.VerifyOptions{DisableCSRF: true})
|
||||||
|
|
||||||
// registerRoutes register routes
|
// registerWebRoutes register routes
|
||||||
func registerRoutes(m *web.Router) {
|
func registerWebRoutes(m *web.Router) {
|
||||||
// required to be signed in or signed out
|
// required to be signed in or signed out
|
||||||
reqSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: true})
|
reqSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: true})
|
||||||
reqSignOut := verifyAuthWithOptions(&common.VerifyOptions{SignOutRequired: true})
|
reqSignOut := verifyAuthWithOptions(&common.VerifyOptions{SignOutRequired: true})
|
||||||
// optional sign in (if signed in, use the user as doer, if not, no doer)
|
// optional sign in (if signed in, use the user as doer, if not, no doer)
|
||||||
optSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: setting.Service.RequireSignInView})
|
optSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: setting.Service.RequireSignInViewStrict})
|
||||||
optExploreSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView})
|
optExploreSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: setting.Service.RequireSignInViewStrict || setting.Service.Explore.RequireSigninView})
|
||||||
|
|
||||||
validation.AddBindingRules()
|
validation.AddBindingRules()
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ func packageAssignment(ctx *packageAssignmentCtx, errCb func(int, string, any))
|
|||||||
}
|
}
|
||||||
|
|
||||||
func determineAccessMode(ctx *Base, pkg *Package, doer *user_model.User) (perm.AccessMode, error) {
|
func determineAccessMode(ctx *Base, pkg *Package, doer *user_model.User) (perm.AccessMode, error) {
|
||||||
if setting.Service.RequireSignInView && (doer == nil || doer.IsGhost()) {
|
if setting.Service.RequireSignInViewStrict && (doer == nil || doer.IsGhost()) {
|
||||||
return perm.AccessModeNone, nil
|
return perm.AccessModeNone, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ func createOrUpdateConfigFile(ctx context.Context, repo *repo_model.Repository,
|
|||||||
"Initialize Cargo Config",
|
"Initialize Cargo Config",
|
||||||
func(t *files_service.TemporaryUploadRepository) error {
|
func(t *files_service.TemporaryUploadRepository) error {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
err := json.NewEncoder(&b).Encode(BuildConfig(owner, setting.Service.RequireSignInView || owner.Visibility != structs.VisibleTypePublic || repo.IsPrivate))
|
err := json.NewEncoder(&b).Encode(BuildConfig(owner, setting.Service.RequireSignInViewStrict || owner.Visibility != structs.VisibleTypePublic || repo.IsPrivate))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,7 @@
|
|||||||
<dt>{{ctx.Locale.Tr "admin.config.enable_openid_signin"}}</dt>
|
<dt>{{ctx.Locale.Tr "admin.config.enable_openid_signin"}}</dt>
|
||||||
<dd>{{svg (Iif .Service.EnableOpenIDSignIn "octicon-check" "octicon-x")}}</dd>
|
<dd>{{svg (Iif .Service.EnableOpenIDSignIn "octicon-check" "octicon-x")}}</dd>
|
||||||
<dt>{{ctx.Locale.Tr "admin.config.require_sign_in_view"}}</dt>
|
<dt>{{ctx.Locale.Tr "admin.config.require_sign_in_view"}}</dt>
|
||||||
<dd>{{svg (Iif .Service.RequireSignInView "octicon-check" "octicon-x")}}</dd>
|
<dd>{{svg (Iif .Service.RequireSignInViewStrict "octicon-check" "octicon-x")}}</dd>
|
||||||
<dt>{{ctx.Locale.Tr "admin.config.mail_notify"}}</dt>
|
<dt>{{ctx.Locale.Tr "admin.config.mail_notify"}}</dt>
|
||||||
<dd>{{svg (Iif .Service.EnableNotifyMail "octicon-check" "octicon-x")}}</dd>
|
<dd>{{svg (Iif .Service.EnableNotifyMail "octicon-check" "octicon-x")}}</dd>
|
||||||
<dt>{{ctx.Locale.Tr "admin.config.enable_captcha"}}</dt>
|
<dt>{{ctx.Locale.Tr "admin.config.enable_captcha"}}</dt>
|
||||||
|
@ -148,9 +148,9 @@ func TestAPIOrgEditBadVisibility(t *testing.T) {
|
|||||||
|
|
||||||
func TestAPIOrgDeny(t *testing.T) {
|
func TestAPIOrgDeny(t *testing.T) {
|
||||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||||
setting.Service.RequireSignInView = true
|
setting.Service.RequireSignInViewStrict = true
|
||||||
defer func() {
|
defer func() {
|
||||||
setting.Service.RequireSignInView = false
|
setting.Service.RequireSignInViewStrict = false
|
||||||
}()
|
}()
|
||||||
|
|
||||||
orgName := "user1_org"
|
orgName := "user1_org"
|
||||||
|
@ -111,7 +111,7 @@ func TestPackageContainer(t *testing.T) {
|
|||||||
AddTokenAuth(anonymousToken)
|
AddTokenAuth(anonymousToken)
|
||||||
MakeRequest(t, req, http.StatusOK)
|
MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
defer test.MockVariableValue(&setting.Service.RequireSignInView, true)()
|
defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)()
|
||||||
|
|
||||||
req = NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
|
req = NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
|
||||||
MakeRequest(t, req, http.StatusUnauthorized)
|
MakeRequest(t, req, http.StatusUnauthorized)
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -131,11 +132,7 @@ func TestPackageGeneric(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("RequireSignInView", func(t *testing.T) {
|
t.Run("RequireSignInView", func(t *testing.T) {
|
||||||
defer tests.PrintCurrentTest(t)()
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)()
|
||||||
setting.Service.RequireSignInView = true
|
|
||||||
defer func() {
|
|
||||||
setting.Service.RequireSignInView = false
|
|
||||||
}()
|
|
||||||
|
|
||||||
req = NewRequest(t, "GET", url+"/dummy.bin")
|
req = NewRequest(t, "GET", url+"/dummy.bin")
|
||||||
MakeRequest(t, req, http.StatusUnauthorized)
|
MakeRequest(t, req, http.StatusUnauthorized)
|
||||||
|
@ -74,7 +74,7 @@ func testGitSmartHTTP(t *testing.T, u *url.URL) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testRenamedRepoRedirect(t *testing.T) {
|
func testRenamedRepoRedirect(t *testing.T) {
|
||||||
defer test.MockVariableValue(&setting.Service.RequireSignInView, true)()
|
defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)()
|
||||||
|
|
||||||
// git client requires to get a 301 redirect response before 401 unauthorized response
|
// git client requires to get a 301 redirect response before 401 unauthorized response
|
||||||
req := NewRequest(t, "GET", "/user2/oldrepo1/info/refs")
|
req := NewRequest(t, "GET", "/user2/oldrepo1/info/refs")
|
||||||
|
@ -15,11 +15,13 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/test"
|
"code.gitea.io/gitea/modules/test"
|
||||||
"code.gitea.io/gitea/modules/translation"
|
"code.gitea.io/gitea/modules/translation"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
|
"code.gitea.io/gitea/routers"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
"github.com/markbates/goth"
|
"github.com/markbates/goth"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testLoginFailed(t *testing.T, username, password, message string) {
|
func testLoginFailed(t *testing.T, username, password, message string) {
|
||||||
@ -158,3 +160,32 @@ func TestEnablePasswordSignInFormAndEnablePasskeyAuth(t *testing.T) {
|
|||||||
NewHTMLParser(t, resp.Body).AssertElement(t, ".signin-passkey", true)
|
NewHTMLParser(t, resp.Body).AssertElement(t, ".signin-passkey", true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRequireSignInView(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
t.Run("NoRequireSignInView", func(t *testing.T) {
|
||||||
|
require.False(t, setting.Service.RequireSignInViewStrict)
|
||||||
|
require.False(t, setting.Service.BlockAnonymousAccessExpensive)
|
||||||
|
req := NewRequest(t, "GET", "/user2/repo1/src/branch/master")
|
||||||
|
MakeRequest(t, req, http.StatusOK)
|
||||||
|
})
|
||||||
|
t.Run("RequireSignInView", func(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)()
|
||||||
|
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
|
||||||
|
req := NewRequest(t, "GET", "/user2/repo1/src/branch/master")
|
||||||
|
resp := MakeRequest(t, req, http.StatusSeeOther)
|
||||||
|
assert.Equal(t, "/user/login", resp.Header().Get("Location"))
|
||||||
|
})
|
||||||
|
t.Run("BlockAnonymousAccessExpensive", func(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, false)()
|
||||||
|
defer test.MockVariableValue(&setting.Service.BlockAnonymousAccessExpensive, true)()
|
||||||
|
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", "/user2/repo1")
|
||||||
|
MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
req = NewRequest(t, "GET", "/user2/repo1/src/branch/master")
|
||||||
|
resp := MakeRequest(t, req, http.StatusSeeOther)
|
||||||
|
assert.Equal(t, "/user/login", resp.Header().Get("Location"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user