@@ -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