Skip to content

Commit dadf4d4

Browse files
authored
Fix Security Lint Warnings in Tests and Build (#2487)
1 parent 0f75af9 commit dadf4d4

File tree

21 files changed

+384
-215
lines changed

21 files changed

+384
-215
lines changed

config/default.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ module.exports = {
7878
},
7979

8080
cors: {
81+
// eslint-disable-next-line security/detect-unsafe-regex
8182
allowedOrigins: /(https:\/\/([a-zA-Z0-9-_]+\.)?realdevsquad\.com$)/, // Allow realdevsquad.com, *.realdevsquad.com
8283
},
8384

controllers/discordactions.js

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -366,32 +366,28 @@ const updateDiscordNicknames = async (req, res) => {
366366
const totalNicknamesNotUpdated = { count: 0, errors: [] };
367367
const nickNameUpdatedUsers = [];
368368
let counter = 0;
369-
for (let i = 0; i < usersToBeEffected.length; i++) {
370-
const { discordId, username, first_name: firstName } = usersToBeEffected[i];
369+
for (const user of usersToBeEffected) {
370+
const { discordId, username, first_name: firstName, id } = user;
371371
try {
372372
if (counter % 10 === 0 && counter !== 0) {
373373
await new Promise((resolve) => setTimeout(resolve, 5500));
374374
}
375-
if (!discordId) {
376-
throw new Error("user not verified");
377-
} else if (!username) {
378-
throw new Error(`does not have a username`);
379-
}
375+
if (!discordId) throw new Error("user not verified");
376+
if (!username) throw new Error("does not have a username");
377+
380378
const response = await setUserDiscordNickname(username.toLowerCase(), discordId);
381-
if (response) {
382-
const message = await response.message;
383-
if (message) {
384-
counter++;
385-
totalNicknamesUpdated.count++;
386-
nickNameUpdatedUsers.push(usersToBeEffected[i].id);
387-
}
379+
if (response?.message) {
380+
counter++;
381+
totalNicknamesUpdated.count++;
382+
nickNameUpdatedUsers.push(id);
388383
}
389384
} catch (error) {
390385
totalNicknamesNotUpdated.count++;
391386
totalNicknamesNotUpdated.errors.push(`User: ${username ?? firstName}, ${error.message}`);
392387
logger.error(`Error in updating discord Nickname: ${error}`);
393388
}
394389
}
390+
395391
return res.json({
396392
totalNicknamesUpdated,
397393
totalNicknamesNotUpdated,

controllers/issues.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const getIssues = async (req, res) => {
1414
const { q: queryString } = req.query;
1515
let issues = {};
1616
const githubOrg = config.get("githubApi.org");
17+
// eslint-disable-next-line security/detect-non-literal-regexp
1718
const githubIssuerUrlPattern = new RegExp(`^https://github.com/${githubOrg}/.+/issues/\\d+$`);
1819

1920
if (githubIssuerUrlPattern.test(queryString)) {

middlewares/validators/monitor.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,19 +70,30 @@ const validateCreateTrackedProgressRecord = async (req, res, next) => {
7070
const validateUpdateTrackedProgress = async (req, res, next) => {
7171
const { type, typeId } = req.params;
7272
const { monitored, frequency } = req.body;
73-
const updatedData = { type, [TYPE_MAP[type]]: typeId, monitored, frequency };
74-
const monitoredSchema = joi.object().keys({
73+
74+
const keyExists = Reflect.has(TYPE_MAP, type);
75+
const resolvedKey = keyExists ? Reflect.get(TYPE_MAP, type) : null;
76+
77+
const updatedData = { type, monitored, frequency };
78+
79+
if (resolvedKey && typeof resolvedKey === "string") {
80+
Reflect.set(updatedData, resolvedKey, typeId);
81+
}
82+
83+
const monitoredSchema = joi.object({
7584
monitored: joi.boolean().optional().messages({
7685
"boolean.base": "monitored field must be a boolean value.",
7786
}),
7887
});
88+
7989
const updateSchema = baseSchema.concat(monitoredSchema).or("monitored", "frequency");
90+
8091
try {
8192
await updateSchema.validateAsync(updatedData, { abortEarly: false });
8293
next();
8394
} catch (error) {
8495
logger.error(`Error validating payload: ${error}`);
85-
res.boom.badRequest(error.details[0].message);
96+
res.boom.badRequest(error.details?.[0]?.message || "Invalid payload");
8697
}
8798
};
8899

middlewares/validators/task-requests.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ const joi = require("joi");
33
const { RQLQueryParser } = require("../../utils/RQLParser");
44
const githubOrg = config.get("githubApi.org");
55
const githubBaseUrl = config.get("githubApi.baseUrl");
6+
// eslint-disable-next-line security/detect-non-literal-regexp
67
const githubIssuerUrlPattern = new RegExp(`^${githubBaseUrl}/repos/${githubOrg}/.+/issues/\\d+$`);
8+
// eslint-disable-next-line security/detect-non-literal-regexp
79
const githubIssueHtmlUrlPattern = new RegExp(`^${GITHUB_URL}/${githubOrg}/.+/issues/\\d+$`); // Example: https://github.com/Real-Dev-Squad/website-status/issues/1050
810
const { TASK_REQUEST_STATUS, TASK_REQUEST_TYPE } = require("../../constants/taskRequests");
911

models/discordactions.js

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ const updateUsersNicknameStatus = async (lastNicknameUpdate) => {
520520
const usersCurrentStatus = userStatusModel
521521
.where("currentStatus.updatedAt", ">=", lastNicknameUpdateTimestamp)
522522
.get();
523+
523524
const usersFutureStatus = userStatusModel.where("futureStatus.updatedAt", ">=", lastNicknameUpdateTimestamp).get();
524525

525526
const [usersCurrentStatusSnapshot, usersFutureStatusSnapshots] = await Promise.all([
@@ -528,36 +529,30 @@ const updateUsersNicknameStatus = async (lastNicknameUpdate) => {
528529
]);
529530

530531
const usersCurrentStatusDocs = usersCurrentStatusSnapshot.docs;
531-
let usersFutureStatusDocs = usersFutureStatusSnapshots.docs;
532-
usersFutureStatusDocs = usersFutureStatusDocs.filter(({ id }) => {
533-
const isIdPresent = usersCurrentStatusDocs.find((status) => {
534-
return status.id === id;
535-
});
536-
return !isIdPresent;
532+
const futureDocs = usersFutureStatusSnapshots.docs.filter(({ id }) => {
533+
return !usersCurrentStatusDocs.some((status) => status.id === id);
537534
});
538-
const usersStatusDocs = usersCurrentStatusDocs.concat(usersFutureStatusDocs);
539535

540-
const today = new Date().getTime();
541-
542-
let successfulUpdates = 0;
543-
const nicknameUpdateBatches = [];
536+
const usersStatusDocs = usersCurrentStatusDocs.concat(futureDocs);
544537
const totalUsersStatus = usersStatusDocs.length;
538+
const today = Date.now();
545539

546-
let startIndex = 0;
547-
for (let i = 0; i < Math.ceil(totalUsersStatus / SIMULTANEOUS_WORKER_CALLS); i++) {
548-
const end = Math.min(totalUsersStatus, startIndex + SIMULTANEOUS_WORKER_CALLS);
549-
nicknameUpdateBatches.push(usersStatusDocs.slice(startIndex, end));
550-
startIndex = end;
540+
const nicknameUpdateBatches = [];
541+
for (let start = 0; start < totalUsersStatus; start += SIMULTANEOUS_WORKER_CALLS) {
542+
const end = Math.min(totalUsersStatus, start + SIMULTANEOUS_WORKER_CALLS);
543+
nicknameUpdateBatches.push(usersStatusDocs.slice(start, end));
551544
}
552545

553-
for (let i = 0; i < nicknameUpdateBatches.length; i++) {
546+
let successfulUpdates = 0;
547+
548+
for (const usersStatusDocsBatch of nicknameUpdateBatches) {
554549
const promises = [];
555-
const usersStatusDocsBatch = nicknameUpdateBatches[i];
556-
usersStatusDocsBatch.forEach((document) => {
550+
551+
for (const document of usersStatusDocsBatch) {
557552
const doc = document.data();
558553
const userId = doc.userId;
559-
560554
const { futureStatus = {}, currentStatus = {} } = doc;
555+
561556
const { state: futureState } = futureStatus;
562557
const { state: currentState } = currentStatus;
563558

@@ -572,17 +567,16 @@ const updateUsersNicknameStatus = async (lastNicknameUpdate) => {
572567
} else {
573568
promises.push(usersUtils.updateNickname(userId));
574569
}
575-
});
576-
577-
const settledPromises = await Promise.allSettled(promises);
570+
}
578571

579-
settledPromises.forEach((result) => {
572+
const settled = await Promise.allSettled(promises);
573+
for (const result of settled) {
580574
if (result.status === "fulfilled" && !!result.value) {
581575
successfulUpdates++;
582576
} else {
583577
logger.error(`Error while updating nickname: ${result.reason}`);
584578
}
585-
});
579+
}
586580

587581
await new Promise((resolve) => setTimeout(resolve, 5000));
588582
}

models/progresses.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,10 @@ const getRangeProgressData = async (queryParams) => {
100100
async function getProgressByDate(pathParams, queryParams) {
101101
const { type, typeId, date } = pathParams;
102102
const { dev } = queryParams;
103+
/* eslint-disable security/detect-object-injection */
103104
await assertUserOrTaskExists({ [TYPE_MAP[type]]: typeId });
104105
const query = buildQueryToSearchProgressByDay({ [TYPE_MAP[type]]: typeId, date });
106+
/* eslint-enable security/detect-object-injection */
105107
const result = await query.get();
106108
if (!result.size) {
107109
throw new NotFound(PROGRESS_DOCUMENT_NOT_FOUND);

models/taskRequests.js

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -78,31 +78,40 @@ const fetchTaskRequests = async (dev) => {
7878
const fetchPaginatedTaskRequests = async (queries = {}) => {
7979
try {
8080
let taskRequestsSnapshot = taskRequestsCollection;
81-
8281
let { next, prev, size, q: queryString } = queries;
8382
if (size) size = parseInt(size);
8483

8584
const rqlQueryParser = new RQLQueryParser(queryString);
8685

87-
Object.entries(rqlQueryParser.getFilterQueries()).forEach(([key, value]) => {
88-
const valuesList = value.map(
89-
(query) => query.operator === Operators.INCLUDE && TASK_REQUEST_FILTER_VALUES[query.value]
90-
);
91-
taskRequestsSnapshot = taskRequestsSnapshot.where(TASK_REQUEST_FILTER_KEYS[key], "in", valuesList);
92-
});
86+
const filterQueries = rqlQueryParser.getFilterQueries();
87+
88+
for (const [filterKey, filterValue] of Object.entries(filterQueries)) {
89+
const valuesList = filterValue
90+
.map((query) =>
91+
query.operator === Operators.INCLUDE ? Reflect.get(TASK_REQUEST_FILTER_VALUES, query.value) : null
92+
)
93+
.filter(Boolean);
94+
95+
if (Reflect.has(TASK_REQUEST_FILTER_KEYS, filterKey)) {
96+
const fieldName = Reflect.get(TASK_REQUEST_FILTER_KEYS, filterKey);
97+
taskRequestsSnapshot = taskRequestsSnapshot.where(fieldName, "in", valuesList);
98+
}
99+
}
93100

94101
const sortQueries = rqlQueryParser.getSortQueries();
95102
const sortQueryEntries = Object.entries(sortQueries);
96103

97104
if (sortQueryEntries.length) {
98-
sortQueryEntries.forEach(([key, value]) => {
99-
taskRequestsSnapshot = taskRequestsSnapshot.orderBy(
100-
TASK_REQUEST_SORT_KEYS[key],
101-
TASK_REQUEST_SORT_VALUES[value]
102-
);
103-
});
105+
for (const [sortKey, sortValue] of sortQueryEntries) {
106+
if (Reflect.has(TASK_REQUEST_SORT_KEYS, sortKey) && Reflect.has(TASK_REQUEST_SORT_VALUES, sortValue)) {
107+
const sortField = Reflect.get(TASK_REQUEST_SORT_KEYS, sortKey);
108+
const orderDirection = Reflect.get(TASK_REQUEST_SORT_VALUES, sortValue);
109+
taskRequestsSnapshot = taskRequestsSnapshot.orderBy(sortField, orderDirection);
110+
}
111+
}
104112
} else {
105-
taskRequestsSnapshot = taskRequestsSnapshot.orderBy(TASK_REQUEST_SORT_KEYS.created, "desc");
113+
const defaultField = Reflect.get(TASK_REQUEST_SORT_KEYS, "created");
114+
taskRequestsSnapshot = taskRequestsSnapshot.orderBy(defaultField, "desc");
106115
}
107116

108117
if (next) {
@@ -137,16 +146,13 @@ const fetchPaginatedTaskRequests = async (queries = {}) => {
137146
const isNextLinkRequired = size && resultDataLength === size;
138147
const lastVisibleDoc = isNextLinkRequired && taskRequestsSnapshot.docs[resultDataLength - 1];
139148
const firstDoc = taskRequestsSnapshot.docs[0];
140-
const nextPageParams = {
141-
...queries,
142-
next: lastVisibleDoc?.id,
143-
};
149+
150+
const nextPageParams = { ...queries, next: lastVisibleDoc?.id };
144151
delete nextPageParams.prev;
145-
const prevPageParams = {
146-
...queries,
147-
prev: firstDoc?.id,
148-
};
152+
153+
const prevPageParams = { ...queries, prev: firstDoc?.id };
149154
delete prevPageParams.next;
155+
150156
const nextLink = lastVisibleDoc ? generateLink(nextPageParams) : "";
151157
const prevLink = next || prev ? generateLink(prevPageParams) : "";
152158

0 commit comments

Comments
 (0)