summaryrefslogtreecommitdiffstats
path: root/modules/context/api.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/context/api.go')
-rw-r--r--modules/context/api.go141
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)
+ })
}