- Mail in a Box: comandi per aggiungere/modificare/rimuovere le caselle di posta
- aggiunto idMyGroup: ospiti siti di gruppi (AbitareGliIblei)
This commit is contained in:
218
src/server/modules/Mailinabox.js
Normal file
218
src/server/modules/Mailinabox.js
Normal file
@@ -0,0 +1,218 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const apiUrl = 'https://api.cloudflare.com/client/v4'; // Endpoint
|
||||
|
||||
class Mailinabox {
|
||||
constructor(config) {
|
||||
this.config = config ? config : {};
|
||||
if (!this.config.miabHost) {
|
||||
this.config.miabHost = process.env.MIAB_HOST;
|
||||
this.config.adminEmail = process.env.MIAB_ADMIN_EMAIL;
|
||||
this.config.adminPassword = process.env.MIAB_ADMIN_PASSWORD;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
init() {
|
||||
if (this.config.arrTokens) {
|
||||
this.zones = [];
|
||||
}
|
||||
}
|
||||
|
||||
checkIfParamOk() {
|
||||
if (!this.config.miabHost || !this.config.adminEmail || !this.config.adminPassword) {
|
||||
console.error('Configurazione mancante per il recupero del record DKIM.');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Funzione per ottenere il record DKIM
|
||||
async getDKIMRecord(domain) {
|
||||
|
||||
if (!this.checkIfParamOk()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const url = `https://${this.config.miabHost}/admin/dns/zonefile/${domain}`;
|
||||
const auth = Buffer.from(`${this.config.adminEmail}:${this.config.adminPassword}`).toString('base64');
|
||||
|
||||
try {
|
||||
const response = await axios.get(url, {
|
||||
headers: {
|
||||
'Authorization': `Basic ${auth}`
|
||||
}
|
||||
});
|
||||
|
||||
// console.log(`Record DNS esterni per ${config.domain}:`);
|
||||
|
||||
// Analizza la risposta per estrarre i record DNS
|
||||
const records = response.data.split('\n')
|
||||
.filter(line => line.trim() !== '' && !line.startsWith(';'))
|
||||
.map(line => line.trim());
|
||||
|
||||
// Trova e stampa il record DKIM
|
||||
const dkimRecord = records.find(record => record.includes('mail._domainkey'));
|
||||
if (dkimRecord) {
|
||||
const pMatch = dkimRecord.match(/p=([A-Za-z0-9+/]+)/);
|
||||
if (pMatch && pMatch[1]) {
|
||||
// console.log('Valore di p nel record DKIM:');
|
||||
// console.log(pMatch[1]);
|
||||
return pMatch[1];
|
||||
} else {
|
||||
console.log('Record DKIM non trovato.');
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
} catch (error) {
|
||||
console.error('Errore nel recupero del record DKIM:', error.message);
|
||||
if (error.response) {
|
||||
console.error('Dettagli errore:', error.response.data);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
async MIAB_getEmails(myrec) {
|
||||
|
||||
if (!this.checkIfParamOk() || !myrec.domain) {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = `https://${this.config.miabHost}/admin/mail/users?format=text`;
|
||||
const auth = Buffer.from(`${this.config.adminEmail}:${this.config.adminPassword}`).toString('base64');
|
||||
|
||||
try {
|
||||
const response = await axios.get(url, {
|
||||
headers: {
|
||||
'Authorization': `Basic ${auth}`
|
||||
}
|
||||
});
|
||||
|
||||
const records = response.data.split('\n')
|
||||
.filter(line => line.trim() !== '' && line.indexOf(myrec.domain) > -1)
|
||||
.map(line => line.trim());
|
||||
|
||||
return records;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Errore nel recupero delle Email ', error.message);
|
||||
if (error.response) {
|
||||
console.error('Dettagli errore:', error.response.data);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
async removeEmail(myrec) {
|
||||
|
||||
if (!this.checkIfParamOk() || !myrec.email) {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = `https://${this.config.miabHost}/admin/mail/users/remove`;
|
||||
const auth = Buffer.from(`${this.config.adminEmail}:${this.config.adminPassword}`).toString('base64');
|
||||
|
||||
try {
|
||||
const myrecout = `email=${myrec.email}`;
|
||||
|
||||
const response = await axios.post(url, myrecout, {
|
||||
headers: {
|
||||
'Authorization': `Basic ${auth}`
|
||||
}
|
||||
});
|
||||
|
||||
const ris = response.data;
|
||||
|
||||
return ris;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Errore nella cancellazione della Email ' + record.email, error.message);
|
||||
if (error.response) {
|
||||
console.error('Dettagli errore:', error.response.data);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
async addEmail(myrec) {
|
||||
|
||||
if (!this.checkIfParamOk() || !myrec.email) {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = `https://${this.config.miabHost}/admin/mail/users/add`;
|
||||
const auth = Buffer.from(`${this.config.adminEmail}:${this.config.adminPassword}`).toString('base64');
|
||||
|
||||
try {
|
||||
let privileges = myrec.privileges ? 'admin' : ''
|
||||
const myrecout = `email=${myrec.email}&password=${myrec.pwd}&privileges="${privileges}"`;
|
||||
|
||||
const response = await axios.post(url, myrecout, {
|
||||
headers: {
|
||||
'Authorization': `Basic ${auth}`
|
||||
}
|
||||
});
|
||||
|
||||
const ris = response.data;
|
||||
|
||||
return ris;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Errore nella creazione della Email ' + record.email, error.message);
|
||||
if (error.response) {
|
||||
console.error('Dettagli errore:', error.response.data);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
async setMailUserPassword(myrec) {
|
||||
|
||||
if (!this.checkIfParamOk() || !myrec.email) {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = `https://${this.config.miabHost}/admin/mail/users/password`;
|
||||
const auth = Buffer.from(`${this.config.adminEmail}:${this.config.adminPassword}`).toString('base64');
|
||||
|
||||
try {
|
||||
|
||||
let data = `email=${myrec.email}&password=${myrec.pwd}`;
|
||||
|
||||
const response = await axios.post(url,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
'Authorization': `Basic ${auth}`,
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
}
|
||||
});
|
||||
|
||||
let ris = '';
|
||||
|
||||
if (response.status === 200) {
|
||||
ris = `Password cambiata con successo per ${myrec.email}`;
|
||||
} else {
|
||||
ris = `Errore nel cambio password per ${myrec.email}`;
|
||||
}
|
||||
|
||||
return ris;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Errore nella creazione della Email ' + record.email, error.message);
|
||||
if (error.response) {
|
||||
console.error('Dettagli errore:', error.response.data);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Mailinabox
|
||||
@@ -2,6 +2,8 @@ const axios = require('axios');
|
||||
|
||||
const apiUrl = 'https://api.cloudflare.com/client/v4'; // Endpoint
|
||||
|
||||
const MailinaboxClass = require('./Mailinabox.js');
|
||||
|
||||
class CloudFlare {
|
||||
constructor(config) {
|
||||
this.config = config ? config : {};
|
||||
@@ -62,7 +64,7 @@ class CloudFlare {
|
||||
|
||||
let modif = (recsite.cf_token !== apiToken) || (recsite.cf_zoneId !== zone.id);
|
||||
|
||||
if (modif) {
|
||||
if (modif && apiToken) {
|
||||
// update the Site
|
||||
|
||||
await Site.findOneAndUpdate({ _id: recsite._id }, {
|
||||
@@ -78,6 +80,24 @@ class CloudFlare {
|
||||
console.error('Errore durante l\'aggiornamento del Site:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// Controlla se ho il DKIM !
|
||||
|
||||
if (recsite.enable_servermail && !recsite.dkim) {
|
||||
let miab = new MailinaboxClass(null);
|
||||
miab.init();
|
||||
|
||||
const dkim = await miab.getDKIMRecord(recsite.host);
|
||||
|
||||
if (dkim) {
|
||||
await Site.findOneAndUpdate({ _id: recsite._id }, {
|
||||
$set: {
|
||||
dkim,
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
@@ -130,18 +150,235 @@ class CloudFlare {
|
||||
}
|
||||
}
|
||||
|
||||
// Funzione per creare un record DNS di CloudFlare
|
||||
async createDNSRecord(apiToken, zoneId, dnsRecordData) {
|
||||
const apiUrlDNS = apiUrl + `/zones/${zoneId}/dns_records`;
|
||||
try {
|
||||
const response = await axios.post(apiUrlDNS, dnsRecordData, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${apiToken}`, // Autenticazione con token
|
||||
'Content-Type': 'application/json' // Tipo di contenuto
|
||||
}
|
||||
});
|
||||
const createdRecord = response.data.result;
|
||||
console.log('Record DNS creato:', createdRecord);
|
||||
|
||||
return createdRecord;
|
||||
// Stampa il record DNS creato
|
||||
} catch (error) {
|
||||
console.error('Errore durante la creazione del record DNS:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Funzione per cancellare un record DNS di CloudFlare
|
||||
async deleteDNSRecord(apiToken, zoneId, dnsRecordId) {
|
||||
const apiUrlDNS = apiUrl + `/zones/${zoneId}/dns_records/${dnsRecordId}`;
|
||||
try {
|
||||
const response = await axios.delete(apiUrlDNS, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${apiToken}`, // Autenticazione con token
|
||||
'Content-Type': 'application/json' // Tipo di contenuto
|
||||
}
|
||||
});
|
||||
const deletedRecord = response.data.result;
|
||||
console.log('Record DNS cancellato:', deletedRecord);
|
||||
|
||||
return deletedRecord;
|
||||
} catch (error) {
|
||||
console.error('Errore durante la cancellazione del record DNS:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async setCorrectIpsOnDNS(domainrec) {
|
||||
|
||||
const arrparams = [{ urladd: '', paramsite: 'host_ip' }, { urladd: 'test.', paramsite: 'host_test_ip' }, { urladd: 'api.', paramsite: 'host_api_ip' }, { urladd: 'testapi.', paramsite: 'host_testapi_ip' }]
|
||||
const arrparams = [{ urladd: '', paramsite: 'host_ip', type: 'A' },
|
||||
{ urladd: 'test.', paramsite: 'host_test_ip', type: 'A' },
|
||||
{ urladd: 'api.', paramsite: 'host_api_ip', type: 'A' },
|
||||
{ urladd: 'testapi.', paramsite: 'host_testapi_ip', type: 'A' },
|
||||
{ urladd: 'www.', paramsite: 'host', type: 'CNAME' },
|
||||
]
|
||||
|
||||
for (let i = 0; i < arrparams.length; i++) {
|
||||
this.setSingleIpsOnDNS(domainrec.name, arrparams[i])
|
||||
await this.setSingleIpsOnDNS(domainrec.name, arrparams[i])
|
||||
}
|
||||
|
||||
// Set Server Mail
|
||||
await this.setServerMail(domainrec);
|
||||
|
||||
// pause for 3 second
|
||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||
}
|
||||
|
||||
async setServerMail(domainrec) {
|
||||
|
||||
try {
|
||||
// get the parameters (Token and zoneId on Database)
|
||||
const Site = require('../models/site');
|
||||
|
||||
await Site.findOne({ host: domainrec.name }).lean()
|
||||
.then(async (site) => {
|
||||
if (site) {
|
||||
|
||||
if (site.cf_token && site.cf_zoneId) {
|
||||
const myarrrecdns = await this.fetchDNSRecords(site.cf_token, site.cf_zoneId);
|
||||
|
||||
// MX:
|
||||
let recTypeMX = await myarrrecdns.find((rec) => rec.type === 'MX' && (rec.name === (domainrec.name)));
|
||||
|
||||
if (recTypeMX) {
|
||||
if (recTypeMX.content !== site.servermail) {
|
||||
recTypeMX.content = site.servermail;
|
||||
return this.updateDNSRecord(site.cf_token, site.cf_zoneId, recTypeMX.id, recTypeMX);
|
||||
}
|
||||
} else {
|
||||
// create a new record
|
||||
const newRecord = {
|
||||
type: 'MX',
|
||||
name: domainrec.name,
|
||||
content: site.servermail,
|
||||
ttl: 1,
|
||||
proxied: false,
|
||||
priority: 10,
|
||||
};
|
||||
|
||||
await this.createDNSRecord(site.cf_token, site.cf_zoneId, newRecord);
|
||||
}
|
||||
|
||||
// TXT record spf1 : TXT nomedominio v=spf1 a mx:box.lamiaposta.org ip4:65.21.63.147 ~all
|
||||
|
||||
let recTypeTXTspf1 = await myarrrecdns.find((rec) => rec.type === 'TXT' && (rec.name === (domainrec.name) && (rec.content.indexOf('v=spf1') > -1)));
|
||||
|
||||
if (site.servermailip) {
|
||||
let contentTXTspf1 = `v=spf1 a mx:${site.servermail} ip4:${site.servermailip} ~all`;
|
||||
|
||||
if (recTypeTXTspf1) {
|
||||
if (recTypeTXTspf1.content !== contentTXTspf1) {
|
||||
recTypeTXTspf1.content = contentTXTspf1;
|
||||
return this.updateDNSRecord(site.cf_token, site.cf_zoneId, recTypeTXTspf1.id, recTypeTXTspf1);
|
||||
}
|
||||
} else {
|
||||
// create a new record
|
||||
const newRecord = {
|
||||
type: 'TXT',
|
||||
name: domainrec.name,
|
||||
content: contentTXTspf1,
|
||||
ttl: 3600,
|
||||
};
|
||||
|
||||
await this.createDNSRecord(site.cf_token, site.cf_zoneId, newRecord);
|
||||
}
|
||||
}
|
||||
|
||||
// mail._domainkey.nomedominio v=DKIM1; h=sha256; k=rsa; s=email; p=<dkim>
|
||||
|
||||
let nameDkimtoFind = `mail._domainkey.${domainrec.name}`;
|
||||
|
||||
let recTypeTXTDKIM = await myarrrecdns.find((rec) => rec.type === 'TXT' && (rec.name === nameDkimtoFind));
|
||||
|
||||
if (site.dkim) {
|
||||
let contentTXTDKIM = `v=DKIM1; h=sha256; k=rsa; s=email; p=${site.dkim}`;
|
||||
|
||||
if (recTypeTXTDKIM) {
|
||||
if (recTypeTXTDKIM.content !== contentTXTDKIM) {
|
||||
recTypeTXTDKIM.content = contentTXTDKIM;
|
||||
return this.updateDNSRecord(site.cf_token, site.cf_zoneId, recTypeTXTDKIM.id, recTypeTXTDKIM);
|
||||
}
|
||||
} else {
|
||||
// create a new record
|
||||
const newRecord = {
|
||||
type: 'TXT',
|
||||
name: nameDkimtoFind,
|
||||
content: contentTXTDKIM,
|
||||
ttl: 1,
|
||||
};
|
||||
|
||||
await this.createDNSRecord(site.cf_token, site.cf_zoneId, newRecord);
|
||||
}
|
||||
}
|
||||
|
||||
// DMARC:
|
||||
|
||||
let nameDmarctoFind = `_dmarc.${domainrec.name}`;
|
||||
|
||||
let recTypeTXTdmarc = await myarrrecdns.find((rec) => rec.type === 'TXT' && (rec.name === (nameDmarctoFind) && (rec.content.indexOf('v=DMARC1') > -1)));
|
||||
|
||||
if (site.servermailip) {
|
||||
let contentTXTdmarc = `v=DMARC1; p=quarantine; ruf=mailto:dmarc@${domainrec.name};`;
|
||||
|
||||
if (recTypeTXTdmarc) {
|
||||
if (recTypeTXTdmarc.content !== contentTXTdmarc) {
|
||||
recTypeTXTdmarc.content = contentTXTdmarc;
|
||||
return this.updateDNSRecord(site.cf_token, site.cf_zoneId, recTypeTXTspf1.id, recTypeTXTspf1);
|
||||
}
|
||||
} else {
|
||||
// create a new record
|
||||
const newRecord = {
|
||||
type: 'TXT',
|
||||
name: nameDmarctoFind,
|
||||
content: contentTXTdmarc,
|
||||
ttl: 1,
|
||||
};
|
||||
|
||||
await this.createDNSRecord(site.cf_token, site.cf_zoneId, newRecord);
|
||||
}
|
||||
}
|
||||
|
||||
// AutoConfig:
|
||||
let myType = 'CNAME';
|
||||
let strfind = `autoconfig.${domainrec.name}`;
|
||||
let contentExpected = site.servermail;
|
||||
let rectofind = await myarrrecdns.find((rec) => rec.type === 'CNAME' && (rec.name === strfind));
|
||||
|
||||
if (rectofind) {
|
||||
if (rectofind.content !== contentExpected) {
|
||||
rectofind.content = contentExpected;
|
||||
return this.updateDNSRecord(site.cf_token, site.cf_zoneId, rectofind.id, rectofind);
|
||||
}
|
||||
} else {
|
||||
// create a new record
|
||||
const newRecord = {
|
||||
type: myType,
|
||||
name: strfind,
|
||||
content: contentExpected,
|
||||
ttl: 1,
|
||||
};
|
||||
|
||||
await this.createDNSRecord(site.cf_token, site.cf_zoneId, newRecord);
|
||||
}
|
||||
|
||||
// AutoDiscover:
|
||||
myType = 'CNAME';
|
||||
strfind = `autodiscover.${domainrec.name}`;
|
||||
contentExpected = site.servermail;
|
||||
rectofind = await myarrrecdns.find((rec) => rec.type === 'CNAME' && (rec.name === strfind));
|
||||
|
||||
if (rectofind) {
|
||||
if (rectofind.content !== contentExpected) {
|
||||
rectofind.content = contentExpected;
|
||||
return this.updateDNSRecord(site.cf_token, site.cf_zoneId, rectofind.id, rectofind);
|
||||
}
|
||||
} else {
|
||||
// create a new record
|
||||
const newRecord = {
|
||||
type: myType,
|
||||
name: strfind,
|
||||
content: contentExpected,
|
||||
ttl: 1,
|
||||
};
|
||||
|
||||
await this.createDNSRecord(site.cf_token, site.cf_zoneId, newRecord);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
console.error('e', e);
|
||||
}
|
||||
}
|
||||
|
||||
async setSingleIpsOnDNS(domain, paramobj) {
|
||||
try {
|
||||
// get the parameters (Token and zoneId on Database)
|
||||
@@ -154,15 +391,36 @@ class CloudFlare {
|
||||
if (site.cf_token && site.cf_zoneId) {
|
||||
const myarrrecdns = await this.fetchDNSRecords(site.cf_token, site.cf_zoneId);
|
||||
|
||||
// find
|
||||
let recTypeA = await myarrrecdns.find((rec) => rec.type === 'A' && (rec.name === (paramobj.urladd + domain)));
|
||||
let nametofind = paramobj.urladd + domain;
|
||||
|
||||
// find
|
||||
let recType = await myarrrecdns.find((rec) => rec.type === paramobj.type && (rec.name === nametofind));
|
||||
|
||||
let paramexpected = '';
|
||||
try {
|
||||
paramexpected = site[paramobj.paramsite];
|
||||
} catch (e) {
|
||||
|
||||
if (recTypeA && site[paramobj.paramsite]) {
|
||||
if (recTypeA.content !== site[paramobj.paramsite]) {
|
||||
recTypeA.content = site[paramobj.paramsite];
|
||||
return this.updateDNSRecord(site.cf_token, site.cf_zoneId, recTypeA.id, recTypeA);
|
||||
}
|
||||
}
|
||||
|
||||
if (recType && paramexpected) {
|
||||
if (recType.content !== paramexpected) {
|
||||
recType.content = paramexpected;
|
||||
return this.updateDNSRecord(site.cf_token, site.cf_zoneId, recType.id, recType);
|
||||
}
|
||||
} else {
|
||||
// create a new record
|
||||
const newRecord = {
|
||||
type: paramobj.type,
|
||||
name: nametofind,
|
||||
content: paramexpected,
|
||||
ttl: 1,
|
||||
proxied: true,
|
||||
};
|
||||
|
||||
await this.createDNSRecord(site.cf_token, site.cf_zoneId, newRecord);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -171,6 +429,7 @@ class CloudFlare {
|
||||
console.error('e', e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = CloudFlare
|
||||
Reference in New Issue
Block a user