- primo aggiornamento myreccard

- aggiunta sito germogliamo.app
- aggiornato login con il parametro "browser_random" che serve per fare un login anche su 2 pagine contemporaneamente.
This commit is contained in:
Surya Paolo
2025-11-25 17:45:24 +01:00
parent c61572a715
commit 70698fab44
15 changed files with 134 additions and 50 deletions

View File

@@ -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_

View File

@@ -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_

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -18,6 +18,7 @@ const SubscriberSchema = new Schema({
userId: String,
access: String,
browser: String,
browser_random: String,
createDate: {
type: Date,
default: Date.now

View File

@@ -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;
};

View File

@@ -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}`);

View File

@@ -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();

View File

@@ -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,

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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;

View File

@@ -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,
};
}