This is the template project that's checked out and configured when you run the bando-up command from ljsthw-bandolier. This is where the code really lives.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
bandolier-template/lib/email.js

168 lines
4.1 KiB

import nodemailer from "nodemailer";
import fs from 'fs/promises';
import _ from 'lodash';
import logging from "./logging.js";
import { promises } from "dns";
const log = logging.create("lib/email.js");
// TODO: move this out to an easy to access/change location
let configuration = {};
const configure_transporter = async () => {
if(process.env.DANGER_ADMIN || process.env.DEBUG) {
configuration = {
streamTransport: true,
debug: true,
logger: log,
newline: 'windows'
}
} else {
configuration = JSON.parse(await fs.readFile("./secrets/email.json"));
console.log("EMAIL CONFIG", configuration);
}
return nodemailer.createTransport(configuration);
}
// TODO: trash hacks to get the config out for the mail testing tool
export const get_config = () => configuration;
export const transporter = await configure_transporter();
export const load_templates = async (name) => {
const html = await fs.readFile(`emails/${name}.html`);
const txt = await fs.readFile(`emails/${name}.txt`);
return {
html: _.template(html),
txt: _.template(txt)
}
}
export const debug_templates = async (templates, name) => {
if(process.env.DEBUG) {
log.debug(`Writing debug email for ${name} to debug/emails/${name}.(html|txt)`);
await fs.mkdir("debug/emails", { recursive: true});
log.debug(`Emails written to debug/emails/${name}.(html|txt)`);
await fs.writeFile(`debug/emails/${name}.html`, templates.html);
await fs.writeFile(`debug/emails/${name}.txt`, templates.text);
}
}
/* This never rejects the promise it makes but instead returns
* any errors it receives or undefined if none.
*/
export const send_email = async (data) => {
const result = new Promise((resolve, reject) => {
transporter.sendMail(data, (err, info) => {
try {
if(err) {
log.error(err);
resolve(err);
} else {
if(process.env.DEBUG) {
log.debug(info.envelope);
log.debug(info.messageId);
// I only do this when I'm lazy
// info.message.pipe(process.stdout);
}
resolve(undefined);
}
} catch(error) {
resolve(error);
}
});
});
return result;
}
const add_reverse_error = (result, error) => {
if(result.reverse_errors === undefined) {
result.reverse_errors = [];
}
let res_error = { error: {...error} };
res_error.message = error.message;
result.reverse_errors.push(res_error);
}
export const dns_check = async (hostname) => {
let result = {
ip4: {},
ip6: {}
};
const res = new promises.Resolver();
res.setServers(['8.8.8.8']);
try {
result.ip4.host = await res.resolve4(hostname);
} catch(error) {
// the errors in dns are stupid. You only get .message if you call it.
result.ip4.error = {...error};
result.ip4.error.message = error.message;
}
// no point doing reverse DNS if no IP4 address
if(result.ip4.host) {
result.ip4.reverse = [];
for(let ip4 of result.ip4.host) {
try {
let host = await res.reverse(ip4);
result.ip4.reverse.push(host);
} catch(error) {
add_reverse_error(res.ip4, error);
}
}
}
try {
result.ip6.host = await res.resolve6(hostname);
} catch(error) {
result.ip6.error = {...error};
result.ip6.error.message = error.message;
}
// no point in doing reverse DNS if no address
if(result.ip6.host) {
result.ip6.reverse = [];
for(let ip6 of result.ip6.host) {
try {
let host = await res.reverse(ip6);
result.ip6.reverse.push(host);
} catch(error) {
add_reverse_error(result.ip6, error);
}
}
}
try {
result.mx = await res.resolveMx(hostname);
} catch(error) {
result.mx_error = {...error};
result.mx_error.message = error.message;
}
try {
result.spf = await res.resolveTxt(hostname);
} catch(error) {
result.spf_error = {...error};
result.spf_error.message = error.message;
}
try {
result.dmarc = await res.resolveTxt(`_dmarc.${hostname}`);
} catch(error) {
result.dmarc_error = {...error};
result.dmarc_error.message = error.message;
}
return result;
}