Add initial version of querying by hash prefix

This commit is contained in:
Martijn van der Ven
2020-05-23 16:54:21 +02:00
parent ca46f4c9ac
commit 803b1fa505
4 changed files with 103 additions and 0 deletions

View File

@@ -10,6 +10,7 @@ var loggerMiddleware = require('./middleware/logger.js');
// Routes
var getSkipSegments = require('./routes/getSkipSegments.js').endpoint;
var postSkipSegments = require('./routes/postSkipSegments.js');
var getSkipSegmentsByHash = require('./routes/getSkipSegmentsByHash.js');
var voteOnSponsorTime = require('./routes/voteOnSponsorTime.js');
var viewedVideoSponsorTime = require('./routes/viewedVideoSponsorTime.js');
var setUsername = require('./routes/setUsername.js');
@@ -48,6 +49,9 @@ app.post('/api/postVideoSponsorTimes', oldSubmitSponsorTimes);
app.get('/api/skipSegments', getSkipSegments);
app.post('/api/skipSegments', postSkipSegments);
// add the privacy protecting skip segments functions
app.get('/api/skipSegments/:prefix', getSkipSegmentsByHash);
//voting endpoint
app.get('/api/voteOnSponsorTime', voteOnSponsorTime);
app.post('/api/voteOnSponsorTime', voteOnSponsorTime);

View File

@@ -26,6 +26,10 @@ if (config.createDatabaseIfNotExist && !config.readOnly) {
// Upgrade database if required
if (!config.readOnly) {
// Register hashing function needed for running database upgrade
db.function("sha256", function (string) {
return require('crypto').createHash("sha256").update(string).digest("hex");
});
ugradeDB(db, "sponsorTimes");
ugradeDB(privateDB, "private")
}

View File

@@ -0,0 +1,69 @@
const config = require('../config.js');
const { db, privateDB } = require('../databases/databases.js');
const getHash = require('../utils/getHash.js');
const getIP = require('../utils/getIP.js');
/**
* @typedef {Object} Segment
* @property {string} videoID YouTube video ID the segment is meant for
* @property {number[]} segment Tuple of start and end times in seconds
* @property {string} category Category of content to skip
* @property {string} UUID Unique identifier for the specific segment
*/
/**
* @param {string} prefix Lowercased hexadecimal hash prefix
* @param {string} hashedIP Custom hash of the visitors IP address
* @returns {Segment[]}
*/
function getSkipSegmentsByHash(prefix, hashedIP) {
/**
* @constant
* @type {Segment[]}
* @default
*/
const segments = [];
const rows = db.prepare('SELECT videoID, startTime, endTime, UUID, category, shadowHidden FROM sponsorTimes WHERE votes >= -1 AND hashedVideoID LIKE ? ORDER BY startTime')
.all(prefix + '%');
const onlyForCurrentUser = privateDB.prepare('SELECT videoID FROM sponsorTimes WHERE hashedIP = ?').all(hashedIP).map(row => row.videoID);
for (const row of rows) {
/** @TODO check if this logic does what is expected. */
if (row.shadowHidden === 1 && onlyForCurrentUser.indexOf(row.videoID) === -1) {
// The current visitors IP did not submit for the current video.
// Do not send shadowHidden segments to them.
continue;
}
segments.push({
videoID: row.videoID,
segment: [row.startTime, row.endTime],
category: row.category,
UUID: row.UUID
});
}
return segments;
}
const minimumPrefix = config.minimumPrefix || '3';
const maximumPrefix = config.maximumPrefix || '32'; // Half the hash.
const prefixChecker = new RegExp('^[\\dA-F]{' + minimumPrefix + ',' + maximumPrefix + '}$', 'i');
module.exports = async function (req, res) {
if (!prefixChecker.test(req.params.prefix)) {
res.sendStatus(400).end(); // Exit early on faulty prefix
}
const segments = getSkipSegmentsByHash(
req.params.prefix.toLowerCase(),
getHash(getIP(req) + config.globalSalt)
);
if (segments) {
res.send(segments)
}
}