Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,6 @@ jobs:
bun install
bun test

codacy:
uses: jd-apprentice/jd-workflows/.github/workflows/codacy.yml@main
needs: [gitleaks, test]
with:
name: Codacy
secrets:
project_token: ${{ secrets.CODACY_PROJECT_TOKEN }}

dev:
runs-on: ubuntu-latest
needs: [gitleaks, test]
Expand Down
4 changes: 2 additions & 2 deletions __tests__/app/__tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ describe('INTEGRATION - App Module', () => {
})
});

test('GET /api - when asking for the api route should return 200 and api message', async () => {
test('GET /v1/api - when asking for the api route should return 200 and api message', async () => {
await request(app)
.get('/api')
.get('/v1/api')
.expect(contentTypeKey, contentTypeValue)
.expect(httpSuccess)
.then((response) => {
Expand Down
2 changes: 1 addition & 1 deletion __tests__/image/__tests__/integration/images.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { jest, describe, test, beforeAll, expect, beforeEach } from "bun:test";
import request from "supertest";
import { Response } from "supertest";

const baseRoute = "/api/images";
const baseRoute = "/v1/api/images";
const contentTypeKey = "Content-Type";
const contentTypeValue = /json/;
const httpSuccess = 200;
Expand Down
2 changes: 1 addition & 1 deletion __tests__/tag/__tests__/tags.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { describe, test, expect, beforeAll, jest, beforeEach } from 'bun:test';
const contentTypeKey = 'Content-Type';
const contentTypeValue = /json/;
const httpSuccess = 200;
const baseRoute = "/api/tags";
const baseRoute = "/v1/api/tags";

const tagResponse = {
_id: expect.any(String),
Expand Down
2 changes: 1 addition & 1 deletion __tests__/user/__tests__/users.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const contentTypeKey = 'Content-Type';
const contentTypeValue = /json/;
const httpSuccess = 200;
const httpUnauthorized = 401;
const baseRoute = "/api/user";
const baseRoute = "/v1/api/user";

const userResponse = {
_id: expect.any(String),
Expand Down
Binary file modified bun.lockb
Binary file not shown.
8 changes: 8 additions & 0 deletions src/app/constants/cors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const allowedOrigins = ['https://waifuland.jonathan.com.ar', 'https://waifus.jonathan.com.ar'];
export const corsConfiguration = {
origin: allowedOrigins,
methods: ['GET', 'POST', 'PUT'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 3600
}
5 changes: 3 additions & 2 deletions src/app/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import cors from 'cors';

// Internal Modules
import { routes } from './routes/index';
import { corsConfiguration } from './constants/cors';

// Express
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cors());
app.use(cors(corsConfiguration));
app.use(helmet());
app.use('/api', routes);
app.use('/v1/api', routes);
app.use('/', (req, res) =>
res.status(200).json({ message: 'Allo! Catch-all route.' }),
);
Expand Down
7 changes: 7 additions & 0 deletions src/common/utils/limiter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import rateLimit from 'express-rate-limit';

export const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
message: 'Too many requests from this IP, please try again after 15 minutes',
});
2 changes: 1 addition & 1 deletion src/image/image-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class ImageRepository {
* @return { Promise<IImage> } - A new image created
*/
async create(image: IImage): Promise<IImage> {
const tagExists = await Tag.findOne({ tag_id: image.tag.tag_id });
const tagExists = await Tag.findOne({ tag_id: { $eq: image.tag } });
const _idTag = tagExists?._id;
return Image.create({
...image,
Expand Down
6 changes: 4 additions & 2 deletions src/image/image-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@
import { isAdmin, validateToken } from '../user/user-middleware';
import ImageController from './image-controller';
import upload from './image-middleware';
import { limiter } from 'src/common/utils/limiter';

const imageRouter = Router();

imageRouter.post(
'/',
limiter,
validateToken,
isAdmin,

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
a database access
, but is not rate-limited.
upload.single('image'),
ImageController.uploadFile,
);
imageRouter.get('/', ImageController.getRandomImage);
imageRouter.get('/all', ImageController.getImages);
imageRouter.get('/', limiter, ImageController.getRandomImage);
imageRouter.get('/all', limiter, ImageController.getImages);

export default imageRouter;
2 changes: 1 addition & 1 deletion src/tag/tag-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class TagRepository {
* @returns {Promise<FindCursor | null>} - One single tag
*/
async findByTagId(tagId: string): Promise<FindCursor | null> {
return Tag.findOne({ tag_id: tagId });
return Tag.findOne({ tag_id: { $eq: tagId } });
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/tag/tag-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { Router } from 'express';

// Internal Modules
import tagController from './tag-controller';
import { limiter } from 'src/common/utils/limiter';

const tagRouter = Router();

tagRouter.get('/', tagController.getTags);
tagRouter.get('/:id', tagController.getTagsId);
tagRouter.get('/', limiter, tagController.getTags);
tagRouter.get('/:id', limiter, tagController.getTagsId);

export default tagRouter;
6 changes: 3 additions & 3 deletions src/user/user-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const userExists = async (
next: NextFunction,
): Promise<Boom | NextFunction | Response | unknown> => {
const { username }: UsernameType = req.body;
const user: UsernameType | null = await User.findOne({ username });
const user: UsernameType | null = await User.findOne({ username: { $eq: username } });
return user ? res.json(boom.conflict('User already exists')) : next();
};

Expand All @@ -37,7 +37,7 @@ const validateUser = async (
): Promise<Boom | NextFunction | Response | unknown> => {
try {
const { username, password } = req.body;
const userExists = await User.findOne({ username });
const userExists = await User.findOne({ username: { $eq: username } });
const user = userExists?.username;
const pass = userExists?.password;
const isMatch = pass && (await bcrypt.compare(password, pass)); // Compare the password with the hash password
Expand All @@ -60,7 +60,7 @@ const isAdmin = async (
): Promise<Boom | NextFunction | Response | unknown> => {
try {
const { username } = req.body;
const user = await User.findOne({ username });
const user = await User.findOne({ username: { $eq: username } });
return user?.isAdmin ? next() : res.json(boom.unauthorized('Not admin'));
} catch (error) {
return res.status(400) && res.json(boom.badRequest('User not found'));
Expand Down
4 changes: 2 additions & 2 deletions src/user/user-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ class UserRepository {
* @param {string} id - id of the user
*/
async findUser(id: string): Promise<IUser | null> {
return User.findOne({ _id: id });
return User.findOne({ _id: { $eq: id } });
}

/**
* @description Find a user by username
* @param {string} username - username of the user
*/
async findUserByUsername(username: string): Promise<IUser | null> {
return User.findOne({ username });
return User.findOne({ username: { $eq: username } });
}

/**
Expand Down
7 changes: 2 additions & 5 deletions src/user/user-routes.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
// External Modules
import { Router } from 'express';
import rateLimit from 'express-rate-limit';

// Internal Modules
import userController from './user-controller';
import upload from '../image/image-middleware';
import { userExists, validateUser, validateToken } from './user-middleware';
import { limiter } from 'src/common/utils/limiter';

const userRouter = Router();

const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
});


userRouter.get('/', limiter, validateToken, userController.getUsers);
userRouter.get('/info', limiter, validateToken, userController.getUserInfo);
userRouter.post('/login', limiter, validateUser, userController.login);

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
a database access
, but is not rate-limited.
userRouter.post('/create', limiter, userExists, userController.createUser);

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
a database access
, but is not rate-limited.
userRouter.get('/:id', limiter, validateToken, userController.getUser);
userRouter.patch(
'/',
Expand Down
Loading