Add malicious vote type for chapters

This commit is contained in:
Ajay 2022-07-04 16:18:58 -04:00
parent cc953884d9
commit f9de547b95
7 changed files with 70 additions and 15 deletions

View file

@ -209,6 +209,7 @@
| userID | TEXT | not null |
| hashedIP | TEXT | not null |
| type | INTEGER | not null |
| originalVoteType | INTEGER | not null | # Since type was reused to also specify the number of votes removed when less than 0, this is being used for the actual type
| index | field |
| -- | :--: |

View file

@ -0,0 +1,9 @@
BEGIN TRANSACTION;
-- Add primary keys
ALTER TABLE "votes" ADD "originalType" INTEGER NOT NULL default -1;
UPDATE "config" SET value = 10 WHERE key = 'version';
COMMIT;

View file

@ -42,6 +42,7 @@ addDefaults(config, {
discordNeuralBlockRejectWebhookURL: null,
discordFailedReportChannelWebhookURL: null,
discordReportChannelWebhookURL: null,
discordMaliciousReportWebhookURL: null,
getTopUsersCacheTimeMinutes: 240,
globalSalt: null,
mode: "",

View file

@ -11,7 +11,7 @@ import { getIP } from "../utils/getIP";
import { getHashCache } from "../utils/getHashCache";
import { config } from "../config";
import { UserID } from "../types/user.model";
import { DBSegment, Category, HashedIP, IPAddress, SegmentUUID, Service, VideoID, VideoIDHash, VideoDuration, ActionType } from "../types/segments.model";
import { DBSegment, Category, HashedIP, IPAddress, SegmentUUID, Service, VideoID, VideoIDHash, VideoDuration, ActionType, VoteType } from "../types/segments.model";
import { QueryCacher } from "../utils/queryCacher";
import axios from "axios";
@ -36,6 +36,7 @@ interface FinalResponse {
interface VoteData {
UUID: string;
nonAnonUserID: string;
originalType: VoteType;
voteTypeEnum: number;
isTempVIP: boolean;
isVIP: boolean;
@ -112,7 +113,9 @@ async function sendWebhooks(voteData: VoteData) {
if (submissionInfoRow !== undefined && userSubmissionCountRow != undefined) {
let webhookURL: string = null;
if (voteData.voteTypeEnum === voteTypes.normal) {
if (voteData.originalType === VoteType.Malicious) {
webhookURL = config.discordMaliciousReportWebhookURL;
} else if (voteData.voteTypeEnum === voteTypes.normal) {
switch (voteData.finalResponse.webhookType) {
case VoteWebhookType.Normal:
webhookURL = config.discordReportChannelWebhookURL;
@ -329,6 +332,8 @@ export async function vote(ip: IPAddress, UUID: SegmentUUID, paramUserID: UserID
return { status: 200 };
}
const originalType = type;
//hash the userID
const nonAnonUserID = await getHashCache(paramUserID);
const userID = await getHashCache(paramUserID + UUID);
@ -421,13 +426,13 @@ export async function vote(ip: IPAddress, UUID: SegmentUUID, paramUserID: UserID
let incrementAmount = 0;
let oldIncrementAmount = 0;
if (type == 1) {
if (type == VoteType.Upvote) {
//upvote
incrementAmount = 1;
} else if (type == 0) {
} else if (type === VoteType.Downvote || type === VoteType.Malicious) {
//downvote
incrementAmount = -1;
} else if (type == 20) {
} else if (type == VoteType.Undo) {
//undo/cancel vote
incrementAmount = 0;
} else {
@ -435,17 +440,13 @@ export async function vote(ip: IPAddress, UUID: SegmentUUID, paramUserID: UserID
return { status: 400 };
}
if (votesRow) {
if (votesRow.type === 1) {
//upvote
if (votesRow.type === VoteType.Upvote) {
oldIncrementAmount = 1;
} else if (votesRow.type === 0) {
//downvote
} else if (votesRow.type === VoteType.Downvote) {
oldIncrementAmount = -1;
} else if (votesRow.type === 2) {
//extra downvote
} else if (votesRow.type === VoteType.ExtraDownvote) {
oldIncrementAmount = -4;
} else if (votesRow.type === 20) {
//undo/cancel vote
} else if (votesRow.type === VoteType.Undo) {
oldIncrementAmount = 0;
} else if (votesRow.type < 0) {
//vip downvote
@ -466,8 +467,14 @@ export async function vote(ip: IPAddress, UUID: SegmentUUID, paramUserID: UserID
type = incrementAmount;
}
if (type === VoteType.Malicious) {
incrementAmount = -Math.min(segmentInfo.votes + 2 - oldIncrementAmount, 5);
type = incrementAmount;
}
// Only change the database if they have made a submission before and haven't voted recently
const userAbleToVote = (!(isOwnSubmission && incrementAmount > 0 && oldIncrementAmount >= 0)
&& !(originalType === VoteType.Malicious && segmentInfo.actionType !== ActionType.Chapter)
&& !finalResponse.blockVote
&& finalResponse.finalStatus === 200
&& (await db.prepare("get", `SELECT "userID" FROM "sponsorTimes" WHERE "userID" = ?`, [nonAnonUserID])) !== undefined
@ -480,9 +487,9 @@ export async function vote(ip: IPAddress, UUID: SegmentUUID, paramUserID: UserID
if (ableToVote) {
//update the votes table
if (votesRow) {
await privateDB.prepare("run", `UPDATE "votes" SET "type" = ? WHERE "userID" = ? AND "UUID" = ?`, [type, userID, UUID]);
await privateDB.prepare("run", `UPDATE "votes" SET "type" = ?, "originalType" = ? WHERE "userID" = ? AND "UUID" = ?`, [type, originalType, userID, UUID]);
} else {
await privateDB.prepare("run", `INSERT INTO "votes" VALUES(?, ?, ?, ?, ?)`, [UUID, userID, hashedIP, type, nonAnonUserID]);
await privateDB.prepare("run", `INSERT INTO "votes" VALUES(?, ?, ?, ?, ?, ?)`, [UUID, userID, hashedIP, type, nonAnonUserID, originalType]);
}
// update the vote count on this sponsorTime
@ -510,6 +517,7 @@ export async function vote(ip: IPAddress, UUID: SegmentUUID, paramUserID: UserID
sendWebhooks({
UUID,
nonAnonUserID,
originalType,
voteTypeEnum,
isTempVIP,
isVIP,

View file

@ -24,6 +24,7 @@ export interface SBSConfig {
discordFailedReportChannelWebhookURL?: string;
discordFirstTimeSubmissionsWebhookURL?: string;
discordCompletelyIncorrectReportWebhookURL?: string;
discordMaliciousReportWebhookURL?: string;
neuralBlockURL?: string;
discordNeuralBlockRejectWebhookURL?: string;
userCounterURL?: string;

View file

@ -120,3 +120,12 @@ export enum SortableFields {
votes = "votes",
views = "views",
}
export enum VoteType {
Downvote = 0,
Upvote = 1,
ExtraDownvote = 2,
Undo = 20,
Malicious = 30
}

View file

@ -67,6 +67,8 @@ describe("voteOnSponsorTime", () => {
await db.prepare("run", insertSponsorTimeQuery, ["duration-changed", 1, 12, 0, 0, "duration-changed-uuid-3", "testman", 20, 0, "sponsor", "skip", 0, 0]);
// add videoDuration to duration-changed-uuid-2
await db.prepare("run", `UPDATE "sponsorTimes" SET "videoDuration" = 150 WHERE "UUID" = 'duration-changed-uuid-2'`);
await db.prepare("run", insertSponsorTimeQuery, ["chapter-video", 1, 10, 0, 0, "chapter-uuid-1", "testman", 0, 0, "chapter", "chapter", 0, 0]);
await db.prepare("run", insertSponsorTimeQuery, ["chapter-video", 1, 10, 0, 0, "non-chapter-uuid-2", "testman", 0, 0, "sponsor", "skip", 0, 0]);
const insertWarningQuery = 'INSERT INTO "warnings" ("userID", "issueTime", "issuerUserID", "enabled") VALUES(?, ?, ?, ?)';
await db.prepare("run", insertWarningQuery, [warnUser01Hash, now, warnVip01Hash, 1]);
@ -223,6 +225,30 @@ describe("voteOnSponsorTime", () => {
.catch(err => done(err));
});
it("should be able to completely downvote chapter using malicious", (done) => {
const UUID = "chapter-uuid-1";
postVote(randomID2, UUID, 30)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await getSegmentVotes(UUID);
assert.strictEqual(row.votes, -2);
done();
})
.catch(err => done(err));
});
it("should not be able to completely downvote non-chapter using malicious", (done) => {
const UUID = "non-chapter-uuid-2";
postVote(randomID2, UUID, 30)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await getSegmentVotes(UUID);
assert.strictEqual(row.votes, 0);
done();
})
.catch(err => done(err));
});
it("Should be able to vote for a category and it should add your vote to the database", (done) => {
const UUID = "vote-uuid-4";
postVoteCategory(randomID2, UUID, "intro")