diff --git a/modules/markup/external/frontend.go b/modules/markup/external/frontend.go
index 3f7c26c5751..2a5d652a75b 100644
--- a/modules/markup/external/frontend.go
+++ b/modules/markup/external/frontend.go
@@ -21,19 +21,12 @@ type frontendRenderer struct {
patterns []string
}
-var (
- _ markup.PostProcessRenderer = (*frontendRenderer)(nil)
- _ markup.ExternalRenderer = (*frontendRenderer)(nil)
-)
+var _ markup.ExternalRenderer = (*frontendRenderer)(nil)
func (p *frontendRenderer) Name() string {
return p.name
}
-func (p *frontendRenderer) NeedPostProcess() bool {
- return false
-}
-
func (p *frontendRenderer) FileNamePatterns() []string {
// TODO: the file extensions are ambiguous, even if the file name matches, it doesn't mean that the file is a 3D model
// There are some approaches to make it more accurate, but they are all complicated:
diff --git a/modules/markup/jupyter/jupyter.go b/modules/markup/jupyter/jupyter.go
index 8acaf64d0d1..d9f9740a9b3 100644
--- a/modules/markup/jupyter/jupyter.go
+++ b/modules/markup/jupyter/jupyter.go
@@ -29,9 +29,8 @@ func init() {
type renderer struct{}
var (
- _ markup.Renderer = (*renderer)(nil)
- _ markup.PostProcessRenderer = (*renderer)(nil)
- _ markup.ExternalRenderer = (*renderer)(nil) // FIXME: this is not an external render, need to refactor the framework in the future
+ _ markup.Renderer = (*renderer)(nil)
+ _ markup.ExternalRenderer = (*renderer)(nil) // FIXME: this is not an external render, need to refactor the framework in the future
)
type mimeHandler struct {
@@ -96,8 +95,6 @@ func (renderer) Name() string {
return "jupyter-render"
}
-func (renderer) NeedPostProcess() bool { return true }
-
func (renderer) GetExternalRendererOptions() markup.ExternalRendererOptions {
return markup.ExternalRendererOptions{
// HINT: no need to let markup render sanitize the output because there are many special CSS class names, inline attributes.
diff --git a/modules/markup/jupyter/jupyter_test.go b/modules/markup/jupyter/jupyter_test.go
index bdea55308cf..1fc987e9d5c 100644
--- a/modules/markup/jupyter/jupyter_test.go
+++ b/modules/markup/jupyter/jupyter_test.go
@@ -274,7 +274,7 @@ func TestIntegrationAndSanitization(t *testing.T) {
"execution_count": 1,
"data": {
"text/html": [
- "
"
+ "| [[name=no-post-process|link=/link]] |
"
]
},
"metadata": {}
@@ -304,7 +304,7 @@ func TestIntegrationAndSanitization(t *testing.T) {
Out [1]:
-
+
| [[name=no-post-process|link=/link]] |
diff --git a/modules/markup/main_test.go b/modules/markup/main_test.go
index f8a77ad86ef..8924e43de33 100644
--- a/modules/markup/main_test.go
+++ b/modules/markup/main_test.go
@@ -14,7 +14,6 @@ import (
func TestMain(m *testing.M) {
setting.IsInTesting = true
markup.RenderBehaviorForTesting.DisableAdditionalAttributes = true
- setting.Markdown.FileNamePatterns = []string{"*.md"}
markup.RefreshFileNamePatterns()
os.Exit(m.Run())
}
diff --git a/modules/setting/markup.go b/modules/setting/markup.go
index 39c59025de2..fa2d9367fd4 100644
--- a/modules/setting/markup.go
+++ b/modules/setting/markup.go
@@ -50,7 +50,8 @@ var Markdown = struct {
MathCodeBlockDetection []string
MathCodeBlockOptions MarkdownMathCodeBlockOptions `ini:"-"`
}{
- EnableMath: true,
+ EnableMath: true,
+ FileNamePatterns: []string{"*.md"},
}
// MarkupRenderer defines the external parser configured in ini
diff --git a/routers/api/v1/misc/markup.go b/routers/api/v1/misc/markup.go
index 8d3cb962842..43aab53d32b 100644
--- a/routers/api/v1/misc/markup.go
+++ b/routers/api/v1/misc/markup.go
@@ -4,8 +4,9 @@
package misc
import (
- "gitea.dev/modules/markup"
- "gitea.dev/modules/markup/markdown"
+ "io"
+
+ "gitea.dev/modules/setting"
api "gitea.dev/modules/structs"
"gitea.dev/modules/util"
"gitea.dev/modules/web"
@@ -84,9 +85,6 @@ func MarkdownRaw(ctx *context.APIContext) {
// "$ref": "#/responses/MarkdownRender"
// "422":
// "$ref": "#/responses/validationError"
- defer ctx.Req.Body.Close()
- if err := markdown.RenderRaw(markup.NewRenderContext(ctx), ctx.Req.Body, ctx.Resp); err != nil {
- ctx.APIErrorInternal(err)
- return
- }
+ textBytes, _ := io.ReadAll(io.LimitReader(ctx.Req.Body, setting.UI.MaxDisplayFileSize))
+ common.RenderMarkup(ctx.Base, ctx.Repo, "markdown", util.UnsafeBytesToString(textBytes), "", "")
}
diff --git a/routers/api/v1/misc/markup_test.go b/routers/api/v1/misc/markup_test.go
index bf02d0a9597..d8b83ea330f 100644
--- a/routers/api/v1/misc/markup_test.go
+++ b/routers/api/v1/misc/markup_test.go
@@ -7,19 +7,15 @@ import (
go_context "context"
"io"
"net/http"
- "os"
"path"
"strings"
"testing"
- repo_model "gitea.dev/models/repo"
- "gitea.dev/models/unittest"
"gitea.dev/modules/markup"
"gitea.dev/modules/setting"
api "gitea.dev/modules/structs"
"gitea.dev/modules/test"
"gitea.dev/modules/web"
- context_service "gitea.dev/services/context"
"gitea.dev/services/contexttest"
"github.com/stretchr/testify/assert"
@@ -27,13 +23,6 @@ import (
const AppURL = "http://localhost:3000/"
-func TestMain(m *testing.M) {
- unittest.MainTest(m, &unittest.TestOptions{
- FixtureFiles: []string{"repository.yml", "user.yml"},
- })
- os.Exit(m.Run())
-}
-
func testRenderMarkup(t *testing.T, mode string, wiki bool, filePath, text, expectedBody string, expectedCode int) {
setting.AppURL = AppURL
defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
@@ -49,13 +38,11 @@ func testRenderMarkup(t *testing.T, mode string, wiki bool, filePath, text, expe
FilePath: filePath,
}
ctx, resp := contexttest.MockAPIContext(t, "POST /api/v1/markup")
- ctx.Repo = &context_service.Repository{}
- ctx.Repo.Repository = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
web.SetForm(ctx, &options)
Markup(ctx)
assert.Equal(t, expectedBody, resp.Body.String())
assert.Equal(t, expectedCode, resp.Code)
- resp.Body.Reset()
+ assert.Contains(t, resp.Header().Get("Content-Security-Policy"), "script-src * 'nonce-")
}
func testRenderMarkdown(t *testing.T, mode string, wiki bool, text, responseBody string, responseCode int) {
@@ -76,11 +63,10 @@ func testRenderMarkdown(t *testing.T, mode string, wiki bool, text, responseBody
Markdown(ctx)
assert.Equal(t, responseBody, resp.Body.String())
assert.Equal(t, responseCode, resp.Code)
- resp.Body.Reset()
+ assert.Contains(t, resp.Header().Get("Content-Security-Policy"), "script-src * 'nonce-")
}
func TestAPI_RenderGFM(t *testing.T) {
- unittest.PrepareTestEnv(t)
markup.Init(&markup.RenderHelperFuncs{
IsUsernameMentionable: func(ctx go_context.Context, username string) bool {
return username == "r-lyeh"
diff --git a/routers/common/errpage.go b/routers/common/errpage.go
index 1426b05ef93..6152a0c05ce 100644
--- a/routers/common/errpage.go
+++ b/routers/common/errpage.go
@@ -40,6 +40,7 @@ func renderServerErrorPage(w http.ResponseWriter, req *http.Request, respCode in
if acceptsHTML {
err := templates.PageRenderer().HTML(outBuf, respCode, tmpl, ctxData, tmplCtx)
if err != nil {
+ log.Error("Failed to render error page template %s: %v", tmpl, err)
_, _ = w.Write([]byte("Internal server error but failed to render error page template, please collect error logs and report to Gitea issue tracker"))
return
}
diff --git a/routers/common/markup.go b/routers/common/markup.go
index 3b626c7031f..a379deda3ea 100644
--- a/routers/common/markup.go
+++ b/routers/common/markup.go
@@ -31,6 +31,8 @@ func RenderMarkup(ctx *context.Base, ctxRepo *context.Repository, mode, text, ur
// for example, when previewing file "/gitea/owner/repo/src/branch/features/feat-123/doc/CHANGE.md", then filePath is "doc/CHANGE.md"
// and the urlPathContext is "/gitea/owner/repo/src/branch/features/feat-123/doc"
+ ctx.SetHeaderContentSecurityPolicyGeneral()
+
if mode == "" || mode == "markdown" {
// raw Markdown doesn't do any special handling
// TODO: raw markdown doesn't do any link processing, so "urlPathContext" doesn't take effect
diff --git a/routers/web/repo/render.go b/routers/web/repo/render.go
index b323da163c0..ef3d3173c36 100644
--- a/routers/web/repo/render.go
+++ b/routers/web/repo/render.go
@@ -64,6 +64,9 @@ func RenderFile(ctx *context.Context) {
extRendererOpts := extRenderer.GetExternalRendererOptions()
if extRendererOpts.ContentSandbox != "" {
ctx.Resp.Header().Add("Content-Security-Policy", "sandbox "+extRendererOpts.ContentSandbox)
+ } else {
+ // if no sandbox, just apply the same CSP as a general Gitea web page
+ ctx.SetHeaderContentSecurityPolicyGeneral()
}
err = markup.RenderWithRenderer(rctx, renderer, rendererInput, ctx.Resp)
diff --git a/services/context/base.go b/services/context/base.go
index 17b464e1c46..50274ec1549 100644
--- a/services/context/base.go
+++ b/services/context/base.go
@@ -188,6 +188,26 @@ func (b *Base) TrN(cnt any, key1, keyN string, args ...any) template.HTML {
return b.Locale.TrN(cnt, key1, keyN, args...)
}
+func CspScriptNonce(ctx reqctx.RequestContext) (ret string) {
+ // Generate a random nonce for each request and cache it in the context to make it usable during the whole rendering process.
+ //
+ // Some "`,
respSub.Body.String(),
)
- assert.Empty(t, respSub.Header().Get("Content-Security-Policy"))
+ assert.NotContains(t, respSub.Header().Get("Content-Security-Policy"), "sandbox")
+ assert.Contains(t, respSub.Header().Get("Content-Security-Policy"), "nonce-")
})
})
})