mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-05-11 18:36:17 +02:00
Add new user limit per 5 mins
This commit is contained in:
parent
9b55dc5d4d
commit
74f6224091
3 changed files with 43 additions and 25 deletions
|
@ -2,7 +2,7 @@ import { Request, Response } from "express";
|
|||
import { Logger } from "../utils/logger";
|
||||
import { isUserVIP } from "../utils/isUserVIP";
|
||||
import { isUserTempVIP } from "../utils/isUserTempVIP";
|
||||
import { getMaxResThumbnail, YouTubeAPI } from "../utils/youtubeApi";
|
||||
import { getMaxResThumbnail } from "../utils/youtubeApi";
|
||||
import { db, privateDB } from "../databases/databases";
|
||||
import { dispatchEvent, getVoteAuthor, getVoteAuthorRaw } from "../utils/webhookUtils";
|
||||
import { getFormattedTime } from "../utils/getFormattedTime";
|
||||
|
@ -17,7 +17,6 @@ import { getVideoDetails, videoDetails } from "../utils/getVideoDetails";
|
|||
import { deleteLockCategories } from "./deleteLockCategories";
|
||||
import { acquireLock } from "../utils/redisLock";
|
||||
import { checkBanStatus } from "../utils/checkBan";
|
||||
import { canVote } from "../utils/permissions";
|
||||
|
||||
const voteTypes = {
|
||||
normal: 0,
|
||||
|
@ -343,14 +342,6 @@ export async function vote(ip: IPAddress, UUID: SegmentUUID, paramUserID: UserID
|
|||
const nonAnonUserID = await getHashCache(paramUserID);
|
||||
const userID = await getHashCache(paramUserID + UUID);
|
||||
|
||||
const permission = await canVote(nonAnonUserID);
|
||||
if (!permission.canSubmit) {
|
||||
return {
|
||||
status: 403,
|
||||
message: permission.reason
|
||||
};
|
||||
}
|
||||
|
||||
//hash the ip 5000 times so no one can get it from the database
|
||||
const hashedIP: HashedIP = await getHashCache((ip + config.globalSalt) as IPAddress);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { Feature, HashedUserID } from "../types/user.model";
|
|||
import { hasFeature } from "./features";
|
||||
import { isUserVIP } from "./isUserVIP";
|
||||
import { oneOf } from "./promise";
|
||||
import redis from "./redis";
|
||||
import { getReputation } from "./reputation";
|
||||
import { getServerConfig } from "./serverConfig";
|
||||
|
||||
|
@ -20,7 +21,8 @@ async function lowDownvotes(userID: HashedUserID): Promise<boolean> {
|
|||
return result.submissionCount > 5 && result.downvotedSubmissions / result.submissionCount < 0.10;
|
||||
}
|
||||
|
||||
async function oldSubmitter(userID: HashedUserID): Promise<boolean> {
|
||||
const fiveMinutes = 5 * 60 * 1000;
|
||||
async function oldSubmitterOrAllowed(userID: HashedUserID): Promise<boolean> {
|
||||
const submitterThreshold = await getServerConfig("old-submitter-block-date");
|
||||
if (!submitterThreshold) {
|
||||
return true;
|
||||
|
@ -29,10 +31,22 @@ async function oldSubmitter(userID: HashedUserID): Promise<boolean> {
|
|||
const result = await db.prepare("get", `SELECT count(*) as "submissionCount" FROM "sponsorTimes" WHERE "userID" = ? AND "timeSubmitted" < ?`
|
||||
, [userID, parseInt(submitterThreshold)], { useReplica: true });
|
||||
|
||||
return result.submissionCount >= 1;
|
||||
const isOldSubmitter = result.submissionCount >= 1;
|
||||
if (!isOldSubmitter) {
|
||||
await redis.zRemRangeByScore("submitters", "-inf", Date.now() - fiveMinutes);
|
||||
const last5MinUsers = await redis.zCard("submitters");
|
||||
const maxUsers = await getServerConfig("max-users-per-minute");
|
||||
|
||||
if (maxUsers && last5MinUsers < parseInt(maxUsers)) {
|
||||
await redis.zAdd("submitters", { score: Date.now(), value: userID });
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return isOldSubmitter;
|
||||
}
|
||||
|
||||
async function oldDeArrowSubmitter(userID: HashedUserID): Promise<boolean> {
|
||||
async function oldDeArrowSubmitterOrAllowed(userID: HashedUserID): Promise<boolean> {
|
||||
const submitterThreshold = await getServerConfig("old-submitter-block-date");
|
||||
if (!submitterThreshold) {
|
||||
return true;
|
||||
|
@ -41,7 +55,19 @@ async function oldDeArrowSubmitter(userID: HashedUserID): Promise<boolean> {
|
|||
const result = await db.prepare("get", `SELECT count(*) as "submissionCount" FROM "titles" WHERE "userID" = ? AND "timeSubmitted" < 1743827196000`
|
||||
, [userID, parseInt(submitterThreshold)], { useReplica: true });
|
||||
|
||||
return result.submissionCount >= 1;
|
||||
const isOldSubmitter = result.submissionCount >= 1;
|
||||
if (!isOldSubmitter) {
|
||||
await redis.zRemRangeByScore("submittersDeArrow", "-inf", Date.now() - fiveMinutes);
|
||||
const last5MinUsers = await redis.zCard("submittersDeArrow");
|
||||
const maxUsers = await getServerConfig("max-users-per-minute-dearrow");
|
||||
|
||||
if (maxUsers && last5MinUsers < parseInt(maxUsers)) {
|
||||
await redis.zAdd("submittersDeArrow", { score: Date.now(), value: userID });
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return isOldSubmitter;
|
||||
}
|
||||
|
||||
export async function canSubmit(userID: HashedUserID, category: Category): Promise<CanSubmitResult> {
|
||||
|
@ -66,16 +92,7 @@ export async function canSubmit(userID: HashedUserID, category: Category): Promi
|
|||
export async function canSubmitGlobal(userID: HashedUserID): Promise<CanSubmitResult> {
|
||||
return {
|
||||
canSubmit: await oneOf([isUserVIP(userID),
|
||||
oldSubmitter(userID)
|
||||
]),
|
||||
reason: "We are currently experiencing a mass spam attack, we are restricting submissions for now"
|
||||
};
|
||||
}
|
||||
|
||||
export async function canVote(userID: HashedUserID): Promise<CanSubmitResult> {
|
||||
return {
|
||||
canSubmit: await oneOf([isUserVIP(userID),
|
||||
oldSubmitter(userID)
|
||||
oldSubmitterOrAllowed(userID)
|
||||
]),
|
||||
reason: "We are currently experiencing a mass spam attack, we are restricting submissions for now"
|
||||
};
|
||||
|
@ -84,7 +101,7 @@ export async function canVote(userID: HashedUserID): Promise<CanSubmitResult> {
|
|||
export async function canSubmitDeArrow(userID: HashedUserID): Promise<CanSubmitResult> {
|
||||
return {
|
||||
canSubmit: await oneOf([isUserVIP(userID),
|
||||
oldDeArrowSubmitter(userID)
|
||||
oldDeArrowSubmitterOrAllowed(userID)
|
||||
]),
|
||||
reason: "We are currently experiencing a mass spam attack, we are restricting submissions for now"
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ import { Postgres } from "../databases/Postgres";
|
|||
import { compress, uncompress } from "lz4-napi";
|
||||
import { LRUCache } from "lru-cache";
|
||||
import { shouldClientCacheKey } from "./redisKeys";
|
||||
import { ZMember } from "@redis/client/dist/lib/commands/generic-transformers";
|
||||
|
||||
export interface RedisStats {
|
||||
activeRequests: number;
|
||||
|
@ -35,6 +36,9 @@ interface RedisSB {
|
|||
sendCommand(args: RedisCommandArguments, options?: RedisClientOptions): Promise<RedisReply>;
|
||||
ttl(key: RedisCommandArgument): Promise<number>;
|
||||
quit(): Promise<void>;
|
||||
zRemRangeByScore(key: string, min: number | RedisCommandArgument, max: number | RedisCommandArgument): Promise<number>;
|
||||
zAdd(key: string, members: ZMember | ZMember[]): Promise<number>;
|
||||
zCard(key: string): Promise<number>;
|
||||
}
|
||||
|
||||
let exportClient: RedisSB = {
|
||||
|
@ -49,6 +53,9 @@ let exportClient: RedisSB = {
|
|||
sendCommand: () => Promise.resolve(null),
|
||||
quit: () => Promise.resolve(null),
|
||||
ttl: () => Promise.resolve(null),
|
||||
zRemRangeByScore: () => Promise.resolve(null),
|
||||
zAdd: () => Promise.resolve(null),
|
||||
zCard: () => Promise.resolve(null)
|
||||
};
|
||||
|
||||
let lastClientFail = 0;
|
||||
|
@ -308,6 +315,9 @@ if (config.redis?.enabled) {
|
|||
.then((reply) => resolve(reply))
|
||||
.catch((err) => reject(err))
|
||||
);
|
||||
exportClient.zRemRangeByScore = client.zRemRangeByScore.bind(client);
|
||||
exportClient.zAdd = client.zAdd.bind(client);
|
||||
exportClient.zCard = client.zCard.bind(client);
|
||||
/* istanbul ignore next */
|
||||
client.on("error", function(error) {
|
||||
lastClientFail = Date.now();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue