Compare commits

...
Author SHA1 Message Date
gorkem-bwl 9ad1e261a4 Merge branch 'develop' into fix/login-error-handling 2025-10-16 05:01:17 -04:00
gorkem-bwl 05442af050 fix: apply prettier formatting to userService.js
- Fixed all prettier formatting issues in userService.js
- All files now pass prettier format check
- Maintained null checks and error handling improvements
2025-09-11 23:55:58 -04:00
gorkem-bwl 25d538504c resolve: merge conflicts with develop branch
- Resolved conflict in translationService.js by using develop branch path format
- Updated locales directory path to use 'src/locales' format
- Maintained existing login error handling improvements
2025-09-11 22:17:13 -04:00
gorkem-bwl e823533809 fix: apply prettier formatting and address code quality issues
- Fix prettier formatting issues in userService.js
- Add null checks before password comparisons to prevent runtime errors
- Improve error logging while maintaining security by not exposing sensitive info
- Address CodeRabbit and LlamaPReview feedback
2025-09-11 22:14:08 -04:00
gorkem-bwl a03996d54b fix: resolve login error handling issues
- Fix translation service to load locales from correct path (src/locales)
- Improve login security to return generic error message for both invalid email and wrong password
- Make frontend error handling generic to display backend error messages properly
- Remove hardcoded string matching in favor of HTTP status code checks

Fixes login flow returning raw localization keys instead of user-facing messages

Fixes #2768
2025-08-12 21:09:14 -04:00
2 changed files with 47 additions and 29 deletions

No files matched your search

+43 -16
View File
@@ -83,24 +83,45 @@ class UserService {
loginUser = async (email, password) => {
// Check if user exists
const user = await this.db.userModule.getUserByEmail(email);
// Compare password
const match = await user.comparePassword(password);
if (match !== true) {
try {
const user = await this.db.userModule.getUserByEmail(email);
// Add null check before password comparison
if (!user || !user.comparePassword) {
throw this.errorService.createAuthenticationError(this.stringService.authIncorrectPassword);
}
// Compare password
const match = await user.comparePassword(password);
if (match !== true) {
throw this.errorService.createAuthenticationError(this.stringService.authIncorrectPassword);
}
// Remove password from user object. Should this be abstracted to DB layer?
const userWithoutPassword = { ...user._doc };
delete userWithoutPassword.password;
delete userWithoutPassword.avatarImage;
// Happy path, return token
const appSettings = await this.settingsService.getSettings();
const token = this.issueToken(userWithoutPassword, appSettings);
// reset avatar image
userWithoutPassword.avatarImage = user.avatarImage;
return { user: userWithoutPassword, token };
} catch (error) {
// Log specific errors while returning generic message for security
this.logger.error({
message: "Login attempt failed",
service: SERVICE_NAME,
method: "loginUser",
error: error.message,
stack: error.stack,
});
// If user is not found, throw a generic authentication error for security
// Don't reveal whether user exists or password is wrong
throw this.errorService.createAuthenticationError(this.stringService.authIncorrectPassword);
}
// Remove password from user object. Should this be abstracted to DB layer?
const userWithoutPassword = { ...user._doc };
delete userWithoutPassword.password;
delete userWithoutPassword.avatarImage;
// Happy path, return token
const appSettings = await this.settingsService.getSettings();
const token = this.issueToken(userWithoutPassword, appSettings);
// reset avatar image
userWithoutPassword.avatarImage = user.avatarImage;
return { user: userWithoutPassword, token };
};
editUser = async (updates, file, currentUser) => {
@@ -111,6 +132,12 @@ class UserService {
updates.email = currentUser.email;
// Get user
const user = await this.db.userModule.getUserByEmail(currentUser.email);
// Add null check before password comparison
if (!user || !user.comparePassword) {
throw this.errorService.createAuthorizationError(this.stringService.authIncorrectPassword);
}
// Compare passwords
const match = await user.comparePassword(updates?.password);
// If not a match, throw a 403
+4 -13
View File
@@ -1,21 +1,12 @@
import sharp from "sharp";
/**
* Generates a 64 * 64 pixel image from a given image
* Converts image to base64 string without resizing
* CSS handles the 64x64 display sizing client-side
* @param {} file
*/
const GenerateAvatarImage = async (file) => {
try {
// Resize to target 64 * 64
let resizedImageBuffer = await sharp(file.buffer)
.resize({
width: 64,
height: 64,
fit: "cover",
})
.toBuffer();
//Get b64 string
const base64Image = resizedImageBuffer.toString("base64");
// Simply convert to base64 - let CSS handle the 64x64 display
const base64Image = file.buffer.toString("base64");
return base64Image;
} catch (error) {
throw error;