From faded05e47c57116328defc7de9c87bcd58be566 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Sat, 13 Apr 2024 00:25:04 +1200 Subject: [PATCH 01/16] Feature: Add UI settings screen --- package-lock.json | 6 + package.json | 1 + server/ui-src/App.vue | 2 - server/ui-src/assets/styles.scss | 18 +-- server/ui-src/components/AboutMailpit.vue | 117 ++++------------- server/ui-src/components/Settings.vue | 119 ++++++++++++++++++ .../ui-src/components/message/HTMLCheck.vue | 76 ++--------- server/ui-src/components/message/Message.vue | 38 +++--- .../components/message/SpamAssassin.vue | 6 +- server/ui-src/stores/mailbox.js | 53 +++++++- 10 files changed, 251 insertions(+), 185 deletions(-) create mode 100644 server/ui-src/components/Settings.vue diff --git a/package-lock.json b/package-lock.json index 6d757e1ca..2be1bf893 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "moment": "^2.29.4", "prismjs": "^1.29.0", "rapidoc": "^9.3.4", + "timezones-list": "^3.0.3", "vue": "^3.2.13", "vue-css-donut-chart": "^2.0.0", "vue-router": "^4.2.4" @@ -3559,6 +3560,11 @@ "node": ">=6" } }, + "node_modules/timezones-list": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/timezones-list/-/timezones-list-3.0.3.tgz", + "integrity": "sha512-C+Vdvvj2c1xB6pu81pOX8geo6mrk/QsudFVlTVQET7QQwu8WAIyhDNeCrK5grU7EMzmbKLWqz7uU6dN8fvQvPQ==" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", diff --git a/package.json b/package.json index 9b2b43c72..dfcdf3d9d 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "moment": "^2.29.4", "prismjs": "^1.29.0", "rapidoc": "^9.3.4", + "timezones-list": "^3.0.3", "vue": "^3.2.13", "vue-css-donut-chart": "^2.0.0", "vue-router": "^4.2.4" diff --git a/server/ui-src/App.vue b/server/ui-src/App.vue index 08a85b6a8..200d91760 100644 --- a/server/ui-src/App.vue +++ b/server/ui-src/App.vue @@ -15,8 +15,6 @@ export default { beforeMount() { document.title = document.title + ' - ' + location.hostname - mailbox.showTagColors = !localStorage.getItem('hideTagColors') == '1' - mailbox.timeZone = localStorage.getItem('timezone') ? localStorage.getItem('timezone') : Intl.DateTimeFormat().resolvedOptions().timeZone; // load global config this.get(this.resolve('/api/v1/webui'), false, function (response) { diff --git a/server/ui-src/assets/styles.scss b/server/ui-src/assets/styles.scss index d3d4b2f83..cdd22d831 100644 --- a/server/ui-src/assets/styles.scss +++ b/server/ui-src/assets/styles.scss @@ -320,16 +320,18 @@ body.blur { display: none; } -.form-control.dropdown { - padding: 0; - border: 0; +#message-view { + .form-control.dropdown { + padding: 0; + border: 0; - input { - font-size: 0.875em; - } + input { + font-size: 0.875em; + } - div { - cursor: text; // html5-tags + div { + cursor: text; // html5-tags + } } } diff --git a/server/ui-src/components/AboutMailpit.vue b/server/ui-src/components/AboutMailpit.vue index 38d04bde8..eae4d2fc4 100644 --- a/server/ui-src/components/AboutMailpit.vue +++ b/server/ui-src/components/AboutMailpit.vue @@ -1,5 +1,6 @@ + + diff --git a/server/ui-src/components/message/HTMLCheck.vue b/server/ui-src/components/message/HTMLCheck.vue index 57c81090c..805cc1c37 100644 --- a/server/ui-src/components/message/HTMLCheck.vue +++ b/server/ui-src/components/message/HTMLCheck.vue @@ -20,7 +20,6 @@ export default { data() { return { error: false, - enabled: true, check: false, platforms: [], allPlatforms: { @@ -37,7 +36,6 @@ export default { }, mounted() { - this.enabled = !localStorage.getItem('htmlCheckDisabled') this.loadConfig() this.doCheck() }, @@ -46,7 +44,7 @@ export default { summary: function () { let self = this - if (!this.enabled || !this.check) { + if (!this.check) { return false } @@ -199,23 +197,19 @@ export default { platforms(v) { localStorage.setItem('html-check-platforms', JSON.stringify(v)) }, - enabled(v) { - if (!v) { - localStorage.setItem('htmlCheckDisabled', true) - this.$emit('setHtmlScore', false) - } else { - localStorage.removeItem('htmlCheckDisabled') - this.doCheck() - } - } + // enabled(v) { + // if (!v) { + // localStorage.setItem('htmlCheckDisabled', true) + // this.$emit('setHtmlScore', false) + // } else { + // localStorage.removeItem('htmlCheckDisabled') + // this.doCheck() + // } + // } }, methods: { doCheck: function () { - if (!this.enabled) { - return - } - this.check = false if (this.message.HTML == "") { @@ -314,20 +308,6 @@ export default { - - - - diff --git a/server/ui-src/components/message/Message.vue b/server/ui-src/components/message/Message.vue index fcb746865..3a5faf338 100644 --- a/server/ui-src/components/message/Message.vue +++ b/server/ui-src/components/message/Message.vue @@ -69,6 +69,14 @@ export default { } }, + computed: { + hasAnyChecksEnabled: function() { + return (mailbox.showHTMLCheck && this.message.HTML) + || mailbox.showLinkCheck + || (mailbox.showSpamCheck && mailbox.uiConfig.SpamAssassin) + } + }, + mounted() { let self = this self.canSaveTags = false @@ -263,7 +271,7 @@ export default { To - + {{ t.Name }} @@ -278,7 +286,7 @@ export default { Cc - + {{ t.Name }} < @@ -423,16 +431,16 @@ export default { role="tab" aria-controls="nav-raw" aria-selected="false"> Raw - diff --git a/server/ui-src/components/message/SpamAssassin.vue b/server/ui-src/components/message/SpamAssassin.vue index 739789634..7f135ed9a 100644 --- a/server/ui-src/components/message/SpamAssassin.vue +++ b/server/ui-src/components/message/SpamAssassin.vue @@ -122,7 +122,11 @@ export default { value: p, color: c }, - ]; + ] + }, + + scoreColor: function() { + return this.graphSections[0].color }, } } diff --git a/server/ui-src/stores/mailbox.js b/server/ui-src/stores/mailbox.js index 3cf368412..96301593c 100644 --- a/server/ui-src/stores/mailbox.js +++ b/server/ui-src/stores/mailbox.js @@ -9,7 +9,6 @@ export const mailbox = reactive({ count: 0, // total in mailbox or search messages: [], // current messages tags: [], // all tags - showTagColors: true, // show/hide tag colors selected: [], // currently selected connected: false, // websocket connection searching: false, // current search, false for none @@ -19,7 +18,13 @@ export const mailbox = reactive({ appInfo: {}, // application information uiConfig: {}, // configuration for UI lastMessage: false, // return scrolling - timeZone: '', // browser timezone + + // settings + showTagColors: !localStorage.getItem('hideTagColors') == '1', + showHTMLCheck: !localStorage.getItem('hideHTMLCheck') == '1', + showLinkCheck: !localStorage.getItem('hideLinkCheck') == '1', + showSpamCheck: !localStorage.getItem('hideSpamCheck') == '1', + timeZone: localStorage.getItem('timeZone') ? localStorage.getItem('timeZone') : Intl.DateTimeFormat().resolvedOptions().timeZone, }) watch( @@ -39,3 +44,47 @@ watch( } } ) + +watch( + () => mailbox.showHTMLCheck, + (v) => { + if (v) { + localStorage.removeItem('hideHTMLCheck') + } else { + localStorage.setItem('hideHTMLCheck', '1') + } + } +) + +watch( + () => mailbox.showLinkCheck, + (v) => { + if (v) { + localStorage.removeItem('hideLinkCheck') + } else { + localStorage.setItem('hideLinkCheck', '1') + } + } +) + +watch( + () => mailbox.showSpamCheck, + (v) => { + if (v) { + localStorage.removeItem('hideSpamCheck') + } else { + localStorage.setItem('hideSpamCheck', '1') + } + } +) + +watch( + () => mailbox.timeZone, + (v) => { + if (v == Intl.DateTimeFormat().resolvedOptions().timeZone) { + localStorage.removeItem('timeZone') + } else { + localStorage.setItem('timeZone', v) + } + } +) From 31e4f84f9a2b5bdc33a4b49c4b668bb4447af278 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Sat, 13 Apr 2024 00:25:48 +1200 Subject: [PATCH 02/16] Chore: Remove deprecated --disable-html-check option --- cmd/root.go | 12 ++++++++---- config/config.go | 11 ++++++++--- server/apiv1/webui.go | 4 ---- server/server.go | 4 +--- server/ui/api/v1/swagger.json | 4 ---- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index e38c5dc44..b6e2bc1e4 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -96,7 +96,6 @@ func init() { rootCmd.Flags().StringVar(&config.UITLSCert, "ui-tls-cert", config.UITLSCert, "TLS certificate for web UI (HTTPS) - requires ui-tls-key") rootCmd.Flags().StringVar(&config.UITLSKey, "ui-tls-key", config.UITLSKey, "TLS key for web UI (HTTPS) - requires ui-tls-cert") rootCmd.Flags().StringVar(&server.AccessControlAllowOrigin, "api-cors", server.AccessControlAllowOrigin, "Set API CORS Access-Control-Allow-Origin header") - rootCmd.Flags().BoolVar(&config.DisableHTMLCheck, "disable-html-check", config.DisableHTMLCheck, "Disable the HTML check functionality (web UI & API)") rootCmd.Flags().BoolVar(&config.BlockRemoteCSSAndFonts, "block-remote-css-and-fonts", config.BlockRemoteCSSAndFonts, "Block access to remote CSS & fonts") rootCmd.Flags().StringVar(&config.EnableSpamAssassin, "enable-spamassassin", config.EnableSpamAssassin, "Enable integration with SpamAssassin") rootCmd.Flags().BoolVar(&config.AllowUntrustedTLS, "allow-untrusted-tls", config.AllowUntrustedTLS, "Do not verify HTTPS certificates (link checker & screenshots)") @@ -155,6 +154,10 @@ func init() { rootCmd.Flags().BoolVar(&config.SMTPRequireSTARTTLS, "smtp-tls-required", config.SMTPRequireSTARTTLS, "smtp-require-starttls") rootCmd.Flags().Lookup("smtp-tls-required").Hidden = true rootCmd.Flags().Lookup("smtp-tls-required").Deprecated = "use --smtp-require-starttls" + + // DEPRECATED FLAG 2024/04/13 - no longer used + rootCmd.Flags().BoolVar(&config.DisableHTMLCheck, "disable-html-check", config.DisableHTMLCheck, "Disable the HTML check functionality (web UI & API)") + rootCmd.Flags().Lookup("disable-html-check").Hidden = true } // Load settings from environment @@ -201,9 +204,6 @@ func initConfigFromEnv() { if len(os.Getenv("MP_API_CORS")) > 0 { server.AccessControlAllowOrigin = os.Getenv("MP_API_CORS") } - if getEnabledFromEnv("MP_DISABLE_HTML_CHECK") { - config.DisableHTMLCheck = true - } if getEnabledFromEnv("MP_BLOCK_REMOTE_CSS_AND_FONTS") { config.BlockRemoteCSSAndFonts = true } @@ -333,6 +333,10 @@ func initDeprecatedConfigFromEnv() { logger.Log().Warn("ENV MP_SMTP_TLS_REQUIRED has been deprecated, use MP_SMTP_REQUIRE_STARTTLS") config.SMTPRequireSTARTTLS = true } + if getEnabledFromEnv("MP_DISABLE_HTML_CHECK") { + logger.Log().Warn("ENV MP_DISABLE_HTML_CHECK has been deprecated and is no longer used") + config.DisableHTMLCheck = true + } } // Wrapper to get a boolean from an environment variable diff --git a/config/config.go b/config/config.go index c5522cbcb..019b9f49a 100644 --- a/config/config.go +++ b/config/config.go @@ -83,9 +83,6 @@ var ( // IgnoreDuplicateIDs will skip messages with the same ID IgnoreDuplicateIDs bool - // DisableHTMLCheck used to disable the HTML check in bother the API and web UI - DisableHTMLCheck = false - // BlockRemoteCSSAndFonts used to disable remote CSS & fonts BlockRemoteCSSAndFonts = false @@ -153,6 +150,9 @@ var ( // RepoBinaryName on Github for updater RepoBinaryName = "mailpit" + + // DisableHTMLCheck DEPRECATED 2024/04/13 - kept here to display console warning only + DisableHTMLCheck = false ) // AutoTag struct for auto-tagging @@ -361,6 +361,11 @@ func VerifyConfig() error { return fmt.Errorf("webhook URL does not appear to be a valid URL (%s)", WebhookURL) } + // DEPRECATED 2024/04/13 + if DisableHTMLCheck { + logger.Log().Warn("--disable-html-check has been deprecated and is no longer used") + } + if EnableSpamAssassin != "" { spamassassin.SetService(EnableSpamAssassin) logger.Log().Infof("[spamassassin] enabled via %s", EnableSpamAssassin) diff --git a/server/apiv1/webui.go b/server/apiv1/webui.go index 0b134c39b..40015f8cc 100644 --- a/server/apiv1/webui.go +++ b/server/apiv1/webui.go @@ -27,9 +27,6 @@ type webUIConfiguration struct { RecipientAllowlist string } - // Whether the HTML check has been globally disabled - DisableHTMLCheck bool - // Whether SpamAssassin is enabled SpamAssassin bool @@ -65,7 +62,6 @@ func WebUIConfig(w http.ResponseWriter, _ *http.Request) { conf.MessageRelay.RecipientAllowlist = config.SMTPRelayConfig.AllowedRecipients } - conf.DisableHTMLCheck = config.DisableHTMLCheck conf.SpamAssassin = config.EnableSpamAssassin != "" conf.DuplicatesIgnored = config.IgnoreDuplicateIDs diff --git a/server/server.go b/server/server.go index cd4ddb85b..04713957c 100644 --- a/server/server.go +++ b/server/server.go @@ -129,9 +129,7 @@ func apiRoutes() *mux.Router { r.HandleFunc(config.Webroot+"api/v1/message/{id}/headers", middleWareFunc(apiv1.GetHeaders)).Methods("GET") r.HandleFunc(config.Webroot+"api/v1/message/{id}/raw", middleWareFunc(apiv1.DownloadRaw)).Methods("GET") r.HandleFunc(config.Webroot+"api/v1/message/{id}/release", middleWareFunc(apiv1.ReleaseMessage)).Methods("POST") - if !config.DisableHTMLCheck { - r.HandleFunc(config.Webroot+"api/v1/message/{id}/html-check", middleWareFunc(apiv1.HTMLCheck)).Methods("GET") - } + r.HandleFunc(config.Webroot+"api/v1/message/{id}/html-check", middleWareFunc(apiv1.HTMLCheck)).Methods("GET") r.HandleFunc(config.Webroot+"api/v1/message/{id}/link-check", middleWareFunc(apiv1.LinkCheck)).Methods("GET") if config.EnableSpamAssassin != "" { r.HandleFunc(config.Webroot+"api/v1/message/{id}/sa-check", middleWareFunc(apiv1.SpamAssassinCheck)).Methods("GET") diff --git a/server/ui/api/v1/swagger.json b/server/ui/api/v1/swagger.json index 74cc14554..c991ee001 100644 --- a/server/ui/api/v1/swagger.json +++ b/server/ui/api/v1/swagger.json @@ -1401,10 +1401,6 @@ "description": "Response includes global web UI settings", "type": "object", "properties": { - "DisableHTMLCheck": { - "description": "Whether the HTML check has been globally disabled", - "type": "boolean" - }, "DuplicatesIgnored": { "description": "Whether messages with duplicate IDs are ignored", "type": "boolean" From 845fe840d49bb5605ee84520889f7d36e714db24 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Sat, 13 Apr 2024 00:29:23 +1200 Subject: [PATCH 03/16] Chore: Move Link check & HTML check features out of beta --- server/apiv1/api.go | 6 ------ server/ui-src/components/message/HTMLCheck.vue | 4 ---- server/ui-src/components/message/LinkCheck.vue | 9 --------- server/ui/api/v1/swagger.json | 4 ++-- 4 files changed, 2 insertions(+), 21 deletions(-) diff --git a/server/apiv1/api.go b/server/apiv1/api.go index a37d02179..700721503 100644 --- a/server/apiv1/api.go +++ b/server/apiv1/api.go @@ -729,9 +729,6 @@ func HTMLCheck(w http.ResponseWriter, r *http.Request) { // // Returns the summary of the message HTML checker. // - // NOTE: This feature is currently in beta and is documented for reference only. - // Please do not integrate with it (yet) as there may be changes. - // // Produces: // - application/json // @@ -784,9 +781,6 @@ func LinkCheck(w http.ResponseWriter, r *http.Request) { // // Returns the summary of the message Link checker. // - // NOTE: This feature is currently in beta and is documented for reference only. - // Please do not integrate with it (yet) as there may be changes. - // // Produces: // - application/json // diff --git a/server/ui-src/components/message/HTMLCheck.vue b/server/ui-src/components/message/HTMLCheck.vue index 805cc1c37..f19482660 100644 --- a/server/ui-src/components/message/HTMLCheck.vue +++ b/server/ui-src/components/message/HTMLCheck.vue @@ -476,10 +476,6 @@ export default {