Merge pull request #257 from mchangrh/vip-cache-clear

VIP endpoint for clearing cache of video
This commit is contained in:
Ajay Ramachandran
2021-06-18 19:01:08 -04:00
committed by GitHub
4 changed files with 133 additions and 3 deletions

View File

@@ -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));

View 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;
}
}

View File

@@ -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