diff --git a/.env.dev.riso b/.env.dev.riso index 7bca35d..f19d428 100644 --- a/.env.dev.riso +++ b/.env.dev.riso @@ -29,8 +29,8 @@ GCM_API_KEY="" PROD=0 PROJECT_DESCR_MAIN='__PROJECTS' SECRK=Askb38v23jjDFaoskBOWj92axXCQ -TOKEN_LIFE=10m -REFRESH_TOKEN_LIFE=14d +TOKEN_LIFE=1m +REFRESH_TOKEN_LIFE=30d FTPSERVER_HOST=139.162.166.31 FTPSERVER_PORT=21 FTPSERVER_USER=ftpusrsrv_ diff --git a/.env.development b/.env.development index f76bbfa..7d4430b 100644 --- a/.env.development +++ b/.env.development @@ -29,8 +29,8 @@ GCM_API_KEY="" PROD=0 PROJECT_DESCR_MAIN='__PROJECTS' SECRK=Askb38v23jjDFaoskBOWj92axXCQ -TOKEN_LIFE=2m -REFRESH_TOKEN_LIFE=14d +TOKEN_LIFE=30d +REFRESH_TOKEN_LIFE=30d FTPSERVER_HOST=139.162.166.31 FTPSERVER_PORT=21 FTPSERVER_USER=ftpusrsrv_ diff --git a/.env.prod.riso b/.env.prod.riso index 49e075c..a881335 100644 --- a/.env.prod.riso +++ b/.env.prod.riso @@ -30,7 +30,7 @@ SECRK=iUUb38v23jjDFaosWj92axkBOXCQ TOKEN_LIFE=30d REFRESH_TOKEN_LIFE=30d AUTH_NEW_SITES=B234HDSAOJ734ndcsdKWNV -DOMAINS=[{"hostname":"riso.app","port":"3006"},{"hostname":"freeplanet.app","port":"3000"},{"hostname":"nuovomondo.app","port":"3032"}] +DOMAINS=[{"hostname":"riso.app","port":"3006"},{"hostname":"freeplanet.app","port":"3000"},{"hostname":"nuovomondo.app","port":"3032"},{"hostname":"germogliamo.app","port":"3042"}] DOMAINS_ALLOWED=["riso.app","comunitanuovomondo.app","nuovomondo.app","kolibrilab.it","artenergetica.org","freeplanet.app","www.freeplanet.app","freeplanet.app:3000","freeplanet.app:3001","www.freeplanet.app:3000","www.freeplanet.app:3001"] #DOMAINS=[{"hostname":"abitaregliiblei.it","port":"3021"},{"hostname":"riso.app","port":"3005"}] SCRIPTS_DIR=admin_scripts diff --git a/src/controllers/UserController.js b/src/controllers/UserController.js index 0d32500..e51eb7c 100644 --- a/src/controllers/UserController.js +++ b/src/controllers/UserController.js @@ -55,7 +55,7 @@ class UserController { } // Send response with tokens - res.header('x-auth', result.token).header('x-refrtok', result.refreshToken).send(result.user); + res.header('x-auth', result.token).header('x-refrtok', result.refreshToken).header('x-browser-random', result.browser_random).send(result.user); } catch (error) { console.error('Error in registration:', error.message); res.status(400).send({ @@ -72,7 +72,9 @@ class UserController { async login(req, res) { try { console.log('LOGIN'); - const { username, password, idapp, keyappid } = req.body; + const { username, password, idapp, keyappid, br } = req.body; + + const browser_random = br; // Validate API key if (keyappid !== process.env.KEY_APP_ID) { @@ -89,7 +91,7 @@ class UserController { } // Attempt login - const result = await this.authService.authenticate(idapp, username, password, req); + const result = await this.authService.authenticate(idapp, username, password, req, browser_random); console.log('attempt...', result); @@ -101,7 +103,7 @@ class UserController { } // Send response with tokens - res.header('x-auth', result.token).header('x-refrtok', result.refreshToken).send({ + res.header('x-auth', result.token).header('x-refrtok', result.refreshToken).header('x-browser-random', result.browser_random).send({ usertosend: result.user, code: server_constants.RIS_CODE_OK, subsExistonDb: result.subsExistonDb, @@ -262,7 +264,9 @@ class UserController { */ async refreshToken(req, res) { try { - const { refreshToken } = req.body; + const { refreshToken, br } = req.body; + + const browser_random = br; if (!refreshToken) { return res.status(400).send({ error: 'Refresh token mancante' }); @@ -277,6 +281,7 @@ class UserController { res.status(200).send({ token: result.token, refreshToken: result.refreshToken, + browser_random, }); } catch (error) { console.error('Error in refreshToken:', error.message); diff --git a/src/middleware/authenticate.js b/src/middleware/authenticate.js index af434be..fc77938 100755 --- a/src/middleware/authenticate.js +++ b/src/middleware/authenticate.js @@ -19,8 +19,11 @@ const authenticateMiddleware = async (req, res, next, withUser = false, lean = f try { const logPrefix = noError ? (withUser ? (lean ? 'WITHUSERLEAN' : 'WITHUSER') : 'NOERROR') : 'AUTH'; + // Validazione token const token = req.header('x-auth'); + const browser_random = req.header('x-browser-random'); + const refreshToken = req.header('x-refrtok'); if (!token) { return handleAuthFailure(req, res, next, { code: server_constants.RIS_CODE_HTTP_INVALID_TOKEN, @@ -31,13 +34,13 @@ const authenticateMiddleware = async (req, res, next, withUser = false, lean = f } // Recupera utente - const refreshToken = req.header('x-refrtok'); - const user = await User.findByToken(token, 'auth', false, withUser, lean); + const user = await User.findByToken(token, 'auth', browser_random, false, withUser, lean); // Imposta dati richiesta req.user = user.code === server_constants.RIS_CODE_OK ? user.user : null; req.token = user.code === server_constants.RIS_CODE_OK ? token : null; req.refreshToken = refreshToken; + req.browser_random = browser_random; req.code = user.code; req.statuscode2 = null; diff --git a/src/models/subscribers.js b/src/models/subscribers.js index 13172f9..d53d458 100755 --- a/src/models/subscribers.js +++ b/src/models/subscribers.js @@ -18,6 +18,7 @@ const SubscriberSchema = new Schema({ userId: String, access: String, browser: String, + browser_random: String, createDate: { type: Date, default: Date.now diff --git a/src/models/user.js b/src/models/user.js index 91c6c8a..527df26 100755 --- a/src/models/user.js +++ b/src/models/user.js @@ -136,6 +136,10 @@ const UserSchema = new mongoose.Schema({ type: String, default: '', }, + browser_random: { + type: String, + default: '', + }, date_login: { type: Date, }, @@ -571,7 +575,7 @@ UserSchema.methods.toJSON = function () { return _.pick(userObject, ['_id', ...shared_consts.fieldsUserToChange()]); }; -UserSchema.methods.generateAuthToken = function (req) { +UserSchema.methods.generateAuthToken = function (req, browser_random) { const user = this; const useragent = req.get('User-Agent'); @@ -607,13 +611,24 @@ UserSchema.methods.generateAuthToken = function (req) { const date_login = new Date(); - // Controlla se il token è già presente per la coppia access-browser - const idx = user.tokens.findIndex((tok) => tok.access === access && tok.browser === browser); + /* + if (user.tokens) { + console.log('token salvati: ' + user.tokens.length); + } else { + console.log('⚠️ Nessun Token salvato! '); + }*/ + + // Controlla se il token è già presente per la tripla access-browser-browser_random + const idx = user.tokens.findIndex( + (tok) => + tok.access === access && tok.browser === browser && (!browser_random || tok.browser_random === browser_random) + ); + if (idx === -1) { - user.tokens.push({ access, browser, token, date_login, refreshToken }); + user.tokens.push({ access, browser, token, date_login, refreshToken, browser_random }); } else { // Se il token esiste già, sostituisce il valore vecchio con il nuovo - user.tokens[idx] = { access, browser, token, date_login, refreshToken }; + user.tokens[idx] = { access, browser, token, date_login, refreshToken, browser_random }; } user.lasttimeonline = new Date(); @@ -622,11 +637,11 @@ UserSchema.methods.generateAuthToken = function (req) { .save() .then(() => { console.log('########## HO CREATO UN NUOVO TOKEN E REFRESHTOKEN !!!!! ----------- '); - return { token, refreshToken }; + return { token, refreshToken, browser_random }; }) .catch((err) => { console.log('Error', err.message); - return { token: '', refreshToken: '' }; + return { token: '', refreshToken: '', browser_random }; }); }; @@ -802,7 +817,16 @@ UserSchema.statics.isFacilitatore = function (perm) { */ // Funzione helper separata per trovare l'utente -async function findUserByTokenAndAccess(User, decoded, token, typeaccess, withuser, withlean, project) { +async function findUserByTokenAndAccessAndBrowserRandom( + User, + decoded, + token, + typeaccess, + browser_random, + withuser, + withlean, + project +) { try { const query = { _id: decoded._id, @@ -810,6 +834,7 @@ async function findUserByTokenAndAccess(User, decoded, token, typeaccess, withus $elemMatch: { token, access: typeaccess, + browser_random, }, }, }; @@ -829,6 +854,7 @@ async function findUserByTokenAndAccess(User, decoded, token, typeaccess, withus $elemMatch: { token, access: typeaccess, + browser_random, }, }, }; @@ -842,7 +868,14 @@ async function findUserByTokenAndAccess(User, decoded, token, typeaccess, withus } // Funzione principale refactored -UserSchema.statics.findByToken = async function (token, typeaccess, con_auth, withuser, withlean = false) { +UserSchema.statics.findByToken = async function ( + token, + typeaccess, + browser_random, + con_auth, + withuser, + withlean = false +) { const User = this; let code = server_constants.RIS_CODE_HTTP_INVALID_TOKEN; let user = null; @@ -884,7 +917,16 @@ UserSchema.statics.findByToken = async function (token, typeaccess, con_auth, wi }; // Ricerca utente con funzione separata - user = await findUserByTokenAndAccess(User, decoded, token, typeaccess, withuser, withlean, project); + user = await findUserByTokenAndAccessAndBrowserRandom( + User, + decoded, + token, + typeaccess, + browser_random, + withuser, + withlean, + project + ); // Verifica scadenza token per idapp specifici if (user) { @@ -1634,7 +1676,6 @@ UserSchema.statics.setAmmissioneByTokenAndUsername = async function (idapp, user const User = this; try { - if (username === undefined) return false; const myquery = { @@ -1660,7 +1701,11 @@ UserSchema.statics.setAmmissioneByTokenAndUsername = async function (idapp, user return recfound; } - const rec = await User.findOneAndUpdate(myquery, { $set: { token_da_ammettere: token, date_token_ammettere: new Date(), } }, { new: true }); + const rec = await User.findOneAndUpdate( + myquery, + { $set: { token_da_ammettere: token, date_token_ammettere: new Date() } }, + { new: true } + ); return rec; } catch (e) { console.error('Error setAmmissione', e); @@ -1677,7 +1722,13 @@ UserSchema.statics.findAmmissioneByTokenAndUsername = async function (idapp, tok token_da_ammettere: token, }; - const rec = await User.findOne(myquery, { verified_by_aportador: 1, username: 1, aportador_solidario: 1, idapp: 1, lang: 1 }); + const rec = await User.findOne(myquery, { + verified_by_aportador: 1, + username: 1, + aportador_solidario: 1, + idapp: 1, + lang: 1, + }); return rec && username.toLowerCase() === rec.username.toLowerCase() ? rec : null; }; diff --git a/src/router/index_router.js b/src/router/index_router.js index 6943da7..dc2722a 100755 --- a/src/router/index_router.js +++ b/src/router/index_router.js @@ -296,9 +296,10 @@ router.post(process.env.LINK_REQUEST_NEWPASSWORD, async (req, res) => { // Ritorna il token per poter effettuare le chiamate... router.post(process.env.LINK_UPDATE_PWD, async (req, res) => { try { - const body = _.pick(req.body, ['idapp', 'email', 'tokenforgot', 'tokenforgot_code', 'password']); + const body = _.pick(req.body, ['idapp', 'email', 'tokenforgot', 'tokenforgot_code', 'password', 'br']); const idapp = body.idapp; const email = body.email.toLowerCase().trim(); + const browser_random = body.br; const tokenforgot = body.tokenforgot; const tokenforgot_code = body.tokenforgot_code; const password = body.password; @@ -347,6 +348,7 @@ router.post(process.env.LINK_UPDATE_PWD, async (req, res) => { res .header('x-auth', ris.token) .header('x-refrtok', ris.refreshToken) + .header('x-browser-random', ris.browser_random) .send({ code: server_constants.RIS_CODE_OK }); // Ritorna il token di ritorno }); }); @@ -2024,7 +2026,7 @@ async function testMongoPerformance(ind, iterations = 20) { const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiJQUk9WQU1TR0AxQSIsInNtYXJ0IjoiNjIwODAwYWRjMTI5ZDFlYmE3NjBiZWNiIiwiYWNjZXNzIjoiYXV0aCIsInVuIjoic3VyeWExOTc3IiwiaWF0IjoxNzQxODcyMzEwLCJleHAiOjE3NDE4Nzk1MTB9.SXJLmsS6EZVhaU7sUWYMnaqGpiiy8RfE9K43xTdxNuU'; - await User.findByToken(token, 'auth', true, true); + await User.findByToken(token, 'auth', '', true, true); } } catch (err) { log(`Errore nell'iterazione ${i + 1}: ${err.message}`); diff --git a/src/router/subscribe_router.js b/src/router/subscribe_router.js index 17ebe88..d9fe5fb 100755 --- a/src/router/subscribe_router.js +++ b/src/router/subscribe_router.js @@ -37,6 +37,7 @@ router.post('/', authenticate, async (req, res) => { subscriptionModel.userId = req.body.others.userId; subscriptionModel.access = req.body.others.access; subscriptionModel.browser = req.get('User-Agent'); + subscriptionModel.browser_random = req.body.others.browser_random; // console.log('subscriptionModel.browser', subscriptionModel.browser); @@ -45,6 +46,7 @@ router.post('/', authenticate, async (req, res) => { userId: subscriptionModel.userId, access: subscriptionModel.access, browser: subscriptionModel.browser, + browser_random: subscriptionModel.browser_random, }).then(itemsub => { return itemsub; }).catch(err => { @@ -96,8 +98,9 @@ router.delete('/del', authenticate, async (req, res) => { if (req.user) { const browser = req.get('User-Agent'); + const browser_random = req.body.browser_random; return await Subscription.findOneAndDelete( - { userId: req.user._id, access: req.access, browser }).then(() => { + { userId: req.user._id, access: req.access, browser, browser_random }).then(() => { res.status(200).send(); }, () => { res.status(400).send(); diff --git a/src/router/users_router.js b/src/router/users_router.js index 0fd3bcb..dfbfd4e 100755 --- a/src/router/users_router.js +++ b/src/router/users_router.js @@ -58,9 +58,9 @@ const mongoose = require('mongoose').set('debug', false); const Subscription = require('../models/subscribers'); const Macro = require('../modules/Macro'); -async function existSubScribe(userId, access, browser) { +async function existSubScribe(userId, access, browser, browser_random) { try { - const itemsub = await Subscription.findOne({ userId, access, browser }).lean(); + const itemsub = await Subscription.findOne({ userId, access, browser, browser_random }).lean(); return itemsub; } catch (err) { return null; @@ -101,6 +101,7 @@ router.post('/', async (req, res) => { 'lang', 'profile', 'aportador_solidario', + 'br', ]); body.email = body.email.toLowerCase(); @@ -112,6 +113,8 @@ router.post('/', async (req, res) => { user.name = user.name.trim(); user.surname = user.surname.trim(); + const browser_random = body.br; + if (user.aportador_solidario === 'tuo_username' || user.aportador_solidario === '{username}') { user.aportador_solidario = 'surya1977'; } @@ -313,8 +316,8 @@ router.post('/', async (req, res) => { // Invia la richiesta di ammissione all'Invitante! await telegrambot.askConfirmationUser(myuser.idapp, shared_consts.CallFunz.REGISTRATION, myuser); - const { token, refreshToken } = await myuser.generateAuthToken(req); - res.header('x-auth', token).header('x-refrtok', refreshToken).send(myuser); + const { token, refreshToken, browser_random } = await myuser.generateAuthToken(req, browser_random); + res.header('x-auth', token).header('x-refrtok', refreshToken).header('x-browser-random', browser_random).send(myuser); return true; } } @@ -327,7 +330,7 @@ router.post('/', async (req, res) => { .then((usertrovato) => { // tools.mylog("TROVATO USERNAME ? ", user.username, usertrovato); if (usertrovato !== null) { - return user.generateAuthToken(req); + return user.generateAuthToken(req, browser_random); } else { res.status(400).send(); return 0; @@ -365,7 +368,7 @@ router.post('/', async (req, res) => { // if (!tools.testing()) { await sendemail.sendEmail_Registration(user.lang, user.email, user, user.idapp, user.linkreg); // } - res.header('x-auth', ris.token).header('x-refrtok', ris.refreshToken).send(user); + res.header('x-auth', ris.token).header('x-refrtok', ris.refreshToken).header('x-browser-random', ris.browser_random).send(user); return true; }); }) @@ -667,7 +670,7 @@ router.post('/newtok', async (req, res) => { return res.status(403).send({ error: 'Refresh token non valido' }); } - const { token, refreshToken: newRefreshToken } = await recFound.generateAuthToken(req); + const { token, refreshToken: newRefreshToken } = await recFound.generateAuthToken(req, browser_random); return res.status(200).send({ token, @@ -708,8 +711,10 @@ function checkBlocked(req, res, next) { } router.post('/login', checkBlocked, async (req, res) => { - const body = _.pick(req.body, ['username', 'password', 'idapp', 'keyappid', 'lang']); + const body = _.pick(req.body, ['username', 'password', 'idapp', 'keyappid', 'lang', 'br']); const userpass = new User(body); + + const browser_random = body.br; // const subs = _.pick(req.body, ['subs']); // tools.mylog("LOG: u: " + user.username + " p:" + user.password); @@ -783,7 +788,7 @@ router.post('/login', checkBlocked, async (req, res) => { return res.status(401).send({ code: server_constants.RIS_CODE_LOGIN_ERR }); } else { - const myris = await user.generateAuthToken(req); + const myris = await user.generateAuthToken(req, browser_random); const usertosend = new User(); @@ -791,7 +796,7 @@ router.post('/login', checkBlocked, async (req, res) => { usertosend[field] = user[field]; }); - const subsExistonDb = await existSubScribe(usertosend._id, 'auth', req.get('User-Agent')); + const subsExistonDb = await existSubScribe(usertosend._id, 'auth', req.get('User-Agent'), myris.browser_random); res.header('x-auth', myris.token).header('x-refrtok', myris.refreshToken).send({ usertosend, diff --git a/src/server/serverUtils.js b/src/server/serverUtils.js index 61bc365..85f9d8c 100644 --- a/src/server/serverUtils.js +++ b/src/server/serverUtils.js @@ -56,7 +56,7 @@ function createCorsOptions(domains, domainsAllowed, isProduction, noCors = false if (noCors) { console.log('NOCORS mode enabled'); return { - exposedHeaders: ['x-auth', 'x-refrtok'], + exposedHeaders: ['x-auth', 'x-refrtok', 'x-browser-random'], }; } @@ -91,8 +91,8 @@ function createCorsOptions(domains, domainsAllowed, isProduction, noCors = false origin: originValidator, credentials: true, methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'], - allowedHeaders: ['Origin', 'X-Requested-With', 'Content-Type', 'Accept', 'Authorization', 'x-auth', 'x-refrtok'], - exposedHeaders: ['x-auth', 'x-refrtok'], + allowedHeaders: ['Origin', 'X-Requested-With', 'Content-Type', 'Accept', 'Authorization', 'x-auth', 'x-refrtok', 'x-browser-random'], + exposedHeaders: ['x-auth', 'x-refrtok', 'x-browser-random'], maxAge: 86400, preflightContinue: false, optionsSuccessStatus: 204, diff --git a/src/server/setupRouters.js b/src/server/setupRouters.js index 0c57363..7dcb77f 100644 --- a/src/server/setupRouters.js +++ b/src/server/setupRouters.js @@ -45,7 +45,8 @@ function setupRouters(app) { const router = require(`../router/${file}`); app.use(path, router); } catch (err) { - console.error(`❌ Errore caricamento router ${file}: ${err.message}`); + console.error(`❌ Errore caricamento router ${file}:`, err.stack ? err.stack : err.message); + return false; } }); @@ -56,6 +57,8 @@ function setupRouters(app) { service: 'invita-amico-api', }); }); + + return true; } function setupMailchimpRoutes(app) { diff --git a/src/server/startServer.js b/src/server/startServer.js index 3272a5e..db29cfc 100644 --- a/src/server/startServer.js +++ b/src/server/startServer.js @@ -24,7 +24,12 @@ async function startServer(app, port) { await myLoad().then(async (ris) => { setupExpress(app, corsOptions); - setupRouters(app); + const ok = setupRouters(app); + + if (!ok) { + console.error('Errore durante setupRouters'); + process.exit(1); + } setupMailchimpRoutes(app); console.log('DOMAINS:', domains) diff --git a/src/services/AuthService.js b/src/services/AuthService.js index 2867be4..beae919 100644 --- a/src/services/AuthService.js +++ b/src/services/AuthService.js @@ -14,7 +14,7 @@ class AuthService { /** * Authenticate user with username and password */ - async authenticate(idapp, username, password, req) { + async authenticate(idapp, username, password, req, browser_random) { try { console.log('STO FACENDO LOGIN...'); // Check if user is blocked @@ -42,7 +42,7 @@ class AuthService { delete this.failedLoginAttempts[username]; // Generate tokens - const { token, refreshToken } = await user.generateAuthToken(req); + const { token, refreshToken, browser_random } = await user.generateAuthToken(req); // Prepare user data to send const userToSend = this._prepareUserData(user); @@ -50,12 +50,13 @@ class AuthService { console.log('userToSend', userToSend); // Check subscription - const subsExistonDb = await this._checkSubscription(user._id, req.get('User-Agent')); + const subsExistonDb = await this._checkSubscription(user._id, req.get('User-Agent'), browser_random); return { error: false, token, refreshToken, + browser_random, user: userToSend, subsExistonDb, }; @@ -93,12 +94,13 @@ class AuthService { }; } - const { token, refreshToken: newRefreshToken } = await user.generateAuthToken(req); + const { token, refreshToken: newRefreshToken, browser_random } = await user.generateAuthToken(req); return { error: false, token, refreshToken: newRefreshToken, + browser_random, }; } catch (error) { console.error('Error in refreshToken:', error.message); @@ -224,12 +226,13 @@ class AuthService { * Check if subscription exists * @private */ - async _checkSubscription(userId, userAgent) { + async _checkSubscription(userId, userAgent, browser_random) { try { const subscription = await Subscription.findOne({ userId, access: 'auth', browser: userAgent, + browser_random, }).lean(); return !!subscription; diff --git a/src/services/RegistrationService.js b/src/services/RegistrationService.js index 6a110d5..5226ae6 100644 --- a/src/services/RegistrationService.js +++ b/src/services/RegistrationService.js @@ -215,16 +215,18 @@ class RegistrationService { const myuser = await User.findOne({ _id: existingUser._id }); + if (myuser) { // Ask confirmation from inviter await telegrambot.askConfirmationUser(myuser.idapp, shared_consts.CallFunz.REGISTRATION, myuser); - const { token, refreshToken } = await myuser.generateAuthToken(req); + const { token, refreshToken, browser_random } = await myuser.generateAuthToken(req); return { error: false, token, refreshToken, + browser_random, user: myuser, }; } @@ -255,7 +257,7 @@ class RegistrationService { } // Generate tokens - const { token, refreshToken } = await savedUser.generateAuthToken(req); + const { token, refreshToken, browser_random } = await savedUser.generateAuthToken(req); if (!savedUser.verified_by_aportador) { // Send confirmation request to inviter @@ -278,6 +280,7 @@ class RegistrationService { error: false, token, refreshToken, + browser_random, user: savedUser, }; }