-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vil 616 #1009
Conversation
} | ||
|
||
public head(options: RouteOptions, handler: RequestHandler): void { | ||
this.router.head(options.path, handleErrors(authenticate(options.userType)), handleErrors(handler)); |
Check failure
Code scanning / CodeQL
Missing rate limiting High
authorization
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix AI about 1 month ago
To fix the problem, we need to introduce rate limiting to the routes in the Controller
class. The best way to do this is by using the express-rate-limit
package, which allows us to easily set up rate limiting middleware. We will create a rate limiter and apply it to all routes defined in the Controller
class.
- Install the
express-rate-limit
package. - Import the
express-rate-limit
package in thecontroller.ts
file. - Create a rate limiter with a reasonable configuration (e.g., 100 requests per 15 minutes).
- Apply the rate limiter to all routes in the
Controller
class.
-
Copy modified lines R5-R6 -
Copy modified lines R25-R33 -
Copy modified line R36 -
Copy modified line R40 -
Copy modified line R44 -
Copy modified line R48 -
Copy modified line R52 -
Copy modified lines R59-R60 -
Copy modified lines R77-R78
@@ -4,3 +4,4 @@ | ||
import multer from 'multer'; | ||
import path from 'path'; | ||
import path from 'path'; | ||
import rateLimit from 'express-rate-limit'; | ||
|
||
@@ -23,9 +24,14 @@ | ||
|
||
constructor(name: string) { | ||
this.router = Router({ mergeParams: true }); | ||
this.name = name; | ||
} | ||
private rateLimiter = rateLimit({ | ||
windowMs: 15 * 60 * 1000, // 15 minutes | ||
max: 100, // limit each IP to 100 requests per windowMs | ||
}); | ||
|
||
constructor(name: string) { | ||
this.router = Router({ mergeParams: true }); | ||
this.name = name; | ||
} | ||
|
||
public get(options: RouteOptions, handler: RequestHandler): void { | ||
this.router.get(options.path, handleErrors(authenticate(options.userType)), handleErrors(handler)); | ||
this.router.get(options.path, this.rateLimiter, handleErrors(authenticate(options.userType)), handleErrors(handler)); | ||
} | ||
@@ -33,3 +39,3 @@ | ||
public head(options: RouteOptions, handler: RequestHandler): void { | ||
this.router.head(options.path, handleErrors(authenticate(options.userType)), handleErrors(handler)); | ||
this.router.head(options.path, this.rateLimiter, handleErrors(authenticate(options.userType)), handleErrors(handler)); | ||
} | ||
@@ -37,3 +43,3 @@ | ||
public post(options: RouteOptions, handler: RequestHandler): void { | ||
this.router.post(options.path, handleErrors(authenticate(options.userType)), handleErrors(handler)); | ||
this.router.post(options.path, this.rateLimiter, handleErrors(authenticate(options.userType)), handleErrors(handler)); | ||
} | ||
@@ -41,3 +47,3 @@ | ||
public put(options: RouteOptions, handler: RequestHandler): void { | ||
this.router.put(options.path, handleErrors(authenticate(options.userType)), handleErrors(handler)); | ||
this.router.put(options.path, this.rateLimiter, handleErrors(authenticate(options.userType)), handleErrors(handler)); | ||
} | ||
@@ -45,3 +51,3 @@ | ||
public delete(options: RouteOptions, handler: RequestHandler): void { | ||
this.router.delete(options.path, handleErrors(authenticate(options.userType)), handleErrors(handler)); | ||
this.router.delete(options.path, this.rateLimiter, handleErrors(authenticate(options.userType)), handleErrors(handler)); | ||
} | ||
@@ -52,3 +58,4 @@ | ||
options.path, | ||
this.uploadVideoMiddleware.single(options.multerFieldName), | ||
this.rateLimiter, | ||
this.uploadVideoMiddleware.single(options.multerFieldName), | ||
handleErrors(async (req, res, next) => { | ||
@@ -69,3 +76,4 @@ | ||
options.path, | ||
this.uploadMiddleware.single(options.multerFieldName), | ||
this.rateLimiter, | ||
this.uploadMiddleware.single(options.multerFieldName), | ||
handleErrors(authenticate(options.userType)), |
const filePath = req.file?.path; | ||
if (filePath) { | ||
res.on('finish', () => { | ||
fs.remove(filePath).catch(); |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
user-provided value
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix AI about 1 month ago
To fix the problem, we need to ensure that the filePath
is validated before it is used in the fs.remove
function. We can achieve this by normalizing the path using path.resolve
and ensuring it is within a designated safe directory. This will prevent directory traversal attacks by removing any ..
segments and ensuring the path is within the intended directory.
- Normalize the
filePath
usingpath.resolve
. - Check that the normalized path starts with the designated safe directory.
- If the path is valid, proceed with the file removal; otherwise, handle the error appropriately.
-
Copy modified lines R56-R67
@@ -55,8 +55,14 @@ | ||
// clean up the file after the request is handled | ||
const filePath = req.file?.path; | ||
if (filePath) { | ||
res.on('finish', () => { | ||
fs.remove(filePath).catch(); | ||
}); | ||
} | ||
const filePath = req.file?.path; | ||
if (filePath) { | ||
const safeDir = path.resolve(__dirname, '../fileUpload/videos'); | ||
const resolvedPath = path.resolve(filePath); | ||
if (resolvedPath.startsWith(safeDir)) { | ||
res.on('finish', () => { | ||
fs.remove(resolvedPath).catch(); | ||
}); | ||
} else { | ||
console.error('Invalid file path:', resolvedPath); | ||
} | ||
} | ||
next(); |
Motivation
Enable filtering on a given phase for a given village.
Changes
Created a
phaseHistory
entity to track the starting and ending dates of phases for all villages.Created a phase filter on the statistics dashboard.
Made sure that teachers cannot rollback on a past phase.
Test
When you're logged in as a teacher, create a new student and note what is the active phase.
Using the phase filter, you should see the newly created student on the statistics dashboard when you're logged in as an administrator. Note that the table is displaying all data, whereas the purple cards display data by phases.