Merge pull request #26 from ajayyy/experimental

ShadowHide + Sql Schemas
This commit is contained in:
Ajay Ramachandran
2019-08-24 17:06:23 -04:00
committed by GitHub
4 changed files with 130 additions and 8 deletions

3
.gitignore vendored
View File

@@ -88,4 +88,5 @@ typings/
.dynamodb/ .dynamodb/
# Databases # Databases
databases databases/sponsorTimes.db
databases/private.db

16
databases/_private.db.sql Normal file
View File

@@ -0,0 +1,16 @@
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "shadowBannedUsers" (
"userID" TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS "votes" (
"UUID" TEXT NOT NULL,
"userID" INTEGER NOT NULL,
"hashedIP" INTEGER NOT NULL,
"type" INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS "sponsorTimes" (
"videoID" TEXT NOT NULL,
"hashedIP" TEXT NOT NULL,
"timeSubmitted" INTEGER NOT NULL
);
COMMIT;

View File

@@ -0,0 +1,17 @@
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "sponsorTimes" (
"videoID" TEXT NOT NULL,
"startTime" REAL NOT NULL,
"endTime" REAL NOT NULL,
"votes" INTEGER NOT NULL,
"UUID" TEXT NOT NULL UNIQUE,
"userID" TEXT NOT NULL,
"timeSubmitted" INTEGER NOT NULL,
"views" INTEGER NOT NULL,
"shadowHidden" INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS "userNames" (
"userID" TEXT NOT NULL,
"userName" TEXT NOT NULL
);
COMMIT;

102
index.js
View File

@@ -18,6 +18,8 @@ http.createServer(app).listen(80);
//global salt that is added to every ip before hashing to //global salt that is added to every ip before hashing to
// make it even harder for someone to decode the ip // make it even harder for someone to decode the ip
var globalSalt = "49cb0d52-1aec-4b89-85fc-fab2c53062fb"; var globalSalt = "49cb0d52-1aec-4b89-85fc-fab2c53062fb";
//this is the user that can add shadow bans
var adminUserID = "7b89ea26f77bda8176e655eee86029f28c1e6514b6d6e3450bce362b5b126ca3";
//if so, it will use the x-forwarded header instead of the ip address of the connection //if so, it will use the x-forwarded header instead of the ip address of the connection
var behindProxy = true; var behindProxy = true;
@@ -37,7 +39,9 @@ app.get('/api/getVideoSponsorTimes', function (req, res) {
let votes = [] let votes = []
let UUIDs = []; let UUIDs = [];
db.prepare("SELECT startTime, endTime, votes, UUID FROM sponsorTimes WHERE videoID = ? ORDER BY startTime").all(videoID, function(err, rows) { let hashedIP = getHash(getIP(req) + globalSalt);
db.prepare("SELECT startTime, endTime, votes, UUID, shadowHidden FROM sponsorTimes WHERE videoID = ? ORDER BY startTime").all(videoID, async function(err, rows) {
if (err) console.log(err); if (err) console.log(err);
for (let i = 0; i < rows.length; i++) { for (let i = 0; i < rows.length; i++) {
@@ -46,6 +50,22 @@ app.get('/api/getVideoSponsorTimes', function (req, res) {
//too untrustworthy, just ignore it //too untrustworthy, just ignore it
continue; continue;
} }
//check if shadowHidden
//this means it is hidden to everyone but the original ip that submitted it
if (rows[i].shadowHidden == 1) {
//get the ip
//await the callback
let result = await new Promise((resolve, reject) => {
privateDB.prepare("SELECT hashedIP FROM sponsorTimes WHERE videoID = ?").all(videoID, (err, rows) => resolve({err, rows}));
});
if (!result.rows.some((e) => e.hashedIP === hashedIP)) {
//this isn't their ip, don't send it to them
continue;
}
}
sponsorTimes.push([]); sponsorTimes.push([]);
let index = sponsorTimes.length - 1; let index = sponsorTimes.length - 1;
@@ -128,7 +148,7 @@ app.get('/api/postVideoSponsorTimes', function (req, res) {
let timeSubmitted = Date.now(); let timeSubmitted = Date.now();
let yesterday = timeSubmitted - 86400000; let yesterday = timeSubmitted - 86400000;
//check to see if this ip has submitted too many sponsors today //check to see if this ip has submitted too many sponsors today
privateDB.prepare("SELECT COUNT(*) as count FROM sponsorTimes WHERE hashedIP = ? AND videoID = ? AND timeSubmitted > ?").get([hashedIP, videoID, yesterday], function(err, row) { privateDB.prepare("SELECT COUNT(*) as count FROM sponsorTimes WHERE hashedIP = ? AND videoID = ? AND timeSubmitted > ?").get([hashedIP, videoID, yesterday], function(err, row) {
if (row.count >= 10) { if (row.count >= 10) {
@@ -142,12 +162,19 @@ app.get('/api/postVideoSponsorTimes', function (req, res) {
res.sendStatus(429); res.sendStatus(429);
} else { } else {
//check if this info has already been submitted first //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) { db.prepare("SELECT UUID FROM sponsorTimes WHERE startTime = ? and endTime = ? and videoID = ?").get([startTime, endTime, videoID], async function(err, row) {
if (err) console.log(err); if (err) console.log(err);
//check to see if this user is shadowbanned
let result = await new Promise((resolve, reject) => {
privateDB.prepare("SELECT count(*) as userCount FROM shadowBannedUsers WHERE userID = ?").get(userID, (err, row) => resolve({err, row}));
});
let shadowBanned = result.row.userCount;
if (row == null) { if (row == null) {
//not a duplicate, execute query //not a duplicate, execute query
db.prepare("INSERT INTO sponsorTimes VALUES(?, ?, ?, ?, ?, ?, ?, ?)").run(videoID, startTime, endTime, 0, UUID, userID, timeSubmitted, 0); db.prepare("INSERT INTO sponsorTimes VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)").run(videoID, startTime, endTime, 0, UUID, userID, timeSubmitted, 0, shadowBanned);
//add to private db as well //add to private db as well
privateDB.prepare("INSERT INTO sponsorTimes VALUES(?, ?, ?)").run(videoID, hashedIP, timeSubmitted); privateDB.prepare("INSERT INTO sponsorTimes VALUES(?, ?, ?)").run(videoID, hashedIP, timeSubmitted);
@@ -264,7 +291,7 @@ app.post('/api/setUsername', function (req, res) {
let userID = req.query.userID; let userID = req.query.userID;
let userName = req.query.username; let userName = req.query.username;
if (userID == undefined || userName == undefined) { if (userID == undefined || userName == undefined || userID === "undefined") {
//invalid request //invalid request
res.sendStatus(400); res.sendStatus(400);
return; return;
@@ -318,6 +345,67 @@ app.get('/api/getUsername', function (req, res) {
}); });
}); });
//Endpoint used to hide a certain user's data
app.get('/api/shadowBanUser', async function (req, res) {
let userID = req.query.userID;
let shadowUserID = req.query.shadowUserID;
let enabled = req.query.enabled;
if (enabled === undefined){
enabled = true;
} else {
enabled = enabled === "true";
}
//if enabled is false and the old submissions should be made visible again
let unHideOldSubmissions = req.query.unHideOldSubmissions;
if (enabled === undefined){
unHideOldSubmissions = true;
} else {
unHideOldSubmissions = unHideOldSubmissions === "true";
}
if (userID == undefined || shadowUserID == undefined) {
//invalid request
res.sendStatus(400);
return;
}
//hash the userIDs
userID = getHash(userID);
if (userID !== adminUserID) {
//not authorized
res.sendStatus(403);
return;
}
//check to see if this user is already shadowbanned
let result = await new Promise((resolve, reject) => {
privateDB.prepare("SELECT count(*) as userCount FROM shadowBannedUsers WHERE userID = ?").get(shadowUserID, (err, row) => resolve({err, row}));
});
if (enabled && result.row.userCount == 0) {
//add them to the shadow ban list
//add it to the table
privateDB.prepare("INSERT INTO shadowBannedUsers VALUES(?)").run(shadowUserID);
//find all previous submissions and hide them
db.prepare("UPDATE sponsorTimes SET shadowHidden = 1 WHERE userID = ?").run(shadowUserID);
} else if (!enabled && result.row.userCount > 0) {
//remove them from the shadow ban list
privateDB.prepare("DELETE FROM shadowBannedUsers WHERE userID = ?").run(shadowUserID);
//find all previous submissions and unhide them
if (unHideOldSubmissions) {
db.prepare("UPDATE sponsorTimes SET shadowHidden = 0 WHERE userID = ?").run(shadowUserID);
}
}
res.sendStatus(200);
});
//Gets all the views added up for one userID //Gets all the views added up for one userID
//Useful to see how much one user has contributed //Useful to see how much one user has contributed
app.get('/api/getViewsForUser', function (req, res) { app.get('/api/getViewsForUser', function (req, res) {
@@ -374,7 +462,7 @@ app.get('/api/getTopUsers', function (req, res) {
let totalSubmissions = []; let totalSubmissions = [];
let minutesSaved = []; let minutesSaved = [];
db.prepare("SELECT sponsorTimes.userID as userID, COUNT(*) as totalSubmissions, SUM(views) as viewCount, SUM((sponsorTimes.endTime - sponsorTimes.startTime) / 60 * sponsorTimes.views) as minutesSaved, userNames.userName as userName FROM sponsorTimes LEFT JOIN userNames ON sponsorTimes.userID=userNames.userID WHERE sponsorTimes.votes > -1 GROUP BY sponsorTimes.userID ORDER BY " + sortBy + " DESC LIMIT 50").all(function(err, rows) { db.prepare("SELECT sponsorTimes.userID as userID, COUNT(*) as totalSubmissions, SUM(views) as viewCount, SUM((sponsorTimes.endTime - sponsorTimes.startTime) / 60 * sponsorTimes.views) as minutesSaved, userNames.userName as userName FROM sponsorTimes LEFT JOIN userNames ON sponsorTimes.userID=userNames.userID WHERE sponsorTimes.votes > -1 GROUP BY sponsorTimes.userID ORDER BY " + sortBy + " DESC LIMIT 100").all(function(err, rows) {
for (let i = 0; i < rows.length; i++) { for (let i = 0; i < rows.length; i++) {
if (rows[i].userName != null) { if (rows[i].userName != null) {
userNames[i] = rows[i].userName; userNames[i] = rows[i].userName;