163 lines
6.6 KiB
JavaScript
163 lines
6.6 KiB
JavaScript
const settings = require('./settings');
|
||
const db = require('./db');
|
||
const nodemailer = require('nodemailer');
|
||
|
||
// ─── Channel senders ──────────────────────────────────────────────────────────
|
||
|
||
async function sendGotify(title, message) {
|
||
const { gotify } = settings.get();
|
||
if (!gotify.enabled || !gotify.url || !gotify.token) return;
|
||
const base = gotify.url.replace(/\/$/, '');
|
||
try {
|
||
const res = await fetch(`${base}/message?token=${encodeURIComponent(gotify.token)}`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ title, message, priority: gotify.priority ?? 5 }),
|
||
});
|
||
if (!res.ok) console.error(`[notify] Gotify error ${res.status}: ${await res.text().catch(() => '')}`);
|
||
} catch (err) {
|
||
console.error('[notify] Gotify failed:', err.message);
|
||
}
|
||
}
|
||
|
||
async function sendNtfy(title, message) {
|
||
const { ntfy } = settings.get();
|
||
if (!ntfy.enabled || !ntfy.url || !ntfy.topic) return;
|
||
const base = ntfy.url.replace(/\/$/, '');
|
||
const headers = {
|
||
'Content-Type': 'text/plain',
|
||
'Title': title,
|
||
'Priority': String(ntfy.priority ?? 3),
|
||
};
|
||
if (ntfy.token) headers['Authorization'] = `Bearer ${ntfy.token}`;
|
||
try {
|
||
const res = await fetch(`${base}/${encodeURIComponent(ntfy.topic)}`, {
|
||
method: 'POST',
|
||
headers,
|
||
body: message,
|
||
});
|
||
if (!res.ok) console.error(`[notify] ntfy error ${res.status}: ${await res.text().catch(() => '')}`);
|
||
} catch (err) {
|
||
console.error('[notify] ntfy failed:', err.message);
|
||
}
|
||
}
|
||
|
||
async function sendSmtp(title, message) {
|
||
const { smtp } = settings.get();
|
||
if (!smtp.enabled || !smtp.host || !smtp.to || !smtp.from) return;
|
||
try {
|
||
const transporter = nodemailer.createTransport({
|
||
host: smtp.host,
|
||
port: Number(smtp.port) || 587,
|
||
secure: smtp.secure === true || smtp.secure === 'true',
|
||
auth: smtp.username ? { user: smtp.username, pass: smtp.password } : undefined,
|
||
});
|
||
await transporter.sendMail({
|
||
from: smtp.from,
|
||
to: smtp.to,
|
||
subject: title,
|
||
text: message,
|
||
});
|
||
} catch (err) {
|
||
console.error('[notify] SMTP failed:', err.message);
|
||
}
|
||
}
|
||
|
||
async function sendWebhook(title, message) {
|
||
const { webhook } = settings.get();
|
||
if (!webhook.enabled || !webhook.url) return;
|
||
const body = JSON.stringify({ content: `**${title}**\n${message}` });
|
||
const headers = { 'Content-Type': 'application/json' };
|
||
if (webhook.secret) headers['X-Webhook-Secret'] = webhook.secret;
|
||
try {
|
||
const res = await fetch(webhook.url, { method: 'POST', headers, body });
|
||
if (!res.ok) console.error(`[notify] Webhook error ${res.status}: ${await res.text().catch(() => '')}`);
|
||
} catch (err) {
|
||
console.error('[notify] Webhook failed:', err.message);
|
||
}
|
||
}
|
||
|
||
// ─── Broadcast to all enabled channels ───────────────────────────────────────
|
||
|
||
async function notify(title, message) {
|
||
await Promise.all([
|
||
sendGotify(title, message),
|
||
sendNtfy(title, message),
|
||
sendSmtp(title, message),
|
||
sendWebhook(title, message),
|
||
]);
|
||
}
|
||
|
||
// ─── Exported senders for test routes ────────────────────────────────────────
|
||
|
||
async function testGotify(cfg) {
|
||
const base = cfg.url.replace(/\/$/, '');
|
||
const res = await fetch(`${base}/message?token=${encodeURIComponent(cfg.token)}`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ title: '🦥 Sloth Manager — Test', message: 'Gotify notifications are working correctly.', priority: cfg.priority ?? 5 }),
|
||
});
|
||
if (!res.ok) throw new Error(`Gotify returned ${res.status}: ${await res.text().catch(() => '')}`);
|
||
}
|
||
|
||
async function testNtfy(cfg) {
|
||
const base = cfg.url.replace(/\/$/, '');
|
||
const headers = { 'Content-Type': 'text/plain', Title: '🦥 Sloth Manager — Test', Priority: String(cfg.priority ?? 3) };
|
||
if (cfg.token) headers['Authorization'] = `Bearer ${cfg.token}`;
|
||
const res = await fetch(`${base}/${encodeURIComponent(cfg.topic)}`, { method: 'POST', headers, body: 'ntfy notifications are working correctly.' });
|
||
if (!res.ok) throw new Error(`ntfy returned ${res.status}: ${await res.text().catch(() => '')}`);
|
||
}
|
||
|
||
async function testSmtp(cfg) {
|
||
const transporter = nodemailer.createTransport({
|
||
host: cfg.host,
|
||
port: Number(cfg.port) || 587,
|
||
secure: cfg.secure === true || cfg.secure === 'true',
|
||
auth: cfg.username ? { user: cfg.username, pass: cfg.password } : undefined,
|
||
});
|
||
await transporter.verify();
|
||
await transporter.sendMail({
|
||
from: cfg.from,
|
||
to: cfg.to,
|
||
subject: '🦥 Sloth Manager — Test',
|
||
text: 'SMTP notifications are working correctly.',
|
||
});
|
||
}
|
||
|
||
async function testWebhook(cfg) {
|
||
const headers = { 'Content-Type': 'application/json' };
|
||
if (cfg.secret) headers['X-Webhook-Secret'] = cfg.secret;
|
||
const res = await fetch(cfg.url, {
|
||
method: 'POST',
|
||
headers,
|
||
body: JSON.stringify({ content: '**🦥 Sloth Manager — Test**\nWebhook notifications are working correctly.' }),
|
||
});
|
||
if (!res.ok) throw new Error(`Webhook returned ${res.status}: ${await res.text().catch(() => '')}`);
|
||
}
|
||
|
||
// ─── Event helpers ────────────────────────────────────────────────────────────
|
||
|
||
function eventEnabled(key) {
|
||
return settings.get().notifications?.[key] !== false;
|
||
}
|
||
|
||
function recordAdded(provider, zoneId, record) {
|
||
if (!eventEnabled('dns_add')) return;
|
||
const zoneName = db.getZoneName(provider, zoneId);
|
||
return notify(`DNS Record Added`, `[${provider}] ${zoneName}\n+ ${record.type} ${record.name} → ${record.content}`);
|
||
}
|
||
|
||
function recordUpdated(provider, zoneId, oldRecord, newRecord) {
|
||
if (!eventEnabled('dns_update')) return;
|
||
const zoneName = db.getZoneName(provider, zoneId);
|
||
return notify(`DNS Record Updated`, `[${provider}] ${zoneName}\n✎ ${oldRecord.type} ${oldRecord.name}\n ${oldRecord.content} → ${newRecord.content}`);
|
||
}
|
||
|
||
function recordDeleted(provider, zoneId, record) {
|
||
if (!eventEnabled('dns_delete')) return;
|
||
const zoneName = db.getZoneName(provider, zoneId);
|
||
return notify(`DNS Record Deleted`, `[${provider}] ${zoneName}\n− ${record.type} ${record.name} ${record.content}`);
|
||
}
|
||
|
||
module.exports = { notify, testGotify, testNtfy, testSmtp, testWebhook, recordAdded, recordUpdated, recordDeleted };
|