From 6fcb844cb668150afe997bed3bb72357802b6700 Mon Sep 17 00:00:00 2001
From: David D'Hauwe <43988646+daviddhauwe@users.noreply.github.com>
Date: Mon, 6 Jun 2022 21:08:17 +0200
Subject: [PATCH] Email Mta Node added security and authentication
---
social/email/61-email.html | 405 +++++++++++++++--------
social/email/61-email.js | 107 ++++--
social/email/locales/en-US/61-email.json | 11 +-
3 files changed, 356 insertions(+), 167 deletions(-)
diff --git a/social/email/61-email.html b/social/email/61-email.html
index b6885ccc..ab4a1281 100644
--- a/social/email/61-email.html
+++ b/social/email/61-email.html
@@ -61,45 +61,45 @@
@@ -190,24 +190,24 @@
+
\ No newline at end of file
diff --git a/social/email/61-email.js b/social/email/61-email.js
index f1ac8a89..94052d76 100644
--- a/social/email/61-email.js
+++ b/social/email/61-email.js
@@ -19,6 +19,7 @@ module.exports = function(RED) {
var simpleParser = require("mailparser").simpleParser;
var SMTPServer = require("smtp-server").SMTPServer;
//var microMTA = require("micromta").microMTA;
+ var fs = require('fs');
if (parseInt(process.version.split("v")[1].split(".")[0]) < 8) {
throw "Error : Requires nodejs version >= 8.";
@@ -565,47 +566,81 @@ module.exports = function(RED) {
function EmailMtaNode(n) {
- RED.nodes.createNode(this,n);
+ RED.nodes.createNode(this, n);
this.port = n.port;
+ this.secure = n.secure;
+ this.starttls = n.starttls;
+ this.certFile = n.certFile;
+ this.keyFile = n.keyFile;
+ this.users = n.users;
+ this.auth = n.auth;
+ try {
+ this.options = JSON.parse(n.expert);
+ } catch (error) {
+ this.options = {};
+ }
var node = this;
+ if (!Array.isArray(node.options.disabledCommands)) {
+ node.options.disabledCommands = [];
+ }
+ node.options.secure = node.secure;
+ if (node.certFile) {
+ node.options.cert = fs.readFileSync(node.certFile);
+ }
+ if (node.keyFile) {
+ node.options.key = fs.readFileSync(node.keyFile);
+ }
+ if (!node.starttls) {
+ node.options.disabledCommands.push("STARTTLS");
+ }
+ if (!node.auth) {
+ node.options.disabledCommands.push("AUTH");
+ }
- node.mta = new SMTPServer({
- secure: false,
- logger: false,
- disabledCommands: ['AUTH', 'STARTTLS'],
-
- onData: function (stream, session, callback) {
- simpleParser(stream, { skipTextToHtml:true, skipTextLinks:true }, (err, parsed) => {
- if (err) { node.error(RED._("email.errors.parsefail"),err); }
- else {
- node.status({fill:"green", shape:"dot", text:""});
- var msg = {}
- msg.payload = parsed.text;
- msg.topic = parsed.subject;
- msg.date = parsed.date;
- msg.header = {};
- parsed.headers.forEach((v, k) => {msg.header[k] = v;});
- if (parsed.html) { msg.html = parsed.html; }
- if (parsed.to) {
- if (typeof(parsed.to) === "string" && parsed.to.length > 0) { msg.to = parsed.to; }
- else if (parsed.to.hasOwnProperty("text") && parsed.to.text.length > 0) { msg.to = parsed.to.text; }
- }
- if (parsed.cc) {
- if (typeof(parsed.cc) === "string" && parsed.cc.length > 0) { msg.cc = parsed.cc; }
- else if (parsed.cc.hasOwnProperty("text") && parsed.cc.text.length > 0) { msg.cc = parsed.cc.text; }
- }
- if (parsed.cc && parsed.cc.length > 0) { msg.cc = parsed.cc; }
- if (parsed.bcc && parsed.bcc.length > 0) { msg.bcc = parsed.bcc; }
- if (parsed.from && parsed.from.value && parsed.from.value.length > 0) { msg.from = parsed.from.value[0].address; }
- if (parsed.attachments) { msg.attachments = parsed.attachments; }
- else { msg.attachments = []; }
- node.send(msg); // Propagate the message down the flow
- setTimeout(function() { node.status({})}, 500);
+ node.options.onData = function (stream, session, callback) {
+ simpleParser(stream, { skipTextToHtml:true, skipTextLinks:true }, (err, parsed) => {
+ if (err) { node.error(RED._("email.errors.parsefail"),err); }
+ else {
+ node.status({fill:"green", shape:"dot", text:""});
+ var msg = {}
+ msg.payload = parsed.text;
+ msg.topic = parsed.subject;
+ msg.date = parsed.date;
+ msg.header = {};
+ parsed.headers.forEach((v, k) => {msg.header[k] = v;});
+ if (parsed.html) { msg.html = parsed.html; }
+ if (parsed.to) {
+ if (typeof(parsed.to) === "string" && parsed.to.length > 0) { msg.to = parsed.to; }
+ else if (parsed.to.hasOwnProperty("text") && parsed.to.text.length > 0) { msg.to = parsed.to.text; }
}
- callback();
- });
+ if (parsed.cc) {
+ if (typeof(parsed.cc) === "string" && parsed.cc.length > 0) { msg.cc = parsed.cc; }
+ else if (parsed.cc.hasOwnProperty("text") && parsed.cc.text.length > 0) { msg.cc = parsed.cc.text; }
+ }
+ if (parsed.cc && parsed.cc.length > 0) { msg.cc = parsed.cc; }
+ if (parsed.bcc && parsed.bcc.length > 0) { msg.bcc = parsed.bcc; }
+ if (parsed.from && parsed.from.value && parsed.from.value.length > 0) { msg.from = parsed.from.value[0].address; }
+ if (parsed.attachments) { msg.attachments = parsed.attachments; }
+ else { msg.attachments = []; }
+ node.send(msg); // Propagate the message down the flow
+ setTimeout(function() { node.status({})}, 500);
+ }
+ callback();
+ });
+ }
+
+ node.options.onAuth = function (auth, session, callback) {
+ let id = node.users.findIndex(function (item) {
+ return item.name === auth.username;
+ });
+ if (id >= 0 && node.users[id].password === auth.password) {
+ callback(null, { user: id + 1 });
+ } else {
+ callback(new Error("Invalid username or password"));
}
- });
+ }
+
+ node.mta = new SMTPServer(node.options);
node.mta.listen(node.port);
diff --git a/social/email/locales/en-US/61-email.json b/social/email/locales/en-US/61-email.json
index 9d876117..67567904 100644
--- a/social/email/locales/en-US/61-email.json
+++ b/social/email/locales/en-US/61-email.json
@@ -34,7 +34,16 @@
"never": "never",
"required": "if required",
"always": "always",
- "rejectUnauthorised": "Check server certificate is valid"
+ "rejectUnauthorised": "Check server certificate is valid",
+ "enableSecure": "Secure connection",
+ "enableStarttls": "Start TLS",
+ "starttlsUpgrade": "Upgrade cleartext connection with STARTTLS",
+ "certFile": "Certificate",
+ "keyFile":"Private key",
+ "users": "Users",
+ "auth": "Authenticate users",
+ "addButton": "Add",
+ "expert": "Expert"
},
"default-message": "__description__\n\nFile from Node-RED is attached: __filename__",
"tip": {