From 46805f48300b700b8cef23edfba0f791ed8aaeea Mon Sep 17 00:00:00 2001 From: Ajay Date: Thu, 28 Jul 2022 12:22:49 -0400 Subject: [PATCH] Require permission for filler submissions --- src/config.ts | 1 + src/routes/addFeature.ts | 6 ++++-- src/routes/getUserInfo.ts | 17 +++++++++++++---- src/routes/postSkipSegments.ts | 10 ++++++---- src/types/config.model.ts | 1 + src/types/segments.model.ts | 2 +- src/types/user.model.ts | 3 ++- src/utils/permissions.ts | 30 ++++++++++++++++++++++++++---- 8 files changed, 54 insertions(+), 16 deletions(-) diff --git a/src/config.ts b/src/config.ts index ee9e26f..c680c23 100644 --- a/src/config.ts +++ b/src/config.ts @@ -44,6 +44,7 @@ addDefaults(config, { discordReportChannelWebhookURL: null, discordMaliciousReportWebhookURL: null, minReputationToSubmitChapter: 0, + minReputationToSubmitFiller: 0, getTopUsersCacheTimeMinutes: 240, globalSalt: null, mode: "", diff --git a/src/routes/addFeature.ts b/src/routes/addFeature.ts index 8319015..d7aeaff 100644 --- a/src/routes/addFeature.ts +++ b/src/routes/addFeature.ts @@ -18,10 +18,12 @@ interface AddFeatureRequest extends Request { const allowedFeatures = { vip: [ - Feature.ChapterSubmitter + Feature.ChapterSubmitter, + Feature.FillerSubmitter ], admin: [ - Feature.ChapterSubmitter + Feature.ChapterSubmitter, + Feature.FillerSubmitter ] } diff --git a/src/routes/getUserInfo.ts b/src/routes/getUserInfo.ts index 8f31a01..f9bf492 100644 --- a/src/routes/getUserInfo.ts +++ b/src/routes/getUserInfo.ts @@ -5,9 +5,9 @@ import { Request, Response } from "express"; import { Logger } from "../utils/logger"; import { HashedUserID, UserID } from "../types/user.model"; import { getReputation } from "../utils/reputation"; -import { SegmentUUID } from "../types/segments.model"; +import { Category, SegmentUUID } from "../types/segments.model"; import { config } from "../config"; -import { canSubmitChapter } from "../utils/permissions"; +import { canSubmit } from "../utils/permissions"; const maxRewardTime = config.maxRewardTimePerSegmentInSeconds; async function dbGetSubmittedSegmentSummary(userID: HashedUserID): Promise<{ minutesSaved: number, segmentCount: number }> { @@ -106,6 +106,15 @@ async function dbGetBanned(userID: HashedUserID): Promise { } } +async function getPermissions(userID: HashedUserID): Promise> { + const result: Record = {}; + for (const category of config.categoryList) { + result[category] = (await canSubmit(userID, category as Category)).canSubmit; + } + + return result; +} + type cases = Record const executeIfFunction = (f: any) => @@ -130,7 +139,7 @@ const dbGetValue = (userID: HashedUserID, property: string): Promise getReputation(userID), vip: () => isUserVIP(userID), lastSegmentID: () => dbGetLastSegmentForUser(userID), - canSubmitChapter: () => canSubmitChapter(userID) + permissions: () => getPermissions(userID) })("")(property); }; @@ -140,7 +149,7 @@ async function getUserInfo(req: Request, res: Response): Promise { const defaultProperties: string[] = ["userID", "userName", "minutesSaved", "segmentCount", "ignoredSegmentCount", "viewCount", "ignoredViewCount", "warnings", "warningReason", "reputation", "vip", "lastSegmentID"]; - const allProperties: string[] = [...defaultProperties, "banned", "canSubmitChapter"]; + const allProperties: string[] = [...defaultProperties, "banned", "permissions"]; let paramValues: string[] = req.query.values ? JSON.parse(req.query.values as string) : req.query.value diff --git a/src/routes/postSkipSegments.ts b/src/routes/postSkipSegments.ts index 4ef2748..05edcd9 100644 --- a/src/routes/postSkipSegments.ts +++ b/src/routes/postSkipSegments.ts @@ -21,7 +21,7 @@ import { parseUserAgent } from "../utils/userAgent"; import { getService } from "../utils/getService"; import axios from "axios"; import { vote } from "./voteOnSponsorTime"; -import { canSubmitChapter } from "../utils/permissions"; +import { canSubmit } from "../utils/permissions"; type CheckResult = { pass: boolean, @@ -230,8 +230,10 @@ async function checkInvalidFields(videoID: VideoID, userID: UserID, hashedUserID invalidFields.push("segment description"); } - if (segmentPair.actionType === ActionType.Chapter && !(await canSubmitChapter(hashedUserID))) { - invalidFields.push("permission to submit chapters"); + const permission = await canSubmit(hashedUserID, segmentPair.category); + if (!permission.canSubmit) { + invalidFields.push(`permission to submit ${segmentPair.category}`); + errors.push(permission.reason); } } @@ -241,7 +243,7 @@ async function checkInvalidFields(videoID: VideoID, userID: UserID, hashedUserID const formattedErrors = errors.reduce((p, c, i) => p + (i !== 0 ? ". " : " ") + c, ""); return { pass: false, - errorMessage: `No valid ${formattedFields} field(s) provided.${formattedErrors}`, + errorMessage: `No valid ${formattedFields}.${formattedErrors}`, errorCode: 400 }; } diff --git a/src/types/config.model.ts b/src/types/config.model.ts index 9030e69..47b3108 100644 --- a/src/types/config.model.ts +++ b/src/types/config.model.ts @@ -28,6 +28,7 @@ export interface SBSConfig { neuralBlockURL?: string; discordNeuralBlockRejectWebhookURL?: string; minReputationToSubmitChapter: number; + minReputationToSubmitFiller: number; userCounterURL?: string; proxySubmission?: string; behindProxy: string | boolean; diff --git a/src/types/segments.model.ts b/src/types/segments.model.ts index 324d196..841bb99 100644 --- a/src/types/segments.model.ts +++ b/src/types/segments.model.ts @@ -5,7 +5,7 @@ import { HashedUserID, UserID } from "./user.model"; export type SegmentUUID = string & { __segmentUUIDBrand: unknown }; export type VideoID = string & { __videoIDBrand: unknown }; export type VideoDuration = number & { __videoDurationBrand: unknown }; -export type Category = ("sponsor" | "selfpromo" | "interaction" | "intro" | "outro" | "preview" | "music_offtopic" | "poi_highlight" | "chapter") & { __categoryBrand: unknown }; +export type Category = ("sponsor" | "selfpromo" | "interaction" | "intro" | "outro" | "preview" | "music_offtopic" | "filler" | "poi_highlight" | "chapter") & { __categoryBrand: unknown }; export type VideoIDHash = VideoID & HashedValue; export type IPAddress = string & { __ipAddressBrand: unknown }; export type HashedIP = IPAddress & HashedValue; diff --git a/src/types/user.model.ts b/src/types/user.model.ts index 355e8bb..c3009df 100644 --- a/src/types/user.model.ts +++ b/src/types/user.model.ts @@ -4,5 +4,6 @@ export type UserID = string & { __userIDBrand: unknown }; export type HashedUserID = UserID & HashedValue; export enum Feature { - ChapterSubmitter = 0 + ChapterSubmitter = 0, + FillerSubmitter = 1 } \ No newline at end of file diff --git a/src/utils/permissions.ts b/src/utils/permissions.ts index 4269ed0..2227cda 100644 --- a/src/utils/permissions.ts +++ b/src/utils/permissions.ts @@ -1,11 +1,33 @@ import { config } from "../config"; +import { Category } from "../types/segments.model"; import { Feature, HashedUserID } from "../types/user.model"; import { hasFeature } from "./features"; import { isUserVIP } from "./isUserVIP"; import { getReputation } from "./reputation"; -export async function canSubmitChapter(userID: HashedUserID): Promise { - return (await isUserVIP(userID)) - || (await getReputation(userID)) > config.minReputationToSubmitChapter - || (await hasFeature(userID, Feature.ChapterSubmitter)); +interface CanSubmitResult { + canSubmit: boolean; + reason?: string; +} + +export async function canSubmit(userID: HashedUserID, category: Category): Promise { + switch (category) { + case "chapter": + return { + canSubmit: (await isUserVIP(userID)) + || (await getReputation(userID)) > config.minReputationToSubmitChapter + || (await hasFeature(userID, Feature.ChapterSubmitter)) + }; + case "filler": + return { + canSubmit: (await isUserVIP(userID)) + || (await getReputation(userID)) > config.minReputationToSubmitFiller + || (await hasFeature(userID, Feature.FillerSubmitter)), + reason: "Someone is submitting over 180,000 spam filler submissions and refuses to stop even after talking with them, so we have to restrict it for now. You can request submission access on chat.sponsor.ajay.app, discord.gg/SponsorBlock or matrix.to/#/#sponsor:ajay.app" + }; + } + + return { + canSubmit: true + }; } \ No newline at end of file