Skip to content

Commit 22f3b33

Browse files
committed
Added file preview checker
1 parent 00dfc85 commit 22f3b33

File tree

4 files changed

+63
-12
lines changed

4 files changed

+63
-12
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nexus-bot-typescript",
3-
"version": "3.7.10",
3+
"version": "3.8.0",
44
"description": "A Discord bot for Nexus Mods, written in TypeScript",
55
"main": "dist/app.js",
66
"scripts": {

src/api/automod.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import query from './dbConnect';
22
import { QueryResult } from 'pg';
3-
import { IAutomodRule } from "../types/util";
3+
import { IAutomodRule, IBadFileRule } from "../types/util";
44

55
async function getAutomodRules(): Promise<IAutomodRule[]> {
66
return new Promise((resolve, reject) => {
@@ -32,4 +32,24 @@ async function deleteAutomodRule(id: number): Promise<void> {
3232
})
3333
}
3434

35-
export { getAutomodRules, createAutomodRule, deleteAutomodRule };
35+
async function getBadFiles(): Promise<IBadFileRule[]> {
36+
return new Promise((resolve, reject) => {
37+
query('SELECT * FROM automod_badfiles ORDER BY id ASC', [],
38+
(error: Error, results?: QueryResult) => {
39+
if (error) reject(error);
40+
resolve(results?.rows || []);
41+
});
42+
});
43+
}
44+
45+
async function addBadFile(type: 'low' | 'high', func: string, test: string, flagMessage: string) {
46+
return new Promise((resolve, reject) => {
47+
query('INSERT INTO automod_badfiles (type, test, "flagMessage", "funcName") VALUES ($1, $2, $3, $4) RETURNING id', [type, test.toLowerCase(), flagMessage, func],
48+
(error, results?: QueryResult) => {
49+
if (error) reject(error);
50+
resolve(results?.rows[0].id)
51+
})
52+
})
53+
}
54+
55+
export { getAutomodRules, createAutomodRule, deleteAutomodRule, getBadFiles, addBadFile };

src/feeds/AutoModManager.ts

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { APIEmbed, EmbedBuilder, flatten, RESTPostAPIWebhookWithTokenJSONBody } from "discord.js";
2-
import { getAutomodRules } from "../api/automod";
1+
import { APIEmbed, EmbedBuilder, RESTPostAPIWebhookWithTokenJSONBody } from "discord.js";
2+
import { getAutomodRules, getBadFiles } from "../api/automod";
33
import { ISlackMessage, PublishToDiscord, PublishToSlack } from "../api/moderationWebhooks";
44
import { IMod } from "../api/queries/v2";
55
import { IModResults } from "../api/queries/v2-latestmods";
66
import { getUserByNexusModsId } from "../api/users";
77
import { logMessage } from "../api/util";
88
import { ClientExt } from "../types/DiscordTypes";
9-
import { IAutomodRule } from "../types/util";
9+
import { IAutomodRule, IBadFileRule } from "../types/util";
1010
import { tall } from 'tall';
1111
import { DiscordBotUser, DummyNexusModsUser } from "../api/DiscordBotUser";
1212
import axios, { AxiosResponse } from "axios";
@@ -21,10 +21,13 @@ interface IModWithFlags {
2121
}
2222
}
2323

24+
25+
2426
export class AutoModManager {
2527
private static instance: AutoModManager;
2628

2729
private AutoModRules: IAutomodRule[] = [];
30+
private BadFiles: IBadFileRule[] = [];
2831
private client: ClientExt;
2932
private updateTimer: NodeJS.Timeout;
3033
private lastCheck: Date = new Date(new Date().valueOf() - (60000 * 10))
@@ -71,7 +74,8 @@ export class AutoModManager {
7174

7275
private async getRules() {
7376
try {
74-
this.AutoModRules = await getAutomodRules()
77+
this.AutoModRules = await getAutomodRules();
78+
this.BadFiles = await getBadFiles();
7579
}
7680
catch(err) {
7781
logMessage("Error getting automod rules", err, true)
@@ -105,7 +109,7 @@ export class AutoModManager {
105109

106110
let results: IModWithFlags[] = []
107111
for (const mod of modsToCheck) {
108-
results.push(await analyseMod(mod, this.AutoModRules, user))
112+
results.push(await analyseMod(mod, this.AutoModRules, this.BadFiles, user))
109113
}
110114
this.addToLastReports(results);
111115
// const concerns = results.filter(m => (m.flags.high.length) !== 0);
@@ -139,7 +143,7 @@ export class AutoModManager {
139143
const mod = modInfo[0];
140144
if (!mod) throw new Error('Mod not found')
141145
logMessage('Checking specific mod', { name: mod.name, game: mod.game.name });
142-
const analysis = await analyseMod(mod, this.AutoModRules, user);
146+
const analysis = await analyseMod(mod, this.AutoModRules, this.BadFiles, user);
143147
if (analysis.flags.high.length) {
144148
await PublishToDiscord(flagsToDiscordEmbeds([analysis]))
145149
await PublishToSlack(flagsToSlackMessage([analysis]))
@@ -252,7 +256,7 @@ function flagsToDiscordEmbeds(data: IModWithFlags[]): RESTPostAPIWebhookWithToke
252256
}
253257
}
254258

255-
async function analyseMod(mod: Partial<IMod>, rules: IAutomodRule[], user: DiscordBotUser): Promise<IModWithFlags> {
259+
async function analyseMod(mod: Partial<IMod>, rules: IAutomodRule[], badFiles: IBadFileRule[], user: DiscordBotUser): Promise<IModWithFlags> {
256260
let flags: {high: string[], low: string[]} = { high: [], low: [] };
257261
const now = new Date()
258262
const anHourAgo = new Date(now.valueOf() - (60000 * 60))
@@ -269,7 +273,7 @@ async function analyseMod(mod: Partial<IMod>, rules: IAutomodRule[], user: Disco
269273
// Check the content preview for first mod uploads
270274
if (mod.uploader!.modCount <= 1) {
271275
try {
272-
const previewCheck = await checkFilePreview(mod, user)
276+
const previewCheck = await checkFilePreview(mod, user, badFiles)
273277
if (previewCheck.flags.high.length) flags.high.push(...previewCheck.flags.high)
274278
if (previewCheck.flags.low.length) flags.low.push(...previewCheck.flags.low)
275279
}
@@ -356,7 +360,7 @@ const nonPlayableExtensions: string[] = [
356360
"rtf", "tex", "docx", "odt", "pdf", "url"
357361
];
358362

359-
async function checkFilePreview(mod: Partial<IMod>, user: DiscordBotUser): Promise<IModWithFlags> {
363+
async function checkFilePreview(mod: Partial<IMod>, user: DiscordBotUser, badFiles: IBadFileRule[]): Promise<IModWithFlags> {
360364
const flags: { high: string[], low: string[] } = { high: [], low: [] };
361365
const modFiles = await user.NexusMods.API.v1.ModFiles(mod.game!.domainName!, mod.modId!);
362366
const latestFile = modFiles.files.sort((a, b) => a.uploaded_timestamp > b.uploaded_timestamp ? 1 : -1)[0];
@@ -375,6 +379,11 @@ async function checkFilePreview(mod: Partial<IMod>, user: DiscordBotUser): Promi
375379
else {
376380
const allFiles: string[] = flattenDirectory(request.data);
377381

382+
// Check known bad files
383+
const fileFlags = checkKnownBadFiles(allFiles, badFiles);
384+
if (fileFlags.high) flags.high.push(...fileFlags.high)
385+
if (fileFlags.low) flags.low.push(...fileFlags.low)
386+
378387
// Check if it's exclusively non-playable files
379388
const playableFiles = allFiles.filter(file => {
380389
const extension: string | undefined = file.split('.').pop()?.toLowerCase();
@@ -406,3 +415,17 @@ function flattenDirectory(input: IPreviewDirectory): string[] {
406415
}
407416
return files;
408417
}
418+
419+
function checkKnownBadFiles(flattenedFiles: string[], badFiles: IBadFileRule[]): { low: string[], high: string[] } {
420+
const flags = { low: new Array<string>(), high: new Array<string>() };
421+
422+
for (const badFileRule of badFiles) {
423+
let result = null;
424+
if (badFileRule.funcName === 'match') result = flattenedFiles.find(f => f.toLowerCase().match(badFileRule.test) !== null);
425+
else result = flattenedFiles.find(f => f.toLowerCase()[badFileRule.funcName](badFileRule.test))
426+
// If we found something!
427+
if (result) flags[badFileRule.type].push(`${badFileRule.flagMessage} -- Rule: ${badFileRule.test}, Func: ${badFileRule.funcName}`);
428+
}
429+
430+
return flags;
431+
}

src/types/util.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,12 @@ export interface IAutomodRule {
183183
filter: string;
184184
added: Date;
185185
reason: string;
186+
}
187+
188+
export interface IBadFileRule {
189+
id: number;
190+
type: 'low' | 'high';
191+
funcName: 'includes' | 'startsWith' | 'endsWith' | 'match';
192+
test: string;
193+
flagMessage: string;
186194
}

0 commit comments

Comments
 (0)