From 9d5fb816c937114966d4f589e1ad4e164ff3a187 Mon Sep 17 00:00:00 2001 From: Andris Reinman Date: Sun, 19 Mar 2017 13:39:34 +0200 Subject: [PATCH 1/8] Fixes issue with HTML entities --- lib/tools.js | 7 +++++-- package.json | 16 ++++++++-------- routes/archive.js | 5 ++++- services/sender.js | 2 +- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/tools.js b/lib/tools.js index 4fc8b396..edd43296 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -6,6 +6,7 @@ let Isemail = require('isemail'); let urllib = require('url'); let juice = require('juice'); let jsdom = require('jsdom'); +let he = require('he'); let _ = require('./translate')._; let util = require('util'); @@ -169,7 +170,7 @@ function getMessageLinks(serviceUrl, campaign, list, subscription) { }; } -function formatMessage(serviceUrl, campaign, list, subscription, message, filter) { +function formatMessage(serviceUrl, campaign, list, subscription, message, filter, isHTML) { filter = typeof filter === 'function' ? filter : (str => str); let links = getMessageLinks(serviceUrl, campaign, list, subscription); @@ -180,7 +181,9 @@ function formatMessage(serviceUrl, campaign, list, subscription, message, filter return links[key]; } if (subscription.mergeTags.hasOwnProperty(key)) { - return subscription.mergeTags[key]; + return isHTML ? he.encode(subscription.mergeTags[key], { + useNamedReferences: true + }) : subscription.mergeTags[key]; } return false; }; diff --git a/package.json b/package.json index dab0933f..b6db168b 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "async": "^2.1.5", - "aws-sdk": "^2.24.0", + "aws-sdk": "^2.28.0", "bcrypt-nodejs": "0.0.3", "body-parser": "^1.17.1", "bounce-handler": "^7.3.2-fork.2", @@ -64,7 +64,7 @@ "is-url": "^1.2.2", "isemail": "^2.2.1", "jquery-file-upload-middleware": "^0.1.8", - "jsdom": "^9.11.0", + "jsdom": "^9.12.0", "juice": "^4.0.2", "libmime": "^3.1.0", "marked": "^0.3.6", @@ -75,22 +75,22 @@ "multer": "^1.3.0", "multiparty": "^4.1.3", "mysql": "^2.13.0", - "node-gettext": "^2.0.0-rc.0", + "node-gettext": "^2.0.0-rc.1", "node-mocks-http": "^1.6.1", - "nodemailer": "^3.1.5", + "nodemailer": "^3.1.7", "nodemailer-openpgp": "^1.0.2", "npmlog": "^4.0.2", - "openpgp": "^2.4.0", + "openpgp": "^2.5.1", "passport": "^0.3.2", "passport-local": "^1.0.0", "premailer-api": "^1.0.4", "redfour": "^1.0.0", - "redis": "^2.6.5", - "request": "^2.80.0", + "redis": "^2.7.1", + "request": "^2.81.0", "serve-favicon": "^2.4.1", "shortid": "^2.2.8", "slugify": "^1.1.0", - "smtp-server": "^2.0.2", + "smtp-server": "^2.0.3", "striptags": "^3.0.1", "toml": "^2.3.2" } diff --git a/routes/archive.js b/routes/archive.js index df384379..bd005db1 100644 --- a/routes/archive.js +++ b/routes/archive.js @@ -67,7 +67,7 @@ router.get('/:campaign/:list/:subscription', passport.csrfProtection, (req, res, let render = (view, layout) => { res.render(view, { layout, - message: renderTags ? tools.formatMessage(serviceUrl, campaign, list, subscription, html) : html, + message: renderTags ? tools.formatMessage(serviceUrl, campaign, list, subscription, html, false, true) : html, campaign, list, subscription, @@ -80,6 +80,9 @@ router.get('/:campaign/:list/:subscription', passport.csrfProtection, (req, res, res.render('partials/tracking-scripts', { layout: 'archive/layout-raw' }, (err, scripts) => { + if (err) { + return next(err); + } html = scripts ? html.replace(/<\/body\b/i, match => scripts + match) : html; render('archive/view-raw', 'archive/layout-raw'); }); diff --git a/services/sender.js b/services/sender.js index a76dafa4..400168bb 100644 --- a/services/sender.js +++ b/services/sender.js @@ -371,7 +371,7 @@ function formatMessage(message, callback) { let campaignAddress = [campaign.cid, list.cid, message.subscription.cid].join('.'); - let renderedHtml = renderTags ? tools.formatMessage(configItems.serviceUrl, campaign, list, message.subscription, html) : html; + let renderedHtml = renderTags ? tools.formatMessage(configItems.serviceUrl, campaign, list, message.subscription, html, false, true) : html; let renderedText = (text || '').trim() ? (renderTags ? tools.formatMessage(configItems.serviceUrl, campaign, list, message.subscription, text) : text) : htmlToText.fromString(renderedHtml, { wordwrap: 130 From 0879fa412a2d4a417aeca5cd5092a8f86531e7ef Mon Sep 17 00:00:00 2001 From: Andris Reinman Date: Sun, 19 Mar 2017 14:06:34 +0200 Subject: [PATCH 2/8] force template html as html code, not an url or file path ensure that external resources are not loaded by jsdom --- lib/tools.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/tools.js b/lib/tools.js index edd43296..6dbf3a44 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -199,8 +199,13 @@ function prepareHtml(html, callback) { if (!(html || '').toString().trim()) { return callback(null, false); } - - jsdom.env(html, (err, win) => { + jsdom.env(false, false, { + html, + features: { + FetchExternalResources: false, // disables resource loading over HTTP / filesystem + ProcessExternalResources: false // do not execute JS within script blocks + } + }, (err, win) => { if (err) { return callback(err); } From ae6affda8193f034e06f7e095ee23821a83d5190 Mon Sep 17 00:00:00 2001 From: Andris Reinman Date: Sun, 19 Mar 2017 14:22:44 +0200 Subject: [PATCH 3/8] do not allow script tags in description html --- lib/models/campaigns.js | 6 ++++++ lib/models/lists.js | 6 ++++++ lib/models/templates.js | 6 ++++++ lib/tools.js | 13 +++++++++++++ package.json | 1 + 5 files changed, 32 insertions(+) diff --git a/lib/models/campaigns.js b/lib/models/campaigns.js index b71d1bbf..98a2a896 100644 --- a/lib/models/campaigns.js +++ b/lib/models/campaigns.js @@ -619,6 +619,9 @@ module.exports.create = (campaign, opts, callback) => { Object.keys(campaign).forEach(key => { let value = typeof campaign[key] === 'number' ? campaign[key] : (campaign[key] || '').toString().trim(); key = tools.toDbKey(key); + if (key === 'description') { + value = tools.purifyHTML(value); + } if (allowedKeys.indexOf(key) >= 0 && keys.indexOf(key) < 0) { keys.push(key); values.push(value); @@ -791,6 +794,9 @@ module.exports.update = (id, updates, callback) => { Object.keys(campaign).forEach(key => { let value = typeof campaign[key] === 'number' ? campaign[key] : (campaign[key] || '').toString().trim(); key = tools.toDbKey(key); + if (key === 'description') { + value = tools.purifyHTML(value); + } if (allowedKeys.indexOf(key) >= 0 && keys.indexOf(key) < 0) { keys.push(key); values.push(value); diff --git a/lib/models/lists.js b/lib/models/lists.js index 4d58952c..97db2210 100644 --- a/lib/models/lists.js +++ b/lib/models/lists.js @@ -123,6 +123,9 @@ module.exports.create = (list, callback) => { Object.keys(list).forEach(key => { let value = list[key].trim(); key = tools.toDbKey(key); + if (key === 'description') { + value = tools.purifyHTML(value); + } if (allowedKeys.indexOf(key) >= 0) { keys.push(key); values.push(value); @@ -182,6 +185,9 @@ module.exports.update = (id, updates, callback) => { Object.keys(updates).forEach(key => { let value = updates[key].trim(); key = tools.toDbKey(key); + if (key === 'description') { + value = tools.purifyHTML(value); + } if (allowedKeys.indexOf(key) >= 0) { keys.push(key); values.push(value); diff --git a/lib/models/templates.js b/lib/models/templates.js index 0753a87f..4171ebb1 100644 --- a/lib/models/templates.js +++ b/lib/models/templates.js @@ -88,6 +88,9 @@ module.exports.create = (template, callback) => { Object.keys(template).forEach(key => { let value = template[key].trim(); key = tools.toDbKey(key); + if (key === 'description') { + value = tools.purifyHTML(value); + } if (allowedKeys.indexOf(key) >= 0) { keys.push(key); values.push(value); @@ -133,6 +136,9 @@ module.exports.update = (id, updates, callback) => { Object.keys(updates).forEach(key => { let value = updates[key].trim(); key = tools.toDbKey(key); + if (key === 'description') { + value = tools.purifyHTML(value); + } if (allowedKeys.indexOf(key) >= 0) { keys.push(key); values.push(value); diff --git a/lib/tools.js b/lib/tools.js index 6dbf3a44..e80b8d4a 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -9,6 +9,7 @@ let jsdom = require('jsdom'); let he = require('he'); let _ = require('./translate')._; let util = require('util'); +let createDOMPurify = require('dompurify'); let blockedUsers = ['abuse', 'admin', 'billing', 'compliance', 'devnull', 'dns', 'ftp', 'hostmaster', 'inoc', 'ispfeedback', 'ispsupport', 'listrequest', 'list', 'maildaemon', 'noc', 'noreply', 'noreply', 'null', 'phish', 'phishing', 'postmaster', 'privacy', 'registrar', 'root', 'security', 'spam', 'support', 'sysadmin', 'tech', 'undisclosedrecipients', 'unsubscribe', 'usenet', 'uucp', 'webmaster', 'www']; @@ -23,6 +24,7 @@ module.exports = { formatMessage, getMessageLinks, prepareHtml, + purifyHTML, workers: new Set() }; @@ -232,3 +234,14 @@ function prepareHtml(html, callback) { return callback(null, juice(preparedHtml)); }); } + +function purifyHTML(html) { + let win = jsdom.jsdom('', { + features: { + FetchExternalResources: false, // disables resource loading over HTTP / filesystem + ProcessExternalResources: false // do not execute JS within script blocks + } + }).defaultView; + let DOMPurify = createDOMPurify(win); + return DOMPurify.sanitize(html); +} diff --git a/package.json b/package.json index b6db168b..f60bb525 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "csurf": "^1.9.0", "csv-generate": "^1.0.0", "csv-parse": "^1.2.0", + "dompurify": "^0.8.5", "escape-html": "^1.0.3", "express": "^4.15.2", "express-session": "^1.15.1", From 77aded3125e5a67bf042c2679d97f96eb2b18393 Mon Sep 17 00:00:00 2001 From: Andris Reinman Date: Sun, 19 Mar 2017 14:29:34 +0200 Subject: [PATCH 4/8] v1.23.0 --- CHANGELOG.txt | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 81317b68..8b94b01b 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,12 @@ # Changelog +## 1.23.0 2017-03-19 + + * Fixed security issue where description tags were able to include script tags. Reported by Andreas Lindh. Fixed with [ae6affda] + * Fixed security issue where templates that looked like file paths loaded content from arbitrary files. Reported by Andreas Lindh. Fixed with [0879fa41] + * Fixed security issue where users were able to use html tags in subscription values. Reported by Andreas Lindh. Fixed with [9d5fb816] + * Support for multiple HTML editors (Mosaico, GrapeJS, Summernote, HTML code) + ## 1.22.0 2017-03-02 * Reverted license back to GPL-v3 to support Mosaico diff --git a/package.json b/package.json index f60bb525..5c0eb349 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "mailtrain", "private": true, - "version": "1.22.0", + "version": "1.23.0", "description": "Self hosted email newsletter app", "main": "index.js", "scripts": { From 490da66b9bee6ac718f3ed3d98d72b0ae6a0b86c Mon Sep 17 00:00:00 2001 From: Andris Reinman Date: Sun, 19 Mar 2017 14:31:37 +0200 Subject: [PATCH 5/8] Renamed changelog.txt to changelog.md --- CHANGELOG.txt | 144 -------------------------------------------------- 1 file changed, 144 deletions(-) delete mode 100644 CHANGELOG.txt diff --git a/CHANGELOG.txt b/CHANGELOG.txt deleted file mode 100644 index 8b94b01b..00000000 --- a/CHANGELOG.txt +++ /dev/null @@ -1,144 +0,0 @@ -# Changelog - -## 1.23.0 2017-03-19 - - * Fixed security issue where description tags were able to include script tags. Reported by Andreas Lindh. Fixed with [ae6affda] - * Fixed security issue where templates that looked like file paths loaded content from arbitrary files. Reported by Andreas Lindh. Fixed with [0879fa41] - * Fixed security issue where users were able to use html tags in subscription values. Reported by Andreas Lindh. Fixed with [9d5fb816] - * Support for multiple HTML editors (Mosaico, GrapeJS, Summernote, HTML code) - -## 1.22.0 2017-03-02 - - * Reverted license back to GPL-v3 to support Mosaico - -## 1.21.0 2017-02-17 - - * Changed license from MIT to EUPL-1.1 - * Added support for sending mail using AWS SES - -## 1.20.0 2016-12-11 - - * Added option to distribute sending queue between multiple processes to speed up delivery - -## 1.19.0 2016-09-15 - - * Changed license from GPL-V3 to MIT - -## 1.18.0 2016-09-08 - - * Updated installation script to bundle ZoneMTA as the default sending engine - * Added new option to disable clicked and opened tracking - * Store remote IP for subscription confirmations - -## 1.17.0 2016-08-29 - - * Added new custom field for JSON data that is rendered using Handlebars when included in an email - -## 1.16.0 2016-08-29 - - * Render list values using Handlebars templates - * Added new API method to create custom fields - * Added LDAP authentication support - -## 1.15.0 2016-07-28 - - * Check SMTP settings using AJAX instead of posting entire form - -## 1.14.0 2016-07-09 - - * Fixed ANY match segments with range queries - * Added an option to disable un/subscribe confirmation messages - * Added support for throttling when sending messages - * Added preview links in message lists - -## 1.13.0 2016-06-23 - - * Added API method to delete subscribers - * Added a counter to triggers with a view to list all subscribers that caused this trigger to fire - -## 1.12.1 2016-06-23 - - * Fixed invalid base SQL dump - -## 1.12.0 2016-06-22 - - * Automation support. Create triggers that send a campaign once fired - * Fixed an issue with unresolved URL redirects - * Added support for relative date ranges in segments - -## 1.11.0 2016-05-31 - - * Retry transactional mail if failed with soft error (4xx) - * New feature to preview campaigns using selected test users - -## 1.10.1 2016-05-26 - - * Fix a bug with SMTP transport instance where campaign sending stalled until server was restarted - -## 1.10.0 2016-05-25 - - * Fetch multiple unsent messages at once to speed up delivery - * Fixed a bug of counting unsubscribers correctly - * Use LONGTEXT for template text fields (messages might include inlined images which are larger than 64kB) - -## 1.9.0 2016-05-16 - - * New look - * Added views for bounced/unsubscribed/complained etc. - -## 1.8.2 2016-05-13 - - * Added missing views for subscribers who clicked on any link and subscribers who opened the message - -## 1.8.1 2016-05-13 - - * Fixed an issue in API - -## 1.8.0 2016-05-13 - - * Show details about subscribers who clicked on a specific link - -## 1.7.0 2016-05-11 - - * Updated API, added new option **REQUIRE_CONFIRMATION** for subscriptions to send confirmation email before subscribing - -## 1.6.0 2016-05-07 - - * Added simple API support for adding and removing list subscriptions - -## 1.5.0 2016-05-05 - - * Fixed a bug in unsubscribing through the admin interface - * Added individual link click stats - -## 1.4.1 2016-05-04 - - * Added support for RSS templates - -## 1.4.0 2016-05-04 - - * Added support for RSS campaigns - * Subscribers get timezone attached to their profile - * Outgoing messages are preprocessed using juice - * Added installation script for easier setup - -## 1.3.0 2016-04-29 - - * Added option to use an URL as message source (when message needs to be rendered a POST request with Merge Tags as the POST body is made against that URL) - * Added option to schedule sending. You can set optional delay time when starting campaign sending. Once this time is reached sending starts automatically - * Show meaningful MySQL error when connection fails - -## 1.2.0 2016-04-25 - - * Rewrite merge tags in links (allows using links like `http://example.com/?u=[FIRST_NAME]` in messages) - * Added view for Imports to list failed addresses - * Automatic SQL table creation on initial run (no need for the `mysql` command anymore) - * Automatic SQL table updates on startup - * Send welcome and unsubscribe confirmation emails for subscribers - * Added support for GPG encryption for outgoing messages (requires custom field "GPG Key" set up for the list) - * Added new SMTP option: allow self-signed certs - * Added new setting: Disable WYSIWG editor (allows better handling of complex HTML templates) - * Allow downgrading user when server started as root (user is downgraded once all ports are bound) - * Added Nitrous.io one-click install button for easy try-out - * Added Max Post Size option to allow larger payloads from bounce webhooks - * Added VERP support to catch bounces using built in VERP smtp-server (disabled by default) From 337649c217971c633f7bab43bd0fbc29e2c1b309 Mon Sep 17 00:00:00 2001 From: Andris Reinman Date: Sun, 19 Mar 2017 14:31:58 +0200 Subject: [PATCH 6/8] Renamed changelog.txt to changelog.md --- CHANGELOG.md | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..8b94b01b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,144 @@ +# Changelog + +## 1.23.0 2017-03-19 + + * Fixed security issue where description tags were able to include script tags. Reported by Andreas Lindh. Fixed with [ae6affda] + * Fixed security issue where templates that looked like file paths loaded content from arbitrary files. Reported by Andreas Lindh. Fixed with [0879fa41] + * Fixed security issue where users were able to use html tags in subscription values. Reported by Andreas Lindh. Fixed with [9d5fb816] + * Support for multiple HTML editors (Mosaico, GrapeJS, Summernote, HTML code) + +## 1.22.0 2017-03-02 + + * Reverted license back to GPL-v3 to support Mosaico + +## 1.21.0 2017-02-17 + + * Changed license from MIT to EUPL-1.1 + * Added support for sending mail using AWS SES + +## 1.20.0 2016-12-11 + + * Added option to distribute sending queue between multiple processes to speed up delivery + +## 1.19.0 2016-09-15 + + * Changed license from GPL-V3 to MIT + +## 1.18.0 2016-09-08 + + * Updated installation script to bundle ZoneMTA as the default sending engine + * Added new option to disable clicked and opened tracking + * Store remote IP for subscription confirmations + +## 1.17.0 2016-08-29 + + * Added new custom field for JSON data that is rendered using Handlebars when included in an email + +## 1.16.0 2016-08-29 + + * Render list values using Handlebars templates + * Added new API method to create custom fields + * Added LDAP authentication support + +## 1.15.0 2016-07-28 + + * Check SMTP settings using AJAX instead of posting entire form + +## 1.14.0 2016-07-09 + + * Fixed ANY match segments with range queries + * Added an option to disable un/subscribe confirmation messages + * Added support for throttling when sending messages + * Added preview links in message lists + +## 1.13.0 2016-06-23 + + * Added API method to delete subscribers + * Added a counter to triggers with a view to list all subscribers that caused this trigger to fire + +## 1.12.1 2016-06-23 + + * Fixed invalid base SQL dump + +## 1.12.0 2016-06-22 + + * Automation support. Create triggers that send a campaign once fired + * Fixed an issue with unresolved URL redirects + * Added support for relative date ranges in segments + +## 1.11.0 2016-05-31 + + * Retry transactional mail if failed with soft error (4xx) + * New feature to preview campaigns using selected test users + +## 1.10.1 2016-05-26 + + * Fix a bug with SMTP transport instance where campaign sending stalled until server was restarted + +## 1.10.0 2016-05-25 + + * Fetch multiple unsent messages at once to speed up delivery + * Fixed a bug of counting unsubscribers correctly + * Use LONGTEXT for template text fields (messages might include inlined images which are larger than 64kB) + +## 1.9.0 2016-05-16 + + * New look + * Added views for bounced/unsubscribed/complained etc. + +## 1.8.2 2016-05-13 + + * Added missing views for subscribers who clicked on any link and subscribers who opened the message + +## 1.8.1 2016-05-13 + + * Fixed an issue in API + +## 1.8.0 2016-05-13 + + * Show details about subscribers who clicked on a specific link + +## 1.7.0 2016-05-11 + + * Updated API, added new option **REQUIRE_CONFIRMATION** for subscriptions to send confirmation email before subscribing + +## 1.6.0 2016-05-07 + + * Added simple API support for adding and removing list subscriptions + +## 1.5.0 2016-05-05 + + * Fixed a bug in unsubscribing through the admin interface + * Added individual link click stats + +## 1.4.1 2016-05-04 + + * Added support for RSS templates + +## 1.4.0 2016-05-04 + + * Added support for RSS campaigns + * Subscribers get timezone attached to their profile + * Outgoing messages are preprocessed using juice + * Added installation script for easier setup + +## 1.3.0 2016-04-29 + + * Added option to use an URL as message source (when message needs to be rendered a POST request with Merge Tags as the POST body is made against that URL) + * Added option to schedule sending. You can set optional delay time when starting campaign sending. Once this time is reached sending starts automatically + * Show meaningful MySQL error when connection fails + +## 1.2.0 2016-04-25 + + * Rewrite merge tags in links (allows using links like `http://example.com/?u=[FIRST_NAME]` in messages) + * Added view for Imports to list failed addresses + * Automatic SQL table creation on initial run (no need for the `mysql` command anymore) + * Automatic SQL table updates on startup + * Send welcome and unsubscribe confirmation emails for subscribers + * Added support for GPG encryption for outgoing messages (requires custom field "GPG Key" set up for the list) + * Added new SMTP option: allow self-signed certs + * Added new setting: Disable WYSIWG editor (allows better handling of complex HTML templates) + * Allow downgrading user when server started as root (user is downgraded once all ports are bound) + * Added Nitrous.io one-click install button for easy try-out + * Added Max Post Size option to allow larger payloads from bounce webhooks + * Added VERP support to catch bounces using built in VERP smtp-server (disabled by default) From 07b7e1a3f2d1aad281d4be41a8799bfe461e5169 Mon Sep 17 00:00:00 2001 From: Andris Reinman Date: Sun, 19 Mar 2017 14:33:27 +0200 Subject: [PATCH 7/8] Renamed changelog.txt to changelog.md --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b94b01b..c682ffb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,9 @@ ## 1.23.0 2017-03-19 - * Fixed security issue where description tags were able to include script tags. Reported by Andreas Lindh. Fixed with [ae6affda] - * Fixed security issue where templates that looked like file paths loaded content from arbitrary files. Reported by Andreas Lindh. Fixed with [0879fa41] - * Fixed security issue where users were able to use html tags in subscription values. Reported by Andreas Lindh. Fixed with [9d5fb816] + * Fixed security issue where description tags were able to include script tags. Reported by Andreas Lindh. Fixed with [ae6affda](https://github.com/andris9/mailtrain/commit/ae6affda8193f034e06f7e095ee23821a83d5190) + * Fixed security issue where templates that looked like file paths loaded content from arbitrary files. Reported by Andreas Lindh. Fixed with [0879fa41](https://github.com/andris9/mailtrain/commit/0879fa412a2d4a417aeca5cd5092a8f86531e7ef) + * Fixed security issue where users were able to use html tags in subscription values. Reported by Andreas Lindh. Fixed with [9d5fb816](https://github.com/andris9/mailtrain/commit/9d5fb816c937114966d4f589e1ad4e164ff3a187) * Support for multiple HTML editors (Mosaico, GrapeJS, Summernote, HTML code) ## 1.22.0 2017-03-02 From 91addb14afb9fb0952cac301a36fb5c91b7f451d Mon Sep 17 00:00:00 2001 From: witzig Date: Sun, 19 Mar 2017 16:03:11 +0100 Subject: [PATCH 8/8] Satisfy ESLint indentation rule --- lib/passport.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/passport.js b/lib/passport.js index 60bbbe3d..04ef20ac 100644 --- a/lib/passport.js +++ b/lib/passport.js @@ -17,7 +17,7 @@ try { LdapStrategy = require('passport-ldapjs').Strategy; // eslint-disable-line global-require } catch (E) { if (config.ldap.enabled) { - log.info('LDAP', 'Module "passport-ldapjs" not installed. LDAP auth will fail.'); + log.info('LDAP', 'Module "passport-ldapjs" not installed. LDAP auth will fail.'); } }