From 6850414a2734fa2ee8476ff1216968cc1384b779 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 17 Jul 2019 21:58:40 -0400 Subject: [PATCH 1/6] Replaced typeof with proper undefined check --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 1d663377..2bbc79a6 100644 --- a/index.js +++ b/index.js @@ -84,7 +84,7 @@ app.get('/api/postVideoSponsorTimes', function (req, res) { let endTime = req.query.endTime; let userID = req.query.userID; - if (typeof videoID != 'string' || startTime == undefined || endTime == undefined || userID == undefined) { + if (videoID != undefined || startTime == undefined || endTime == undefined || userID == undefined) { //invalid request res.sendStatus(400); return; From a0e63e73262d8f4d687cc7860c408822eafd725d Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Fri, 19 Jul 2019 17:00:50 -0400 Subject: [PATCH 2/6] Preventing voting twice accept for changing vote. --- index.js | 67 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/index.js b/index.js index 2bbc79a6..2cb4e920 100644 --- a/index.js +++ b/index.js @@ -140,26 +140,57 @@ app.get('/api/voteOnSponsorTime', function (req, res) { return; } - //-1 for downvote, 1 for upvote. Maybe more depending on reputation in the future - let incrementAmount = 0; - - //don't use userID for now, and just add the vote - if (type == 1) { - //upvote - incrementAmount = 1; - } else if (type == 0) { - //downvote - incrementAmount = -1; - } else { - //unrecongnised type of vote - req.sendStatus(400); - return; - } + //check if vote has already happened + db.prepare("SELECT type FROM votes WHERE userID = ? AND UUID = ?").get(userID, UUID, function(err, row) { + if (err) console.log(err); + + if (row != undefined && row.type == type) { + //they have already done this exact vote + res.status(405).send("Duplicate Vote"); + return; + } + + //-1 for downvote, 1 for upvote. Maybe more depending on reputation in the future + let incrementAmount = 0; + let oldIncrementAmount = 0; + + if (type == 1) { + //upvote + incrementAmount = 1; + } else if (type == 0) { + //downvote + incrementAmount = -1; + } else { + //unrecongnised type of vote + res.sendStatus(400); + return; + } + if (row != undefined) { + if (row.type == 1) { + //upvote + oldIncrementAmount = 1; + } else if (row.type == 0) { + //downvote + oldIncrementAmount = -1; + } + } - db.prepare("UPDATE sponsorTimes SET votes = votes + ? WHERE UUID = ?").run(incrementAmount, UUID); + //update the votes table + if (row != undefined) { + db.prepare("UPDATE votes SET type = ? WHERE userID = ? AND UUID = ?").run(type, userID, UUID); + } else { + db.prepare("INSERT INTO votes VALUES(?, ?, ?)").run(userID, UUID, type); + } + + //update the vote count on this sponsorTime + //oldIncrementAmount will be zero is row is null + db.prepare("UPDATE sponsorTimes SET votes = votes + ? WHERE UUID = ?").run(incrementAmount - oldIncrementAmount, UUID); - //added to db - res.sendStatus(200); + //update the votes table + + //added to db + res.sendStatus(200); + }); }); app.get('/database.db', function (req, res) { From 5e3c8a3b155c6a7788c21d2d26a1f96f79c36858 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 20 Jul 2019 15:29:31 -0400 Subject: [PATCH 3/6] Fixed submissions being broken. --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 2cb4e920..a805fa04 100644 --- a/index.js +++ b/index.js @@ -84,7 +84,7 @@ app.get('/api/postVideoSponsorTimes', function (req, res) { let endTime = req.query.endTime; let userID = req.query.userID; - if (videoID != undefined || startTime == undefined || endTime == undefined || userID == undefined) { + if (videoID == undefined || startTime == undefined || endTime == undefined || userID == undefined) { //invalid request res.sendStatus(400); return; From 5a5118a7b03e8c961717f6bdbdd686a946375b28 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sat, 20 Jul 2019 21:48:08 -0400 Subject: [PATCH 4/6] Made it order the sponsor times by start time. --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index a805fa04..f46e2f22 100644 --- a/index.js +++ b/index.js @@ -36,7 +36,7 @@ app.get('/api/getVideoSponsorTimes', function (req, res) { let votes = [] let UUIDs = []; - db.prepare("SELECT startTime, endTime, votes, UUID FROM sponsorTimes WHERE videoID = ?").all(videoID, function(err, rows) { + db.prepare("SELECT startTime, endTime, votes, UUID FROM sponsorTimes WHERE videoID = ? ORDER BY startTime").all(videoID, function(err, rows) { if (err) console.log(err); for (let i = 0; i < rows.length; i++) { From 930c0bc6a31501a8baa2036e566d7e62361f2127 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Sun, 21 Jul 2019 22:06:01 -0400 Subject: [PATCH 5/6] Added rate limit per day per IP. --- index.js | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/index.js b/index.js index f46e2f22..6501d29a 100644 --- a/index.js +++ b/index.js @@ -105,23 +105,33 @@ app.get('/api/postVideoSponsorTimes', function (req, res) { //get current time let timeSubmitted = Date.now(); - //check to see if the user has already submitted sponsors for this video - db.prepare("SELECT UUID FROM sponsorTimes WHERE userID = ? and videoID = ?").all([userID, videoID], function(err, rows) { - if (rows.length >= 4) { - //too many sponsors for the same video from the same user + let yesterday = timeSubmitted - 86400000; + + //check to see if this ip has submitted too many sponsors today + db.prepare("SELECT COUNT(*) as count FROM sponsorTimes WHERE hashedIP = ? AND videoID = ? AND timeSubmitted > ?").get([hashedIP, videoID, yesterday], function(err, row) { + if (row.count >= 10) { + //too many sponsors for the same video from the same ip address res.sendStatus(429); } else { - //check if this info has already been submitted first - db.prepare("SELECT UUID FROM sponsorTimes WHERE startTime = ? and endTime = ? and videoID = ?").get([startTime, endTime, videoID], function(err, row) { - if (err) console.log(err); - - if (row == null) { - //not a duplicate, execute query - db.prepare("INSERT INTO sponsorTimes VALUES(?, ?, ?, ?, ?, ?, ?, ?)").run(videoID, startTime, endTime, 0, UUID, userID, hashedIP, timeSubmitted); - - res.sendStatus(200); + //check to see if the user has already submitted sponsors for this video + db.prepare("SELECT COUNT(*) as count FROM sponsorTimes WHERE userID = ? and videoID = ?").get([userID, videoID], function(err, row) { + if (row.count >= 4) { + //too many sponsors for the same video from the same user + res.sendStatus(429); } else { - res.sendStatus(409); + //check if this info has already been submitted first + db.prepare("SELECT UUID FROM sponsorTimes WHERE startTime = ? and endTime = ? and videoID = ?").get([startTime, endTime, videoID], function(err, row) { + if (err) console.log(err); + + if (row == null) { + //not a duplicate, execute query + db.prepare("INSERT INTO sponsorTimes VALUES(?, ?, ?, ?, ?, ?, ?, ?)").run(videoID, startTime, endTime, 0, UUID, userID, hashedIP, timeSubmitted); + + res.sendStatus(200); + } else { + res.sendStatus(409); + } + }); } }); } From cd36e2b64be8d209f62c6e102a424da4c5bc97d0 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Mon, 22 Jul 2019 17:10:23 -0400 Subject: [PATCH 6/6] Made it run the hash function 5000 times to ensure no one will brute force the IPs. --- index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 6501d29a..102e55bb 100644 --- a/index.js +++ b/index.js @@ -94,8 +94,12 @@ app.get('/api/postVideoSponsorTimes', function (req, res) { let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; //hash the ip so no one can get it from the database - let hashCreator = crypto.createHash('sha256'); - let hashedIP = hashCreator.update(ip + globalSalt).digest('hex'); + let hashedIP = ip + globalSalt; + //hash it 5000 times, this makes it very hard to brute force + for (let i = 0; i < 5000; i++) { + let hashCreator = crypto.createHash('sha512'); + hashedIP = hashCreator.update(hashedIP).digest('hex'); + } startTime = parseFloat(startTime); endTime = parseFloat(endTime);