Files
freeplanet_serverside/src/controllers/UserController.js
Surya Paolo 70698fab44 - 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.
2025-11-25 17:45:24 +01:00

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;