mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-10 01:01:28 +02:00
Fix script error alert (#37458)
After using CSP nonce, the "onerror" doesn't work anymore. Change it to use a global variable to detect Also help users like #37379 to catch errors more easily. Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
parent
6da8027446
commit
89d358d8a7
@ -5,13 +5,11 @@ package context
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"html"
|
"html"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/httplib"
|
"code.gitea.io/gitea/modules/httplib"
|
||||||
@ -91,31 +89,14 @@ func (c TemplateContext) AppFullLink(link ...string) template.URL {
|
|||||||
return template.URL(s + "/" + strings.TrimPrefix(link[0], "/"))
|
return template.URL(s + "/" + strings.TrimPrefix(link[0], "/"))
|
||||||
}
|
}
|
||||||
|
|
||||||
var globalVars = sync.OnceValue(func() (ret struct {
|
|
||||||
scriptImportRemainingPart string
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
// add onerror handler to alert users when the script fails to load:
|
|
||||||
// * for end users: there were many users reporting that "UI doesn't work", actually they made mistakes in their config
|
|
||||||
// * for developers: help them to remember to run "make watch-frontend" to build frontend assets
|
|
||||||
// the message will be directly put in the onerror JS code's string
|
|
||||||
onScriptErrorPrompt := `Please make sure the asset files can be accessed.`
|
|
||||||
if !setting.IsProd {
|
|
||||||
onScriptErrorPrompt += `\n\nFor development, run: make watch-frontend.`
|
|
||||||
}
|
|
||||||
onScriptErrorJS := fmt.Sprintf(`alert('Failed to load asset file from ' + this.src + '. %s')`, onScriptErrorPrompt)
|
|
||||||
ret.scriptImportRemainingPart = `onerror="` + html.EscapeString(onScriptErrorJS) + `"></script>`
|
|
||||||
return ret
|
|
||||||
})
|
|
||||||
|
|
||||||
func (c TemplateContext) ScriptImport(path string, typ ...string) template.HTML {
|
func (c TemplateContext) ScriptImport(path string, typ ...string) template.HTML {
|
||||||
if len(typ) > 0 {
|
if len(typ) > 0 {
|
||||||
if typ[0] == "module" {
|
if typ[0] == "module" {
|
||||||
return template.HTML(`<script nonce="` + c.CspScriptNonce() + `" type="module" src="` + html.EscapeString(public.AssetURI(path)) + `" ` + globalVars().scriptImportRemainingPart)
|
return template.HTML(`<script nonce="` + c.CspScriptNonce() + `" type="module" src="` + html.EscapeString(public.AssetURI(path)) + `"></script>`)
|
||||||
}
|
}
|
||||||
panic("unsupported script type: " + typ[0])
|
panic("unsupported script type: " + typ[0])
|
||||||
}
|
}
|
||||||
return template.HTML(`<script nonce="` + c.CspScriptNonce() + `" src="` + html.EscapeString(public.AssetURI(path)) + `" ` + globalVars().scriptImportRemainingPart)
|
return template.HTML(`<script nonce="` + c.CspScriptNonce() + `" src="` + html.EscapeString(public.AssetURI(path)) + `"></script>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c TemplateContext) CspScriptNonce() (ret string) {
|
func (c TemplateContext) CspScriptNonce() (ret string) {
|
||||||
|
|||||||
@ -11,5 +11,8 @@
|
|||||||
{{template "base/footer_content" .}}
|
{{template "base/footer_content" .}}
|
||||||
{{ctx.ScriptImport "js/index.js" "module"}}
|
{{ctx.ScriptImport "js/index.js" "module"}}
|
||||||
{{template "custom/footer" .}}
|
{{template "custom/footer" .}}
|
||||||
|
<script nonce="{{ctx.CspScriptNonce}}" type="module">
|
||||||
|
if (!window.config?.frontendInited) alert("Frontend is not initialized, check console errors or asset files.")
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
1
web_src/js/globals.d.ts
vendored
1
web_src/js/globals.d.ts
vendored
@ -53,6 +53,7 @@ interface Window {
|
|||||||
enableTimeTracking: boolean,
|
enableTimeTracking: boolean,
|
||||||
mermaidMaxSourceCharacters: number,
|
mermaidMaxSourceCharacters: number,
|
||||||
i18n: Record<string, string>,
|
i18n: Record<string, string>,
|
||||||
|
frontendInited: boolean,
|
||||||
},
|
},
|
||||||
$: JQueryStatic,
|
$: JQueryStatic,
|
||||||
jQuery: JQueryStatic,
|
jQuery: JQueryStatic,
|
||||||
|
|||||||
@ -171,3 +171,5 @@ const initDur = performance.now() - initStartTime;
|
|||||||
if (initDur > 500) {
|
if (initDur > 500) {
|
||||||
console.error(`slow init functions took ${initDur.toFixed(3)}ms`);
|
console.error(`slow init functions took ${initDur.toFixed(3)}ms`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.config.frontendInited = true;
|
||||||
|
|||||||
@ -12,6 +12,7 @@ window.config = {
|
|||||||
enableTimeTracking: true,
|
enableTimeTracking: true,
|
||||||
mermaidMaxSourceCharacters: 5000,
|
mermaidMaxSourceCharacters: 5000,
|
||||||
i18n: {},
|
i18n: {},
|
||||||
|
frontendInited: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
window.testModules = {};
|
window.testModules = {};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user