@@ -6,12 +6,14 @@ package markup
66import (
77 "context"
88 "fmt"
9+ "html/template"
910 "io"
1011 "net/url"
1112 "strconv"
1213 "strings"
1314 "time"
1415
16+ "code.gitea.io/gitea/modules/htmlutil"
1517 "code.gitea.io/gitea/modules/markup/internal"
1618 "code.gitea.io/gitea/modules/setting"
1719 "code.gitea.io/gitea/modules/util"
@@ -164,23 +166,28 @@ func RenderString(ctx *RenderContext, content string) (string, error) {
164166}
165167
166168func renderIFrame (ctx * RenderContext , output io.Writer ) error {
167- // set height="0" ahead, otherwise the scrollHeight would be max(150, realHeight)
168- // at the moment, only "allow-scripts" is allowed for sandbox mode.
169- // "allow-same-origin" should never be used, it leads to XSS attack, and it makes the JS in iframe can access parent window's config and CSRF token
170- // TODO: when using dark theme, if the rendered content doesn't have proper style, the default text color is black, which is not easy to read
171- _ , err := io .WriteString (output , fmt .Sprintf (`
172- <iframe src="%s/%s/%s/render/%s/%s"
173- name="giteaExternalRender"
174- onload="this.height=giteaExternalRender.document.documentElement.scrollHeight"
175- width="100%%" height="0" scrolling="no" frameborder="0" style="overflow: hidden"
176- sandbox="allow-scripts"
177- ></iframe>` ,
178- setting .AppSubURL ,
169+ src := fmt .Sprintf ("%s/%s/%s/render/%s/%s" , setting .AppSubURL ,
179170 url .PathEscape (ctx .RenderOptions .Metas ["user" ]),
180171 url .PathEscape (ctx .RenderOptions .Metas ["repo" ]),
181- ctx .RenderOptions .Metas ["RefTypeNameSubURL" ],
182- url .PathEscape (ctx .RenderOptions .RelativePath ),
183- ))
172+ util .PathEscapeSegments (ctx .RenderOptions .Metas ["RefTypeNameSubURL" ]),
173+ util .PathEscapeSegments (ctx .RenderOptions .RelativePath ),
174+ )
175+
176+ defaultWidth := "100%"
177+ defaultHeight := "300"
178+
179+ // ATTENTION! at the moment, only "allow-scripts" is allowed for sandbox mode.
180+ // "allow-same-origin" should never be used, it leads to XSS attack, and it makes the JS in iframe can access parent window's config and CSRF token
181+ iframe := htmlutil .HTMLFormat (`
182+ <iframe data-src="%s"
183+ class="external-render-iframe"
184+ sandbox="allow-scripts allow-popups"
185+ width="%s" height="%s"
186+ ></iframe>
187+ ` ,
188+ src , defaultWidth , defaultHeight )
189+
190+ _ , err := io .WriteString (output , string (iframe ))
184191 return err
185192}
186193
@@ -193,21 +200,26 @@ func pipes() (io.ReadCloser, io.WriteCloser, func()) {
193200}
194201
195202func RenderWithRenderer (ctx * RenderContext , renderer Renderer , input io.Reader , output io.Writer ) error {
203+ var extraHeadHTML template.HTML
196204 if externalRender , ok := renderer .(ExternalRenderer ); ok && externalRender .DisplayInIFrame () {
197205 if ! ctx .RenderOptions .InStandalonePage {
198206 // for an external "DisplayInIFrame" render, it could only output its content in a standalone page
199207 // otherwise, a <iframe> should be outputted to embed the external rendered page
200208 return renderIFrame (ctx , output )
201209 }
202- // else: this is a standalone page, fallthrough to the real rendering
210+ // else: this is a standalone page, fallthrough to the real rendering, and add extra JS/CSS
211+ extraStyleHref := setting .AppSubURL + "/assets/css/external-render-iframe.css"
212+ extraScriptSrc := setting .AppSubURL + "/assets/js/external-render-iframe.js"
213+ // "<script>" must go before "<link>", to make Golang's http.DetectContentType() can still recognize the content as "text/html"
214+ extraHeadHTML = htmlutil .HTMLFormat (`<script src="%s"></script><link rel="stylesheet" href="%s">` , extraScriptSrc , extraStyleHref )
203215 }
204216
205217 ctx .usedByRender = true
206218 if ctx .RenderHelper != nil {
207219 defer ctx .RenderHelper .CleanUp ()
208220 }
209221
210- finalProcessor := ctx .RenderInternal .Init (output )
222+ finalProcessor := ctx .RenderInternal .Init (output , extraHeadHTML )
211223 defer finalProcessor .Close ()
212224
213225 // input -> (pw1=pr1) -> renderer -> (pw2=pr2) -> SanitizeReader -> finalProcessor -> output
0 commit comments