-
Notifications
You must be signed in to change notification settings - Fork 590
Backend #18
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
base: main
Are you sure you want to change the base?
Backend #18
Changes from 4 commits
d6d24c5
0cc3f18
41463cd
9f3344c
0a107f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| const mongoose= require('mongoose'); | ||
| const express= require('express'); | ||
| const bodyParser= require('body-parser'); | ||
| const mongoose= require('mongoose'); | ||
|
|
||
| const authRoutes= require('./routes/auth'); | ||
| const scanRoutes= require('./routes/scan'); | ||
|
|
||
| const app=express(); | ||
| app.use(corse()); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix CORS middleware typo and import. The CORS middleware has a typo and is not imported. +const cors = require('cors');
const app=express();
-app.use(corse());
+app.use(cors()); |
||
| app.use(bodyParser.json()); | ||
|
|
||
| app.use('/api/auth', authRoutes); | ||
| app.use('/api/scan', scanRoutes); | ||
|
|
||
| mongoose.connect('mongodb://localhost:27017/digital-mess-card', { //Mongodb connection | ||
| useNewUrlParser: true, | ||
| useUnifiedTopology: true, | ||
| }); | ||
|
||
|
|
||
| app.get('/',(req,res)=>{ | ||
| res.send('Digital MESS Card'); //Route | ||
| }); | ||
|
|
||
| const PORT= 5000; | ||
| app.listen(PORT, () => { | ||
| console.log(`Server running on http://localhost:${PORT}`); | ||
| }) | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,16 @@ | ||||||||||||||||
| const jwt= require('jsonwebtoken'); | ||||||||||||||||
|
|
||||||||||||||||
| const authenticate= (req,res,next) => { //Authenticate access | ||||||||||||||||
| const token=req.header('Authorization'); | ||||||||||||||||
| if (!token) return res.status(401).send('Access Denied'); | ||||||||||||||||
|
||||||||||||||||
| const token=req.header('Authorization'); | |
| if (!token) return res.status(401).send('Access Denied'); | |
| const authHeader = req.header('Authorization'); | |
| if (!authHeader?.startsWith('Bearer ')) { | |
| return res.status(401).json({ error: 'Missing or invalid authorization header' }); | |
| } | |
| const token = authHeader.split(' ')[1]; |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move secret key to environment variables.
Don't hardcode the JWT secret key in the code. Use environment variables instead.
- const decoded= jwt.verify(token, 'secret_key');
+ const decoded = jwt.verify(token, process.env.JWT_SECRET);| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,7 @@ | ||||||||||||||||||||||||
| const mongoose= require('mongoose'); | ||||||||||||||||||||||||
| const scanSchema =new mongoose.Schema({ //Scan date update in db | ||||||||||||||||||||||||
| userId: { type: String, enum: ['lunch', 'snck'], required: true }, | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
| date :{ type: Date, default: Date.now}, | ||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add missing fields and optimize schema for queries. The schema is missing:
const mongoose= require('mongoose');
const scanSchema =new mongoose.Schema({
- userId: { type: String, enum: ['lunch', 'snck'], required: true },
- date :{ type: Date, default: Date.now},
+ scanType: { type: String, enum: ['lunch', 'snack'], required: true },
+ userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
+ date: { type: Date, default: Date.now, index: true }
});📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| module.exports= mongoose.model('Scan', scanSchema); | ||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,8 @@ | ||||||
| const mongoose= require('mongoose'); | ||||||
|
|
||||||
| const userSchema= new mongoose.schema({ //login details connected to db | ||||||
|
||||||
| const userSchema= new mongoose.schema({ //login details connected to db | |
| const userSchema= new mongoose.Schema({ //login details connected to db |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strengthen password security.
The current password validation is insufficient:
- Allows weak passwords (only alphanumeric)
- No minimum length requirement
- No password hashing
- password:{ type: String, required: true, match:/^[a-zA-Z0-9]+$/,
- }
+ password: {
+ type: String,
+ required: true,
+ minlength: 8,
+ match: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
+ }Also, add a pre-save hook to hash the password:
const bcrypt = require('bcrypt');
userSchema.pre('save', async function(next) {
if (this.isModified('password')) {
this.password = await bcrypt.hash(this.password, 10);
}
next();
});| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,26 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const express= require('express'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const bcrypt= require('bcryptjs'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const jwt= require('jsonwebtoken'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const User= require('../models/User'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const router= express.Router(); //to register new user | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| router.post('/register', async(req, res) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { username, password}=req.body; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const hashedPassword=await bcrypt.hash(password, 10); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const User= new User({username, password: hashedPassword }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await username.save(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res.status(201).send('User registered'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| router.post('/register', async(req, res) => { | |
| const { username, password}=req.body; | |
| const hashedPassword=await bcrypt.hash(password, 10); | |
| const User= new User({username, password: hashedPassword }); | |
| await username.save(); | |
| res.status(201).send('User registered'); | |
| }); | |
| router.post('/register', async (req, res) => { | |
| try { | |
| const { username, password } = req.body; | |
| if (!username || !password) { | |
| return res.status(400).json({ error: 'Username and password are required' }); | |
| } | |
| if (password.length < 8) { | |
| return res.status(400).json({ error: 'Password must be at least 8 characters long' }); | |
| } | |
| const existingUser = await User.findOne({ username }); | |
| if (existingUser) { | |
| return res.status(400).json({ error: 'Username already exists' }); | |
| } | |
| const hashedPassword = await bcrypt.hash(password, 10); | |
| const user = new User({ username, password: hashedPassword }); | |
| await user.save(); | |
| res.status(201).json({ message: 'User registered successfully' }); | |
| } catch (error) { | |
| console.error('Registration error:', error); | |
| res.status(500).json({ error: 'Internal server error' }); | |
| } | |
| }); |
🧰 Tools
🪛 Biome (1.9.4)
[error] 10-10: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace hardcoded JWT secret with environment variable.
Using a hardcoded secret key for JWT signing is a security risk. Move it to environment variables.
- Create a
.envfile in your project root:
JWT_SECRET=your_secure_random_string_here
- Install and configure dotenv:
+require('dotenv').config();- Replace the hardcoded secret:
-const token= jwt.sign({ userId: user._id }, 'secret_key');
+const token= jwt.sign({ userId: user._id }, process.env.JWT_SECRET);
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling and improve security in login endpoint.
The login endpoint needs error handling and security improvements.
Here's a suggested implementation:
router.post('/login', async (req, res) => {
+ try {
const { username, password } = req.body;
+ if (!username || !password) {
+ return res.status(400).json({ error: 'Username and password are required' });
+ }
const user= await User.findOne({ username });
if (user && await bcrypt.compare(password, user.password)) {
- const token= jwt.sign({ userId: user._id }, 'secret_key');
+ const token= jwt.sign(
+ { userId: user._id },
+ process.env.JWT_SECRET,
+ { expiresIn: '24h' }
+ );
res.json({ token });
} else {
- res.status(400).send('Invalid credentials');
+ res.status(401).json({ error: 'Invalid credentials' });
}
+ } catch (error) {
+ console.error('Login error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| router.post('/login', async (req, res) => { //to check whether the login details are valid | |
| const { username, password } = req.body; | |
| const user= await User.findOne({ username }); | |
| if (user && await bcrypt.compare(password, user.password)) { | |
| const token= jwt.sign({ userId: user._id }, 'secret_key'); | |
| res.json({ token }); | |
| } else { | |
| res.status(400).send('Invalid credentials'); | |
| } | |
| }); | |
| router.post('/login', async (req, res) => { //to check whether the login details are valid | |
| try { | |
| const { username, password } = req.body; | |
| if (!username || !password) { | |
| return res.status(400).json({ error: 'Username and password are required' }); | |
| } | |
| const user = await User.findOne({ username }); | |
| if (user && await bcrypt.compare(password, user.password)) { | |
| const token = jwt.sign( | |
| { userId: user._id }, | |
| process.env.JWT_SECRET, | |
| { expiresIn: '24h' } | |
| ); | |
| res.json({ token }); | |
| } else { | |
| res.status(401).json({ error: 'Invalid credentials' }); | |
| } | |
| } catch (error) { | |
| console.error('Login error:', error); | |
| res.status(500).json({ error: 'Internal server error' }); | |
| } | |
| }); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,29 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const express= require('express'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const Scan= require('../models/Scan'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const {authenticate}=require('../middleware/auth'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const router=express.Router(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| router.post('/scan',authenticate, async(req,res)=> { //to get info about user and the current time | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const {type}= req.body; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const userId=req.userId; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const now= new Date(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const hours= now.getHours(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const minutes=now.getMinutes(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(type==='lunch' && !(hours>=11 && minutes>=30 && hours<14)){ //to check whether scanning of lunch time is valid | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(400).send('Lunch sacnning is only allwed between 11:30 AM and 2:00 PM'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(type=== 'snack' && !(hours>=15 && minutes>=30 && hours<17)){ //to check whether scanning of snack time is valid | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(400).send('Snack scanning is only allowed between 3:30 PM and 5:00 PM'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const existingScan=await Scan.findone({ userId, type, date: { $gte: new Date().setHours(0,0,0,0)}}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const existingScan=await Scan.findone({ userId, type, date: { $gte: new Date().setHours(0,0,0,0)}}); | |
| const existingScan=await Scan.findOne({ userId, type, date: { $gte: new Date().setHours(0,0,0,0)}}); |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix variable case mismatch.
The variable case doesn't match the imported Scan model.
- const scan= new scan({userId, type});
+ const scan= new Scan({userId, type});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const scan= new scan({userId, type}); | |
| const scan= new Scan({userId, type}); |
🧰 Tools
🪛 Biome (1.9.4)
[error] 24-24: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling and input validation.
The scan endpoint lacks error handling and input validation.
Here's a suggested implementation:
router.post('/scan',authenticate, async(req,res)=> {
+ try {
const {type}= req.body;
+ if (!type) {
+ return res.status(400).json({ error: 'Scan type is required' });
+ }
+ if (!['lunch', 'snack'].includes(type)) {
+ return res.status(400).json({ error: 'Invalid scan type' });
+ }
const userId=req.userId;
const now= new Date();
const hours= now.getHours();
const minutes=now.getMinutes();
const currentTime = hours * 60 + minutes;
- if(type==='lunch' && !(currentTime >= 690 && currentTime <= 840)){
- return res.status(400).send('Lunch sacnning is only allwed between 11:30 AM and 2:00 PM');
+ if(type==='lunch' && !(currentTime >= 690 && currentTime <= 840)){
+ return res.status(400).json({ error: 'Lunch scanning is only allowed between 11:30 AM and 2:00 PM' });
}
- if(type=== 'snack' && !(currentTime >= 930 && currentTime <= 1020)){
- return res.status(400).send('Snack scanning is only allowed between 3:30 PM and 5:00 PM');
+ if(type=== 'snack' && !(currentTime >= 930 && currentTime <= 1020)){
+ return res.status(400).json({ error: 'Snack scanning is only allowed between 3:30 PM and 5:00 PM' });
}
const existingScan=await Scan.findOne({ userId, type, date: { $gte: new Date().setHours(0,0,0,0)}});
if (existingScan){
- return res.status(400).send('Already scanned today');
+ return res.status(400).json({ error: 'Already scanned today' });
}
const scan= new Scan({userId, type});
await scan.save();
- res.send('Scan successful');
+ res.status(201).json({ message: 'Scan successful' });
+ } catch (error) {
+ console.error('Scan error:', error);
+ res.status(500).json({ error: 'Internal server error' });
+ }
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| router.post('/scan',authenticate, async(req,res)=> { //to get info about user and the current time | |
| const {type}= req.body; | |
| const userId=req.userId; | |
| const now= new Date(); | |
| const hours= now.getHours(); | |
| const minutes=now.getMinutes(); | |
| if(type==='lunch' && !(hours>=11 && minutes>=30 && hours<14)){ //to check whether scanning of lunch time is valid | |
| return res.status(400).send('Lunch sacnning is only allwed between 11:30 AM and 2:00 PM'); | |
| } | |
| if(type=== 'snack' && !(hours>=15 && minutes>=30 && hours<17)){ //to check whether scanning of snack time is valid | |
| return res.status(400).send('Snack scanning is only allowed between 3:30 PM and 5:00 PM'); | |
| } | |
| const existingScan=await Scan.findone({ userId, type, date: { $gte: new Date().setHours(0,0,0,0)}}); | |
| if (existingScan){ //to check whether a scanning already occured in the given time | |
| return res.status(400).send('Already scanned today'); | |
| } | |
| const scan= new scan({userId, type}); | |
| await scan.save(); //to save current scan | |
| res.send('Scan successful'); | |
| }); | |
| router.post('/scan', authenticate, async (req, res) => { | |
| try { | |
| const { type } = req.body; | |
| if (!type) { | |
| return res.status(400).json({ error: 'Scan type is required' }); | |
| } | |
| if (!['lunch', 'snack'].includes(type)) { | |
| return res.status(400).json({ error: 'Invalid scan type' }); | |
| } | |
| const userId = req.userId; | |
| const now = new Date(); | |
| const hours = now.getHours(); | |
| const minutes = now.getMinutes(); | |
| const currentTime = hours * 60 + minutes; | |
| if (type === 'lunch' && !(currentTime >= 690 && currentTime <= 840)) { | |
| return res.status(400).json({ error: 'Lunch scanning is only allowed between 11:30 AM and 2:00 PM' }); | |
| } | |
| if (type === 'snack' && !(currentTime >= 930 && currentTime <= 1020)) { | |
| return res.status(400).json({ error: 'Snack scanning is only allowed between 3:30 PM and 5:00 PM' }); | |
| } | |
| const existingScan = await Scan.findOne({ | |
| userId, | |
| type, | |
| date: { $gte: new Date().setHours(0, 0, 0, 0) } | |
| }); | |
| if (existingScan) { | |
| return res.status(400).json({ error: 'Already scanned today' }); | |
| } | |
| const scan = new Scan({ userId, type }); | |
| await scan.save(); | |
| res.status(201).json({ message: 'Scan successful' }); | |
| } catch (error) { | |
| console.error('Scan error:', error); | |
| res.status(500).json({ error: 'Internal server error' }); | |
| } | |
| }); |
🧰 Tools
🪛 Biome (1.9.4)
[error] 24-24: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove duplicate mongoose import.
The mongoose module is imported twice.
const mongoose= require('mongoose'); const express= require('express'); const bodyParser= require('body-parser'); -const mongoose= require('mongoose');Also applies to: 4-4