121 lines
3.5 KiB
JavaScript
121 lines
3.5 KiB
JavaScript
const fs = require("fs");
|
|
const path = require("path");
|
|
const { exec } = require("child_process");
|
|
const { MAILSERVER_CONTAINER, CONFIG_PATH, ROOT_PATH } = process.env;
|
|
const { models } = require(path.join(ROOT_PATH, "./db/db"));
|
|
const { Mailbox, Domain } = models;
|
|
|
|
async function generateMailserverConfig() {
|
|
try {
|
|
const mailboxes = await Mailbox.query().select("username", "password");
|
|
const accountLines = mailboxes.map(
|
|
(mailbox) => `${mailbox.username}|${mailbox.password}`
|
|
);
|
|
fs.writeFileSync(
|
|
path.join(CONFIG_PATH, "postfix/postfix-accounts.cf"),
|
|
accountLines.join("\n")
|
|
);
|
|
|
|
const domains = await Domain.query().select("domain");
|
|
fs.writeFileSync(
|
|
path.join(CONFIG_PATH, "postfix/postfix-virtual-mailbox-domains.cf"),
|
|
domains.map((d) => d.domain).join("\n")
|
|
);
|
|
|
|
await reloadMailserver();
|
|
|
|
return true;
|
|
} catch (error) {
|
|
console.error("Error generating mailserver config:", error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function reloadMailserver() {
|
|
return new Promise((resolve, reject) => {
|
|
exec(
|
|
`docker exec ${MAILSERVER_CONTAINER} postfix reload`,
|
|
(error, stdout, stderr) => {
|
|
if (error) {
|
|
console.error(`Error reloading Postfix: ${error.message}`);
|
|
return reject(error);
|
|
}
|
|
console.log("Postfix configuration reloaded successfully");
|
|
resolve(true);
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
async function hashPassword(password) {
|
|
// This is a simple bcrypt hash, for dovecot you might need a different format
|
|
// The docker-mailserver typically uses SHA512-CRYPT
|
|
return new Promise((resolve, reject) => {
|
|
exec(
|
|
`docker exec ${MAILSERVER_CONTAINER} doveadm pw -s SHA512-CRYPT -p "${password}"`,
|
|
(error, stdout, stderr) => {
|
|
if (error) {
|
|
console.error(`Error generating password hash: ${error.message}`);
|
|
return reject(error);
|
|
}
|
|
resolve(stdout.trim());
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
async function cleanupOrphanedMailboxes() {
|
|
try {
|
|
// Get all valid mailboxes from database
|
|
const validMailboxes = await Mailbox.query().select("username");
|
|
|
|
// Create a lookup map for quick checking
|
|
const validMailboxMap = {};
|
|
validMailboxes.forEach((username) => {
|
|
const [user, domain] = username.split("@");
|
|
if (!validMailboxMap[domain]) validMailboxMap[domain] = [];
|
|
validMailboxMap[domain].push(user);
|
|
});
|
|
|
|
// Scan mail directory
|
|
const mailPath = "/var/mail";
|
|
const domains = await fs.readdir(mailPath);
|
|
|
|
for (const domain of domains) {
|
|
const domainPath = path.join(mailPath, domain);
|
|
const stat = await fs.stat(domainPath);
|
|
|
|
if (stat.isDirectory()) {
|
|
const users = await fs.readdir(domainPath);
|
|
|
|
for (const user of users) {
|
|
const userPath = path.join(domainPath, user);
|
|
const userStat = await fs.stat(userPath);
|
|
|
|
if (userStat.isDirectory()) {
|
|
// Check if this is an orphaned mailbox
|
|
const isValid =
|
|
validMailboxMap[domain] && validMailboxMap[domain].includes(user);
|
|
|
|
if (!isValid) {
|
|
console.log(`Removing orphaned mailbox: ${user}@${domain}`);
|
|
await fs.rm(userPath, { recursive: true, force: true });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log("Mailbox cleanup completed");
|
|
} catch (error) {
|
|
console.error("Error during mailbox cleanup:", error);
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
generateMailserverConfig,
|
|
reloadMailserver,
|
|
hashPassword,
|
|
cleanupOrphanedMailboxes,
|
|
};
|