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/
# 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;

View File

@@ -18,6 +18,8 @@ http.createServer(app).listen(80);
//global salt that is added to every ip before hashing to
// make it even harder for someone to decode the ip
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
var behindProxy = true;
@@ -37,7 +39,9 @@ app.get('/api/getVideoSponsorTimes', function (req, res) {
let votes = []
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);
for (let i = 0; i < rows.length; i++) {
@@ -46,6 +50,22 @@ app.get('/api/getVideoSponsorTimes', function (req, res) {
//too untrustworthy, just ignore it
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([]);
let index = sponsorTimes.length - 1;
@@ -142,12 +162,19 @@ app.get('/api/postVideoSponsorTimes', function (req, res) {
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) {
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);
//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) {
//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
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 userName = req.query.username;
if (userID == undefined || userName == undefined) {
if (userID == undefined || userName == undefined || userID === "undefined") {
//invalid request
res.sendStatus(400);
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
//Useful to see how much one user has contributed
app.get('/api/getViewsForUser', function (req, res) {
@@ -374,7 +462,7 @@ app.get('/api/getTopUsers', function (req, res) {
let totalSubmissions = [];
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++) {
if (rows[i].userName != null) {
userNames[i] = rows[i].userName;