diff --git a/Makefile b/Makefile index ffffb1faf..f023608b1 100644 --- a/Makefile +++ b/Makefile @@ -156,8 +156,8 @@ endif FORGEJO_API_SPEC := public/assets/forgejo/api.v1.yml SWAGGER_SPEC := templates/swagger/v1_json.tmpl -SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|g -SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|"basePath": "/api/v1"|g +SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape}}/api/v1"|g +SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape}}/api/v1"|"basePath": "/api/v1"|g SWAGGER_EXCLUDE := code.gitea.io/sdk SWAGGER_NEWLINE_COMMAND := -e '$$a\' SWAGGER_SPEC_BRANDING := s|Gitea API|Forgejo API|g diff --git a/modules/context/context_response.go b/modules/context/context_response.go index d9102b77b..829bca1f5 100644 --- a/modules/context/context_response.go +++ b/modules/context/context_response.go @@ -90,6 +90,20 @@ func (ctx *Context) HTML(status int, name base.TplName) { } } +// JSONTemplate renders the template as JSON response +// keep in mind that the template is processed in HTML context, so JSON-things should be handled carefully, eg: by JSEscape +func (ctx *Context) JSONTemplate(tmpl base.TplName) { + t, err := ctx.Render.TemplateLookup(string(tmpl), nil) + if err != nil { + ctx.ServerError("unable to find template", err) + return + } + ctx.Resp.Header().Set("Content-Type", "application/json") + if err = t.Execute(ctx.Resp, ctx.Data); err != nil { + ctx.ServerError("unable to execute template", err) + } +} + // RenderToString renders the template content to a string func (ctx *Context) RenderToString(name base.TplName, data map[string]any) (string, error) { var buf strings.Builder diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 90371fa8f..3bf1919b4 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -38,7 +38,7 @@ func NewFuncMap() template.FuncMap { "Safe": Safe, "Escape": Escape, "QueryEscape": url.QueryEscape, - "JSEscape": template.JSEscapeString, + "JSEscape": JSEscapeSafe, "Str2html": Str2html, // TODO: rename it to SanitizeHTML "URLJoin": util.URLJoin, "DotEscape": DotEscape, @@ -214,6 +214,10 @@ func Escape(s any) template.HTML { panic(fmt.Sprintf("unexpected type %T", s)) } +func JSEscapeSafe(s string) template.HTML { + return template.HTML(template.JSEscapeString(s)) +} + func RenderEmojiPlain(s any) any { switch v := s.(type) { case string: diff --git a/modules/templates/helper_test.go b/modules/templates/helper_test.go index ec83e9ac3..739a92f34 100644 --- a/modules/templates/helper_test.go +++ b/modules/templates/helper_test.go @@ -52,3 +52,7 @@ func TestSubjectBodySeparator(t *testing.T) { "", "Insuficient\n--\nSeparators") } + +func TestJSEscapeSafe(t *testing.T) { + assert.EqualValues(t, `\u0026\u003C\u003E\'\"`, JSEscapeSafe(`&<>'"`)) +} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 58814d3b2..1babccb65 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -8,7 +8,7 @@ // // Schemes: https, http // BasePath: /api/v1 -// Version: {{AppVer | JSEscape | Safe}} +// Version: {{AppVer | JSEscape}} // License: MIT http://opensource.org/licenses/MIT // // Consumes: diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 2adcb3aea..e840e03bc 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -579,16 +579,8 @@ func GrantApplicationOAuth(ctx *context.Context) { // OIDCWellKnown generates JSON so OIDC clients know Gitea's capabilities func OIDCWellKnown(ctx *context.Context) { - t, err := ctx.Render.TemplateLookup("user/auth/oidc_wellknown", nil) - if err != nil { - ctx.ServerError("unable to find template", err) - return - } - ctx.Resp.Header().Set("Content-Type", "application/json") ctx.Data["SigningKey"] = oauth2.DefaultSigningKey - if err = t.Execute(ctx.Resp, ctx.Data); err != nil { - ctx.ServerError("unable to execute template", err) - } + ctx.JSONTemplate("user/auth/oidc_wellknown") } // OIDCKeys generates the JSON Web Key Set diff --git a/routers/web/shared/user/header.go b/routers/web/shared/user/header.go index 203e5fa5a..6830bdb8a 100644 --- a/routers/web/shared/user/header.go +++ b/routers/web/shared/user/header.go @@ -4,6 +4,8 @@ package user import ( + "net/url" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" access_model "code.gitea.io/gitea/models/perm/access" @@ -37,7 +39,7 @@ func PrepareContextForProfileBigAvatar(ctx *context.Context) { ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID) ctx.Data["IsBlocked"] = ctx.Doer != nil && user_model.IsBlocked(ctx, ctx.Doer.ID, ctx.ContextUser.ID) ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail && ctx.ContextUser.Email != "" && ctx.IsSigned && !ctx.ContextUser.KeepEmailPrivate - ctx.Data["UserLocationMapURL"] = setting.Service.UserLocationMapURL + ctx.Data["ContextUserLocationMapURL"] = setting.Service.UserLocationMapURL + url.QueryEscape(ctx.ContextUser.Location) // Show OpenID URIs openIDs, err := user_model.GetUserOpenIDs(ctx, ctx.ContextUser.ID) diff --git a/routers/web/swagger_json.go b/routers/web/swagger_json.go index 493c97aa6..42e9dbe96 100644 --- a/routers/web/swagger_json.go +++ b/routers/web/swagger_json.go @@ -4,22 +4,10 @@ package web import ( - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" ) -// tplSwaggerV1Json swagger v1 json template -const tplSwaggerV1Json base.TplName = "swagger/v1_json" - // SwaggerV1Json render swagger v1 json func SwaggerV1Json(ctx *context.Context) { - t, err := ctx.Render.TemplateLookup(string(tplSwaggerV1Json), nil) - if err != nil { - ctx.ServerError("unable to find template", err) - return - } - ctx.Resp.Header().Set("Content-Type", "application/json") - if err = t.Execute(ctx.Resp, ctx.Data); err != nil { - ctx.ServerError("unable to execute template", err) - } + ctx.JSONTemplate("swagger/v1_json") } diff --git a/templates/shared/user/profile_big_avatar.tmpl b/templates/shared/user/profile_big_avatar.tmpl index fefaa9dd1..e731cfe2e 100644 --- a/templates/shared/user/profile_big_avatar.tmpl +++ b/templates/shared/user/profile_big_avatar.tmpl @@ -31,9 +31,8 @@