const koa = require('koa') const koaRouter = require('@koa/router') const bodyParser = require('koa-bodyparser') const nodemailer = require('nodemailer') const cors = require('koa-cors') const proxyaddr = require('proxy-addr') const { RateLimiterMemory } = require('rate-limiter-flexible') const app = new koa() app.proxy = true; app.use(cors({ methods: 'POST' })) app.use(bodyParser()) const router = new koaRouter() const { contacts, mailConfig, rateConfig } = require(process.env.CONTACT_CONFIG || './config.json') if (!contacts || !mailConfig || !rateConfig) { throw new Error("Incomplete config") } const rateLimit = new RateLimiterMemory(rateConfig) const transport = nodemailer.createTransport(mailConfig) transport.verify() .then(() => console.log(`Email transport ready`)) .catch((err) => { console.error('Cannot verify email transport'); console.error(err); process.exit(1); }) router.post('/api/contact/:id', async (ctx) => { const { params: { id }, request, response } = ctx // check if we have an ID if (!contacts[id]) { response.status = 400 response.body = { error: `Invalid contact id "${id}"` } return } // check for request properties const { name, email, phone, message } = request.body if (!name || !email || !message) { ctx.status = 400 ctx.body = { status: 'error', message: 'invalid request' } return } // check rate limit const source = proxyaddr(request, 'loopback') try { // only counting as 1 point per request await rateLimit.consume(source, 1) } catch (err) { ctx.status = 429 ctx.set('Retry-After', err.msBeforeNext / 1000) ctx.body = { status: 'ratelimit', message: 'Too many messages, play nice friend' } return } const contact = contacts[id] const emailBody = `You have received a message via ${contact.site} from ${name}: Contact info: - Name: ${name} - Email: ${email} - Phone: ${phone || 'None supplied'} Message: ${message} ` console.log(`Received new message:\n${JSON.stringify({ name, email, phone, message, ip: source }, null, 2)}`) await transport.sendMail({ from: `tempest.dev Mailer <${mailConfig.from || mailConfig.auth.user}>`, to: contact.address, subject: contact.subject, text: emailBody }) ctx.status = 200 ctx.body = { status: 'Message sent' } }) app .use(router.routes()) .use(router.allowedMethods()) .listen(process.env.PORT || 3000)