aboutsummaryrefslogtreecommitdiffstats
path: root/routers/web
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2022-06-16 11:33:23 +0800
committerGitHub <noreply@github.com>2022-06-16 11:33:23 +0800
commitb01dce2a6e98c25915a8e98afb741a1c34d05aba (patch)
treeb391ae8dff3ed5270b9721900bdc667b05fd555c /routers/web
parent7d1770cd714416bd80f114681d19e3076a0b0966 (diff)
downloadgitea-b01dce2a6e98c25915a8e98afb741a1c34d05aba.tar.gz
gitea-b01dce2a6e98c25915a8e98afb741a1c34d05aba.zip
Allow render HTML with css/js external links (#19017)
* Allow render HTML with css/js external links * Fix bug because of filename escape chars * Fix lint * Update docs about new configuration item * Fix bug of render HTML in sub directory * Add CSP head for displaying iframe in rendering file * Fix test * Apply suggestions from code review Co-authored-by: delvh <dev.lh@web.de> * Some improvements * some improvement * revert change in SanitizerDisabled of external renderer * Add sandbox for iframe and support allow-scripts and allow-same-origin * refactor * fix * fix lint * fine tune * use single option RENDER_CONTENT_MODE, use sandbox=allow-scripts * fine tune CSP * Apply suggestions from code review Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: delvh <dev.lh@web.de> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Diffstat (limited to 'routers/web')
-rw-r--r--routers/web/repo/compare.go4
-rw-r--r--routers/web/repo/render.go79
-rw-r--r--routers/web/repo/view.go36
-rw-r--r--routers/web/web.go7
4 files changed, 108 insertions, 18 deletions
diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go
index 605594d5a9..5c46882f3d 100644
--- a/routers/web/repo/compare.go
+++ b/routers/web/repo/compare.go
@@ -139,7 +139,7 @@ func setCsvCompareContext(ctx *context.Context) {
return csvReader, reader, err
}
- baseReader, baseBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, Filename: diffFile.OldName}, baseCommit)
+ baseReader, baseBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, RelativePath: diffFile.OldName}, baseCommit)
if baseBlobCloser != nil {
defer baseBlobCloser.Close()
}
@@ -151,7 +151,7 @@ func setCsvCompareContext(ctx *context.Context) {
return CsvDiffResult{nil, "unable to load file from base commit"}
}
- headReader, headBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, Filename: diffFile.Name}, headCommit)
+ headReader, headBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, RelativePath: diffFile.Name}, headCommit)
if headBlobCloser != nil {
defer headBlobCloser.Close()
}
diff --git a/routers/web/repo/render.go b/routers/web/repo/render.go
new file mode 100644
index 0000000000..28a6d2f429
--- /dev/null
+++ b/routers/web/repo/render.go
@@ -0,0 +1,79 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repo
+
+import (
+ "bytes"
+ "io"
+ "net/http"
+ "path"
+
+ "code.gitea.io/gitea/modules/charset"
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/markup"
+ "code.gitea.io/gitea/modules/typesniffer"
+ "code.gitea.io/gitea/modules/util"
+)
+
+// RenderFile renders a file by repos path
+func RenderFile(ctx *context.Context) {
+ blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath)
+ if err != nil {
+ if git.IsErrNotExist(err) {
+ ctx.NotFound("GetBlobByPath", err)
+ } else {
+ ctx.ServerError("GetBlobByPath", err)
+ }
+ return
+ }
+
+ dataRc, err := blob.DataAsync()
+ if err != nil {
+ ctx.ServerError("DataAsync", err)
+ return
+ }
+ defer dataRc.Close()
+
+ buf := make([]byte, 1024)
+ n, _ := util.ReadAtMost(dataRc, buf)
+ buf = buf[:n]
+
+ st := typesniffer.DetectContentType(buf)
+ isTextFile := st.IsText()
+
+ rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc))
+
+ if markupType := markup.Type(blob.Name()); markupType == "" {
+ if isTextFile {
+ _, err = io.Copy(ctx.Resp, rd)
+ if err != nil {
+ ctx.ServerError("Copy", err)
+ }
+ return
+ }
+ ctx.Error(http.StatusInternalServerError, "Unsupported file type render")
+ return
+ }
+
+ treeLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
+ if ctx.Repo.TreePath != "" {
+ treeLink += "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
+ }
+
+ ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'; sandbox allow-scripts")
+ err = markup.Render(&markup.RenderContext{
+ Ctx: ctx,
+ RelativePath: ctx.Repo.TreePath,
+ URLPrefix: path.Dir(treeLink),
+ Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
+ GitRepo: ctx.Repo.GitRepo,
+ InStandalonePage: true,
+ }, rd, ctx.Resp)
+ if err != nil {
+ ctx.ServerError("Render", err)
+ return
+ }
+}
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 01bd2d8923..fe60cf44c7 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -356,11 +356,11 @@ func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelin
ctx.Data["MarkupType"] = string(markupType)
var result strings.Builder
err := markup.Render(&markup.RenderContext{
- Ctx: ctx,
- Filename: readmeFile.name,
- URLPrefix: readmeTreelink,
- Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
- GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
+ RelativePath: ctx.Repo.TreePath,
+ URLPrefix: readmeTreelink,
+ Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
+ GitRepo: ctx.Repo.GitRepo,
}, rd, &result)
if err != nil {
log.Error("Render failed: %v then fallback", err)
@@ -528,18 +528,22 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
if !detected {
markupType = ""
}
+ metas := ctx.Repo.Repository.ComposeDocumentMetas()
+ metas["BranchNameSubURL"] = ctx.Repo.BranchNameSubURL()
err := markup.Render(&markup.RenderContext{
- Ctx: ctx,
- Type: markupType,
- Filename: blob.Name(),
- URLPrefix: path.Dir(treeLink),
- Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
- GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
+ Type: markupType,
+ RelativePath: ctx.Repo.TreePath,
+ URLPrefix: path.Dir(treeLink),
+ Metas: metas,
+ GitRepo: ctx.Repo.GitRepo,
}, rd, &result)
if err != nil {
ctx.ServerError("Render", err)
return
}
+ // to prevent iframe load third-party url
+ ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'")
ctx.Data["EscapeStatus"], ctx.Data["FileContent"] = charset.EscapeControlString(result.String())
} else if readmeExist && !shouldRenderSource {
buf := &bytes.Buffer{}
@@ -627,11 +631,11 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
ctx.Data["MarkupType"] = markupType
var result strings.Builder
err := markup.Render(&markup.RenderContext{
- Ctx: ctx,
- Filename: blob.Name(),
- URLPrefix: path.Dir(treeLink),
- Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
- GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
+ RelativePath: ctx.Repo.TreePath,
+ URLPrefix: path.Dir(treeLink),
+ Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
+ GitRepo: ctx.Repo.GitRepo,
}, rd, &result)
if err != nil {
ctx.ServerError("Render", err)
diff --git a/routers/web/web.go b/routers/web/web.go
index ad005f74df..374bafbc8d 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1161,6 +1161,13 @@ func RegisterRoutes(m *web.Route) {
m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.SingleDownload)
}, repo.MustBeNotEmpty, reqRepoCodeReader)
+ m.Group("/render", func() {
+ m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RenderFile)
+ m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RenderFile)
+ m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RenderFile)
+ m.Get("/blob/{sha}", context.RepoRefByType(context.RepoRefBlob), repo.RenderFile)
+ }, repo.MustBeNotEmpty, reqRepoCodeReader)
+
m.Group("/commits", func() {
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RefCommits)
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RefCommits)