1. The "web" package shouldn't depends on "modules/context" package, instead, let each "web context" register themselves to the "web" package. 2. The old Init/Free doesn't make sense, so simplify it * The ctx in "Init(ctx)" is never used, and shouldn't be used that way * The "Free" is never called and shouldn't be called because the SSPI instance is shared --------- Co-authored-by: Giteabot <teabot@gitea.io>tags/v1.21.0-rc0
@@ -191,7 +191,7 @@ func runWeb(ctx *cli.Context) error { | |||
} | |||
// Set up Chi routes | |||
c := routers.NormalRoutes(graceful.GetManager().HammerContext()) | |||
c := routers.NormalRoutes() | |||
err := listen(c, true) | |||
<-graceful.GetManager().Done() | |||
log.Info("PID: %d Gitea Web Finished", os.Getpid()) |
@@ -20,6 +20,8 @@ import ( | |||
"code.gitea.io/gitea/modules/httpcache" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/web" | |||
web_types "code.gitea.io/gitea/modules/web/types" | |||
"gitea.com/go-chi/cache" | |||
) | |||
@@ -41,6 +43,12 @@ type APIContext struct { | |||
Package *Package | |||
} | |||
func init() { | |||
web.RegisterResponseStatusProvider[*APIContext](func(req *http.Request) web_types.ResponseStatusProvider { | |||
return req.Context().Value(apiContextKey).(*APIContext) | |||
}) | |||
} | |||
// Currently, we have the following common fields in error response: | |||
// * message: the message for end users (it shouldn't be used for error type detection) | |||
// if we need to indicate some errors, we should introduce some new fields like ErrorCode or ErrorType |
@@ -96,7 +96,11 @@ func (b *Base) SetTotalCountHeader(total int64) { | |||
// Written returns true if there are something sent to web browser | |||
func (b *Base) Written() bool { | |||
return b.Resp.Status() > 0 | |||
return b.Resp.WrittenStatus() != 0 | |||
} | |||
func (b *Base) WrittenStatus() int { | |||
return b.Resp.WrittenStatus() | |||
} | |||
// Status writes status code |
@@ -21,7 +21,9 @@ import ( | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/templates" | |||
"code.gitea.io/gitea/modules/translation" | |||
"code.gitea.io/gitea/modules/web" | |||
"code.gitea.io/gitea/modules/web/middleware" | |||
web_types "code.gitea.io/gitea/modules/web/types" | |||
"gitea.com/go-chi/cache" | |||
"gitea.com/go-chi/session" | |||
@@ -58,6 +60,12 @@ type Context struct { | |||
Package *Package | |||
} | |||
func init() { | |||
web.RegisterResponseStatusProvider[*Context](func(req *http.Request) web_types.ResponseStatusProvider { | |||
return req.Context().Value(WebContextKey).(*Context) | |||
}) | |||
} | |||
// TrHTMLEscapeArgs runs ".Locale.Tr()" but pre-escapes all arguments with html.EscapeString. | |||
// This is useful if the locale message is intended to only produce HTML content. | |||
func (ctx *Context) TrHTMLEscapeArgs(msg string, args ...string) string { |
@@ -11,6 +11,8 @@ import ( | |||
"code.gitea.io/gitea/modules/graceful" | |||
"code.gitea.io/gitea/modules/process" | |||
"code.gitea.io/gitea/modules/web" | |||
web_types "code.gitea.io/gitea/modules/web/types" | |||
) | |||
// PrivateContext represents a context for private routes | |||
@@ -21,6 +23,12 @@ type PrivateContext struct { | |||
Repo *Repository | |||
} | |||
func init() { | |||
web.RegisterResponseStatusProvider[*PrivateContext](func(req *http.Request) web_types.ResponseStatusProvider { | |||
return req.Context().Value(privateContextKey).(*PrivateContext) | |||
}) | |||
} | |||
// Deadline is part of the interface for context.Context and we pass this to the request context | |||
func (ctx *PrivateContext) Deadline() (deadline time.Time, ok bool) { | |||
if ctx.Override != nil { |
@@ -5,15 +5,20 @@ package context | |||
import ( | |||
"net/http" | |||
web_types "code.gitea.io/gitea/modules/web/types" | |||
) | |||
// ResponseWriter represents a response writer for HTTP | |||
type ResponseWriter interface { | |||
http.ResponseWriter | |||
http.Flusher | |||
Status() int | |||
web_types.ResponseStatusProvider | |||
Before(func(ResponseWriter)) | |||
Size() int // used by access logger template | |||
Status() int // used by access logger template | |||
Size() int // used by access logger template | |||
} | |||
var _ ResponseWriter = &Response{} | |||
@@ -46,6 +51,10 @@ func (r *Response) Write(bs []byte) (int, error) { | |||
return size, nil | |||
} | |||
func (r *Response) Status() int { | |||
return r.status | |||
} | |||
func (r *Response) Size() int { | |||
return r.written | |||
} | |||
@@ -71,8 +80,8 @@ func (r *Response) Flush() { | |||
} | |||
} | |||
// Status returned status code written | |||
func (r *Response) Status() int { | |||
// WrittenStatus returned status code written | |||
func (r *Response) WrittenStatus() int { | |||
return r.status | |||
} | |||
@@ -9,6 +9,7 @@ import ( | |||
"net/http" | |||
"net/http/httptest" | |||
"net/url" | |||
"strings" | |||
"testing" | |||
access_model "code.gitea.io/gitea/models/perm/access" | |||
@@ -25,19 +26,26 @@ import ( | |||
"github.com/stretchr/testify/assert" | |||
) | |||
// MockContext mock context for unit tests | |||
// TODO: move this function to other packages, because it depends on "models" package | |||
func MockContext(t *testing.T, path string) *context.Context { | |||
resp := httptest.NewRecorder() | |||
func mockRequest(t *testing.T, reqPath string) *http.Request { | |||
method, path, found := strings.Cut(reqPath, " ") | |||
if !found { | |||
method = "GET" | |||
path = reqPath | |||
} | |||
requestURL, err := url.Parse(path) | |||
assert.NoError(t, err) | |||
req := &http.Request{ | |||
URL: requestURL, | |||
Form: url.Values{}, | |||
} | |||
req := &http.Request{Method: method, URL: requestURL, Form: url.Values{}} | |||
req = req.WithContext(middleware.WithContextData(req.Context())) | |||
return req | |||
} | |||
// MockContext mock context for unit tests | |||
// TODO: move this function to other packages, because it depends on "models" package | |||
func MockContext(t *testing.T, reqPath string) (*context.Context, *httptest.ResponseRecorder) { | |||
resp := httptest.NewRecorder() | |||
req := mockRequest(t, reqPath) | |||
base, baseCleanUp := context.NewBaseContext(resp, req) | |||
base.Data = middleware.ContextData{} | |||
base.Data = middleware.GetContextData(req.Context()) | |||
base.Locale = &translation.MockLocale{} | |||
ctx := &context.Context{ | |||
Base: base, | |||
@@ -48,29 +56,23 @@ func MockContext(t *testing.T, path string) *context.Context { | |||
chiCtx := chi.NewRouteContext() | |||
ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) | |||
return ctx | |||
return ctx, resp | |||
} | |||
// MockAPIContext mock context for unit tests | |||
// TODO: move this function to other packages, because it depends on "models" package | |||
func MockAPIContext(t *testing.T, path string) *context.APIContext { | |||
func MockAPIContext(t *testing.T, reqPath string) (*context.APIContext, *httptest.ResponseRecorder) { | |||
resp := httptest.NewRecorder() | |||
requestURL, err := url.Parse(path) | |||
assert.NoError(t, err) | |||
req := &http.Request{ | |||
URL: requestURL, | |||
Form: url.Values{}, | |||
} | |||
req := mockRequest(t, reqPath) | |||
base, baseCleanUp := context.NewBaseContext(resp, req) | |||
base.Data = middleware.ContextData{} | |||
base.Data = middleware.GetContextData(req.Context()) | |||
base.Locale = &translation.MockLocale{} | |||
ctx := &context.APIContext{Base: base} | |||
_ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later | |||
chiCtx := chi.NewRouteContext() | |||
ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) | |||
return ctx | |||
return ctx, resp | |||
} | |||
// LoadRepo load a repo into a test context. |
@@ -9,25 +9,15 @@ import ( | |||
"net/http" | |||
"reflect" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/web/routing" | |||
"code.gitea.io/gitea/modules/web/types" | |||
) | |||
// ResponseStatusProvider is an interface to check whether the response has been written by the handler | |||
type ResponseStatusProvider interface { | |||
Written() bool | |||
} | |||
// TODO: decouple this from the context package, let the context package register these providers | |||
var argTypeProvider = map[reflect.Type]func(req *http.Request) ResponseStatusProvider{ | |||
reflect.TypeOf(&context.APIContext{}): func(req *http.Request) ResponseStatusProvider { return context.GetAPIContext(req) }, | |||
reflect.TypeOf(&context.Context{}): func(req *http.Request) ResponseStatusProvider { return context.GetWebContext(req) }, | |||
reflect.TypeOf(&context.PrivateContext{}): func(req *http.Request) ResponseStatusProvider { return context.GetPrivateContext(req) }, | |||
} | |||
var responseStatusProviders = map[reflect.Type]func(req *http.Request) types.ResponseStatusProvider{} | |||
func RegisterHandleTypeProvider[T any](fn func(req *http.Request) ResponseStatusProvider) { | |||
argTypeProvider[reflect.TypeOf((*T)(nil)).Elem()] = fn | |||
func RegisterResponseStatusProvider[T any](fn func(req *http.Request) types.ResponseStatusProvider) { | |||
responseStatusProviders[reflect.TypeOf((*T)(nil)).Elem()] = fn | |||
} | |||
// responseWriter is a wrapper of http.ResponseWriter, to check whether the response has been written | |||
@@ -36,10 +26,10 @@ type responseWriter struct { | |||
status int | |||
} | |||
var _ ResponseStatusProvider = (*responseWriter)(nil) | |||
var _ types.ResponseStatusProvider = (*responseWriter)(nil) | |||
func (r *responseWriter) Written() bool { | |||
return r.status > 0 | |||
func (r *responseWriter) WrittenStatus() int { | |||
return r.status | |||
} | |||
func (r *responseWriter) Header() http.Header { | |||
@@ -68,7 +58,7 @@ var ( | |||
func preCheckHandler(fn reflect.Value, argsIn []reflect.Value) { | |||
hasStatusProvider := false | |||
for _, argIn := range argsIn { | |||
if _, hasStatusProvider = argIn.Interface().(ResponseStatusProvider); hasStatusProvider { | |||
if _, hasStatusProvider = argIn.Interface().(types.ResponseStatusProvider); hasStatusProvider { | |||
break | |||
} | |||
} | |||
@@ -101,7 +91,7 @@ func prepareHandleArgsIn(resp http.ResponseWriter, req *http.Request, fn reflect | |||
case httpReqType: | |||
argsIn[i] = reflect.ValueOf(req) | |||
default: | |||
if argFn, ok := argTypeProvider[argTyp]; ok { | |||
if argFn, ok := responseStatusProviders[argTyp]; ok { | |||
if isPreCheck { | |||
argsIn[i] = reflect.ValueOf(&responseWriter{}) | |||
} else { | |||
@@ -129,8 +119,8 @@ func handleResponse(fn reflect.Value, ret []reflect.Value) goctx.CancelFunc { | |||
func hasResponseBeenWritten(argsIn []reflect.Value) bool { | |||
for _, argIn := range argsIn { | |||
if statusProvider, ok := argIn.Interface().(ResponseStatusProvider); ok { | |||
if statusProvider.Written() { | |||
if statusProvider, ok := argIn.Interface().(types.ResponseStatusProvider); ok { | |||
if statusProvider.WrittenStatus() != 0 { | |||
return true | |||
} | |||
} | |||
@@ -161,7 +151,7 @@ func toHandlerProvider(handler any) func(next http.Handler) http.Handler { | |||
return http.HandlerFunc(func(respOrig http.ResponseWriter, req *http.Request) { | |||
// wrap the response writer to check whether the response has been written | |||
resp := respOrig | |||
if _, ok := resp.(ResponseStatusProvider); !ok { | |||
if _, ok := resp.(types.ResponseStatusProvider); !ok { | |||
resp = &responseWriter{respWriter: resp} | |||
} | |||
@@ -17,7 +17,7 @@ type ContextDataStore interface { | |||
type ContextData map[string]any | |||
func (ds ContextData) GetData() map[string]any { | |||
func (ds ContextData) GetData() ContextData { | |||
return ds | |||
} | |||
@@ -7,31 +7,31 @@ import ( | |||
"net/http" | |||
"strings" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/web/middleware" | |||
"gitea.com/go-chi/binding" | |||
chi "github.com/go-chi/chi/v5" | |||
"github.com/go-chi/chi/v5" | |||
) | |||
// Bind binding an obj to a handler | |||
func Bind[T any](_ T) any { | |||
return func(ctx *context.Context) { | |||
// Bind binding an obj to a handler's context data | |||
func Bind[T any](_ T) http.HandlerFunc { | |||
return func(resp http.ResponseWriter, req *http.Request) { | |||
theObj := new(T) // create a new form obj for every request but not use obj directly | |||
binding.Bind(ctx.Req, theObj) | |||
SetForm(ctx, theObj) | |||
middleware.AssignForm(theObj, ctx.Data) | |||
data := middleware.GetContextData(req.Context()) | |||
binding.Bind(req, theObj) | |||
SetForm(data, theObj) | |||
middleware.AssignForm(theObj, data) | |||
} | |||
} | |||
// SetForm set the form object | |||
func SetForm(data middleware.ContextDataStore, obj interface{}) { | |||
data.GetData()["__form"] = obj | |||
func SetForm(dataStore middleware.ContextDataStore, obj interface{}) { | |||
dataStore.GetData()["__form"] = obj | |||
} | |||
// GetForm returns the validate form information | |||
func GetForm(data middleware.ContextDataStore) interface{} { | |||
return data.GetData()["__form"] | |||
func GetForm(dataStore middleware.ContextDataStore) interface{} { | |||
return dataStore.GetData()["__form"] | |||
} | |||
// Route defines a route based on chi's router |
@@ -8,8 +8,8 @@ import ( | |||
"strings" | |||
"time" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/web/types" | |||
) | |||
// NewLoggerHandler is a handler that will log routing to the router log taking account of | |||
@@ -86,8 +86,8 @@ func logPrinter(logger log.Logger) func(trigger Event, record *requestRecord) { | |||
} | |||
var status int | |||
if v, ok := record.responseWriter.(context.ResponseWriter); ok { | |||
status = v.Status() | |||
if v, ok := record.responseWriter.(types.ResponseStatusProvider); ok { | |||
status = v.WrittenStatus() | |||
} | |||
logf := log.Info | |||
if strings.HasPrefix(req.RequestURI, "/assets/") { |
@@ -0,0 +1,10 @@ | |||
// Copyright 2023 The Gitea Authors. All rights reserved. | |||
// SPDX-License-Identifier: MIT | |||
package types | |||
// ResponseStatusProvider is an interface to get the written status in the response | |||
// Many packages need this interface, so put it in the separate package to avoid import cycle | |||
type ResponseStatusProvider interface { | |||
WrittenStatus() int | |||
} |
@@ -4,7 +4,6 @@ | |||
package actions | |||
import ( | |||
"context" | |||
"net/http" | |||
"code.gitea.io/gitea/modules/web" | |||
@@ -12,7 +11,7 @@ import ( | |||
"code.gitea.io/gitea/routers/api/actions/runner" | |||
) | |||
func Routes(_ context.Context, prefix string) *web.Route { | |||
func Routes(prefix string) *web.Route { | |||
m := web.NewRoute() | |||
path, handler := ping.NewPingServiceHandler() |
@@ -82,6 +82,7 @@ import ( | |||
"code.gitea.io/gitea/modules/storage" | |||
"code.gitea.io/gitea/modules/util" | |||
"code.gitea.io/gitea/modules/web" | |||
web_types "code.gitea.io/gitea/modules/web/types" | |||
) | |||
const ( | |||
@@ -102,7 +103,7 @@ type ArtifactContext struct { | |||
} | |||
func init() { | |||
web.RegisterHandleTypeProvider[*ArtifactContext](func(req *http.Request) web.ResponseStatusProvider { | |||
web.RegisterResponseStatusProvider[*ArtifactContext](func(req *http.Request) web_types.ResponseStatusProvider { | |||
return req.Context().Value(artifactContextKey).(*ArtifactContext) | |||
}) | |||
} |
@@ -4,7 +4,6 @@ | |||
package packages | |||
import ( | |||
gocontext "context" | |||
"net/http" | |||
"regexp" | |||
"strings" | |||
@@ -96,7 +95,7 @@ func verifyAuth(r *web.Route, authMethods []auth.Method) { | |||
// CommonRoutes provide endpoints for most package managers (except containers - see below) | |||
// These are mounted on `/api/packages` (not `/api/v1/packages`) | |||
func CommonRoutes(ctx gocontext.Context) *web.Route { | |||
func CommonRoutes() *web.Route { | |||
r := web.NewRoute() | |||
r.Use(context.PackageContexter()) | |||
@@ -590,7 +589,7 @@ func CommonRoutes(ctx gocontext.Context) *web.Route { | |||
// ContainerRoutes provides endpoints that implement the OCI API to serve containers | |||
// These have to be mounted on `/v2/...` to comply with the OCI spec: | |||
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md | |||
func ContainerRoutes(ctx gocontext.Context) *web.Route { | |||
func ContainerRoutes() *web.Route { | |||
r := web.NewRoute() | |||
r.Use(context.PackageContexter()) |
@@ -64,7 +64,6 @@ | |||
package v1 | |||
import ( | |||
gocontext "context" | |||
"fmt" | |||
"net/http" | |||
"strings" | |||
@@ -705,7 +704,7 @@ func buildAuthGroup() *auth.Group { | |||
} | |||
// Routes registers all v1 APIs routes to web application. | |||
func Routes(ctx gocontext.Context) *web.Route { | |||
func Routes() *web.Route { | |||
m := web.NewRoute() | |||
m.Use(securityHeaders()) | |||
@@ -722,13 +721,8 @@ func Routes(ctx gocontext.Context) *web.Route { | |||
} | |||
m.Use(context.APIContexter()) | |||
group := buildAuthGroup() | |||
if err := group.Init(ctx); err != nil { | |||
log.Error("Could not initialize '%s' auth method, error: %s", group.Name(), err) | |||
} | |||
// Get user from session if logged in. | |||
m.Use(auth.APIAuth(group)) | |||
m.Use(auth.APIAuth(buildAuthGroup())) | |||
m.Use(auth.VerifyAuthWithOptionsAPI(&auth.VerifyOptions{ | |||
SignInRequired: setting.Service.RequireSignInView, |
@@ -7,18 +7,14 @@ import ( | |||
go_context "context" | |||
"io" | |||
"net/http" | |||
"net/http/httptest" | |||
"net/url" | |||
"strings" | |||
"testing" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/markup" | |||
"code.gitea.io/gitea/modules/setting" | |||
api "code.gitea.io/gitea/modules/structs" | |||
"code.gitea.io/gitea/modules/util" | |||
"code.gitea.io/gitea/modules/test" | |||
"code.gitea.io/gitea/modules/web" | |||
"code.gitea.io/gitea/modules/web/middleware" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
@@ -29,34 +25,16 @@ const ( | |||
AppSubURL = AppURL + Repo + "/" | |||
) | |||
func createAPIContext(req *http.Request) (*context.APIContext, *httptest.ResponseRecorder) { | |||
resp := httptest.NewRecorder() | |||
base, baseCleanUp := context.NewBaseContext(resp, req) | |||
base.Data = middleware.ContextData{} | |||
c := &context.APIContext{Base: base} | |||
_ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later | |||
return c, resp | |||
} | |||
func testRenderMarkup(t *testing.T, mode, filePath, text, responseBody string, responseCode int) { | |||
setting.AppURL = AppURL | |||
options := api.MarkupOption{ | |||
Mode: mode, | |||
Text: "", | |||
Text: text, | |||
Context: Repo, | |||
Wiki: true, | |||
FilePath: filePath, | |||
} | |||
requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markup")) | |||
req := &http.Request{ | |||
Method: "POST", | |||
URL: requrl, | |||
} | |||
ctx, resp := createAPIContext(req) | |||
options.Text = text | |||
ctx, resp := test.MockAPIContext(t, "POST /api/v1/markup") | |||
web.SetForm(ctx, &options) | |||
Markup(ctx) | |||
assert.Equal(t, responseBody, resp.Body.String()) | |||
@@ -66,21 +44,13 @@ func testRenderMarkup(t *testing.T, mode, filePath, text, responseBody string, r | |||
func testRenderMarkdown(t *testing.T, mode, text, responseBody string, responseCode int) { | |||
setting.AppURL = AppURL | |||
options := api.MarkdownOption{ | |||
Mode: mode, | |||
Text: "", | |||
Text: text, | |||
Context: Repo, | |||
Wiki: true, | |||
} | |||
requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) | |||
req := &http.Request{ | |||
Method: "POST", | |||
URL: requrl, | |||
} | |||
ctx, resp := createAPIContext(req) | |||
options.Text = text | |||
ctx, resp := test.MockAPIContext(t, "POST /api/v1/markdown") | |||
web.SetForm(ctx, &options) | |||
Markdown(ctx) | |||
assert.Equal(t, responseBody, resp.Body.String()) | |||
@@ -187,19 +157,12 @@ var simpleCases = []string{ | |||
func TestAPI_RenderSimple(t *testing.T) { | |||
setting.AppURL = AppURL | |||
options := api.MarkdownOption{ | |||
Mode: "markdown", | |||
Text: "", | |||
Context: Repo, | |||
} | |||
requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) | |||
req := &http.Request{ | |||
Method: "POST", | |||
URL: requrl, | |||
} | |||
ctx, resp := createAPIContext(req) | |||
ctx, resp := test.MockAPIContext(t, "POST /api/v1/markdown") | |||
for i := 0; i < len(simpleCases); i += 2 { | |||
options.Text = simpleCases[i] | |||
web.SetForm(ctx, &options) | |||
@@ -211,14 +174,7 @@ func TestAPI_RenderSimple(t *testing.T) { | |||
func TestAPI_RenderRaw(t *testing.T) { | |||
setting.AppURL = AppURL | |||
requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) | |||
req := &http.Request{ | |||
Method: "POST", | |||
URL: requrl, | |||
} | |||
ctx, resp := createAPIContext(req) | |||
ctx, resp := test.MockAPIContext(t, "POST /api/v1/markdown") | |||
for i := 0; i < len(simpleCases); i += 2 { | |||
ctx.Req.Body = io.NopCloser(strings.NewReader(simpleCases[i])) | |||
MarkdownRaw(ctx) |
@@ -17,7 +17,7 @@ import ( | |||
func TestTestHook(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockAPIContext(t, "user2/repo1/wiki/_pages") | |||
ctx, _ := test.MockAPIContext(t, "user2/repo1/wiki/_pages") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) |
@@ -19,7 +19,7 @@ import ( | |||
func TestRepoEdit(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockAPIContext(t, "user2/repo1") | |||
ctx, _ := test.MockAPIContext(t, "user2/repo1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadUser(t, ctx, 2) | |||
ctx.Repo.Owner = ctx.Doer | |||
@@ -65,7 +65,7 @@ func TestRepoEdit(t *testing.T) { | |||
func TestRepoEditNameChange(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockAPIContext(t, "user2/repo1") | |||
ctx, _ := test.MockAPIContext(t, "user2/repo1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadUser(t, ctx, 2) | |||
ctx.Repo.Owner = ctx.Doer |
@@ -174,27 +174,27 @@ func GlobalInitInstalled(ctx context.Context) { | |||
} | |||
// NormalRoutes represents non install routes | |||
func NormalRoutes(ctx context.Context) *web.Route { | |||
func NormalRoutes() *web.Route { | |||
_ = templates.HTMLRenderer() | |||
r := web.NewRoute() | |||
r.Use(common.ProtocolMiddlewares()...) | |||
r.Mount("/", web_routers.Routes(ctx)) | |||
r.Mount("/api/v1", apiv1.Routes(ctx)) | |||
r.Mount("/", web_routers.Routes()) | |||
r.Mount("/api/v1", apiv1.Routes()) | |||
r.Mount("/api/internal", private.Routes()) | |||
r.Post("/-/fetch-redirect", common.FetchRedirectDelegate) | |||
if setting.Packages.Enabled { | |||
// This implements package support for most package managers | |||
r.Mount("/api/packages", packages_router.CommonRoutes(ctx)) | |||
r.Mount("/api/packages", packages_router.CommonRoutes()) | |||
// This implements the OCI API (Note this is not preceded by /api but is instead /v2) | |||
r.Mount("/v2", packages_router.ContainerRoutes(ctx)) | |||
r.Mount("/v2", packages_router.ContainerRoutes()) | |||
} | |||
if setting.Actions.Enabled { | |||
prefix := "/api/actions" | |||
r.Mount(prefix, actions_router.Routes(ctx, prefix)) | |||
r.Mount(prefix, actions_router.Routes(prefix)) | |||
// TODO: Pipeline api used for runner internal communication with gitea server. but only artifact is used for now. | |||
// In Github, it uses ACTIONS_RUNTIME_URL=https://pipelines.actions.githubusercontent.com/fLgcSHkPGySXeIFrg8W8OBSfeg3b5Fls1A1CwX566g8PayEGlg/ |
@@ -19,7 +19,7 @@ import ( | |||
func TestNewUserPost_MustChangePassword(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "admin/users/new") | |||
ctx, _ := test.MockContext(t, "admin/users/new") | |||
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | |||
IsAdmin: true, | |||
@@ -56,7 +56,7 @@ func TestNewUserPost_MustChangePassword(t *testing.T) { | |||
func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "admin/users/new") | |||
ctx, _ := test.MockContext(t, "admin/users/new") | |||
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | |||
IsAdmin: true, | |||
@@ -93,7 +93,7 @@ func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { | |||
func TestNewUserPost_InvalidEmail(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "admin/users/new") | |||
ctx, _ := test.MockContext(t, "admin/users/new") | |||
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | |||
IsAdmin: true, | |||
@@ -123,7 +123,7 @@ func TestNewUserPost_InvalidEmail(t *testing.T) { | |||
func TestNewUserPost_VisibilityDefaultPublic(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "admin/users/new") | |||
ctx, _ := test.MockContext(t, "admin/users/new") | |||
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | |||
IsAdmin: true, | |||
@@ -161,7 +161,7 @@ func TestNewUserPost_VisibilityDefaultPublic(t *testing.T) { | |||
func TestNewUserPost_VisibilityPrivate(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "admin/users/new") | |||
ctx, _ := test.MockContext(t, "admin/users/new") | |||
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ | |||
IsAdmin: true, |
@@ -15,7 +15,7 @@ import ( | |||
func TestCheckProjectBoardChangePermissions(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/-/projects/4/4") | |||
ctx, _ := test.MockContext(t, "user2/-/projects/4/4") | |||
test.LoadUser(t, ctx, 2) | |||
ctx.ContextUser = ctx.Doer // user2 | |||
ctx.SetParams(":id", "4") |
@@ -41,7 +41,7 @@ func TestCleanUploadName(t *testing.T) { | |||
func TestGetUniquePatchBranchName(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
@@ -56,7 +56,7 @@ func TestGetUniquePatchBranchName(t *testing.T) { | |||
func TestGetClosestParentWithFiles(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) |
@@ -32,7 +32,7 @@ func int64SliceToCommaSeparated(a []int64) string { | |||
func TestInitializeLabels(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
assert.NoError(t, repository.LoadRepoConfig()) | |||
ctx := test.MockContext(t, "user2/repo1/labels/initialize") | |||
ctx, _ := test.MockContext(t, "user2/repo1/labels/initialize") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 2) | |||
web.SetForm(ctx, &forms.InitializeLabelsForm{TemplateName: "Default"}) | |||
@@ -57,7 +57,7 @@ func TestRetrieveLabels(t *testing.T) { | |||
{1, "leastissues", []int64{2, 1}}, | |||
{2, "", []int64{}}, | |||
} { | |||
ctx := test.MockContext(t, "user/repo/issues") | |||
ctx, _ := test.MockContext(t, "user/repo/issues") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, testCase.RepoID) | |||
ctx.Req.Form.Set("sort", testCase.Sort) | |||
@@ -75,7 +75,7 @@ func TestRetrieveLabels(t *testing.T) { | |||
func TestNewLabel(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/labels/edit") | |||
ctx, _ := test.MockContext(t, "user2/repo1/labels/edit") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
web.SetForm(ctx, &forms.CreateLabelForm{ | |||
@@ -93,7 +93,7 @@ func TestNewLabel(t *testing.T) { | |||
func TestUpdateLabel(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/labels/edit") | |||
ctx, _ := test.MockContext(t, "user2/repo1/labels/edit") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
web.SetForm(ctx, &forms.CreateLabelForm{ | |||
@@ -113,7 +113,7 @@ func TestUpdateLabel(t *testing.T) { | |||
func TestDeleteLabel(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/labels/delete") | |||
ctx, _ := test.MockContext(t, "user2/repo1/labels/delete") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
ctx.Req.Form.Set("id", "2") | |||
@@ -126,7 +126,7 @@ func TestDeleteLabel(t *testing.T) { | |||
func TestUpdateIssueLabel_Clear(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/issues/labels") | |||
ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
ctx.Req.Form.Set("issue_ids", "1,3") | |||
@@ -151,7 +151,7 @@ func TestUpdateIssueLabel_Toggle(t *testing.T) { | |||
{"toggle", []int64{1, 2}, 2, true}, | |||
} { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/issues/labels") | |||
ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
ctx.Req.Form.Set("issue_ids", int64SliceToCommaSeparated(testCase.IssueIDs)) |
@@ -14,7 +14,7 @@ import ( | |||
func TestCheckProjectBoardChangePermissions(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/projects/1/2") | |||
ctx, _ := test.MockContext(t, "user2/repo1/projects/1/2") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
ctx.SetParams(":id", "1") |
@@ -47,7 +47,7 @@ func TestNewReleasePost(t *testing.T) { | |||
} { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/releases/new") | |||
ctx, _ := test.MockContext(t, "user2/repo1/releases/new") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadGitRepo(t, ctx) | |||
@@ -67,7 +67,7 @@ func TestNewReleasePost(t *testing.T) { | |||
func TestNewReleasesList(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo-release/releases") | |||
ctx, _ := test.MockContext(t, "user2/repo-release/releases") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 57) | |||
test.LoadGitRepo(t, ctx) |
@@ -42,7 +42,7 @@ func TestAddReadOnlyDeployKey(t *testing.T) { | |||
} | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/settings/keys") | |||
ctx, _ := test.MockContext(t, "user2/repo1/settings/keys") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 2) | |||
@@ -71,7 +71,7 @@ func TestAddReadWriteOnlyDeployKey(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/settings/keys") | |||
ctx, _ := test.MockContext(t, "user2/repo1/settings/keys") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 2) | |||
@@ -94,7 +94,7 @@ func TestAddReadWriteOnlyDeployKey(t *testing.T) { | |||
func TestCollaborationPost(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/issues/labels") | |||
ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadUser(t, ctx, 4) | |||
test.LoadRepo(t, ctx, 1) | |||
@@ -129,7 +129,7 @@ func TestCollaborationPost(t *testing.T) { | |||
func TestCollaborationPost_InactiveUser(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/issues/labels") | |||
ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadUser(t, ctx, 9) | |||
test.LoadRepo(t, ctx, 1) | |||
@@ -152,7 +152,7 @@ func TestCollaborationPost_InactiveUser(t *testing.T) { | |||
func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/issues/labels") | |||
ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadUser(t, ctx, 4) | |||
test.LoadRepo(t, ctx, 1) | |||
@@ -193,7 +193,7 @@ func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) { | |||
func TestCollaborationPost_NonExistentUser(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/issues/labels") | |||
ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
@@ -215,7 +215,7 @@ func TestCollaborationPost_NonExistentUser(t *testing.T) { | |||
func TestAddTeamPost(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "org26/repo43") | |||
ctx, _ := test.MockContext(t, "org26/repo43") | |||
ctx.Req.Form.Set("team", "team11") | |||
@@ -255,7 +255,7 @@ func TestAddTeamPost(t *testing.T) { | |||
func TestAddTeamPost_NotAllowed(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "org26/repo43") | |||
ctx, _ := test.MockContext(t, "org26/repo43") | |||
ctx.Req.Form.Set("team", "team11") | |||
@@ -295,7 +295,7 @@ func TestAddTeamPost_NotAllowed(t *testing.T) { | |||
func TestAddTeamPost_AddTeamTwice(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "org26/repo43") | |||
ctx, _ := test.MockContext(t, "org26/repo43") | |||
ctx.Req.Form.Set("team", "team11") | |||
@@ -336,7 +336,7 @@ func TestAddTeamPost_AddTeamTwice(t *testing.T) { | |||
func TestAddTeamPost_NonExistentTeam(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "org26/repo43") | |||
ctx, _ := test.MockContext(t, "org26/repo43") | |||
ctx.Req.Form.Set("team", "team-non-existent") | |||
@@ -369,7 +369,7 @@ func TestAddTeamPost_NonExistentTeam(t *testing.T) { | |||
func TestDeleteTeam(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "org3/team1/repo3") | |||
ctx, _ := test.MockContext(t, "org3/team1/repo3") | |||
ctx.Req.Form.Set("id", "2") | |||
@@ -78,7 +78,7 @@ func assertPagesMetas(t *testing.T, expectedNames []string, metas interface{}) { | |||
func TestWiki(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/wiki/?action=_pages") | |||
ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_pages") | |||
ctx.SetParams("*", "Home") | |||
test.LoadRepo(t, ctx, 1) | |||
Wiki(ctx) | |||
@@ -90,7 +90,7 @@ func TestWiki(t *testing.T) { | |||
func TestWikiPages(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/wiki/?action=_pages") | |||
ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_pages") | |||
test.LoadRepo(t, ctx, 1) | |||
WikiPages(ctx) | |||
assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) | |||
@@ -100,7 +100,7 @@ func TestWikiPages(t *testing.T) { | |||
func TestNewWiki(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new") | |||
ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_new") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
NewWiki(ctx) | |||
@@ -115,7 +115,7 @@ func TestNewWikiPost(t *testing.T) { | |||
} { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new") | |||
ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_new") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
web.SetForm(ctx, &forms.NewWikiForm{ | |||
@@ -133,7 +133,7 @@ func TestNewWikiPost(t *testing.T) { | |||
func TestNewWikiPost_ReservedName(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new") | |||
ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_new") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
web.SetForm(ctx, &forms.NewWikiForm{ | |||
@@ -150,7 +150,7 @@ func TestNewWikiPost_ReservedName(t *testing.T) { | |||
func TestEditWiki(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_edit") | |||
ctx, _ := test.MockContext(t, "user2/repo1/wiki/Home?action=_edit") | |||
ctx.SetParams("*", "Home") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
@@ -166,7 +166,7 @@ func TestEditWikiPost(t *testing.T) { | |||
"New/<page>", | |||
} { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_new") | |||
ctx, _ := test.MockContext(t, "user2/repo1/wiki/Home?action=_new") | |||
ctx.SetParams("*", "Home") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
@@ -188,7 +188,7 @@ func TestEditWikiPost(t *testing.T) { | |||
func TestDeleteWikiPagePost(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_delete") | |||
ctx, _ := test.MockContext(t, "user2/repo1/wiki/Home?action=_delete") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
DeleteWikiPagePost(ctx) | |||
@@ -207,7 +207,7 @@ func TestWikiRaw(t *testing.T) { | |||
} { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1/wiki/raw/"+url.PathEscape(filepath)) | |||
ctx, _ := test.MockContext(t, "user2/repo1/wiki/raw/"+url.PathEscape(filepath)) | |||
ctx.SetParams("*", filepath) | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) |
@@ -20,7 +20,7 @@ func TestArchivedIssues(t *testing.T) { | |||
setting.UI.IssuePagingNum = 1 | |||
assert.NoError(t, unittest.LoadFixtures()) | |||
ctx := test.MockContext(t, "issues") | |||
ctx, _ := test.MockContext(t, "issues") | |||
test.LoadUser(t, ctx, 30) | |||
ctx.Req.Form.Set("state", "open") | |||
@@ -53,7 +53,7 @@ func TestIssues(t *testing.T) { | |||
setting.UI.IssuePagingNum = 1 | |||
assert.NoError(t, unittest.LoadFixtures()) | |||
ctx := test.MockContext(t, "issues") | |||
ctx, _ := test.MockContext(t, "issues") | |||
test.LoadUser(t, ctx, 2) | |||
ctx.Req.Form.Set("state", "closed") | |||
Issues(ctx) | |||
@@ -69,7 +69,7 @@ func TestPulls(t *testing.T) { | |||
setting.UI.IssuePagingNum = 20 | |||
assert.NoError(t, unittest.LoadFixtures()) | |||
ctx := test.MockContext(t, "pulls") | |||
ctx, _ := test.MockContext(t, "pulls") | |||
test.LoadUser(t, ctx, 2) | |||
ctx.Req.Form.Set("state", "open") | |||
Pulls(ctx) | |||
@@ -82,7 +82,7 @@ func TestMilestones(t *testing.T) { | |||
setting.UI.IssuePagingNum = 1 | |||
assert.NoError(t, unittest.LoadFixtures()) | |||
ctx := test.MockContext(t, "milestones") | |||
ctx, _ := test.MockContext(t, "milestones") | |||
test.LoadUser(t, ctx, 2) | |||
ctx.SetParams("sort", "issues") | |||
ctx.Req.Form.Set("state", "closed") | |||
@@ -101,7 +101,7 @@ func TestMilestonesForSpecificRepo(t *testing.T) { | |||
setting.UI.IssuePagingNum = 1 | |||
assert.NoError(t, unittest.LoadFixtures()) | |||
ctx := test.MockContext(t, "milestones") | |||
ctx, _ := test.MockContext(t, "milestones") | |||
test.LoadUser(t, ctx, 2) | |||
ctx.SetParams("sort", "issues") | |||
ctx.SetParams("repo", "1") |
@@ -83,7 +83,7 @@ func TestChangePassword(t *testing.T) { | |||
t.Run(req.OldPassword+"__"+req.NewPassword, func(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
setting.PasswordComplexity = req.PasswordComplexity | |||
ctx := test.MockContext(t, "user/settings/security") | |||
ctx, _ := test.MockContext(t, "user/settings/security") | |||
test.LoadUser(t, ctx, 2) | |||
test.LoadRepo(t, ctx, 1) | |||
@@ -104,7 +104,7 @@ func ctxDataSet(args ...any) func(ctx *context.Context) { | |||
} | |||
// Routes returns all web routes | |||
func Routes(ctx gocontext.Context) *web.Route { | |||
func Routes() *web.Route { | |||
routes := web.NewRoute() | |||
routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler | |||
@@ -146,13 +146,8 @@ func Routes(ctx gocontext.Context) *web.Route { | |||
mid = append(mid, common.Sessioner(), context.Contexter()) | |||
group := buildAuthGroup() | |||
if err := group.Init(ctx); err != nil { | |||
log.Error("Could not initialize '%s' auth method, error: %s", group.Name(), err) | |||
} | |||
// Get user from session if logged in. | |||
mid = append(mid, auth_service.Auth(group)) | |||
mid = append(mid, auth_service.Auth(buildAuthGroup())) | |||
// GetHead allows a HEAD request redirect to GET if HEAD method is not defined for that route | |||
mid = append(mid, middleware.GetHead) |
@@ -4,7 +4,6 @@ | |||
package auth | |||
import ( | |||
"context" | |||
"net/http" | |||
"reflect" | |||
"strings" | |||
@@ -14,9 +13,7 @@ import ( | |||
// Ensure the struct implements the interface. | |||
var ( | |||
_ Method = &Group{} | |||
_ Initializable = &Group{} | |||
_ Freeable = &Group{} | |||
_ Method = &Group{} | |||
) | |||
// Group implements the Auth interface with serval Auth. | |||
@@ -49,35 +46,6 @@ func (b *Group) Name() string { | |||
return strings.Join(names, ",") | |||
} | |||
// Init does nothing as the Basic implementation does not need to allocate any resources | |||
func (b *Group) Init(ctx context.Context) error { | |||
for _, method := range b.methods { | |||
initializable, ok := method.(Initializable) | |||
if !ok { | |||
continue | |||
} | |||
if err := initializable.Init(ctx); err != nil { | |||
return err | |||
} | |||
} | |||
return nil | |||
} | |||
// Free does nothing as the Basic implementation does not have to release any resources | |||
func (b *Group) Free() error { | |||
for _, method := range b.methods { | |||
freeable, ok := method.(Freeable) | |||
if !ok { | |||
continue | |||
} | |||
if err := freeable.Free(); err != nil { | |||
return err | |||
} | |||
} | |||
return nil | |||
} | |||
// Verify extracts and validates | |||
func (b *Group) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { | |||
// Try to sign in with each of the enabled plugins |
@@ -29,26 +29,11 @@ type Method interface { | |||
Verify(http *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) | |||
} | |||
// Initializable represents a structure that requires initialization | |||
// It usually should only be called once before anything else is called | |||
type Initializable interface { | |||
// Init should be called exactly once before using any of the other methods, | |||
// in order to allow the plugin to allocate necessary resources | |||
Init(ctx context.Context) error | |||
} | |||
// Named represents a named thing | |||
type Named interface { | |||
Name() string | |||
} | |||
// Freeable represents a structure that is required to be freed | |||
type Freeable interface { | |||
// Free should be called exactly once before application closes, in order to | |||
// give chance to the plugin to free any allocated resources | |||
Free() error | |||
} | |||
// PasswordAuthenticator represents a source of authentication | |||
type PasswordAuthenticator interface { | |||
Authenticate(user *user_model.User, login, password string) (*user_model.User, error) |
@@ -4,10 +4,10 @@ | |||
package auth | |||
import ( | |||
"context" | |||
"errors" | |||
"net/http" | |||
"strings" | |||
"sync" | |||
"code.gitea.io/gitea/models/auth" | |||
"code.gitea.io/gitea/models/avatars" | |||
@@ -32,13 +32,12 @@ var ( | |||
// sspiAuth is a global instance of the websspi authentication package, | |||
// which is used to avoid acquiring the server credential handle on | |||
// every request | |||
sspiAuth *websspi.Authenticator | |||
sspiAuth *websspi.Authenticator | |||
sspiAuthOnce sync.Once | |||
// Ensure the struct implements the interface. | |||
_ Method = &SSPI{} | |||
_ Named = &SSPI{} | |||
_ Initializable = &SSPI{} | |||
_ Freeable = &SSPI{} | |||
_ Method = &SSPI{} | |||
_ Named = &SSPI{} | |||
) | |||
// SSPI implements the SingleSignOn interface and authenticates requests | |||
@@ -47,32 +46,25 @@ var ( | |||
// Returns nil if authentication fails. | |||
type SSPI struct{} | |||
// Init creates a new global websspi.Authenticator object | |||
func (s *SSPI) Init(ctx context.Context) error { | |||
config := websspi.NewConfig() | |||
var err error | |||
sspiAuth, err = websspi.New(config) | |||
if err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
// Name represents the name of auth method | |||
func (s *SSPI) Name() string { | |||
return "sspi" | |||
} | |||
// Free releases resources used by the global websspi.Authenticator object | |||
func (s *SSPI) Free() error { | |||
return sspiAuth.Free() | |||
} | |||
// Verify uses SSPI (Windows implementation of SPNEGO) to authenticate the request. | |||
// If authentication is successful, returns the corresponding user object. | |||
// If negotiation should continue or authentication fails, immediately returns a 401 HTTP | |||
// response code, as required by the SPNEGO protocol. | |||
func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { | |||
var errInit error | |||
sspiAuthOnce.Do(func() { | |||
config := websspi.NewConfig() | |||
sspiAuth, errInit = websspi.New(config) | |||
}) | |||
if errInit != nil { | |||
return nil, errInit | |||
} | |||
if !s.shouldAuthenticate(req) { | |||
return nil, nil | |||
} |
@@ -24,7 +24,7 @@ func TestMain(m *testing.M) { | |||
func TestArchive_Basic(t *testing.T) { | |||
assert.NoError(t, unittest.PrepareTestDatabase()) | |||
ctx := test.MockContext(t, "user27/repo49") | |||
ctx, _ := test.MockContext(t, "user27/repo49") | |||
firstCommit, secondCommit := "51f84af23134", "aacbdfe9e1c4" | |||
test.LoadRepo(t, ctx, 49) |
@@ -54,7 +54,7 @@ func getExpectedReadmeContentsResponse() *api.ContentsResponse { | |||
func TestGetContents(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
@@ -82,7 +82,7 @@ func TestGetContents(t *testing.T) { | |||
func TestGetContentsOrListForDir(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
@@ -117,7 +117,7 @@ func TestGetContentsOrListForDir(t *testing.T) { | |||
func TestGetContentsOrListForFile(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
@@ -145,7 +145,7 @@ func TestGetContentsOrListForFile(t *testing.T) { | |||
func TestGetContentsErrors(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
@@ -176,7 +176,7 @@ func TestGetContentsErrors(t *testing.T) { | |||
func TestGetContentsOrListErrors(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
@@ -207,7 +207,7 @@ func TestGetContentsOrListErrors(t *testing.T) { | |||
func TestGetContentsOrListOfEmptyRepos(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user30/empty") | |||
ctx, _ := test.MockContext(t, "user30/empty") | |||
ctx.SetParams(":id", "52") | |||
test.LoadRepo(t, ctx, 52) | |||
test.LoadUser(t, ctx, 30) | |||
@@ -225,7 +225,7 @@ func TestGetContentsOrListOfEmptyRepos(t *testing.T) { | |||
func TestGetBlobBySHA(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
test.LoadUser(t, ctx, 2) |
@@ -17,7 +17,7 @@ import ( | |||
func TestGetDiffPreview(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
@@ -139,7 +139,7 @@ func TestGetDiffPreview(t *testing.T) { | |||
func TestGetDiffPreviewErrors(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) |
@@ -98,7 +98,7 @@ func getExpectedFileResponse() *api.FileResponse { | |||
func TestGetFileResponseFromCommit(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) |
@@ -15,7 +15,7 @@ import ( | |||
func TestGetTreeBySHA(t *testing.T) { | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
test.LoadUser(t, ctx, 2) |
@@ -38,7 +38,7 @@ func TestMain(m *testing.M) { | |||
defer cancel() | |||
tests.InitTest(false) | |||
c = routers.NormalRoutes(context.TODO()) | |||
c = routers.NormalRoutes() | |||
os.Unsetenv("GIT_AUTHOR_NAME") | |||
os.Unsetenv("GIT_AUTHOR_EMAIL") |
@@ -22,10 +22,10 @@ import ( | |||
func TestActivityPubPerson(t *testing.T) { | |||
setting.Federation.Enabled = true | |||
c = routers.NormalRoutes(context.TODO()) | |||
c = routers.NormalRoutes() | |||
defer func() { | |||
setting.Federation.Enabled = false | |||
c = routers.NormalRoutes(context.TODO()) | |||
c = routers.NormalRoutes() | |||
}() | |||
onGiteaRun(t, func(*testing.T, *url.URL) { | |||
@@ -60,10 +60,10 @@ func TestActivityPubPerson(t *testing.T) { | |||
func TestActivityPubMissingPerson(t *testing.T) { | |||
setting.Federation.Enabled = true | |||
c = routers.NormalRoutes(context.TODO()) | |||
c = routers.NormalRoutes() | |||
defer func() { | |||
setting.Federation.Enabled = false | |||
c = routers.NormalRoutes(context.TODO()) | |||
c = routers.NormalRoutes() | |||
}() | |||
onGiteaRun(t, func(*testing.T, *url.URL) { | |||
@@ -75,10 +75,10 @@ func TestActivityPubMissingPerson(t *testing.T) { | |||
func TestActivityPubPersonInbox(t *testing.T) { | |||
setting.Federation.Enabled = true | |||
c = routers.NormalRoutes(context.TODO()) | |||
c = routers.NormalRoutes() | |||
defer func() { | |||
setting.Federation.Enabled = false | |||
c = routers.NormalRoutes(context.TODO()) | |||
c = routers.NormalRoutes() | |||
}() | |||
srv := httptest.NewServer(c) |
@@ -4,7 +4,6 @@ | |||
package integration | |||
import ( | |||
"context" | |||
"net/http" | |||
"net/url" | |||
"testing" | |||
@@ -18,10 +17,10 @@ import ( | |||
func TestNodeinfo(t *testing.T) { | |||
setting.Federation.Enabled = true | |||
c = routers.NormalRoutes(context.TODO()) | |||
c = routers.NormalRoutes() | |||
defer func() { | |||
setting.Federation.Enabled = false | |||
c = routers.NormalRoutes(context.TODO()) | |||
c = routers.NormalRoutes() | |||
}() | |||
onGiteaRun(t, func(*testing.T, *url.URL) { |
@@ -4,7 +4,6 @@ | |||
package integration | |||
import ( | |||
"context" | |||
"net/http" | |||
"net/http/httptest" | |||
"os" | |||
@@ -57,7 +56,7 @@ func TestSessionFileCreation(t *testing.T) { | |||
oldSessionConfig := setting.SessionConfig.ProviderConfig | |||
defer func() { | |||
setting.SessionConfig.ProviderConfig = oldSessionConfig | |||
c = routers.NormalRoutes(context.TODO()) | |||
c = routers.NormalRoutes() | |||
}() | |||
var config session.Options | |||
@@ -76,7 +75,7 @@ func TestSessionFileCreation(t *testing.T) { | |||
setting.SessionConfig.ProviderConfig = string(newConfigBytes) | |||
c = routers.NormalRoutes(context.TODO()) | |||
c = routers.NormalRoutes() | |||
t.Run("NoSessionOnViewIssue", func(t *testing.T) { | |||
defer tests.PrintCurrentTest(t)() |
@@ -87,7 +87,7 @@ func TestMain(m *testing.M) { | |||
defer cancel() | |||
tests.InitTest(true) | |||
c = routers.NormalRoutes(context.TODO()) | |||
c = routers.NormalRoutes() | |||
// integration test settings... | |||
if setting.CfgProvider != nil { |
@@ -244,7 +244,7 @@ func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA | |||
func TestChangeRepoFilesForCreate(t *testing.T) { | |||
// setup | |||
onGiteaRun(t, func(t *testing.T, u *url.URL) { | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
@@ -281,7 +281,7 @@ func TestChangeRepoFilesForCreate(t *testing.T) { | |||
func TestChangeRepoFilesForUpdate(t *testing.T) { | |||
// setup | |||
onGiteaRun(t, func(t *testing.T, u *url.URL) { | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
@@ -315,7 +315,7 @@ func TestChangeRepoFilesForUpdate(t *testing.T) { | |||
func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) { | |||
// setup | |||
onGiteaRun(t, func(t *testing.T, u *url.URL) { | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
@@ -366,7 +366,7 @@ func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) { | |||
func TestChangeRepoFilesWithoutBranchNames(t *testing.T) { | |||
// setup | |||
onGiteaRun(t, func(t *testing.T, u *url.URL) { | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
@@ -402,7 +402,7 @@ func TestChangeRepoFilesForDelete(t *testing.T) { | |||
func testDeleteRepoFiles(t *testing.T, u *url.URL) { | |||
// setup | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
@@ -441,7 +441,7 @@ func TestChangeRepoFilesForDeleteWithoutBranchNames(t *testing.T) { | |||
func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) { | |||
// setup | |||
unittest.PrepareTestEnv(t) | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) | |||
@@ -471,7 +471,7 @@ func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) { | |||
func TestChangeRepoFilesErrors(t *testing.T) { | |||
// setup | |||
onGiteaRun(t, func(t *testing.T, u *url.URL) { | |||
ctx := test.MockContext(t, "user2/repo1") | |||
ctx, _ := test.MockContext(t, "user2/repo1") | |||
ctx.SetParams(":id", "1") | |||
test.LoadRepo(t, ctx, 1) | |||
test.LoadRepoCommit(t, ctx) |