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
7 changes: 7 additions & 0 deletions api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const bcrypt = require('bcrypt');
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const session = require("express-session");
const helmet = require('helmet');
const csurf = require('csurf');

// then express and cors
app.use(express.json());
Expand All @@ -19,6 +21,10 @@ app.use(cors({
credentials: true
}));

// Security enhancements
app.use(helmet()); // Use Helmet to secure HTTP headers
app.use(csurf()); // Enable CSRF protection

// this for the cookies
app.use(cookieParser());
app.use(bodyParser.urlencoded({extended:true }));
Expand All @@ -31,6 +37,7 @@ app.use(session({
cookie: {
// cookie expires in 8 hours
expires: 60 * 60 * 8,
secure: true, // Ensure cookies are sent over HTTPS
},
}));

Expand Down
2 changes: 1 addition & 1 deletion api/middlewares/Authent.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const validateTheToken = (req, res, next) =>{
else{

try {
const validTokenito = verify(accessToken, "hereputyoursecret");
const validTokenito = verify(accessToken, process.env.JWT_SECRET);
if(validTokenito){
req.user = validTokenito;
return next();
Expand Down
9 changes: 8 additions & 1 deletion api/routes/Items.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ const { Op } = require("sequelize");
const fs = require('fs');
const js2xml = require('js2xml').Js2Xml;
const xml2js = require('xml2js');
const rateLimit = require('express-rate-limit');

// Apply rate limiting to the importxmls route
const importXmlsLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 10 // limit each IP to 10 requests per windowMs
});

router.get('/', async (req, res) => {

Expand Down Expand Up @@ -1042,7 +1049,7 @@ router.get('/top/:id', async (req, res) => {

// this to import the xmls in the database
// comment out so it doesn't run when the site is "online"
router.post('/importxmls', async (req, res) => {
router.post('/importxmls', importXmlsLimiter, async (req, res) => {

const parser = new xml2js.Parser();
var path = require("path");
Expand Down
11 changes: 9 additions & 2 deletions api/routes/Photos.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ const { upload } = require('../middlewares/Upload');
const { Photo, Item } = require('../models');
const fs = require('fs');
const path = require("path");
const rateLimit = require('express-rate-limit');

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

// No token cause this needs to work for guests as well
router.get('/:id', async (req, res) => {
Expand Down Expand Up @@ -82,11 +89,11 @@ router.post('/:id', validateTheToken, upload.single('image'), async (req, res) =


// validate the user too before deleting
router.delete('/:id', validateTheToken, async (req, res)=>{
router.delete('/:id', validateTheToken, limiter, async (req, res)=>{
const myId = req.params.id;
const photograph = await Photo.findOne({ where: {id: myId}});
const itemId = photograph.ItemId;
const localpath = path.join(__dirname, '..', 'images', photograph.url.split('/').pop())
const localpath = path.join(__dirname, '..', 'images', path.basename(photograph.url.split('/').pop()));

await Photo.destroy({where : {
id: myId,
Expand Down
38 changes: 25 additions & 13 deletions api/routes/Users.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ const bcrypt = require('bcrypt');
const {sign} =require('jsonwebtoken');
const { validateTheToken } = require('../middlewares/Authent');
const { Op } = require("sequelize");
const rateLimit = require('express-rate-limit');

// Rate limiting middleware for login route
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // limit each IP to 5 requests per windowMs
message: "Too many login attempts from this IP, please try again after 15 minutes"
});

router.post('/', async (req, res) => {

Expand Down Expand Up @@ -35,7 +43,7 @@ router.post('/', async (req, res) => {

});

router.post('/login', async (req, res) => {
router.post('/login', loginLimiter, async (req, res) => {

const { username , password } = req.body;

Expand All @@ -57,7 +65,7 @@ router.post('/login', async (req, res) => {
res.json({error: "Wrong User Credentials!"});
}
else{
const accessToken = sign({username: user.username, id: user.id}, "hereputyoursecret");
const accessToken = sign({username: user.username, id: user.id}, process.env.JWT_SECRET);
res.json({token: accessToken, username: user.username, id: user.id });
}
});
Expand Down Expand Up @@ -159,18 +167,22 @@ router.put('/approve', validateTheToken, async (req, res) => {
const username = req.user.username;

if (username==='admin'){
for (var i = 0; i < userList.length; i++) {
var userId = userList[i];
console.log(userId);
await User.update({
approved: true
},
{where : {
id: userId
}
});
if (Array.isArray(userList) && userList.length <= 100) { // Validate userList
for (var i = 0; i < userList.length; i++) {
var userId = userList[i];
console.log(userId);
await User.update({
approved: true
},
{where : {
id: userId
}
});
}
res.json("Succesfully approved users!");
} else {
res.json("Invalid user list!");
}
res.json("Succesfully approved users!");
}
else{
res.json("This is forbidden!")
Expand Down
3 changes: 2 additions & 1 deletion front/src/components/Admin/Download.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export function Download(props){
},
}).then((response) => {

const create_url = window.URL.createObjectURL(new Blob([JSON.stringify(response.data, null, "\t")]));
const sanitizedData = JSON.stringify(response.data, null, "\t").replace(/</g, "\\u003c").replace(/>/g, "\\u003e");
const create_url = window.URL.createObjectURL(new Blob([sanitizedData]));
const generate_link = document.createElement('a');

generate_link.href = create_url;
Expand Down
1 change: 1 addition & 0 deletions front/src/components/Admin/DownloadXML.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export function DownloadXML(props){
generate_link.setAttribute('download', 'auctions.xml');
document.body.appendChild(generate_link);
generate_link.click();
document.body.removeChild(generate_link); // Ensure the link is removed after use
});
}

Expand Down
5 changes: 3 additions & 2 deletions front/src/components/Modals/Recommendations.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ function Recommendations() {

// Displaying the items of this particular page
const displayItems = itemList.slice( visitedPages, visitedPages + itemsPerPage ).map((value, key)=>{
const sanitizedSrc = value.coverPhoto.startsWith('http') ? value.coverPhoto : '';
return <div className='item' onClick={()=>{navigate(`/item/${value.id}`)}}>
<div className='name'>{value.name} </div>
<div className='body'>
<img className='lando_image' src={value.coverPhoto} alt="cover" />
<img className='lando_image' src={sanitizedSrc} alt="cover" />
</div>
<div className='footer gradient-custom'>
<div > {value.location}, {value.country}</div>
Expand Down Expand Up @@ -84,4 +85,4 @@ function Recommendations() {
);
}

export default Recommendations
export default Recommendations
3 changes: 2 additions & 1 deletion front/src/components/Searching/Auctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,11 @@ function Auctions() {

// Displaying the items of this particular page
const displayItems = itemList.slice( visitedPages, visitedPages + itemsPerPage ).map((value, key)=>{
const sanitizedCoverPhoto = value.coverPhoto.startsWith('http') ? value.coverPhoto : ''; // Sanitize the URL
return <div className='item' key={key} onClick={()=>{navigate(`/item/${value.id}`)}}>
<div className='name'>{value.name} </div>
<div className='body'>
<img className='lando_image' src={value.coverPhoto} alt="coverphoto" />
<img className='lando_image' src={sanitizedCoverPhoto} alt="coverphoto" />
</div>
<div className='footer gradient-custom'>
<div > {value.location}, {value.country}</div>
Expand Down
2 changes: 1 addition & 1 deletion front/src/components/Searching/FilterCategories.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ function FilterCategories() {
return <div className='item' onClick={()=>{navigate(`/item/${value.id}`)}}>
<div className='name'>{value.name} </div>
<div className='body'>
<img className='lando_image' alt="cover" src={value.coverPhoto} />
<img className='lando_image' alt="cover" src={encodeURI(value.coverPhoto)} />
</div>
<div className='footer gradient-custom'>
<div > {value.location}, {value.country}</div>
Expand Down
4 changes: 2 additions & 2 deletions front/src/pages/Profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ function Profile() {
return <div className='item' onClick={()=>{navigate(`/item/${value.id}`)}}>
<div className='name'>{value.name} </div>
<div className='body'>
<img className='lando_image' src={value.coverPhoto} alt="product" />
<img className='lando_image' src={encodeURI(value.coverPhoto)} alt="product" />
</div>
<div className='footer gradient-custom'>
<div > {value.location}, {value.country}</div>
Expand Down Expand Up @@ -329,4 +329,4 @@ function Profile() {
)
}

export default Profile;
export default Profile;