diff --git a/CHANGELOG.md b/CHANGELOG.md index 316c6d5..ed6227f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ Notable changes to Mailpit will be documented in this file. +## [v1.19.3] + +### Chore +- Update Go dependencies +- Display nicer noscript message when JavaScript is disabled + +### Fix +- **Security:** Prevent bypass of Contend Security Policy using stored XSS, and sanitize preview HTML data (DOMPurify) + + ## [v1.19.2] ### Chore diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..1a14729 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,19 @@ +# Reporting security vulnerabilities + +Your efforts to responsibly disclose your findings are appreciated. + +** **Please do _not_ report security vulnerabilities through public GitHub issues.** ** + +If you believe you have found a **security vulnerability**, then please report it to security@axllent.org so +your findings can be investigated, and if confirmed, fixed and released in a timely manner. + +Your report should include: + +- Mailpit version +- A vulnerability description +- Reproduction steps (if applicable) +- Any other details you think are likely to be important + +You should receive an initial acknowledgement within 24 hours in most cases, and will kept updated throughout the process. + +With your consent, your contributions will be publicly acknowledged. diff --git a/config/config.go b/config/config.go index 9d443b9..c2fdaa6 100644 --- a/config/config.go +++ b/config/config.go @@ -205,6 +205,9 @@ func VerifyConfig() error { cssFontRestriction = "'self'" } + // The default Content Security Policy is updates on every application page load to replace script-src 'self' + // with a random nonce ID to prevent XSS. This applies to the Mailpit app & API. + // See server.middleWareFunc() ContentSecurityPolicy = fmt.Sprintf("default-src 'self'; script-src 'self'; style-src %s 'unsafe-inline'; frame-src 'self'; img-src * data: blob:; font-src %s data:; media-src 'self'; connect-src 'self' ws: wss:; object-src 'none'; base-uri 'self';", cssFontRestriction, cssFontRestriction, ) diff --git a/go.mod b/go.mod index 567d696..4826937 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/PuerkitoBio/goquery v1.9.2 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de github.com/axllent/semver v0.0.1 - github.com/gomarkdown/markdown v0.0.0-20240626202925-2eda941fd024 + github.com/gomarkdown/markdown v0.0.0-20240723152757-afa4a469d4f9 github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.3 github.com/jhillyerd/enmime v1.2.0 @@ -28,7 +28,7 @@ require ( golang.org/x/text v0.16.0 golang.org/x/time v0.5.0 gopkg.in/yaml.v3 v3.0.1 - modernc.org/sqlite v1.30.2 + modernc.org/sqlite v1.31.1 ) require ( @@ -44,7 +44,7 @@ require ( github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -58,8 +58,8 @@ require ( golang.org/x/image v0.18.0 // indirect golang.org/x/sys v0.22.0 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect - modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect - modernc.org/libc v1.55.3 // indirect + modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e // indirect + modernc.org/libc v1.55.4 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.8.0 // indirect modernc.org/strutil v1.2.0 // indirect diff --git a/go.sum b/go.sum index 4d92bd5..e60efa4 100644 --- a/go.sum +++ b/go.sum @@ -23,8 +23,8 @@ github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= -github.com/gomarkdown/markdown v0.0.0-20240626202925-2eda941fd024 h1:saBP362Qm7zDdDXqv61kI4rzhmLFq3Z1gx34xpl6cWE= -github.com/gomarkdown/markdown v0.0.0-20240626202925-2eda941fd024/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/gomarkdown/markdown v0.0.0-20240723152757-afa4a469d4f9 h1:TRYrIWJziqvMVn1owO8bmkDJTlMQFYnf74yhD8LXfgU= +github.com/gomarkdown/markdown v0.0.0-20240723152757-afa4a469d4f9/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -63,8 +63,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mhale/smtpd v0.8.3 h1:8j8YNXajksoSLZja3HdwvYVZPuJSqAxFsib3adzRRt8= @@ -132,8 +132,8 @@ golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -184,8 +184,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -197,16 +197,16 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= -modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y= -modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s= +modernc.org/ccgo/v4 v4.20.4 h1:3pPOlMcblnu5CBU3w1BFtepwBnLezGjPYTH8xBeYZM8= +modernc.org/ccgo/v4 v4.20.4/go.mod h1:meYiLeaGpKQmHBw8roW4DXLkDvusG+MD7LJ/kYyAouU= modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= -modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= -modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b h1:BnN1t+pb1cy61zbvSUV7SeI0PwosMhlAEi/vBY4qxp8= -modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= -modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= -modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= +modernc.org/gc/v2 v2.4.3 h1:Ik4ZcMbC7aY4ZDPUhzXVXi7GMub9QcXLTfXn3mWpNw8= +modernc.org/gc/v2 v2.4.3/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= +modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e h1:WPC4v0rNIFb2PY+nBBEEKyugPPRHPzUgyN3xZPpGK58= +modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/libc v1.55.4 h1:iWzZ96v1Iut2Sm4lEp0yzFde20M9zpcI0wY3DFcb+8g= +modernc.org/libc v1.55.4/go.mod h1:GPuVtbWvXUo590z/xfVIQcOqnugb1WovSfMJWMe0ZfA= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= @@ -215,8 +215,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= -modernc.org/sqlite v1.30.2 h1:IPVVkhLu5mMVnS1dQgh3h0SAACRWcVk7aoLP9Us3UCk= -modernc.org/sqlite v1.30.2/go.mod h1:DUmsiWQDaAvU4abhc/N+djlom/L2o8f7gZ95RCvyoLU= +modernc.org/sqlite v1.31.1 h1:XVU0VyzxrYHlBhIs1DiEgSl0ZtdnPtbLVy8hSkzxGrs= +modernc.org/sqlite v1.31.1/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/package-lock.json b/package-lock.json index 6788fbf..fde6e5c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "bootstrap5-tags": "^1.6.1", "color-hash": "^2.0.2", "dayjs": "^1.11.10", + "dompurify": "^3.1.6", "ical.js": "^2.0.1", "modern-screenshot": "^4.4.30", "prismjs": "^1.29.0", @@ -1417,6 +1418,11 @@ "node": ">=8" } }, + "node_modules/dompurify": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", + "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==" + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", diff --git a/package.json b/package.json index d48725c..be6f5a1 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "bootstrap5-tags": "^1.6.1", "color-hash": "^2.0.2", "dayjs": "^1.11.10", + "dompurify": "^3.1.6", "ical.js": "^2.0.1", "modern-screenshot": "^4.4.30", "prismjs": "^1.29.0", diff --git a/server/server.go b/server/server.go index aee94d5..55dfae3 100644 --- a/server/server.go +++ b/server/server.go @@ -25,6 +25,7 @@ import ( "github.com/axllent/mailpit/server/pop3" "github.com/axllent/mailpit/server/websockets" "github.com/gorilla/mux" + "github.com/lithammer/shortuuid/v4" ) //go:embed ui @@ -75,11 +76,11 @@ func Listen() { } // UI shortcut - r.HandleFunc(config.Webroot+"view/latest", handlers.RedirectToLatestMessage).Methods("GET") + r.HandleFunc(config.Webroot+"view/latest", middleWareFunc(handlers.RedirectToLatestMessage)).Methods("GET") // frontend testing - r.HandleFunc(config.Webroot+"view/{id}.html", handlers.GetMessageHTML).Methods("GET") - r.HandleFunc(config.Webroot+"view/{id}.txt", handlers.GetMessageText).Methods("GET") + r.HandleFunc(config.Webroot+"view/{id}.html", middleWareFunc(handlers.GetMessageHTML)).Methods("GET") + r.HandleFunc(config.Webroot+"view/{id}.txt", middleWareFunc(handlers.GetMessageText)).Methods("GET") // web UI via virtual index.html r.PathPrefix(config.Webroot + "view/").Handler(middleWareFunc(index)).Methods("GET") @@ -179,7 +180,21 @@ func (w gzipResponseWriter) Write(b []byte) (int, error) { func middleWareFunc(fn http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Referrer-Policy", "no-referrer") - w.Header().Set("Content-Security-Policy", config.ContentSecurityPolicy) + + // generate a new random nonce on every request + randomNonce := shortuuid.New() + // header used to pass nonce through to function + r.Header.Set("mp-nonce", randomNonce) + + // Prevent JavaScript XSS by adding a nonce for script-src + cspHeader := strings.Replace( + config.ContentSecurityPolicy, + "script-src 'self';", + fmt.Sprintf("script-src 'nonce-%s';", randomNonce), + 1, + ) + + w.Header().Set("Content-Security-Policy", cspHeader) if AccessControlAllowOrigin != "" && strings.HasPrefix(r.RequestURI, config.Webroot+"api/") { w.Header().Set("Access-Control-Allow-Origin", AccessControlAllowOrigin) @@ -281,7 +296,7 @@ func swaggerBasePath(w http.ResponseWriter, _ *http.Request) { } // Just returns the default HTML template -func index(w http.ResponseWriter, _ *http.Request) { +func index(w http.ResponseWriter, r *http.Request) { var h = ` @@ -298,10 +313,12 @@ func index(w http.ResponseWriter, _ *http.Request) {
- +
- + ` @@ -314,9 +331,11 @@ func index(w http.ResponseWriter, _ *http.Request) { data := struct { Webroot string Version string + Nonce string }{ Webroot: config.Webroot, Version: config.Version, + Nonce: r.Header.Get("mp-nonce"), } buff := new(bytes.Buffer) diff --git a/server/ui-src/components/message/Message.vue b/server/ui-src/components/message/Message.vue index c8c80af..e826fc4 100644 --- a/server/ui-src/components/message/Message.vue +++ b/server/ui-src/components/message/Message.vue @@ -9,6 +9,7 @@ import Tags from 'bootstrap5-tags' import { Tooltip } from 'bootstrap' import commonMixins from '../../mixins/CommonMixins' import { mailbox } from '../../stores/mailbox' +import DOMPurify from 'dompurify' export default { props: { @@ -73,6 +74,57 @@ export default { return (mailbox.showHTMLCheck && this.message.HTML) || mailbox.showLinkCheck || (mailbox.showSpamCheck && mailbox.uiConfig.SpamAssassin) + }, + + // remove bad HTML, JavaScript, iframes etc + sanitizedHTML() { + DOMPurify.addHook('afterSanitizeAttributes', (node) => { + if (node.hasAttribute('href') && node.getAttribute('href').substring(0, 1) == '#') { + return + } + if ('target' in node) { + node.setAttribute('target', '_blank'); + node.setAttribute('rel', 'noopener noreferrer'); + } + if (!node.hasAttribute('target') && (node.hasAttribute('xlink:href') || node.hasAttribute('href'))) { + node.setAttribute('xlink:show', '_blank'); + } + }); + + const clean = DOMPurify.sanitize( + this.message.HTML, + { + WHOLE_DOCUMENT: true, + SANITIZE_DOM: false, + ADD_TAGS: [ + 'link', + 'meta', + 'o:p', + 'style', + ], + ADD_ATTR: [ + 'bordercolor', + 'charset', + 'content', + 'hspace', + 'http-equiv', + 'itemprop', + 'itemscope', + 'itemtype', + 'link', + 'vertical-align', + 'vlink', + 'vspace', + 'xml:lang' + ], + FORBID_ATTR: ['script'], + } + ) + + // for debugging + // this.debugDOMPurify(DOMPurify.removed) + + return clean } }, @@ -133,7 +185,7 @@ export default { // delay 0.2s until vue has rendered the iframe content window.setTimeout(() => { let p = document.getElementById('preview-html') - if (p) { + if (p && typeof p.contentWindow.document.body != 'undefined') { // make links open in new window let anchorEls = p.contentWindow.document.body.querySelectorAll('a') for (var i = 0; i < anchorEls.length; i++) { @@ -185,9 +237,31 @@ export default { this.resizeIframe(el) }, - sanitizeHTML(h) { - // remove tag if set - return h.replace(//mi, '') + // this function is unused but kept here to use for debugging + debugDOMPurify(removed) { + if (!removed.length) { + return + } + + const ignoreNodes = ['target', 'base', 'script', 'v:shapes'] + + let d = removed.filter((r) => { + if (typeof r.attribute != 'undefined' && + (ignoreNodes.includes(r.attribute.nodeName) || r.attribute.nodeName.startsWith('xmlns:')) + ) { + return false + } + // inline comments + if (typeof r.element != 'undefined' && (r.element.nodeType == 8 || r.element.tagName == 'SCRIPT')) { + return false + } + + return true + }) + + if (d.length) { + console.log(d) + } }, saveTags() { @@ -292,7 +366,7 @@ export default { Bcc - + {{ t.Name }} < @@ -510,9 +584,8 @@ export default {