Files
myprojplanet_vite/src/views/admin/server/server.ts
Surya Paolo 791e18f167 - Mail in a Box: comandi per aggiungere/modificare/rimuovere le caselle di posta
- aggiunto idMyGroup: ospiti siti di gruppi (AbitareGliIblei)
2024-09-12 14:49:30 +02:00

794 lines
25 KiB
TypeScript
Executable File

import { defineComponent, onMounted, ref, computed, watch, onUnmounted, nextTick } from 'vue'
import { CTitleBanner } from '../../../components/CTitleBanner'
import { CDateTime } from '../../../components/CDateTime'
import { CMyFieldDb } from '../../../components/CMyFieldDb'
import { useQuasar } from 'quasar'
import { useI18n } from '@/boot/i18n'
import { useUserStore } from '@store/UserStore'
import { useGlobalStore } from '@store/globalStore'
import { useCircuitStore } from '@store/CircuitStore'
import { tools } from '@store/Modules/tools'
import { costanti } from '@costanti'
import { shared_consts } from '@src/common/shared_vuejs'
export default defineComponent({
name: 'server',
components: { CTitleBanner, CDateTime, CMyFieldDb },
props: {},
setup() {
const $q = useQuasar()
const { t } = useI18n()
const circuitStore = useCircuitStore()
const userStore = useUserStore()
const messages = ref('')
const input = ref('')
const scriptName = ref('')
const inputRequired = ref(false)
const inputPrompt = ref('')
const statusWs = ref('')
const rischeckDNS = ref('')
const errorDNS = ref(false)
let ws: any = null;
const ris = ref('')
const riga = ref(0)
const numpersone = ref(7)
const date_start = ref(new Date())
const col = ref(0)
const placca = ref('')
const valmin = ref(200)
const circuitId = ref('')
const valmax = ref(400)
const defmin = ref(shared_consts.CIRCUIT_PARAMS.SCOPERTO_MIN_GRP)
const defmax = ref(shared_consts.CIRCUIT_PARAMS.SCOPERTO_MAX_GRP)
const defpersmin = ref(100)
const defpersmax = ref(200)
const search_username = ref('')
const replace_username = ref('')
const incaricamento = ref(false)
const myarrscript = ref(<any>[])
const myarroptionsdir = ref(<any>[])
const myarrdir = ref(<any>[])
const mydir = ref(<string>'')
const scrollArea = ref(<any>null)
const globalStore = useGlobalStore()
const selectedApi = ref(<string>'');
const dnsPageActive = ref(false)
const dnsCheckMySite = ref(false)
const optionsApi = ref(<any>[])
const arrZones = ref(<any>[])
const arrDNS = ref(<any>[])
const arrEmails = ref(<any>[])
const optZones = ref(<any>[])
const selected = ref(<any>[])
const selZoneId = ref('')
const showNewEmail = ref(false)
const showchangePwd = ref(false)
const newEmail = ref('')
const newPassword = ref('')
const changeEmail = ref('')
const changePassword = ref('')
const isPwd = ref(true)
const emailSel = ref('')
const isFormValid = computed(() => {
return newEmail.value && newEmail.value.includes('@') && newPassword.value.length >= 8
})
const isFormValidChange = computed(() => {
return emailSel.value && emailSel.value.includes('@') && changePassword.value.length >= 8
})
const columnsZones = [
{ name: 'id', align: 'right', label: 'ID', field: 'id', visible: true },
{ name: 'name', required: true, label: 'Nome', align: 'left', field: 'name', sortable: true, visible: true },
{ name: 'status', align: 'center', label: 'Status', field: 'status', sortable: true, visible: true },
{ name: 'proxied', align: 'center', label: 'Proxy', field: 'proxied', sortable: true, visible: true },
{ name: 'type', required: true, label: 'Tipo', align: 'left', field: 'type', sortable: true, visible: true },
];
const columnsDNS = [
{ name: 'id', required: false, label: 'Id', align: 'left', field: 'id', sortable: false, visible: false },
{ name: 'name', required: true, label: 'Nome', align: 'left', field: 'name', sortable: true, visible: true },
{ name: 'type', required: true, label: 'Tipo', align: 'left', field: 'type', sortable: true, visible: true },
{ name: 'proxied', required: true, align: 'center', label: 'Proxy', field: 'proxied', sortable: true, visible: true },
{ name: 'priority', required: true, align: 'center', label: 'Pri', field: 'priority', sortable: true, visible: true },
{ name: 'ttl', required: true, align: 'center', label: 'TTL', field: 'ttl', sortable: false, visible: true },
{ name: 'content', required: true, label: 'Valore', align: 'left', field: 'content', sortable: true, visible: true },
{ name: 'delete', required: true, label: 'Azioni', align: 'left', field: 'delete', sortable: true, visible: true },
];
const viscolumnsDNS = [
{ name: 'name', required: true, label: 'Nome', align: 'left', field: 'name', sortable: true, visible: true, editable: true },
{ name: 'type', required: true, label: 'Tipo', align: 'left', field: 'type', sortable: true, visible: true, editable: true },
{ name: 'proxied', required: true, align: 'center', label: 'Proxy', field: 'proxied', sortable: true, visible: true, editable: true },
{ name: 'priority', required: true, align: 'center', label: 'Pri', field: 'priority', sortable: true, visible: true },
{ name: 'ttl', required: true, align: 'center', label: 'TTL', field: 'ttl', sortable: false, visible: true },
{ name: 'content', required: true, label: 'Valore', align: 'left', field: 'content', sortable: true, visible: true, editable: true },
{ name: 'delete', required: true, label: 'Azioni', align: 'left', field: 'delete', sortable: true, visible: true },
];
const pagination = {
rowsPerPage: 20,
}
watch(() => selectedApi.value, async (to: any, from: any) => {
if (selectedApi.value) {
incaricamento.value = true
tools.setCookie('CF_API_SEL', selectedApi.value)
arrZones.value = await globalStore.getCloudFlareTok("getzones", selectedApi.value, "")
incaricamento.value = false
selZoneId.value = tools.getCookie('CF_API_ZONE_ID_' + selectedApi.value, '')
optZones.value = []
for (let i = 0; i < arrZones.value.length; i++) {
optZones.value.push({ label: arrZones.value[i].name, value: arrZones.value[i].id })
}
}
})
watch(() => mydir.value, async (to: any, from: any) => {
// ...
// console.log('Watching ' + mydir.value)
myarrscript.value = []
optionsApi.value = []
dnsPageActive.value = (mydir.value === '2_DNS')
incaricamento.value = true
tools.setCookie('CF_API_DIR', mydir.value)
if (dnsPageActive.value) {
// get the Tokens
optionsApi.value = await globalStore.getCloudFlareTok("gettok", selectedApi.value, "")
} else {
if (mydir.value)
myarrscript.value = await getArrayByScript('ls "admin_scripts/' + mydir.value + '/"', 'sh')
}
incaricamento.value = false
})
async function updateArrDns() {
arrDNS.value = []
arrDNS.value = await globalStore.getCloudFlareTok("getDNS", selectedApi.value, selZoneId.value)
}
async function getEmails() {
arrEmails.value = []
arrEmails.value = await globalStore.getMailInABox("getEmails", { domain: tools.getDomainSite() })
}
async function addEmailServer(email: string, pwd: string) {
incaricamento.value = true
const ris = await globalStore.getMailInABox("addEmail", { domain: tools.getDomainSite(), email, pwd })
if (ris)
tools.showPositiveNotif($q, ris)
else {
tools.showNegativeNotif($q, t('miab.err_addemail'))
}
await checkDNSSite()
incaricamento.value = false
}
async function setMailUserPassword(email: string, pwd: string) {
incaricamento.value = true
const ris = await globalStore.getMailInABox("setMailUserPassword", { domain: tools.getDomainSite(), email, pwd })
if (ris)
tools.showPositiveNotif($q, ris)
else {
tools.showNegativeNotif($q, t('miab.err_setmailuserpwd'))
}
await checkDNSSite()
incaricamento.value = false
}
async function removeEmails(email: String) {
$q.dialog({
message: t('miab.deleteemail') + email + ' ?',
ok: {
label: t('dialog.yes'),
push: true,
},
cancel: {
label: t('dialog.cancel'),
},
title: 'Funzione:',
}).onOk(async () => {
incaricamento.value = true
const ris = await globalStore.getMailInABox("removeEmails", { domain: tools.getDomainSite(), email })
if (ris)
tools.showPositiveNotif($q, ris)
else {
tools.showNegativeNotif($q, t('miab.err_removed'))
}
await checkDNSSite()
incaricamento.value = false
})
}
watch(() => selZoneId.value, async (to: any, from: any) => {
if (selZoneId.value) {
incaricamento.value = true
await updateArrDns()
const checksiteprec = dnsCheckMySite.value
dnsCheckMySite.value = dnsPageActive.value && (getNameBySelZoneinId() === tools.getDomainSite())
if (dnsCheckMySite.value && !checksiteprec) {
await checkDNSSite()
}
incaricamento.value = false
tools.setCookie('CF_API_ZONE_ID_' + selectedApi.value, selZoneId.value)
/*optDNS.value = []
for (let i = 0; i < arrZones.value.length; i++) {
optDNS.value.push({ label: arrZones.value[i].name, value: arrZones.value[i].id })
}*/
}
})
watch(() => messages.value, async (to: any, from: any) => {
await nextTick(); // Aspetta che il DOM si aggiorni
scrollToBottom();
});
async function eseguiScriptSenzaConferma(script: string, ritornaout: boolean, dir: string, listafiles: boolean, extfiles: string, withinput: boolean) {
// console.log('eseguiScriptSenzaConferma ' + script)
const mydata = {
script,
dir,
tokcheck: "php8.1_version_762321HSD121nJDokq@?!aFS.tar.gz",
listafiles,
extfiles,
withinput
}
incaricamento.value = true
const risfunz = await globalStore.execScript({ mydata })
incaricamento.value = false
if (ritornaout) {
if (listafiles) {
return risfunz.arrout
} else {
return risfunz.stdout
}
} else {
return risfunz
}
}
async function getArrayByScript(script: string, extfiles: string) {
let mystr = 'admin_scripts/'
if (mydir.value) {
mystr += mydir.value
}
return await eseguiScriptSenzaConferma(script, true, mystr, true, extfiles, false)
}
async function mounted() {
myarrdir.value = await getArrayByScript('cd admin_scripts; ls -d */', '')
myarroptionsdir.value = []
if (myarrdir.value) {
for (let i = 0; i < myarrdir.value.length; i++) {
const opt = { label: myarrdir.value[i].label, value: myarrdir.value[i].value }
myarroptionsdir.value.push(opt)
}
}
if (myarrdir.value && myarrdir.value.length > 0) {
mydir.value = myarrdir.value[0].value
}
connectWebSocket()
scrollToBottom()
mydir.value = tools.getCookie('CF_API_DIR')
selectedApi.value = tools.getCookie('CF_API_SEL', '')
}
const scrollToBottom = () => {
nextTick(() => {
if (scrollArea.value) {
const el = scrollArea.value.$el;
let scrollHeight = el.scrollHeight
if (el) {
// Use el.scrollIntoView() to instantly scroll to the element
scrollArea.value.setScrollPosition('vertical', 10000)
}
}
})
};
onUnmounted(() => {
if (ws) {
ws.close();
statusWs.value = 'CLOSE';
}
});
function EseguiScript(script: string) {
const userStore = useUserStore()
$q.dialog({
message: t('dialog.continue') + ' ' + script + ' ?',
ok: {
label: t('dialog.yes'),
push: true,
},
cancel: {
label: t('dialog.cancel'),
},
title: 'Funzione:',
}).onOk(async () => {
incaricamento.value = true
$q.loading.show({ message: t('otherpages.update') })
const risfunz = await eseguiScriptSenzaConferma(script, false, '', false, '', true)
$q.loading.hide()
// await globalStore.loadSite()
incaricamento.value = false
console.log('EseguiScript', risfunz)
//write the string of the time now
let timenowstr = '<span style="font-style: italic; color: gray;">✅ Eseguito alle ' + tools.getstrTimeAll(Date.now()) + ' -> ' + '</span><br>'
if (risfunz.stderr)
ris.value = timenowstr + '<span style="color: red;">' + 'ERRORE: ' + risfunz.stderr + '</span><br>' + ris.value
if (risfunz.stdout)
ris.value = timenowstr + risfunz.stdout + '<br>' + ris.value
})
}
const connectWebSocket = () => {
let myurlws = tools.getWssUrl()
ws = new WebSocket(myurlws)
const input = ref('');
console.log('connectWebSocket ... ' + myurlws)
ws.onmessage = (event: any) => {
const data = JSON.parse(event.data);
if (data.type === 'output' || data.type === 'error') {
messages.value += data.data;
scrollToBottom()
} else if (data.type === 'input_required') {
inputRequired.value = true;
inputPrompt.value = data.prompt;
} else if (data.type === 'close') {
messages.value += '\n' + data.data
}
};
ws.onclose = () => {
statusWs.value = 'CLOSE';
messages.value += '\nConnessione chiusa. Riconnessione...'
setTimeout(connectWebSocket, 5000);
};
};
const startScript = (scriptName: string) => {
if (ws && ws.readyState === WebSocket.OPEN && scriptName) {
// ('Start Script ', ws)
statusWs.value = 'OPEN'
// messages.value = '' // Pulisce i messaggi precedenti
inputRequired.value = false;
let timenowstr = '<br><span style="font-style: italic; color: gray;">✅ Eseguito alle ' + tools.getstrTimeAll(Date.now()) + ' -> ' + '</span><br>'
messages.value += timenowstr
ws.send(JSON.stringify({ user_id: userStore.my._id, type: 'start_script', scriptName, dir: mydir.value }));
}
};
const sendInput = () => {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'input', data: input.value }));
// messages.value.push(input.value + '\n')
input.value = '';
inputRequired.value = false;
}
};
// get the label of the selectedApi (value)
const getLabelSelApi = () => {
const myrec = optionsApi.value.find((opt: any) => opt.value === selectedApi.value)
return myrec ? myrec.label : ''
}
const getNameBySelZoneinId = () => {
if (arrZones.value) {
const myrec = arrZones.value.find((zone: any) => zone.id === selZoneId.value)
return myrec ? myrec.name : ''
} else {
return ''
}
}
const getSelectedString = () => {
return selected.value.length === 0 ? '' : `${selected.value[0].name} selezionata.`
}
const toggleSelect = (row: any) => {
if (selected.value.length > 0 && selected.value[0].id === row.id) {
selected.value = [];
} else {
selected.value = [row];
}
}
const saveContentDNS = async (content: string, initialValue: string) => {
console.log('record da salvare su CF:', content)
if (selected.value && selected.value.length > 0 && selected.value[0].id) {
const indrec = arrDNS.value.findIndex((rec: any) => rec.id === selected.value[0].id)
arrDNS.value[indrec].content = content
await saveRecordDNS(arrDNS.value[indrec])
}
}
const saveNameDNS = async (name: string, initialValue: string) => {
if (selected.value && selected.value.length > 0 && selected.value[0].id) {
const indrec = arrDNS.value.findIndex((rec: any) => rec.id === selected.value[0].id)
arrDNS.value[indrec].name = name
await saveRecordDNS(arrDNS.value[indrec])
}
}
const saveTTLDNS = async (ttl: string, initialValue: string) => {
if (selected.value && selected.value.length > 0 && selected.value[0].id) {
const indrec = arrDNS.value.findIndex((rec: any) => rec.id === selected.value[0].id)
arrDNS.value[indrec].ttl = ttl
await saveRecordDNS(arrDNS.value[indrec])
}
}
const savePriorityDNS = async (priority: string, initialValue: string) => {
if (selected.value && selected.value.length > 0 && selected.value[0].id) {
const indrec = arrDNS.value.findIndex((rec: any) => rec.id === selected.value[0].id)
arrDNS.value[indrec].priority = priority
await saveRecordDNS(arrDNS.value[indrec])
}
}
const saveTypeDNS = async (type: string, initialValue: string) => {
if (selected.value && selected.value.length > 0 && selected.value[0].id) {
const indrec = arrDNS.value.findIndex((rec: any) => rec.id === selected.value[0].id)
arrDNS.value[indrec].type = type
await saveRecordDNS(arrDNS.value[indrec])
}
}
const setCorrectIpsOnDNS = async () => {
incaricamento.value = true
let myrecord = {
name: tools.getDomainSite()
}
await globalStore.getCloudFlareTok("setCorrectIpsOnDNS", selectedApi.value, selZoneId.value, null, myrecord)
await checkDNSSite()
incaricamento.value = false
}
const saveRecordDNS = async (row: any) => {
console.log('record da salvare su CF:', row)
const recupdated = await globalStore.getCloudFlareTok("setRecordDNS", selectedApi.value, selZoneId.value, row.id, row)
if (recupdated) {
const indrec = arrDNS.value.findIndex((rec: any) => rec.id === recupdated.id)
// update record
arrDNS.value[indrec] = recupdated
tools.showPositiveNotif($q, t('db.recupdated'))
} else {
tools.showNegativeNotif($q, t('db.recfailed'))
}
}
const delRecordDNS = async (row: any) => {
$q.dialog({
message: t('db.deletetherecord') + ' type = ' + row.type + ' ?',
ok: {
label: t('dialog.yes'),
push: true,
},
cancel: {
label: t('dialog.cancel'),
},
title: 'Funzione:',
}).onOk(async () => {
const recupdated = await globalStore.getCloudFlareTok("delRecordDNS", selectedApi.value, selZoneId.value, row.id, null)
if (recupdated) {
// update record
updateArrDns()
tools.showPositiveNotif($q, t('db.deletedrecord'))
} else {
tools.showNegativeNotif($q, t('db.recfailed'))
}
})
}
function getResultCheckDnsParam(title: string, recordReal: any, paramReal: string, strExpected: string) {
let mystr = ''
try {
if (recordReal) {
const contentReal = recordReal[paramReal]
if (strExpected !== contentReal) {
errorDNS.value = true
mystr += `<span style="color: red;">${title}: NO</span><br> 👉🏻 🔴 Attuale__: ${contentReal}<br> 👉🏻 🔵 Aspettato: ${strExpected} <br>`
} else {
mystr += `<span style="color: green;">${title}: 🟢 OK (${contentReal})</span><br>`
}
} else {
errorDNS.value = true
mystr += `<span style="color: gray;">${title}: 🔴 N/A</span><br>`
}
} catch (error) {
mystr += `<span style="color: gray;">${title}: 🔴 N/A Errore nell\'estrazione del parametro ... </span><br>`
}
return mystr
}
async function checkDNSSite() {
incaricamento.value = true
await updateArrDns()
await globalStore.loadSite()
rischeckDNS.value = '<br>'
errorDNS.value = false
const domainSite = tools.getDomainSite();
const domainsData = [
{ url: domainSite, expected: globalStore.site.host_ip, type: 'A' },
{ url: 'api.' + domainSite, expected: globalStore.site.host_api_ip, type: 'A' },
{ url: 'test.' + domainSite, expected: globalStore.site.host_test_ip, type: 'A' },
{ url: 'testapi.' + domainSite, expected: globalStore.site.host_testapi_ip, type: 'A' },
{ url: 'www.' + domainSite, expected: domainSite, type: 'CNAME' }
];
// Controllo DNS
if (dnsPageActive.value) {
let checkDomainA1 = '';
for (let i = 0; i < domainsData.length; i++) {
let ris = tools.getHostPuntamento(arrDNS.value, domainsData[i].url, domainsData[i].expected!, domainsData[i].type);
checkDomainA1 += ris.text;
if (!ris.ok) {
errorDNS.value = true;
}
}
let checkServerMailEnabled = '<br>';
if (globalStore.site.enable_servermail) {
// Controlla type MX
const mxRecord = arrDNS.value.find((record: any) => record.type === 'MX' && record.name === domainSite);
checkServerMailEnabled += getResultCheckDnsParam('Server mail enabled', mxRecord, 'content', globalStore.site.servermail!)
// *** Controlla type TXT spf1 ***
let contentTXTspf1Expected = `v=spf1 a mx:${globalStore.site.servermail} ip4:${globalStore.site.servermailip} ~all`;
const mxRecordTXTspf1 = arrDNS.value.find((record: any) => record.type === 'TXT' && record.name === domainSite && (record.content.indexOf('v=spf1') > -1))
checkServerMailEnabled += getResultCheckDnsParam('TXT spf1 RECORD', mxRecordTXTspf1, 'content', contentTXTspf1Expected)
let nameDkimtoFind = `mail._domainkey.${domainSite}`;
// Controllo DKIM:
const mxRecordTXTDKIM = arrDNS.value.find((record: any) => record.type === 'TXT' && record.name === nameDkimtoFind)
let contentTXTDKIMExpected = `v=DKIM1; h=sha256; k=rsa; s=email; p=${globalStore.site.dkim}`
checkServerMailEnabled += getResultCheckDnsParam('DKIM1', mxRecordTXTDKIM, 'content', contentTXTDKIMExpected)
// Controllo DMARC:
const mxRecordTXTDMARC = arrDNS.value.find((record: any) => record.type === 'TXT' && record.name === `_dmarc.${domainSite}`)
let contentTXTMARCExpected = `v=DMARC1; p=quarantine; ruf=mailto:dmarc@${domainSite};`;
checkServerMailEnabled += getResultCheckDnsParam('DMARC RECORD', mxRecordTXTDMARC, 'content', contentTXTMARCExpected)
// Controlla autoconfig
const recAutoConfig = arrDNS.value.find((record: any) => record.type === 'CNAME' && record.name === `autoconfig.${domainSite}`);
checkServerMailEnabled += getResultCheckDnsParam('AutoConfig CNAME', recAutoConfig, 'content', globalStore.site.servermail!)
// Controlla autodiscover
const recAutoDiscover = arrDNS.value.find((record: any) => record.type === 'CNAME' && record.name === `autodiscover.${domainSite}`);
checkServerMailEnabled += getResultCheckDnsParam('AutoDiscover CNAME', recAutoDiscover, 'content', globalStore.site.servermail!)
await getEmails()
}
rischeckDNS.value = checkDomainA1 + checkServerMailEnabled
incaricamento.value = false
}
}
async function addEmail() {
// Implementa qui la logica per aggiungere la nuova email
console.log('Aggiunta nuova email:', newEmail.value)
await addEmailServer(newEmail.value, newPassword.value)
// Resetta i campi e chiudi il dialog
newEmail.value = ''
newPassword.value = ''
showNewEmail.value = false
}
async function setMailUserPwd() {
// Implementa qui la logica per aggiungere la nuova email
await setMailUserPassword(emailSel.value, changePassword.value)
// Resetta i campi e chiudi il dialog
emailSel.value = ''
changePassword.value = ''
showchangePwd.value = false
}
onMounted(mounted)
return {
EseguiScript,
tools,
costanti,
search_username,
replace_username,
valmin,
valmax,
defmin,
defmax,
defpersmin,
defpersmax,
circuitId,
circuitStore,
incaricamento,
ris,
myarrscript,
mydir,
myarrdir,
myarroptionsdir,
messages,
input,
scriptName,
startScript,
sendInput,
inputRequired,
inputPrompt,
statusWs,
scrollArea,
selectedApi,
dnsPageActive,
optionsApi,
arrZones,
getLabelSelApi,
columnsZones,
pagination,
selected,
getSelectedString,
toggleSelect,
optZones,
selZoneId,
arrDNS,
columnsDNS,
getNameBySelZoneinId,
viscolumnsDNS,
saveRecordDNS,
saveContentDNS,
saveNameDNS,
saveTypeDNS,
saveTTLDNS,
savePriorityDNS,
dnsCheckMySite,
checkDNSSite,
rischeckDNS,
globalStore,
setCorrectIpsOnDNS,
errorDNS,
delRecordDNS,
arrEmails,
removeEmails,
addEmail,
newEmail,
newPassword,
changeEmail,
changePassword,
showNewEmail,
showchangePwd,
isFormValid,
isPwd,
setMailUserPwd,
emailSel,
isFormValidChange,
}
},
})