129 lines
3.1 KiB
JavaScript
129 lines
3.1 KiB
JavaScript
const express = require("express");
|
|
const helmet = require("helmet");
|
|
const rateLimit = require("express-rate-limit");
|
|
const nodemailer = require("nodemailer");
|
|
const morgan = require("morgan");
|
|
|
|
require("dotenv").config();
|
|
const ENV = process.env.ENVIRONMENT || "TEST";
|
|
const SENDER_EMAIL = process.env.EMAIL;
|
|
const USERNAME = process.env.USERNAME || SENDER_EMAIL;
|
|
const SENDER_PASS = process.env.EMAIL_PASSWORD;
|
|
const SERV_HOST = process.env.EMAIL_HOST;
|
|
const SERV_PORT = process.env.EMAIL_PORT;
|
|
|
|
const allowedIPs = process.env.ALLOWED_IPS.split(",");
|
|
|
|
const app = express();
|
|
app.enable("trust proxy");
|
|
app.disable("x-powered-by");
|
|
app.use(express.json());
|
|
app.use(helmet());
|
|
app.use(
|
|
morgan(
|
|
"[ :method :url ] ~:status | :date[web] | :total-time[digits] ms | IP :remote-addr | :user-agent"
|
|
)
|
|
);
|
|
|
|
// 10 requests per minute
|
|
const rootLimiter = rateLimit({
|
|
windowMs: 60 * 1000,
|
|
max: 10,
|
|
});
|
|
app.use("/", rootLimiter);
|
|
|
|
// Middleware function to check IP address
|
|
const ipFilter = (req, res, next) => {
|
|
if (ENV === "TEST" || ENV === "TEST-MAIL") next();
|
|
|
|
const clientIp = req.ip;
|
|
|
|
if (allowedIPs.includes(clientIp)) {
|
|
next();
|
|
} else {
|
|
res.status(403).send("Access denied");
|
|
}
|
|
};
|
|
|
|
const transporter = nodemailer.createTransport({
|
|
host: SERV_HOST,
|
|
port: SERV_PORT,
|
|
secure: true,
|
|
auth: {
|
|
user: USERNAME,
|
|
pass: SENDER_PASS,
|
|
},
|
|
});
|
|
|
|
// 1 request per minute
|
|
const mailRouteLimiter = rateLimit({
|
|
windowMs: 1 * 60 * 1000,
|
|
max: 1,
|
|
message: "Please wait at least 1 minute before sending another request!",
|
|
});
|
|
|
|
const promiseSendingAMail = async (mail) => {
|
|
await new Promise((resolve, reject) => {
|
|
transporter.sendMail(mail, (err, info) => {
|
|
if (err) reject(err);
|
|
else resolve(info);
|
|
});
|
|
});
|
|
}
|
|
|
|
app.post("/api/mail", ipFilter, mailRouteLimiter, async (req, res) => {
|
|
const { subject, text, recipient } = req.body;
|
|
|
|
const mail = {
|
|
from: `"Arbeit Mail Service" <${SENDER_EMAIL}>`,
|
|
to: recipient,
|
|
replyTo: "noreply@arbeit.studio",
|
|
subject,
|
|
text,
|
|
};
|
|
|
|
await new Promise((resolve, reject) => {
|
|
transporter.verify((err, success) => {
|
|
if (err) {
|
|
console.error(err);
|
|
reject(err);
|
|
} else {
|
|
console.info("Server is ready to receive mails.");
|
|
resolve(success);
|
|
}
|
|
})
|
|
})
|
|
|
|
if (ENV === "PROD") {
|
|
try {
|
|
const info = await promiseSendingAMail(mail);
|
|
console.info("Sent something:", mail);
|
|
res.status(200).json({ success: true, message: "Mail sent successfully!" });
|
|
} catch (err) {
|
|
console.error("Failed to send:", mail, err);
|
|
res.status(500).json({ success: false, message: "Mail could not be sent!" });
|
|
}
|
|
} else {
|
|
console.log(mail);
|
|
if (ENV === "TEST-MAIL") {
|
|
try {
|
|
await promiseSendingAMail(mail);
|
|
} catch (err) {
|
|
console.error("Failed to send test mail:", mail, err);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
app.get("/api/hello", (req, res) => {
|
|
res.status(200).json({
|
|
message: "Close the world, .txen eht nepO",
|
|
author: "Yigid BALABAN <fyb@fybx.dev>",
|
|
authorHomepage: "https://fybx.dev/",
|
|
});
|
|
});
|
|
|
|
app.listen(3313, () => {
|
|
console.log("Server up on 3313");
|
|
});
|