- aggiunta sito germogliamo.app - aggiornato login con il parametro "browser_random" che serve per fare un login anche su 2 pagine contemporaneamente.
493 lines
13 KiB
JavaScript
493 lines
13 KiB
JavaScript
const UserService = require('../services/UserService');
|
|
const AuthService = require('../services/AuthService');
|
|
const RegistrationService = require('../services/RegistrationService');
|
|
const { validateRegistration, validateLogin } = require('../validators/userValidators');
|
|
const telegrambot = require('../telegram/telegrambot');
|
|
const tools = require('../tools/general');
|
|
const server_constants = require('../tools/server_constants');
|
|
const shared_consts = require('../tools/shared_nodejs');
|
|
|
|
class UserController {
|
|
constructor() {
|
|
this.userService = new UserService();
|
|
this.authService = new AuthService();
|
|
this.registrationService = new RegistrationService();
|
|
}
|
|
|
|
/**
|
|
* Register new user
|
|
* POST /users
|
|
*/
|
|
async register(req, res) {
|
|
try {
|
|
tools.mylog('POST /users - Registration');
|
|
|
|
// Validate input
|
|
const validationError = validateRegistration(req.body);
|
|
if (validationError) {
|
|
await tools.snooze(5000);
|
|
return res.status(400).send({
|
|
code: validationError.code,
|
|
msg: validationError.message,
|
|
});
|
|
}
|
|
|
|
const userData = this._extractUserData(req.body);
|
|
userData.ipaddr = tools.getiPAddressUser(req);
|
|
|
|
// Check security (IP bans, block words, etc.)
|
|
const securityCheck = await this._performSecurityChecks(userData, req);
|
|
if (securityCheck.blocked) {
|
|
return res.status(securityCheck.status).send({
|
|
code: securityCheck.code,
|
|
msg: securityCheck.message,
|
|
});
|
|
}
|
|
|
|
// Process registration
|
|
const result = await this.registrationService.registerUser(userData, req);
|
|
|
|
if (result.error) {
|
|
return res.status(400).send({
|
|
code: result.code,
|
|
msg: result.message,
|
|
});
|
|
}
|
|
|
|
// Send response with tokens
|
|
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({
|
|
code: server_constants.RIS_CODE_ERR,
|
|
msg: error.message,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* User login
|
|
* POST /users/login
|
|
*/
|
|
async login(req, res) {
|
|
try {
|
|
console.log('LOGIN');
|
|
const { username, password, idapp, keyappid, br } = req.body;
|
|
|
|
const browser_random = br;
|
|
|
|
// Validate API key
|
|
if (keyappid !== process.env.KEY_APP_ID) {
|
|
return res.status(400).send({ code: server_constants.RIS_CODE_ERR });
|
|
}
|
|
|
|
// Validate input
|
|
const validationError = validateLogin(req.body);
|
|
if (validationError) {
|
|
return res.status(400).send({
|
|
code: validationError.code,
|
|
msg: validationError.message,
|
|
});
|
|
}
|
|
|
|
// Attempt login
|
|
const result = await this.authService.authenticate(idapp, username, password, req, browser_random);
|
|
|
|
console.log('attempt...', result);
|
|
|
|
if (result.error) {
|
|
return res.status(result.status).send({
|
|
code: result.code,
|
|
msg: result.message,
|
|
});
|
|
}
|
|
|
|
// Send response with tokens
|
|
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,
|
|
});
|
|
} catch (error) {
|
|
console.error('Error in login:', error.message);
|
|
res.status(400).send({
|
|
code: server_constants.RIS_CODE_LOGIN_ERR_GENERIC,
|
|
msgerr: error.message,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get user profile
|
|
* POST /users/profile
|
|
*/
|
|
async getProfile(req, res) {
|
|
try {
|
|
const usernameOrig = req.user?.username || '';
|
|
const perm = req.user?.perm || tools.Perm.PERM_NONE;
|
|
const { username, idapp, idnotif } = req.body;
|
|
|
|
// Mark notification as read if present
|
|
if (idnotif) {
|
|
await this.userService.markNotificationAsRead(idapp, usernameOrig, idnotif);
|
|
}
|
|
|
|
// Get user profile
|
|
const profile = await this.userService.getUserProfile(idapp, username, usernameOrig, perm);
|
|
|
|
res.send(profile);
|
|
} catch (error) {
|
|
console.error('Error in getProfile:', error.message);
|
|
res.status(400).send({
|
|
code: server_constants.RIS_CODE_ERR,
|
|
msg: error.message,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update user saldo (balance)
|
|
* POST /users/updatesaldo
|
|
*/
|
|
async updateSaldo(req, res) {
|
|
try {
|
|
const username = req.user.username;
|
|
const { idapp, circuitId, groupname, lastdr } = req.body;
|
|
|
|
const result = await this.userService.updateUserBalance(idapp, username, circuitId, groupname, lastdr);
|
|
|
|
res.send({ ris: result });
|
|
} catch (error) {
|
|
console.error('Error in updateSaldo:', error.message);
|
|
res.status(400).send({
|
|
code: server_constants.RIS_CODE_ERR,
|
|
msg: error.message,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get user's friends
|
|
* POST /users/friends
|
|
*/
|
|
async getFriends(req, res) {
|
|
try {
|
|
const username = req.user.username;
|
|
const { idapp } = req.body;
|
|
|
|
const friends = await this.userService.getUserFriends(idapp, username);
|
|
|
|
res.send(friends);
|
|
} catch (error) {
|
|
console.error('Error in getFriends:', error.message);
|
|
res.status(400).send({
|
|
code: server_constants.RIS_CODE_ERR,
|
|
msg: error.message,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute friend command (add, remove, etc.)
|
|
* POST /users/friends/cmd
|
|
*/
|
|
async executeFriendCommand(req, res) {
|
|
try {
|
|
const usernameLogged = req.user.username;
|
|
const { idapp, usernameOrig, usernameDest, cmd, value } = req.body;
|
|
|
|
// Security check
|
|
if (!this._canExecuteFriendCommand(req.user, usernameOrig, usernameDest, cmd)) {
|
|
return res.status(server_constants.RIS_CODE_ERR_UNAUTHORIZED).send({
|
|
code: server_constants.RIS_CODE_ERR_UNAUTHORIZED,
|
|
msg: '',
|
|
});
|
|
}
|
|
|
|
const result = await this.userService.executeFriendCommand(req, idapp, usernameOrig, usernameDest, cmd, value);
|
|
|
|
res.send(result);
|
|
} catch (error) {
|
|
console.error('Error in executeFriendCommand:', error.message);
|
|
res.status(400).send({
|
|
code: server_constants.RIS_CODE_ERR,
|
|
msg: error.message,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get user's groups
|
|
* POST /users/groups
|
|
*/
|
|
async getGroups(req, res) {
|
|
try {
|
|
const username = req.user.username;
|
|
const { idapp } = req.body;
|
|
|
|
const groups = await this.userService.getUserGroups(idapp, username, req);
|
|
|
|
res.send(groups);
|
|
} catch (error) {
|
|
console.error('Error in getGroups:', error.message);
|
|
res.status(400).send({
|
|
code: server_constants.RIS_CODE_ERR,
|
|
msg: error.message,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get user's circuits
|
|
* POST /users/circuits
|
|
*/
|
|
async getCircuits(req, res) {
|
|
try {
|
|
const username = req.user.username;
|
|
const { idapp, nummovTodownload } = req.body;
|
|
|
|
const circuits = await this.userService.getUserCircuits(idapp, username, req.user, nummovTodownload);
|
|
|
|
res.send(circuits);
|
|
} catch (error) {
|
|
console.error('Error in getCircuits:', error.message);
|
|
res.status(400).send({
|
|
code: server_constants.RIS_CODE_ERR,
|
|
msg: error.message,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Refresh authentication token
|
|
* POST /users/newtok
|
|
*/
|
|
async refreshToken(req, res) {
|
|
try {
|
|
const { refreshToken, br } = req.body;
|
|
|
|
const browser_random = br;
|
|
|
|
if (!refreshToken) {
|
|
return res.status(400).send({ error: 'Refresh token mancante' });
|
|
}
|
|
|
|
const result = await this.authService.refreshToken(refreshToken, req);
|
|
|
|
if (result.error) {
|
|
return res.status(result.status).send({ error: result.message });
|
|
}
|
|
|
|
res.status(200).send({
|
|
token: result.token,
|
|
refreshToken: result.refreshToken,
|
|
browser_random,
|
|
});
|
|
} catch (error) {
|
|
console.error('Error in refreshToken:', error.message);
|
|
res.status(500).send({ error: 'Errore interno del server' });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Logout user (remove token)
|
|
* DELETE /users/me/token
|
|
*/
|
|
async logout(req, res) {
|
|
try {
|
|
await this.authService.removeToken(req.user, req.token);
|
|
res.status(200).send();
|
|
} catch (error) {
|
|
console.error('Error in logout:', error.message);
|
|
res.status(400).send();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if username exists
|
|
* GET /users/:idapp/:username
|
|
*/
|
|
async checkUsername(req, res) {
|
|
try {
|
|
const { username, idapp } = req.params;
|
|
|
|
const exists = await this.userService.checkUsernameExists(idapp, username);
|
|
|
|
if (!exists) {
|
|
return res.status(404).send();
|
|
}
|
|
|
|
res.status(200).send();
|
|
} catch (error) {
|
|
console.error('Error in checkUsername:', error.message);
|
|
res.status(400).send();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update user permissions
|
|
* POST /users/setperm
|
|
*/
|
|
async setPermissions(req, res) {
|
|
try {
|
|
const { idapp, username, perm } = req.body;
|
|
|
|
await this.userService.setUserPermissions(req.user._id, {
|
|
idapp,
|
|
username,
|
|
perm,
|
|
});
|
|
|
|
res.status(200).send();
|
|
} catch (error) {
|
|
console.error('Error in setPermissions:', error.message);
|
|
res.status(400).send();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Database operations (admin only)
|
|
* POST /users/dbop
|
|
*/
|
|
async executeDbOperation(req, res) {
|
|
try {
|
|
const { mydata, idapp } = req.body;
|
|
|
|
// Check permissions
|
|
if (!this._hasAdminPermissions(req.user)) {
|
|
return res.status(404).send({
|
|
code: server_constants.RIS_CODE_ERR_UNAUTHORIZED,
|
|
});
|
|
}
|
|
|
|
const result = await this.userService.executeDbOperation(idapp, mydata, req, res);
|
|
|
|
res.send({
|
|
code: server_constants.RIS_CODE_OK,
|
|
data: result,
|
|
});
|
|
} catch (error) {
|
|
console.error('Error in executeDbOperation:', error.message);
|
|
res.status(400).send({
|
|
code: server_constants.RIS_CODE_ERR,
|
|
msg: error.message,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get map information
|
|
* POST /users/infomap
|
|
*/
|
|
async getMapInfo(req, res) {
|
|
try {
|
|
const { idapp } = req.body;
|
|
|
|
const mapData = await this.userService.getMapInformation(idapp);
|
|
|
|
res.send({
|
|
code: server_constants.RIS_CODE_OK,
|
|
ris: mapData,
|
|
});
|
|
} catch (error) {
|
|
console.error('Error in getMapInfo:', error.message);
|
|
res.status(400).send({
|
|
code: server_constants.RIS_CODE_ERR,
|
|
msg: error.message,
|
|
});
|
|
}
|
|
}
|
|
|
|
// ===== PRIVATE HELPER METHODS =====
|
|
|
|
_extractUserData(body) {
|
|
const fields = [
|
|
'email',
|
|
'password',
|
|
'username',
|
|
'group',
|
|
'name',
|
|
'surname',
|
|
'idapp',
|
|
'keyappid',
|
|
'lang',
|
|
'profile',
|
|
'aportador_solidario',
|
|
];
|
|
|
|
const userData = {};
|
|
fields.forEach((field) => {
|
|
if (body[field] !== undefined) {
|
|
userData[field] = body[field];
|
|
}
|
|
});
|
|
|
|
// Normalize data
|
|
if (userData.email) userData.email = userData.email.toLowerCase().trim();
|
|
if (userData.username) userData.username = userData.username.trim();
|
|
if (userData.name) userData.name = userData.name.trim();
|
|
if (userData.surname) userData.surname = userData.surname.trim();
|
|
|
|
return userData;
|
|
}
|
|
|
|
async _performSecurityChecks(userData, req) {
|
|
const { User } = require('../models/user');
|
|
|
|
// Check for blocked words
|
|
if (tools.blockwords(userData.username) || tools.blockwords(userData.name) || tools.blockwords(userData.surname)) {
|
|
await tools.snooze(5000);
|
|
return {
|
|
blocked: true,
|
|
status: 404,
|
|
code: server_constants.RIS_CODE_ERR,
|
|
};
|
|
}
|
|
|
|
// Check IP ban
|
|
const lastRecord = await User.getLastRec(userData.idapp);
|
|
if (lastRecord && process.env.LOCALE !== '1') {
|
|
if (lastRecord.ipaddr === userData.ipaddr && lastRecord.date_reg) {
|
|
const isTooRecent = tools.isdiffSecDateLess(lastRecord.date_reg, 3);
|
|
if (isTooRecent) {
|
|
const msg = `${userData.ipaddr}: [${userData.username}] ${userData.name} ${userData.surname}`;
|
|
tools.writeIPToBan(msg);
|
|
await telegrambot.sendMsgTelegramToTheAdmin(userData.idapp, '‼️ BAN: ' + msg, true);
|
|
await tools.snooze(5000);
|
|
|
|
return {
|
|
blocked: true,
|
|
status: 400,
|
|
code: server_constants.RIS_CODE_BANIP,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
return { blocked: false };
|
|
}
|
|
|
|
_canExecuteFriendCommand(user, usernameOrig, usernameDest, cmd) {
|
|
const { User } = require('../models/user');
|
|
|
|
if (User.isAdmin(user.perm) || User.isManager(user.perm)) {
|
|
return true;
|
|
}
|
|
|
|
const allowedCommands = [shared_consts.FRIENDSCMD.SETFRIEND, shared_consts.FRIENDSCMD.SETHANDSHAKE];
|
|
|
|
if (allowedCommands.includes(cmd)) {
|
|
return usernameOrig === user.username || usernameDest === user.username;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
_hasAdminPermissions(user) {
|
|
const { User } = require('../models/user');
|
|
return User.isCollaboratore(user.perm);
|
|
}
|
|
}
|
|
|
|
module.exports = UserController;
|