mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2024-11-10 01:02:30 +01:00
Merge pull request #257 from mchangrh/vip-cache-clear
VIP endpoint for clearing cache of video
This commit is contained in:
commit
1770608525
4 changed files with 133 additions and 3 deletions
|
@ -29,6 +29,7 @@ import {apiCspMiddleware} from './middleware/apiCsp';
|
|||
import {rateLimitMiddleware} from './middleware/requestRateLimit';
|
||||
import dumpDatabase, {redirectLink} from './routes/dumpDatabase';
|
||||
import {endpoint as getSegmentInfo} from './routes/getSegmentInfo';
|
||||
import {postClearCache} from './routes/postClearCache';
|
||||
|
||||
export function createServer(callback: () => void) {
|
||||
// Create a service (the app object is just a callback).
|
||||
|
@ -136,6 +137,9 @@ function setupRoutes(app: Express) {
|
|||
//get segment info
|
||||
app.get('/api/segmentInfo', getSegmentInfo);
|
||||
|
||||
//clear cache as VIP
|
||||
app.post('/api/clearCache', postClearCache)
|
||||
|
||||
if (config.postgres) {
|
||||
app.get('/database', (req, res) => dumpDatabase(req, res, true));
|
||||
app.get('/database.json', (req, res) => dumpDatabase(req, res, false));
|
||||
|
|
55
src/routes/postClearCache.ts
Normal file
55
src/routes/postClearCache.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { Logger } from '../utils/logger';
|
||||
import { HashedUserID, UserID } from '../types/user.model';
|
||||
import { getHash } from '../utils/getHash';
|
||||
import { Request, Response } from 'express';
|
||||
import { Service, VideoID } from '../types/segments.model';
|
||||
import { QueryCacher } from '../utils/queryCacher';
|
||||
import { isUserVIP } from '../utils/isUserVIP';
|
||||
import { VideoIDHash } from "../types/segments.model";
|
||||
|
||||
export async function postClearCache(req: Request, res: Response) {
|
||||
const videoID = req.query.videoID as VideoID;
|
||||
let userID = req.query.userID as UserID;
|
||||
const service = req.query.service as Service ?? Service.YouTube;
|
||||
|
||||
const invalidFields = [];
|
||||
if (typeof videoID !== 'string') {
|
||||
invalidFields.push('videoID');
|
||||
}
|
||||
if (typeof userID !== 'string') {
|
||||
invalidFields.push('userID');
|
||||
}
|
||||
|
||||
if (invalidFields.length !== 0) {
|
||||
// invalid request
|
||||
const fields = invalidFields.reduce((p, c, i) => p + (i !== 0 ? ', ' : '') + c, '');
|
||||
res.status(400).send(`No valid ${fields} field(s) provided`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// hash the userID as early as possible
|
||||
const hashedUserID: HashedUserID = getHash(userID);
|
||||
// hash videoID
|
||||
const hashedVideoID: VideoIDHash = getHash(videoID, 1);
|
||||
|
||||
// Ensure user is a VIP
|
||||
if (!(await isUserVIP(hashedUserID))){
|
||||
Logger.warn("Permission violation: User " + hashedUserID + " attempted to clear cache for video " + videoID + ".");
|
||||
res.status(403).json({"message": "Not a VIP"});
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
QueryCacher.clearVideoCache({
|
||||
videoID,
|
||||
hashedVideoID,
|
||||
service
|
||||
});
|
||||
res.status(200).json({
|
||||
message: "Cache cleared on video " + videoID
|
||||
});
|
||||
} catch(err) {
|
||||
res.status(500).send()
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -22,15 +22,14 @@ async function get<T>(fetchFromDB: () => Promise<T>, key: string): Promise<T> {
|
|||
return data;
|
||||
}
|
||||
|
||||
function clearVideoCache(videoInfo: { videoID: VideoID; hashedVideoID: VideoIDHash; service: Service; userID: UserID; }) {
|
||||
function clearVideoCache(videoInfo: { videoID: VideoID; hashedVideoID: VideoIDHash; service: Service; userID?: UserID; }) {
|
||||
if (videoInfo) {
|
||||
redis.delAsync(skipSegmentsKey(videoInfo.videoID, videoInfo.service));
|
||||
redis.delAsync(skipSegmentsHashKey(videoInfo.hashedVideoID, videoInfo.service));
|
||||
redis.delAsync(reputationKey(videoInfo.userID));
|
||||
if (videoInfo.userID) redis.delAsync(reputationKey(videoInfo.userID));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const QueryCacher = {
|
||||
get,
|
||||
clearVideoCache
|
||||
|
|
72
test/cases/postClearCache.ts
Normal file
72
test/cases/postClearCache.ts
Normal file
|
@ -0,0 +1,72 @@
|
|||
import fetch from 'node-fetch';
|
||||
import {Done, getbaseURL} from '../utils';
|
||||
import {db} from '../../src/databases/databases';
|
||||
import {getHash} from '../../src/utils/getHash';
|
||||
|
||||
describe('postClearCache', () => {
|
||||
before(async () => {
|
||||
await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES ('` + getHash("clearing-vip") + "')");
|
||||
let startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES';
|
||||
await db.prepare("run", startOfQuery + "('clear-test', 0, 1, 2, 'clear-uuid', 'testman', 0, 50, 'sponsor', 0, '" + getHash('clear-test', 1) + "')");
|
||||
});
|
||||
|
||||
it('Should be able to clear cache for existing video', (done: Done) => {
|
||||
fetch(getbaseURL()
|
||||
+ "/api/clearCache?userID=clearing-vip&videoID=clear-test", {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(res => {
|
||||
if (res.status === 200) done();
|
||||
else done("Status code was " + res.status);
|
||||
})
|
||||
.catch(err => done(err));
|
||||
});
|
||||
|
||||
it('Should be able to clear cache for nonexistent video', (done: Done) => {
|
||||
fetch(getbaseURL()
|
||||
+ "/api/clearCache?userID=clearing-vip&videoID=dne-video", {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(res => {
|
||||
if (res.status === 200) done();
|
||||
else done("Status code was " + res.status);
|
||||
})
|
||||
.catch(err => done(err));
|
||||
});
|
||||
|
||||
it('Should get 403 as non-vip', (done: Done) => {
|
||||
fetch(getbaseURL()
|
||||
+ "/api/clearCache?userID=regular-user&videoID=clear-tes", {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(async res => {
|
||||
if (res.status !== 403) done('non 403 (' + res.status + ')');
|
||||
else done(); // pass
|
||||
})
|
||||
.catch(err => done(err));
|
||||
});
|
||||
|
||||
it('Should give 400 with missing videoID', (done: Done) => {
|
||||
fetch(getbaseURL()
|
||||
+ "/api/clearCache?userID=clearing-vip", {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(async res => {
|
||||
if (res.status !== 400) done('non 400 (' + res.status + ')');
|
||||
else done(); // pass
|
||||
})
|
||||
.catch(err => done(err));
|
||||
});
|
||||
|
||||
it('Should give 400 with missing userID', (done: Done) => {
|
||||
fetch(getbaseURL()
|
||||
+ "/api/clearCache?userID=clearing-vip", {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(async res => {
|
||||
if (res.status !== 400) done('non 400 (' + res.status + ')');
|
||||
else done(); // pass
|
||||
})
|
||||
.catch(err => done(err));
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue