route OTP email delivery through SMTP relay settings
Make rms.auth.otp_email use SMTP transport with the same host/port/auth/tls settings model as smtp relay, with outbox fallback when SMTP is unavailable. Extend OTP plugin settings schema to expose standard SMTP parameters in plugin config.
This commit is contained in:
@@ -1,4 +1,59 @@
|
|||||||
|
let nodemailer = null;
|
||||||
|
try {
|
||||||
|
nodemailer = require("nodemailer");
|
||||||
|
} catch {
|
||||||
|
nodemailer = null;
|
||||||
|
}
|
||||||
|
|
||||||
async function createPlugin(ctx) {
|
async function createPlugin(ctx) {
|
||||||
|
let transporter = null;
|
||||||
|
let transportKey = "";
|
||||||
|
|
||||||
|
function readTransportConfig() {
|
||||||
|
const host = String(ctx.getSetting("host", ctx.env.SMTP_HOST || "")).trim();
|
||||||
|
const portRaw = Number(ctx.getSetting("port", ctx.env.SMTP_PORT || 587));
|
||||||
|
const secure = String(ctx.getSetting("secure", ctx.env.SMTP_SECURE || "false")) === "true";
|
||||||
|
const authUser = String(ctx.getSetting("authUser", ctx.env.SMTP_USER || "")).trim();
|
||||||
|
const authPass = String(ctx.getSetting("authPass", ctx.env.SMTP_PASS || "")).trim();
|
||||||
|
const allowInvalidCert = String(ctx.getSetting("allowInvalidCert", ctx.env.SMTP_ALLOW_INVALID_CERT || "false")) === "true";
|
||||||
|
return {
|
||||||
|
host,
|
||||||
|
port: Number.isFinite(portRaw) && portRaw > 0 ? portRaw : 587,
|
||||||
|
secure,
|
||||||
|
authUser,
|
||||||
|
authPass,
|
||||||
|
allowInvalidCert
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deliverViaSmtp(entry) {
|
||||||
|
const config = readTransportConfig();
|
||||||
|
if (!config.host || !nodemailer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const key = JSON.stringify(config);
|
||||||
|
if (!transporter || transportKey !== key) {
|
||||||
|
transporter = nodemailer.createTransport({
|
||||||
|
host: config.host,
|
||||||
|
port: config.port,
|
||||||
|
secure: config.secure,
|
||||||
|
auth: config.authUser ? { user: config.authUser, pass: config.authPass } : undefined,
|
||||||
|
tls: config.allowInvalidCert ? { rejectUnauthorized: false } : undefined
|
||||||
|
});
|
||||||
|
transportKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
await transporter.sendMail({
|
||||||
|
from: entry.from,
|
||||||
|
to: entry.to,
|
||||||
|
replyTo: entry.replyTo || undefined,
|
||||||
|
subject: entry.subject,
|
||||||
|
text: entry.text,
|
||||||
|
html: entry.html || undefined
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async execute(action, input) {
|
async execute(action, input) {
|
||||||
if (action !== "send_challenge") {
|
if (action !== "send_challenge") {
|
||||||
@@ -14,14 +69,27 @@ async function createPlugin(ctx) {
|
|||||||
via: "rms.auth.otp_email",
|
via: "rms.auth.otp_email",
|
||||||
to: recipient,
|
to: recipient,
|
||||||
from: String(ctx.getSetting("from", ctx.env.SMTP_FROM || "noreply@arcg.at")),
|
from: String(ctx.getSetting("from", ctx.env.SMTP_FROM || "noreply@arcg.at")),
|
||||||
|
replyTo: String(ctx.getSetting("replyTo", ctx.env.SMTP_REPLY_TO || "")),
|
||||||
subject: String(payload.subject || "ARCG OTP"),
|
subject: String(payload.subject || "ARCG OTP"),
|
||||||
text: String(payload.text || ""),
|
text: String(payload.text || ""),
|
||||||
html: String(payload.html || "")
|
html: String(payload.html || "")
|
||||||
};
|
};
|
||||||
|
let delivered = false;
|
||||||
|
try {
|
||||||
|
delivered = await deliverViaSmtp(entry);
|
||||||
|
} catch (error) {
|
||||||
|
entry.smtpError = String(error && error.message ? error.message : error);
|
||||||
|
}
|
||||||
|
entry.delivered = delivered;
|
||||||
|
entry.transport = delivered ? "smtp" : "outbox-fallback";
|
||||||
await ctx.appendMailOutbox(entry);
|
await ctx.appendMailOutbox(entry);
|
||||||
return { ok: true, delivered: true, transport: "otp-email-plugin" };
|
return { ok: true, delivered, transport: delivered ? "smtp" : "outbox-fallback" };
|
||||||
},
|
},
|
||||||
async health() {
|
async health() {
|
||||||
|
const config = readTransportConfig();
|
||||||
|
if (config.host && !nodemailer) {
|
||||||
|
return { ok: false, message: "nodemailer nicht installiert" };
|
||||||
|
}
|
||||||
return { ok: true };
|
return { ok: true };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,14 @@
|
|||||||
"settingsSchema": {
|
"settingsSchema": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"from": { "type": "string" }
|
"host": { "type": "string" },
|
||||||
|
"port": { "type": "integer", "minimum": 1, "maximum": 65535 },
|
||||||
|
"secure": { "type": "boolean" },
|
||||||
|
"authUser": { "type": "string" },
|
||||||
|
"authPass": { "type": "string" },
|
||||||
|
"from": { "type": "string" },
|
||||||
|
"replyTo": { "type": "string" },
|
||||||
|
"allowInvalidCert": { "type": "boolean" }
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user