Skip to content
Open
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
3 changes: 3 additions & 0 deletions Backend/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MONGO_URI=mongodb://localhost:27017/digital-mess-card
JWT_SECRET=your-secret-key
PORT=5000
27 changes: 27 additions & 0 deletions Backend/Server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const connectDB = require('./config/db');

const express= require('express');
const cors = require('cors');


const authRoutes = require('./routes/auth');
const scanRoutes= require('./routes/scan');

app.use(corse());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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(express.json());

connectDB();

app.use('/api/auth', authRoutes);
app.use('/api/scan', scanRoutes);
require('dotenv').config();
Comment on lines +15 to +17
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Load environment variables before mounting routes.

The dotenv configuration should be loaded before accessing environment variables in routes. Move the require('dotenv').config() call to the top of the file.

+require('dotenv').config();
+
 const connectDB = require('./config/db');
 
 const express = require('express');
 // ... rest of the imports
 
 app.use('/api/auth', authRoutes);
 app.use('/api/scan', scanRoutes);
-require('dotenv').config();
📝 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.

Suggested change
app.use('/api/auth', authRoutes);
app.use('/api/scan', scanRoutes);
require('dotenv').config();
require('dotenv').config();
const connectDB = require('./config/db');
const express = require('express');
// ... rest of the imports
app.use('/api/auth', authRoutes);
app.use('/api/scan', scanRoutes);



app.get('/',(req,res)=>{
res.send('Digital MESS Card'); //Route
});

const PORT= process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
16 changes: 16 additions & 0 deletions Backend/config/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const mongoose= require('mongoose');

const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
});
Comment on lines +1 to +8
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Load environment variables before accessing them.

The dotenv configuration should be loaded before accessing process.env.MONGO_URI. Move the require('dotenv').config() call to the top of the file.

+require('dotenv').config();
 const mongoose= require('mongoose');

 const connectDB = async () => {
     try {
         await mongoose.connect(process.env.MONGO_URI, {
             useNewUrlParser: true,
             useUnifiedTopology: true
📝 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.

Suggested change
const mongoose= require('mongoose');
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
});
require('dotenv').config();
const mongoose= require('mongoose');
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
});

console.log('MongoDB connected');
} catch (err) {
console.error('MongoDB connection error:', err);
process.exit(1);
}
};

module.exports = connectDB;
30 changes: 30 additions & 0 deletions Backend/controllers/authController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const { jwtSecret } = require('../config/auth');

exports.register = async (req, res) => { //to register new user
const { username, password } = req.body;
try {
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 (err) {
res.status(500).json({ error: 'Error registering user' });
}
};
Comment on lines +6 to +16
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add input validation and duplicate username check.

The registration function needs several security improvements:

  1. Add input validation for username and password
  2. Check for existing username before registration
  3. Implement password strength requirements
  4. Provide more specific error handling

Here's a suggested implementation:

 exports.register = async (req, res) => {
     const { username, password } = req.body;
+    // Input validation
+    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' });
+    }
     try {
+        // Check for existing user
+        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 (err) {
-        res.status(500).json({ error: 'Error registering user' });
+        console.error('Registration error:', err);
+        res.status(500).json({ error: 'Internal server error during registration' });
     }
 };


exports.login = async (req, res) => { //Authenticate access
const { username, password } = req.body;
try {
const user= await User.findOne({ username });
if (!user || !(await bcrypt.compare(password, user.password))) { // //to check whether the login details are valid
return res.status(400).json({ error: 'Invalid credentials' });
}
const token= jwt.sign({ userId: user._id }, jwtSecret, { expiresIn: '1h' });
res.json({ token });
} catch (err) {
res.status(500).json({ error: 'Error logging in' });
}
};
Comment on lines +18 to +30
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Enhance login security with rate limiting and better error handling.

The login function needs several security improvements:

  1. Add input validation
  2. Implement rate limiting for failed attempts
  3. Make token expiration configurable
  4. Improve error handling specificity

Here's a suggested implementation:

+const rateLimit = require('express-rate-limit');
+
+// Rate limiting for failed login attempts
+const loginLimiter = rateLimit({
+    windowMs: 15 * 60 * 1000, // 15 minutes
+    max: 5 // limit each IP to 5 requests per windowMs
+});
+
 exports.login = async (req, res) => {
     const { username, password } = req.body;
+    // Input validation
+    if (!username || !password) {
+        return res.status(400).json({ error: 'Username and password are required' });
+    }
     try {
         const user = await User.findOne({ username });
         if (!user || !(await bcrypt.compare(password, user.password))) {
+            // Log failed attempt
+            console.warn(`Failed login attempt for username: ${username}`);
             return res.status(400).json({ error: 'Invalid credentials' });
         }
-        const token = jwt.sign({ userId: user._id }, jwtSecret, { expiresIn: '1h' });
+        const token = jwt.sign(
+            { userId: user._id },
+            jwtSecret,
+            { expiresIn: process.env.JWT_EXPIRATION || '1h' }
+        );
         res.json({ token });
     } catch (err) {
-        res.status(500).json({ error: 'Error logging in' });
+        console.error('Login error:', err);
+        res.status(500).json({ error: 'Internal server error during login' });
     }
 };

Additionally, consider implementing the following security measures:

  1. Add CSRF protection
  2. Implement secure session handling
  3. Add request sanitization
📝 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.

Suggested change
exports.login = async (req, res) => { //Authenticate access
const { username, password } = req.body;
try {
const user= await User.findOne({ username });
if (!user || !(await bcrypt.compare(password, user.password))) { // //to check whether the login details are valid
return res.status(400).json({ error: 'Invalid credentials' });
}
const token= jwt.sign({ userId: user._id }, jwtSecret, { expiresIn: '1h' });
res.json({ token });
} catch (err) {
res.status(500).json({ error: 'Error logging in' });
}
};
const rateLimit = require('express-rate-limit');
// Rate limiting for failed login attempts
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5 // limit each IP to 5 requests per windowMs
});
exports.login = async (req, res) => { //Authenticate access
const { username, password } = req.body;
// Input validation
if (!username || !password) {
return res.status(400).json({ error: 'Username and password are required' });
}
try {
const user = await User.findOne({ username });
if (!user || !(await bcrypt.compare(password, user.password))) { // to check whether the login details are valid
// Log failed attempt
console.warn(`Failed login attempt for username: ${username}`);
return res.status(400).json({ error: 'Invalid credentials' });
}
const token = jwt.sign(
{ userId: user._id },
jwtSecret,
{ expiresIn: process.env.JWT_EXPIRATION || '1h' }
);
res.json({ token });
} catch (err) {
console.error('Login error:', err);
res.status(500).json({ error: 'Internal server error during login' });
}
};

31 changes: 31 additions & 0 deletions Backend/controllers/scanController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const Scan= require('../models/Scan');

exports.scan= 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).json({ error: 'Lunch scanning is only allowed 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).json({ error: 'Snack scanning is only allowed between 3:30 PM and 5:00 PM' });
}
Comment on lines +11 to +17
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix time window comparison logic.

The current time window checks are incorrect and may allow scans outside the intended windows. For example, at 11:00 with minutes >= 30, the lunch check would pass.

-    if (type === 'lunch' && !(hours >= 11 && minutes >= 30 && hours < 14)) {
+    const currentTime = hours * 60 + minutes;
+    const lunchStart = 11 * 60 + 30;  // 11:30
+    const lunchEnd = 14 * 60;         // 14:00
+    if (type === 'lunch' && (currentTime < lunchStart || currentTime >= lunchEnd)) {
         return res.status(400).json({ error: 'Lunch scanning is only allowed between 11:30 AM and 2:00 PM' });
     }
 
-    if (type === 'snack' && !(hours >= 15 && minutes >= 30 && hours < 17)) {
+    const snackStart = 15 * 60 + 30;  // 15:30
+    const snackEnd = 17 * 60;         // 17:00
+    if (type === 'snack' && (currentTime < snackStart || currentTime >= snackEnd)) {


try {
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' }); //to check whether a scanning already occured in the given time
}

const scan = new Scan({ userId, type });
await scan.save(); //to save current scan
res.json({ message: 'Scan successful' });
} catch (err) {
res.status(500).json({ error: 'Error processing scan' });
}
};
15 changes: 15 additions & 0 deletions Backend/middleware/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const jwt= require('jsonwebtoken');
const { jwtSecret }= require('../config/auth');

exports.authenticate= (req,res,next) => {
const token=req.header('Authorization');
if (!token) return res.status(401).json({ error: 'Access denied' });

try{
const decoded= jwt.verify(token, jwtSecret);
req.userId= decoded.userId;
next();
} catch (err) {
res.status(400).json({ error: 'Invalid token' });
}
};
8 changes: 8 additions & 0 deletions Backend/models/Scan.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const mongoose= require('mongoose');
const scanSchema =new mongoose.Schema({ //Scan date update in db
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
type: { type: String, enum: ['lunch', 'snack'], required: true },
date :{ type: Date, default: Date.now},
});

module.exports= mongoose.model('Scan', scanSchema);
8 changes: 8 additions & 0 deletions Backend/models/User.js
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
username:{ type: String, required: true, unique: true },
password:{ type: String, required: true, match:/^[a-zA-Z0-9]+$/,
}
Comment on lines +5 to +6
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Strengthen password security.

The current password validation is insufficient:

  1. Allows weak passwords (only alphanumeric)
  2. No minimum length requirement
  3. 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();
});

});
module.exports= mongoose.model('User', userSchema);
9 changes: 9 additions & 0 deletions Backend/routes/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const express= require('express');
const { register, login } = require('../controllers/authController');

const router= express.Router();

router.post('/register', register);
router.post('/login', login);

module.exports = router;
9 changes: 9 additions & 0 deletions Backend/routes/scan.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const express= require('express');
const { scan }= require('../controllers/scanController');
const { authenticate }= require('../middleware/auth');

const router = express.Router();

router.post('/scan', authenticate, scan);

module.exports= router;
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@


## Basic Details
### Team Name: [Name]
### Team Name: NOX


### Team Members
- Member 1: [Name] - [College]
- Member 2: [Name] - [College]
- Member 3: [Name] - [College]
- Member 1: Anagha TR - SCMS School of engineering and technology
- Member 2: Anaya Wilson - SCMS School of engineering and technology
- Member 3: Aneeja J - SCMS School of engineering and technology

### Hosted Project Link
[mention your project hosted project link here]
Expand Down