- Sistemato INVITI alla App

- Completamento Profilo
- Registrazione tramite Invito, senza richiedere conferma email.
This commit is contained in:
Surya Paolo
2025-11-18 23:56:15 +01:00
parent 1a342de24a
commit 294155d5a3
17 changed files with 203 additions and 98 deletions

View File

@@ -1,12 +1,12 @@
DATABASE=test_PiuCheBuono DATABASE=test_FreePlanet
UDB=paofreeplanet UDB=paofreeplanet
PDB=mypassword@1A PDB=mypassword@1A
SEND_EMAIL=0 SEND_EMAIL=0
SEND_EMAIL_ORDERS=1 SEND_EMAIL_ORDERS=1
PORT=3000 PORT=3000
appTelegram_TEST=["1","17"] appTelegram_TEST=["1","13"]
appTelegram=["1","17"] appTelegram=["1","13"]
appTelegram_DEVELOP=["17"] appTelegram_DEVELOP=["13"]
DOMAIN=mongodb://localhost:27017/ DOMAIN=mongodb://localhost:27017/
AUTH_MONGODB=0 AUTH_MONGODB=0
ENABLE_PUSHNOTIFICATION=1 ENABLE_PUSHNOTIFICATION=1
@@ -29,7 +29,7 @@ GCM_API_KEY=""
PROD=0 PROD=0
PROJECT_DESCR_MAIN='__PROJECTS' PROJECT_DESCR_MAIN='__PROJECTS'
SECRK=Askb38v23jjDFaoskBOWj92axXCQ SECRK=Askb38v23jjDFaoskBOWj92axXCQ
TOKEN_LIFE=2h TOKEN_LIFE=10m
REFRESH_TOKEN_LIFE=14d REFRESH_TOKEN_LIFE=14d
FTPSERVER_HOST=139.162.166.31 FTPSERVER_HOST=139.162.166.31
FTPSERVER_PORT=21 FTPSERVER_PORT=21
@@ -38,9 +38,4 @@ FTPSERVER_PWD=ftpmypwd@1A_
AUTH_NEW_SITES=123123123 AUTH_NEW_SITES=123123123
SCRIPTS_DIR=admin_scripts SCRIPTS_DIR=admin_scripts
CLOUDFLARE_TOKENS=[{"label":"Paolo.arena77@gmail.com","value":"M9EM309v8WFquJKpYgZCw-TViM2wX6vB3wlK6GD0"},{"label":"gruppomacro.com","value":"bqmzGShoX7WqOBzkXocoECyBkPq3GfqcM5t6VFd8"}] CLOUDFLARE_TOKENS=[{"label":"Paolo.arena77@gmail.com","value":"M9EM309v8WFquJKpYgZCw-TViM2wX6vB3wlK6GD0"},{"label":"gruppomacro.com","value":"bqmzGShoX7WqOBzkXocoECyBkPq3GfqcM5t6VFd8"}]
MIAB_HOST=box.lamiaposta.org
MIAB_ADMIN_EMAIL=admin@lamiaposta.org
MIAB_ADMIN_PASSWORD=passpao1pabox@1A
DS_API_KEY="sk-222e3addb3d8455d8b0516d93906eec7" DS_API_KEY="sk-222e3addb3d8455d8b0516d93906eec7"
SERVER_A_URL="http://51.77.156.69:3000"
API_KEY_MSSQL="m68yADSr123MIVIDA@154$DSAGVOK"

View File

@@ -34,7 +34,7 @@ TOKEN_LIFE=2h
REFRESH_TOKEN_LIFE=14d REFRESH_TOKEN_LIFE=14d
AUTH_NEW_SITES=B234HDSAOJ734ndcsdKWNVZZ AUTH_NEW_SITES=B234HDSAOJ734ndcsdKWNVZZ
DOMAINS=[{"hostname":"piuchebuono.app","port":"3030"},{"hostname":"gruppomacro.app","port":"3010"}] DOMAINS=[{"hostname":"piuchebuono.app","port":"3030"},{"hostname":"gruppomacro.app","port":"3010"}]
DOMAINS_ALLOWED=[] DOMAINS_ALLOWED=["gruppomacro.app","piuchebuono.app"]
SCRIPTS_DIR=admin_scripts SCRIPTS_DIR=admin_scripts
CLOUDFLARE_TOKENS=[{"label":"Paolo.arena77@gmail.com","value":"M9EM309v8WFquJKpYgZCw-TViM2wX6vB3wlK6GD0"},{"label":"gruppomacro.com","value":"bqmzGShoX7WqOBzkXocoECyBkPq3GfqcM5t6VFd8"}] CLOUDFLARE_TOKENS=[{"label":"Paolo.arena77@gmail.com","value":"M9EM309v8WFquJKpYgZCw-TViM2wX6vB3wlK6GD0"},{"label":"gruppomacro.com","value":"bqmzGShoX7WqOBzkXocoECyBkPq3GfqcM5t6VFd8"}]
MIAB_HOST=box.lamiaposta.org MIAB_HOST=box.lamiaposta.org

View File

@@ -11,9 +11,9 @@ db.mypages.insertMany([
"_id": new ObjectId("66db21118009ea4503bb6a03"), "_id": new ObjectId("66db21118009ea4503bb6a03"),
"order": 10, "order": 10,
"idapp": "19", "idapp": "19",
"path": "home_logout", "path": "presentazione",
"active": true, "active": true,
"title": "Home NoLoggato", "title": "Presentazione",
}, },
{ {
"_id": new ObjectId("66e322dd5a6360e3b3c71c5a"), "_id": new ObjectId("66e322dd5a6360e3b3c71c5a"),

View File

@@ -36,7 +36,7 @@ html(lang="it")
} }
.email-header { .email-header {
background: linear-gradient(135deg, #f4a460 0%, #d2691e 100%); background: linear-gradient(135deg, #7cb342 0%, #558b2f 100%);
color: white; color: white;
padding: 40px 24px; padding: 40px 24px;
text-align: center; text-align: center;
@@ -51,7 +51,7 @@ html(lang="it")
.email-header .subtitle { .email-header .subtitle {
margin: 8px 0 0 0; margin: 8px 0 0 0;
font-size: 15px; font-size: 17px;
opacity: 0.95; opacity: 0.95;
font-style: italic; font-style: italic;
} }
@@ -75,7 +75,7 @@ html(lang="it")
.highlight-box { .highlight-box {
background: #fff8dc; background: #fff8dc;
border-left: 4px solid #f4a460; border-left: 4px solid #7cb342;
border-radius: 8px; border-radius: 8px;
padding: 16px; padding: 16px;
margin: 20px 0; margin: 20px 0;
@@ -83,7 +83,7 @@ html(lang="it")
.highlight-box p { .highlight-box p {
margin: 0; margin: 0;
font-size: 15px; font-size: 17px;
color: #1a1a1a; color: #1a1a1a;
line-height: 1.6; line-height: 1.6;
} }
@@ -93,18 +93,18 @@ html(lang="it")
border-radius: 8px; border-radius: 8px;
padding: 16px; padding: 16px;
margin: 20px 0; margin: 20px 0;
border: 1px solid #f4a460; border: 1px solid #7cb342;
} }
.riso-info h3 { .riso-info h3 {
font-size: 16px; font-size: 16px;
color: #d2691e; color: #558b2f;
margin-bottom: 10px; margin-bottom: 10px;
text-align: center; text-align: center;
} }
.riso-info p { .riso-info p {
font-size: 14px; font-size: 16px;
color: #555; color: #555;
line-height: 1.6; line-height: 1.6;
margin-bottom: 8px; margin-bottom: 8px;
@@ -140,7 +140,7 @@ html(lang="it")
} }
.benefit-text { .benefit-text {
font-size: 14px; font-size: 16px;
color: #555; color: #555;
line-height: 1.5; line-height: 1.5;
} }
@@ -154,7 +154,7 @@ html(lang="it")
.values-section h3 { .values-section h3 {
font-size: 16px; font-size: 16px;
color: #d2691e; color: #558b2f;
margin-bottom: 12px; margin-bottom: 12px;
text-align: center; text-align: center;
font-weight: 600; font-weight: 600;
@@ -164,12 +164,12 @@ html(lang="it")
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 8px; margin-bottom: 8px;
font-size: 14px; font-size: 16px;
color: #555; color: #555;
} }
.value-item strong { .value-item strong {
color: #d2691e; color: #558b2f;
margin-right: 6px; margin-right: 6px;
} }
@@ -194,7 +194,7 @@ html(lang="it")
font-size: 18px; font-size: 18px;
font-weight: 600; font-weight: 600;
color: white; color: white;
background: linear-gradient(135deg, #f4a460 0%, #d2691e 100%); background: linear-gradient(135deg, #7cb342 0%, #558b2f 100%);
border-radius: 50px; border-radius: 50px;
text-decoration: none; text-decoration: none;
box-shadow: 0 4px 12px rgba(210, 105, 30, 0.3); box-shadow: 0 4px 12px rgba(210, 105, 30, 0.3);
@@ -212,7 +212,7 @@ html(lang="it")
.info-box p { .info-box p {
margin: 0; margin: 0;
color: #2e7d32; color: #2e7d32;
font-size: 14px; font-size: 16px;
line-height: 1.6; line-height: 1.6;
} }
@@ -228,7 +228,7 @@ html(lang="it")
.telegram-box p { .telegram-box p {
margin: 0; margin: 0;
color: #1976d2; color: #1976d2;
font-size: 14px; font-size: 16px;
line-height: 1.6; line-height: 1.6;
} }
@@ -245,10 +245,10 @@ html(lang="it")
} }
.link-box a { .link-box a {
color: #d2691e; color: #558b2f;
text-decoration: none; text-decoration: none;
font-weight: 600; font-weight: 600;
font-size: 14px; font-size: 16px;
} }
.email-footer { .email-footer {
@@ -294,7 +294,7 @@ html(lang="it")
} }
.benefit-item, .value-item { .benefit-item, .value-item {
font-size: 13px; font-size: 15px;
} }
} }
@@ -315,6 +315,11 @@ html(lang="it")
else else
| Hai ricevuto un invito speciale per unirti alla comunità RISO, una rete di persone che credono in un'economia basata su fiducia, comunità e scambi solidali. | Hai ricevuto un invito speciale per unirti alla comunità RISO, una rete di persone che credono in un'economia basata su fiducia, comunità e scambi solidali.
.cta-section
.cta-title Unisciti alla Comunità RISO 🍚💚☀️
a.cta-button(href=linkRegistrazione target="_blank") Registrati Ora
//- Messaggio personalizzato //- Messaggio personalizzato
if messaggioPersonalizzato if messaggioPersonalizzato
.highlight-box .highlight-box
@@ -410,7 +415,7 @@ html(lang="it")
.divider .divider
p Hai ricevuto questa email perché #{usernameInvitante || 'un membro della comunità'} ti ha invitato su #{nomeapp} p Hai ricevuto questa email perché #{usernameInvitante || 'un membro della comunità'} ti ha invitato su #{nomeapp}
p(style="margin-top: 12px; font-size: 12px;") p(style="margin-top: 12px; font-size: 12px;")
| © #{new Date().getFullYear()} #{nomeapp} - Rete Italiana Scambi Orizzontali | #{new Date().getFullYear()} #{nomeapp} - Rete Italiana Scambi Orizzontali
p(style="margin-top: 8px; font-size: 11px; color: #999;") p(style="margin-top: 8px; font-size: 11px; color: #999;")
| Se non sei interessato, puoi semplicemente ignorare questa email. | Se non sei interessato, puoi semplicemente ignorare questa email.
p(style="margin-top: 12px; font-size: 12px;") p(style="margin-top: 12px; font-size: 12px;")

View File

@@ -253,24 +253,25 @@ html(lang="it")
| su #{nomeapp || 'la nostra piattaforma'}! | su #{nomeapp || 'la nostra piattaforma'}!
.email-body .email-body
.intro-text if !verified_email
| Verifica il tuo indirizzo email cliccando sul pulsante qui sotto. .intro-text
.cta-section | Verifica il tuo indirizzo email cliccando sul pulsante qui sotto.
.cta-title 🔐 1. Verifica il tuo account .cta-section
.cta-title 🔐 1. Verifica il tuo account
if strlinkreg if strlinkreg
a.cta-button(href=strlinkreg target="_blank") Verifica Registrazione a.cta-button(href=strlinkreg target="_blank") Verifica Registrazione
.alternative-link .alternative-link
| Oppure copia e incolla questo link nel tuo browser: | Oppure copia e incolla questo link nel tuo browser:
br br
a(href=strlinkreg target="_blank") #{strlinkreg} a(href=strlinkreg target="_blank") #{strlinkreg}
.info-box .info-box
p p
strong ✓ Dopo la verifica strong ✓ Dopo la verifica
| potrai accedere alla piattaforma utilizzando le tue credenziali e | potrai accedere alla piattaforma utilizzando le tue credenziali e
strong  completare il tuo profilo. strong  completare il tuo profilo.
.cta-section .cta-section
.cta-title 🔐 2. Per accedere alla piattaforma #{nomeapp} .cta-title 🔐 2. Per accedere alla piattaforma #{nomeapp}

View File

@@ -856,3 +856,5 @@ Sab 08/11 ORE 20:24: 🤖: Da Surya Ar (SuryaSecondo):
/start 4b989bfb3d9af38551a8459ddf4a902c82e12017600c29bc050cc56fb835a881 /start 4b989bfb3d9af38551a8459ddf4a902c82e12017600c29bc050cc56fb835a881
Dom 09/11 ORE 18:36: 🤖: Da Sùrya undefined (surya1977): Dom 09/11 ORE 18:36: 🤖: Da Sùrya undefined (surya1977):
✅ surya4 è stato Ammesso correttamente (da surya1977)! ✅ surya4 è stato Ammesso correttamente (da surya1977)!
Mar 18/11 ORE 22:31: 🤖: Da Sùrya undefined (surya1977):
✅ surya8 è stato Ammesso correttamente (da surya1977)!

View File

@@ -25,7 +25,6 @@ var file = `.env.${node_env}`;
// GLOBALI (Uguali per TUTTI) // GLOBALI (Uguali per TUTTI)
process.env.LINKVERIF_REG = '/vreg'; process.env.LINKVERIF_REG = '/vreg';
process.env.LINK_INVITO_A_REG = '/invitetoreg';
process.env.LINK_REQUEST_NEWPASSWORD = '/requestnewpwd'; process.env.LINK_REQUEST_NEWPASSWORD = '/requestnewpwd';
process.env.ADD_NEW_SITE = '/addNewSite'; process.env.ADD_NEW_SITE = '/addNewSite';
process.env.LINK_UPDATE_PASSWORD = '/updatepassword'; process.env.LINK_UPDATE_PASSWORD = '/updatepassword';

View File

@@ -159,8 +159,10 @@ async function filterValidItems(mycart) {
const OrdersCart = require('./orderscart'); const OrdersCart = require('./orderscart');
// Cancella l'ordine su Order e OrderCart e cancella il record su Cart // Cancella l'ordine su Order e OrderCart e cancella il record su Cart
await OrdersCart.deleteOrderById(item.order._id.toString()); if (item.order) {
await Order.deleteOrderById(item.order._id.toString()); await OrdersCart.deleteOrderById(item.order._id.toString());
await Order.deleteOrderById(item.order._id.toString());
}
haschanged = true; haschanged = true;
} }

View File

@@ -23,6 +23,9 @@ const ListaInvitiEmailSchema = new Schema({
userIdInvite: { userIdInvite: {
type: String, type: String,
}, },
usernameInvitante: {
type: String,
},
date_Invited: { date_Invited: {
type: Date, type: Date,
default: Date.now, default: Date.now,
@@ -84,4 +87,3 @@ module.exports.findAllIdApp = async function (idapp) {
module.exports.createIndexes() module.exports.createIndexes()
.then(() => { }) .then(() => { })
.catch((err) => { throw err; }); .catch((err) => { throw err; });

View File

@@ -375,9 +375,9 @@ module.exports.generateNewSite_IdApp = async function (idapp, params, createpage
myp = new MyPage({ myp = new MyPage({
order: 10, order: 10,
idapp: mysite.idapp, idapp: mysite.idapp,
path: 'home_logout', path: 'presentazione',
active: true, active: true,
title: 'Home NoLoggato', title: 'Presentazione',
}); });
rispag = await myp.save(); rispag = await myp.save();
} }

View File

@@ -6,11 +6,44 @@ const nodemailer = require('nodemailer');
const { authenticate, authenticate_noerror, auth_default } = require('../middleware/authenticate'); const { authenticate, authenticate_noerror, auth_default } = require('../middleware/authenticate');
const sendemail = require('../sendemail'); const sendemail = require('../sendemail');
const tools = require('../tools/general');
const { User } = require('../models/user');
const ListaInvitiEmail = require('../models/listainvitiemail');
// ========================================== // ==========================================
// ENDPOINT API // ENDPOINT API
// ========================================== // ==========================================
router.post('/getinv', async (req, res) => {
try {
const { tok } = req.body;
// Validazione
if (!tok) {
return res.status(400).json({
success: false,
message: 'token non presente',
});
}
const invitoreg = await ListaInvitiEmail.findOne({ token: tok }).lean();
if (invitoreg) {
return res.status(200).json({ success: true, rec: invitoreg });
} else {
return res.status(200).json({ success: false, rec: null });
}
} catch (e) {
return res.status(200).json({
success: false,
message: 'Errore ' + e.message,
});
}
});
/** /**
* POST /inviti/invia-email * POST /inviti/invia-email
* Invia un invito via email * Invia un invito via email
@@ -38,38 +71,37 @@ router.post('/invia-email', authenticate, async (req, res) => {
const dati = { messaggioPersonalizzato, emailAmico, usernameInvitante }; const dati = { messaggioPersonalizzato, emailAmico, usernameInvitante };
const userInvitante = await User.findOne({ idapp, username: usernameInvitante }, { username: 1 }); const userInvitante = await User.findOne({ idapp, username: usernameInvitante }, { username: 1 }).lean();
const invitoesiste = await ListaInvitiEmail.findOne({ idapp, email }); const invitoesiste = await ListaInvitiEmail.findOne({ idapp, email: emailAmico });
if (invitoesiste) { if (invitoesiste) {
const dateInvito = new Date(invitoesiste.date_Invited); const dateInvito = new Date(invitoesiste.date_Invited);
const dateNow = new Date(); const dateNow = new Date();
const diffTime = Math.abs(dateNow - dateInvito); const diffTime = Math.abs(dateNow - dateInvito);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24 * 7)); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24 * 7));
if (diffDays > 7) { if (diffDays > 1) {
// Posso reinviare l'invito // Posso reinviare l'invito
await ListaInvitiEmail.deleteOne({ _id: invitoesiste._id }); await ListaInvitiEmail.deleteOne({ _id: invitoesiste._id });
invitoesiste = null; invitoesiste = null;
} else { } else {
return res.status(200).json({ return res.status(200).json({
success: false, success: false,
message: `L'invito a questa email è stato già inviato il ${dateInvito.toDateString()}`, message: 'L\'invito a questa email è stato già inviato il ' + tools.getstrDate_DD_MM_YYYY(dateInvito),
emailInviata: false, emailInviata: false,
}); });
} }
} }
const token = crypto.createHash('sha256').update(JSON.stringify(dati)).digest('hex'); dati.token = tools.getTokenRandom();
dati.token = token;
// aggiungi la email alla lista inviti // aggiungi la email alla lista inviti
const listainviti = new ListaInvitiEmail({ const listainviti = new ListaInvitiEmail({
idapp, idapp,
email: emailAmico, email: emailAmico,
userIdInvite: userInvitante.username, usernameInvitante: userInvitante.username,
token, userIdInvite: userInvitante._id,
token: dati.token,
}); });
await listainviti.save(); await listainviti.save();

View File

@@ -3,6 +3,8 @@ const router = express.Router();
const { User } = require('../models/user'); const { User } = require('../models/user');
const ListaInvitiEmail = require('../models/listainvitiemail');
// const { Nave } = require('../models/nave'); // const { Nave } = require('../models/nave');
const Hours = require('../models/hours'); const Hours = require('../models/hours');
//const { NavePersistente } = require('../models/navepersistente'); //const { NavePersistente } = require('../models/navepersistente');
@@ -136,6 +138,17 @@ router.post('/', async (req, res) => {
user.linkreg = reg.getlinkregByEmail(body.idapp, body.email, body.username); user.linkreg = reg.getlinkregByEmail(body.idapp, body.email, body.username);
user.verified_email = false; user.verified_email = false;
// Se è parte di un invito allora verified_email = true
const recinvito = await ListaInvitiEmail.findOne({ email: body.email });
if (recinvito) {
user.verified_email = true;
recinvito.registered = true;
recinvito.userIdRegistered = user._id;
await recinvito.save();
}
user.lasttimeonline = new Date(); user.lasttimeonline = new Date();
user.date_reg = new Date(); user.date_reg = new Date();
user.aportador_iniziale = user.aportador_solidario; user.aportador_iniziale = user.aportador_solidario;

View File

@@ -495,7 +495,7 @@ module.exports = {
return strlinkreg; return strlinkreg;
}, },
getlinkInvitoReg: function (idapp, dati) { getlinkInvitoReg: function (idapp, dati) {
const strlinkreg = tools.getHostByIdApp(idapp) + process.env.LINK_INVITO_A_REG + `/?idapp=${idapp}&tok=${dati.token}`; const strlinkreg = tools.getHostByIdApp(idapp) + `/invitetoreg/${dati.token}`;
return strlinkreg; return strlinkreg;
}, },
sendEmail_Registration: async function (lang, emailto, user, idapp, idreg) { sendEmail_Registration: async function (lang, emailto, user, idapp, idreg) {
@@ -510,6 +510,7 @@ module.exports = {
strlinkreg: this.getlinkReg(idapp, idreg), strlinkreg: this.getlinkReg(idapp, idreg),
forgetpwd: tools.getHostByIdApp(idapp) + '/requestresetpwd', forgetpwd: tools.getHostByIdApp(idapp) + '/requestresetpwd',
emailto: emailto, emailto: emailto,
verified_email: user.verified_email,
user, user,
}; };

View File

@@ -1,61 +1,97 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const express = require('express');
var app = express();
function parseDomains() { function parseDomains() {
try { try {
return { const ris = {
domains: JSON.parse(process.env.DOMAINS || '[]'), domains: JSON.parse(process.env.DOMAINS || '[]'),
domainsAllowed: JSON.parse(process.env.DOMAINS_ALLOWED || '[]'), domainsAllowed: JSON.parse(process.env.DOMAINS_ALLOWED || '[]'),
}; };
return ris;
} catch { } catch {
return { domains: [], domainsAllowed: [] }; return { domains: [], domainsAllowed: [] };
} }
} }
function createCorsOptions(domains = [], domainsAllowed = [], isProduction = false) { function buildAllowedOrigins(domains, domainsAllowed, isProduction) {
// 1⃣ Prepara la lista host ammessi (senza porta) if (!isProduction) {
const baseHosts = isProduction return [
? domains.flatMap((d) => [d.hostname, `api.${d.hostname}`, `test.${d.hostname}`, `testapi.${d.hostname}`]) 'https://localhost:3000',
: ['localhost', '127.0.0.1']; 'https://localhost:8089',
'https://localhost:8082',
'https://localhost:8083',
'https://localhost:8084',
'https://localhost:8085',
'https://localhost:8088',
'https://localhost:8099',
'https://localhost:8094',
'https://192.168.8.182',
'https://192.168.8.182:8084/',
'http://192.168.8.182:8084/',
];
}
const extraHosts = domainsAllowed.map((d) => d.replace(/^https?:\/\//, '').split(':')[0]); const baseOrigins = domains.flatMap((domain) => [
`https://${domain.hostname}`,
`https://api.${domain.hostname}`,
`https://test.${domain.hostname}`,
`https://testapi.${domain.hostname}`,
`http://${domain.hostname}`,
`http://api.${domain.hostname}`,
`http://test.${domain.hostname}`,
`http://testapi.${domain.hostname}`,
]);
const allowedHosts = [...new Set([...baseHosts, ...extraHosts])]; console.log('baseOrigins:', baseOrigins.map((origin) => `'${origin}'`).join(', '));
// 2⃣ Funzione di validazione origin (accetta qualsiasi porta) const allowedExtra = domainsAllowed.flatMap((domain) => [`https://${domain}`, `http://${domain}`]);
const originValidator = (origin, callback) => {
if (!origin) return callback(null, true); // Postman, curl, ecc.
try { return [...baseOrigins, ...allowedExtra];
const url = new URL(origin); }
const host = url.hostname.toLowerCase();
if (allowedHosts.includes(host)) { function createCorsOptions(domains, domainsAllowed, isProduction, noCors = false) {
// if (!isProduction) console.log(`✅ [CORS OK] ${origin}`); if (noCors) {
return callback(null, true); console.log('NOCORS mode enabled');
} return {
exposedHeaders: ['x-auth', 'x-refrtok'],
};
}
if (!isProduction) { const allowedOrigins = buildAllowedOrigins(domains, domainsAllowed, isProduction);
console.warn(`⚠️ [CORS DEV] origin non ammessa: ${origin} (host: ${host})`);
return callback(null, true); // in dev permetti tutto
}
console.error(`❌ [CORS BLOCKED] ${origin}`); let originValidator = (origin, callback) => {
return callback(new Error(`CORS denied for origin ${origin}`), false); if (!origin) {
} catch (err) { // console.log('✅ Origin undefined or empty — allowing');
console.error(`❌ [CORS ERROR] parsing origin: ${origin} -> ${err.message}`); return callback(null, true);
return callback(new Error('CORS denied: invalid origin'), false);
} }
if (typeof origin !== 'string' || !/^https?:\/\/[^\s/$.?#].[^\s]*$/.test(origin)) {
console.error('❌ Invalid origin:', origin);
return callback(new Error('Origine non valida'), false);
}
if (allowedOrigins.includes(origin)) {
return callback(null, true);
}
console.warn('❌ Origin blocked:', origin);
return callback(new Error('CORS non permesso per questa origine'), false);
}; };
// 3⃣ Restituisce loggetto completo per il middleware cors() if (app.get('env') === 'development') {
originValidator = (_origin, callback) => callback(null, true);
}
return { return {
origin: originValidator, origin: originValidator,
credentials: true, credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'], methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'],
allowedHeaders: ['Origin', 'X-Requested-With', 'Content-Type', 'Accept', 'Authorization', 'x-auth', 'x-refrtok'], allowedHeaders: ['Origin', 'X-Requested-With', 'Content-Type', 'Accept', 'Authorization', 'x-auth', 'x-refrtok'],
exposedHeaders: ['x-auth', 'x-refrtok'], exposedHeaders: ['x-auth', 'x-refrtok'],
maxAge: 86400, // 24 ore di caching per la preflight response maxAge: 86400,
preflightContinue: false, preflightContinue: false,
optionsSuccessStatus: 204, optionsSuccessStatus: 204,
}; };

View File

@@ -26,9 +26,14 @@ async function startServer(app, port) {
setupExpress(app, corsOptions); setupExpress(app, corsOptions);
setupRouters(app); setupRouters(app);
setupMailchimpRoutes(app); setupMailchimpRoutes(app);
console.log('DOMAINS:', domains)
console.log(domains.map(({ hostname, port }) => `${hostname}:${port}`).join(', '));
console.table(domains);
// 👇 logica migliorata per gestire HTTPS anche in dev // 👇 logica migliorata per gestire HTTPS anche in dev
if (isProduction) { if (isProduction) {
server = await createHttpsServers(domains, app); await createHttpsServers(domains, app);
} else if (process.env.HTTPS_LOCALHOST === 'true') { } else if (process.env.HTTPS_LOCALHOST === 'true') {
server = await createHttpsLocalServer(app, port); server = await createHttpsLocalServer(app, port);
} else { } else {
@@ -42,11 +47,14 @@ async function startServer(app, port) {
} }
async function createHttpsServers(domains, app) { async function createHttpsServers(domains, app) {
console.log('NUMERO DOMINI:', domains.length);
for (const d of domains) { for (const d of domains) {
console.log('. DOMINIO: ', d.hostname + ' ...');
const credentials = await getCredentials(d.hostname); const credentials = await getCredentials(d.hostname);
const server = https.createServer(credentials, app); const server = https.createServer(credentials, app);
server.listen(d.port, () => console.log(`⭐️ HTTPS ${d.hostname}:${d.port}`)); server.listen(d.port, () => {
return server; console.log(`⭐️ HTTPS ${d.hostname} server running on port ${d.port}`)
});
} }
} }

View File

@@ -819,6 +819,8 @@ connectToDatabase(connectionUrl, options)
`http://testapi.${domain.hostname}`, `http://testapi.${domain.hostname}`,
]); ]);
console.log('baseOrigins:', baseOrigins.map(origin => `'${origin}'`).join(', '));
const allowedExtra = domainsAllowed.flatMap((domain) => [`https://${domain}`, `http://${domain}`]); const allowedExtra = domainsAllowed.flatMap((domain) => [`https://${domain}`, `http://${domain}`]);
return [...baseOrigins, ...allowedExtra]; return [...baseOrigins, ...allowedExtra];
@@ -1059,6 +1061,7 @@ connectToDatabase(connectionUrl, options)
const { domains, domainsAllowed } = parseDomains(); const { domains, domainsAllowed } = parseDomains();
console.log('domains:', domains); console.log('domains:', domains);
console.log('isProduction:', isProduction); console.log('isProduction:', isProduction);

View File

@@ -17,6 +17,7 @@ const axios = require('axios');
const CryptoJS = require('crypto-js'); const CryptoJS = require('crypto-js');
const Url = require('url-parse'); const Url = require('url-parse');
const crypto = require('crypto');
const { ObjectId } = require('mongodb'); const { ObjectId } = require('mongodb');
@@ -6301,6 +6302,11 @@ module.exports = {
return null; return null;
}, },
getTokenRandom() {
return crypto.randomBytes(32).toString('hex');
},
async ensureDir(fullnamepath) { async ensureDir(fullnamepath) {
const dir = path.dirname(fullnamepath); const dir = path.dirname(fullnamepath);