diff options
Diffstat (limited to 'modules/context/api.go')
-rw-r--r-- | modules/context/api.go | 141 |
1 files changed, 104 insertions, 37 deletions
diff --git a/modules/context/api.go b/modules/context/api.go index 7771ec1b14..cf6dc265cd 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -6,18 +6,21 @@ package context import ( + "context" "fmt" + "html" "net/http" "net/url" "strings" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/auth/sso" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/middlewares" "code.gitea.io/gitea/modules/setting" - "gitea.com/macaron/csrf" - "gitea.com/macaron/macaron" + "gitea.com/go-chi/session" ) // APIContext is a specific macaron context for API service @@ -91,7 +94,7 @@ func (ctx *APIContext) Error(status int, title string, obj interface{}) { if status == http.StatusInternalServerError { log.ErrorWithSkip(1, "%s: %s", title, message) - if macaron.Env == macaron.PROD && !(ctx.User != nil && ctx.User.IsAdmin) { + if setting.IsProd() && !(ctx.User != nil && ctx.User.IsAdmin) { message = "" } } @@ -108,7 +111,7 @@ func (ctx *APIContext) InternalServerError(err error) { log.ErrorWithSkip(1, "InternalServerError: %v", err) var message string - if macaron.Env != macaron.PROD || (ctx.User != nil && ctx.User.IsAdmin) { + if !setting.IsProd() || (ctx.User != nil && ctx.User.IsAdmin) { message = err.Error() } @@ -118,6 +121,20 @@ func (ctx *APIContext) InternalServerError(err error) { }) } +var ( + apiContextKey interface{} = "default_api_context" +) + +// WithAPIContext set up api context in request +func WithAPIContext(req *http.Request, ctx *APIContext) *http.Request { + return req.WithContext(context.WithValue(req.Context(), apiContextKey, ctx)) +} + +// GetAPIContext returns a context for API routes +func GetAPIContext(req *http.Request) *APIContext { + return req.Context().Value(apiContextKey).(*APIContext) +} + func genAPILinks(curURL *url.URL, total, pageSize, curPage int) []string { page := NewPagination(total, pageSize, curPage, 0) paginater := page.Paginater @@ -172,7 +189,7 @@ func (ctx *APIContext) RequireCSRF() { headerToken := ctx.Req.Header.Get(ctx.csrf.GetHeaderName()) formValueToken := ctx.Req.FormValue(ctx.csrf.GetFormName()) if len(headerToken) > 0 || len(formValueToken) > 0 { - csrf.Validate(ctx.Context.Context, ctx.csrf) + Validate(ctx.Context, ctx.csrf) } else { ctx.Context.Error(401, "Missing CSRF token.") } @@ -201,42 +218,91 @@ func (ctx *APIContext) CheckForOTP() { } // APIContexter returns apicontext as macaron middleware -func APIContexter() macaron.Handler { - return func(c *Context) { - ctx := &APIContext{ - Context: c, - } - c.Map(ctx) +func APIContexter() func(http.Handler) http.Handler { + var csrfOpts = getCsrfOpts() + + return func(next http.Handler) http.Handler { + + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + var locale = middlewares.Locale(w, req) + var ctx = APIContext{ + Context: &Context{ + Resp: NewResponse(w), + Data: map[string]interface{}{}, + Locale: locale, + Session: session.GetSession(req), + Repo: &Repository{ + PullRequest: &PullRequest{}, + }, + Org: &Organization{}, + }, + Org: &APIOrganization{}, + } + + ctx.Req = WithAPIContext(WithContext(req, ctx.Context), &ctx) + ctx.csrf = Csrfer(csrfOpts, ctx.Context) + + // If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid. + if ctx.Req.Method == "POST" && strings.Contains(ctx.Req.Header.Get("Content-Type"), "multipart/form-data") { + if err := ctx.Req.ParseMultipartForm(setting.Attachment.MaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size + ctx.InternalServerError(err) + return + } + } + + // Get user from session if logged in. + ctx.User, ctx.IsBasicAuth = sso.SignedInUser(ctx.Req, ctx.Resp, &ctx, ctx.Session) + if ctx.User != nil { + ctx.IsSigned = true + ctx.Data["IsSigned"] = ctx.IsSigned + ctx.Data["SignedUser"] = ctx.User + ctx.Data["SignedUserID"] = ctx.User.ID + ctx.Data["SignedUserName"] = ctx.User.Name + ctx.Data["IsAdmin"] = ctx.User.IsAdmin + } else { + ctx.Data["SignedUserID"] = int64(0) + ctx.Data["SignedUserName"] = "" + } + + ctx.Resp.Header().Set(`X-Frame-Options`, `SAMEORIGIN`) + + ctx.Data["CsrfToken"] = html.EscapeString(ctx.csrf.GetToken()) + + next.ServeHTTP(ctx.Resp, ctx.Req) + }) } } // ReferencesGitRepo injects the GitRepo into the Context -func ReferencesGitRepo(allowEmpty bool) macaron.Handler { - return func(ctx *APIContext) { - // Empty repository does not have reference information. - if !allowEmpty && ctx.Repo.Repository.IsEmpty { - return - } - - // For API calls. - if ctx.Repo.GitRepo == nil { - repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) - gitRepo, err := git.OpenRepository(repoPath) - if err != nil { - ctx.Error(500, "RepoRef Invalid repo "+repoPath, err) +func ReferencesGitRepo(allowEmpty bool) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + ctx := GetAPIContext(req) + // Empty repository does not have reference information. + if !allowEmpty && ctx.Repo.Repository.IsEmpty { return } - ctx.Repo.GitRepo = gitRepo - // We opened it, we should close it - defer func() { - // If it's been set to nil then assume someone else has closed it. - if ctx.Repo.GitRepo != nil { - ctx.Repo.GitRepo.Close() + + // For API calls. + if ctx.Repo.GitRepo == nil { + repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) + gitRepo, err := git.OpenRepository(repoPath) + if err != nil { + ctx.Error(500, "RepoRef Invalid repo "+repoPath, err) + return } - }() - } + ctx.Repo.GitRepo = gitRepo + // We opened it, we should close it + defer func() { + // If it's been set to nil then assume someone else has closed it. + if ctx.Repo.GitRepo != nil { + ctx.Repo.GitRepo.Close() + } + }() + } - ctx.Next() + next.ServeHTTP(w, req) + }) } } @@ -266,8 +332,9 @@ func (ctx *APIContext) NotFound(objs ...interface{}) { } // RepoRefForAPI handles repository reference names when the ref name is not explicitly given -func RepoRefForAPI() macaron.Handler { - return func(ctx *APIContext) { +func RepoRefForAPI(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + ctx := GetAPIContext(req) // Empty repository does not have reference information. if ctx.Repo.Repository.IsEmpty { return @@ -319,6 +386,6 @@ func RepoRefForAPI() macaron.Handler { return } - ctx.Next() - } + next.ServeHTTP(w, req) + }) } |