From 33d9c642895ac6a058db5b3019d6b3a8d1d345f0 Mon Sep 17 00:00:00 2001 From: jd-apprentice Date: Fri, 28 Feb 2025 01:05:47 -0300 Subject: [PATCH 1/2] style: sonarqube security --- .vscode/settings.json | 4 ++++ src/image/image-repository.ts | 19 +++++++++++++++---- src/user/user-middleware.ts | 21 +++++++++++++-------- src/user/user-repository.ts | 17 ++++++++++++++--- 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index ebfde9a..593739c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,7 @@ { "editor.formatOnSave": true, + "sonarlint.connectedMode.project": { + "connectionId": "dyallab", + "projectKey": "jd-apprentice_waifuland-api" + }, } \ No newline at end of file diff --git a/src/image/image-repository.ts b/src/image/image-repository.ts index 458f53a..c32f192 100644 --- a/src/image/image-repository.ts +++ b/src/image/image-repository.ts @@ -1,8 +1,12 @@ +// External Modules +import { Types } from 'mongoose'; + // Internal Modules import Image from './schema/image-schema'; -import Tag from '../tag/schema/tag-schema'; -import { hasTag } from '../common/utils/ref'; +import Tag from 'src/tag/schema/tag-schema'; +import { hasTag } from 'src/common/utils/ref'; import { ImageProp } from './interfaces/image-interface'; +import { rollbar } from 'src/app/config/rollbar'; class ImageRepository { /** @@ -11,11 +15,18 @@ class ImageRepository { * @return { Promise } - A new image created */ async create(image: ImageProp): Promise { - const tagExists = await Tag.findOne({ tag_id: { $eq: image.tag } }); + const sanitizedTagId = image.tag.toString().trim(); + if (!Types.ObjectId.isValid(sanitizedTagId)) { + rollbar.error('Invalid tag id'); + throw new Error('Invalid tag id'); + } + + const tagExists = await Tag.findOne({ tag_id: sanitizedTagId }); const _idTag = tagExists?._id; + return Image.create({ ...image, - tag: _idTag ?? image.tag, + tag: _idTag ?? image.tag, // Use validated tag or fallback }); } diff --git a/src/user/user-middleware.ts b/src/user/user-middleware.ts index 78dce49..8293f47 100644 --- a/src/user/user-middleware.ts +++ b/src/user/user-middleware.ts @@ -24,10 +24,11 @@ const userExists = async ( res: Response, next: NextFunction, ): Promise => { - const { username } = req.body; + const { username } = req.body as { username: string }; + const sanitizedUsername = username.toString(); try { - const user = await User.findOne({ username: { $eq: username } }); + const user = await User.findOne({ username: { $eq: sanitizedUsername } }); if (user) { return res.status(409).json({ error: 'User already exists' }); @@ -52,10 +53,12 @@ const validateUser = async ( next: NextFunction, ): Promise => { try { - const { username, password } = req.body; - const user = await User.findOne({ username: { $eq: username } }); + const { username, password } = req.body as { username: string; password: string }; + const [sanitizedUsername, sanitizedPassword] = [username.toString(), password.toString()]; - if (user?.password && (await bcrypt.compare(password, user.password))) { + const user = await User.findOne({ $expr: { $eq: ['$username', sanitizedUsername] } }); + + if (user?.password && (await bcrypt.compare(sanitizedPassword, user.password))) { return next(); } @@ -75,10 +78,11 @@ const isAdmin = async ( res: Response, next: NextFunction, ): Promise => { - const { username } = req.body; + const { username } = req.body as { username: string }; + const sanitizedUsername = username.toString(); try { - const user = await User.findOne({ username: { $eq: username } }); + const user = await User.findOne({ $expr: { $eq: ['$username', sanitizedUsername] } }); if (user?.isAdmin) { return next(); @@ -105,7 +109,8 @@ const validateToken = async ( const { authorization } = req.headers; const token = authorization?.replace('Bearer ', ''); if (secret) { - const decoded = jwt.verify(token as string, secret); + if (!token) return res.json(boom.unauthorized()); + const decoded = jwt.verify(token, secret); return decoded ? next() : res.json(boom.unauthorized()); } } catch (error) { diff --git a/src/user/user-repository.ts b/src/user/user-repository.ts index 6357217..8237277 100644 --- a/src/user/user-repository.ts +++ b/src/user/user-repository.ts @@ -1,5 +1,6 @@ // Internal Modules -import User from '../user/schema/user-schema'; +import { rollbar } from 'src/app/config/rollbar'; +import User from 'src/user/schema/user-schema'; import { IUser, UserPicture } from './interfaces/user-interface'; class UserRepository { @@ -8,6 +9,14 @@ class UserRepository { * @param {Iuser} user - user to be created */ async create(user: IUser) { + const sanitizedUsername = user.username.toString(); + const userExists = await this.findUserByUsername(sanitizedUsername); + + if (userExists) { + rollbar.error('User already exists'); + throw new Error('User already exists'); + } + return User.create(user); } @@ -24,7 +33,8 @@ class UserRepository { * @param {string} id - id of the user */ async findUser(id: string): Promise { - return User.findOne({ _id: { $eq: id } }); + const sanitizedId = id.toString(); + return User.findOne({ $expr: { $eq: ["$_id", sanitizedId] } }) } /** @@ -32,7 +42,8 @@ class UserRepository { * @param {string} username - username of the user */ async findUserByUsername(username: string): Promise { - return User.findOne({ username: { $eq: username } }); + const sanitizedUsername = username.toString(); + return User.findOne({ $expr: { $eq: ["$username", sanitizedUsername] } }); } /** From 24b165af49a3e1bef02ce6e633201aa6671d5e82 Mon Sep 17 00:00:00 2001 From: jd-apprentice Date: Fri, 28 Feb 2025 01:06:06 -0300 Subject: [PATCH 2/2] style: sonarqube security --- src/image/image-repository.ts | 2 +- src/user/user-middleware.ts | 27 ++++++++++++++++++++------- src/user/user-repository.ts | 4 ++-- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/image/image-repository.ts b/src/image/image-repository.ts index c32f192..1579921 100644 --- a/src/image/image-repository.ts +++ b/src/image/image-repository.ts @@ -26,7 +26,7 @@ class ImageRepository { return Image.create({ ...image, - tag: _idTag ?? image.tag, // Use validated tag or fallback + tag: _idTag ?? image.tag, // Use validated tag or fallback }); } diff --git a/src/user/user-middleware.ts b/src/user/user-middleware.ts index 8293f47..949853f 100644 --- a/src/user/user-middleware.ts +++ b/src/user/user-middleware.ts @@ -53,12 +53,23 @@ const validateUser = async ( next: NextFunction, ): Promise => { try { - const { username, password } = req.body as { username: string; password: string }; - const [sanitizedUsername, sanitizedPassword] = [username.toString(), password.toString()]; + const { username, password } = req.body as { + username: string; + password: string; + }; + const [sanitizedUsername, sanitizedPassword] = [ + username.toString(), + password.toString(), + ]; - const user = await User.findOne({ $expr: { $eq: ['$username', sanitizedUsername] } }); + const user = await User.findOne({ + $expr: { $eq: ['$username', sanitizedUsername] }, + }); - if (user?.password && (await bcrypt.compare(sanitizedPassword, user.password))) { + if ( + user?.password && + (await bcrypt.compare(sanitizedPassword, user.password)) + ) { return next(); } @@ -82,7 +93,9 @@ const isAdmin = async ( const sanitizedUsername = username.toString(); try { - const user = await User.findOne({ $expr: { $eq: ['$username', sanitizedUsername] } }); + const user = await User.findOne({ + $expr: { $eq: ['$username', sanitizedUsername] }, + }); if (user?.isAdmin) { return next(); @@ -108,10 +121,10 @@ const validateToken = async ( try { const { authorization } = req.headers; const token = authorization?.replace('Bearer ', ''); + if (!token) return res.status(401).json(boom.unauthorized()); if (secret) { - if (!token) return res.json(boom.unauthorized()); const decoded = jwt.verify(token, secret); - return decoded ? next() : res.json(boom.unauthorized()); + return decoded ? next() : res.status(401).json(boom.unauthorized()); } } catch (error) { return res.status(401).json(boom.unauthorized()); diff --git a/src/user/user-repository.ts b/src/user/user-repository.ts index 8237277..ae6ac08 100644 --- a/src/user/user-repository.ts +++ b/src/user/user-repository.ts @@ -34,7 +34,7 @@ class UserRepository { */ async findUser(id: string): Promise { const sanitizedId = id.toString(); - return User.findOne({ $expr: { $eq: ["$_id", sanitizedId] } }) + return User.findOne({ $expr: { $eq: ['$_id', sanitizedId] } }); } /** @@ -43,7 +43,7 @@ class UserRepository { */ async findUserByUsername(username: string): Promise { const sanitizedUsername = username.toString(); - return User.findOne({ $expr: { $eq: ["$username", sanitizedUsername] } }); + return User.findOne({ $expr: { $eq: ['$username', sanitizedUsername] } }); } /**