Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion backend/src/RegExpRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ const isTimeoutError = (a): a is TimeoutError => {
};

export class RegExpTimeoutError extends Error {
constructor(message: string, public elapsedTimeMs: number) {
constructor(
message: string,
public elapsedTimeMs: number,
) {
super(message);
}
}
Expand Down
2 changes: 1 addition & 1 deletion backend/src/api/docs.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import express from "express";
import z from "zod/v4";
import { $ZodPipeDef } from "zod/v4/core";
import { availableGuildPlugins } from "../plugins/availablePlugins.js";
import { ZeppelinGuildPluginInfo } from "../types.js";
import { indentLines } from "../utils.js";
import { notFound } from "./responses.js";
import { $ZodPipeDef } from "zod/v4/core";

function isZodObject(schema: z.ZodType): schema is z.ZodObject<any> {
return schema.def.type === "object";
Expand Down
15 changes: 6 additions & 9 deletions backend/src/configValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,12 @@ export async function validateGuildConfig(config: any): Promise<string | null> {
}

const plugin = pluginNameToPlugin.get(pluginName)!;
const configManager = new PluginConfigManager(
pluginOptions,
{
configSchema: plugin.configSchema,
defaultOverrides: plugin.defaultOverrides ?? [],
levels: {},
customOverrideCriteriaFunctions: plugin.customOverrideCriteriaFunctions,
},
);
const configManager = new PluginConfigManager(pluginOptions, {
configSchema: plugin.configSchema,
defaultOverrides: plugin.defaultOverrides ?? [],
levels: {},
customOverrideCriteriaFunctions: plugin.customOverrideCriteriaFunctions,
});

try {
await configManager.init();
Expand Down
9 changes: 6 additions & 3 deletions backend/src/data/FishFish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,12 @@ async function getSessionToken(): Promise<string> {
}

const timeUntilExpiry = Date.now() - parseResult.data.expires * 1000;
setTimeout(() => {
sessionTokenPromise = null;
}, timeUntilExpiry - 1 * MINUTES); // Subtract a minute to ensure we refresh before expiry
setTimeout(
() => {
sessionTokenPromise = null;
},
timeUntilExpiry - 1 * MINUTES,
); // Subtract a minute to ensure we refresh before expiry

return parseResult.data.token;
})();
Expand Down
9 changes: 6 additions & 3 deletions backend/src/data/GuildLogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,12 @@ export class GuildLogs extends events.EventEmitter {
this.ignoredLogs.push({ type, ignoreId });

// Clear after expiry (15sec by default)
setTimeout(() => {
this.clearIgnoredLog(type, ignoreId);
}, timeout || 1000 * 15);
setTimeout(
() => {
this.clearIgnoredLog(type, ignoreId);
},
timeout || 1000 * 15,
);
}

isLogIgnored(type: keyof typeof LogType, ignoreId: any) {
Expand Down
34 changes: 18 additions & 16 deletions backend/src/exportSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,24 @@ const basePluginOverrideCriteriaSchema = z.strictObject({
extra: z.any().optional(),
});

const pluginOverrideCriteriaSchema = basePluginOverrideCriteriaSchema.extend({
get zzz_dummy_property_do_not_use() {
return pluginOverrideCriteriaSchema.optional();
},
get all() {
return z.array(pluginOverrideCriteriaSchema).optional();
},
get any() {
return z.array(pluginOverrideCriteriaSchema).optional();
},
get not() {
return pluginOverrideCriteriaSchema.optional();
},
}).meta({
id: "overrideCriteria",
});
const pluginOverrideCriteriaSchema = basePluginOverrideCriteriaSchema
.extend({
get zzz_dummy_property_do_not_use() {
return pluginOverrideCriteriaSchema.optional();
},
get all() {
return z.array(pluginOverrideCriteriaSchema).optional();
},
get any() {
return z.array(pluginOverrideCriteriaSchema).optional();
},
get not() {
return pluginOverrideCriteriaSchema.optional();
},
})
.meta({
id: "overrideCriteria",
});

const outputPath = process.argv[2];
if (!outputPath) {
Expand Down
21 changes: 12 additions & 9 deletions backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,14 +199,17 @@ setInterval(() => {
avgCount++;
lastCheck = now;
}, 500);
setInterval(() => {
const avgBlocking = avgTotal / (avgCount || 1);
// FIXME: Debug
// tslint:disable-next-line:no-console
console.log(`Average blocking in the last 5min: ${avgBlocking / avgTotal}ms`);
avgTotal = 0;
avgCount = 0;
}, 5 * 60 * 1000);
setInterval(
() => {
const avgBlocking = avgTotal / (avgCount || 1);
// FIXME: Debug
// tslint:disable-next-line:no-console
console.log(`Average blocking in the last 5min: ${avgBlocking / avgTotal}ms`);
avgTotal = 0;
avgCount = 0;
},
5 * 60 * 1000,
);

if (env.DEBUG) {
logger.info("NOTE: Bot started in DEBUG mode");
Expand Down Expand Up @@ -335,7 +338,7 @@ connect().then(async () => {

if (loaded.success_emoji || loaded.error_emoji) {
const deprecatedKeys = [] as string[];
const exampleConfig = `plugins:\n common:\n config:\n success_emoji: "👍"\n error_emoji: "👎"`;
// const exampleConfig = `plugins:\n common:\n config:\n success_emoji: "👍"\n error_emoji: "👎"`;

if (loaded.success_emoji) {
deprecatedKeys.push("success_emoji");
Expand Down
11 changes: 7 additions & 4 deletions backend/src/plugins/Automod/actions/changePerms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,13 @@ const permissionNames = keys(PermissionsBitField.Flags) as U.ListOf<keyof typeof
const legacyPermissionNames = keys(legacyPermMap) as U.ListOf<keyof typeof legacyPermMap>;
const allPermissionNames = [...permissionNames, ...legacyPermissionNames] as const;

const permissionTypeMap = allPermissionNames.reduce((map, permName) => {
map[permName] = z.boolean().nullable();
return map;
}, {} as Record<typeof allPermissionNames[number], z.ZodNullable<z.ZodBoolean>>);
const permissionTypeMap = allPermissionNames.reduce(
(map, permName) => {
map[permName] = z.boolean().nullable();
return map;
},
{} as Record<(typeof allPermissionNames)[number], z.ZodNullable<z.ZodBoolean>>,
);
const zPermissionsMap = z.strictObject(permissionTypeMap);

export const ChangePermsAction = automodAction({
Expand Down
2 changes: 1 addition & 1 deletion backend/src/plugins/Automod/commands/DebugAutomodCmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { getOrFetchUser } from "../../../utils/getOrFetchUser.js";
export const DebugAutomodCmd = guildPluginMessageCommand<AutomodPluginType>()({
trigger: "debug_automod",
permission: "can_debug_automod",

signature: {
messageId: ct.string(),
},
Expand Down
8 changes: 6 additions & 2 deletions backend/src/plugins/Automod/functions/runAutomod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ interface RuleResultOutcomeSuccess {

interface RuleResultOutcomeFailure {
success: false;
reason: typeof ruleFailReason[keyof typeof ruleFailReason];
reason: (typeof ruleFailReason)[keyof typeof ruleFailReason];
}

type RuleResultOutcome = RuleResultOutcomeSuccess | RuleResultOutcomeFailure;
Expand All @@ -48,7 +48,11 @@ interface AutomodRunResult {
rulesChecked: RuleResult[];
}

export async function runAutomod(pluginData: GuildPluginData<AutomodPluginType>, context: AutomodContext, dryRun: boolean = false): Promise<AutomodRunResult> {
export async function runAutomod(
pluginData: GuildPluginData<AutomodPluginType>,
context: AutomodContext,
dryRun = false,
): Promise<AutomodRunResult> {
const userId = context.user?.id || context.member?.id || context.message?.user_id;
const user = context.user || (userId && pluginData.client.users!.cache.get(userId as Snowflake));
const member = context.member || (userId && pluginData.guild.members.cache.get(userId as Snowflake)) || null;
Expand Down
12 changes: 10 additions & 2 deletions backend/src/plugins/Automod/triggers/matchInvites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,16 @@ const configSchema = z.strictObject({
exclude_guilds: z.array(zSnowflake).max(255).optional(),
include_invite_codes: z.array(z.string().max(32)).max(255).optional(),
exclude_invite_codes: z.array(z.string().max(32)).max(255).optional(),
include_custom_invite_codes: z.array(z.string().max(32)).max(255).transform(arr => arr.map(str => str.toLowerCase())).optional(),
exclude_custom_invite_codes: z.array(z.string().max(32)).max(255).transform(arr => arr.map(str => str.toLowerCase())).optional(),
include_custom_invite_codes: z
.array(z.string().max(32))
.max(255)
.transform((arr) => arr.map((str) => str.toLowerCase()))
.optional(),
exclude_custom_invite_codes: z
.array(z.string().max(32))
.max(255)
.transform((arr) => arr.map((str) => str.toLowerCase()))
.optional(),
allow_group_dm_invites: z.boolean().default(false),
match_messages: z.boolean().default(true),
match_embeds: z.boolean().default(false),
Expand Down
10 changes: 8 additions & 2 deletions backend/src/plugins/Automod/triggers/matchLinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ export const MatchLinksTrigger = automodTrigger<MatchResultType>()({

if (trigger.exclude_regex) {
if (!regexCache.has(trigger.exclude_regex)) {
const toCache = mergeRegexes(trigger.exclude_regex.map(pattern => inputPatternToRegExp(pattern)), "i");
const toCache = mergeRegexes(
trigger.exclude_regex.map((pattern) => inputPatternToRegExp(pattern)),
"i",
);
regexCache.set(trigger.exclude_regex, toCache);
}
const regexes = regexCache.get(trigger.exclude_regex)!;
Expand All @@ -88,7 +91,10 @@ export const MatchLinksTrigger = automodTrigger<MatchResultType>()({

if (trigger.include_regex) {
if (!regexCache.has(trigger.include_regex)) {
const toCache = mergeRegexes(trigger.include_regex.map(pattern => inputPatternToRegExp(pattern)), "i");
const toCache = mergeRegexes(
trigger.include_regex.map((pattern) => inputPatternToRegExp(pattern)),
"i",
);
regexCache.set(trigger.include_regex, toCache);
}
const regexes = regexCache.get(trigger.include_regex)!;
Expand Down
5 changes: 4 additions & 1 deletion backend/src/plugins/Automod/triggers/matchRegex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ export const MatchRegexTrigger = automodTrigger<MatchResultType>()({

if (!regexCache.has(trigger)) {
const flags = trigger.case_sensitive ? "" : "i";
const toCache = mergeRegexes(trigger.patterns.map(pattern => inputPatternToRegExp(pattern)), flags);
const toCache = mergeRegexes(
trigger.patterns.map((pattern) => inputPatternToRegExp(pattern)),
flags,
);
regexCache.set(trigger, toCache);
}
const regexes = regexCache.get(trigger)!;
Expand Down
11 changes: 3 additions & 8 deletions backend/src/plugins/Automod/triggers/matchWords.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ export const MatchWordsTrigger = automodTrigger<MatchResultType>()({
let pattern;

if (trigger.loose_matching) {
pattern = [...word]
.map((c) => escapeStringRegexp(c))
.join(`[\\s\\-_.,!?]{0,${looseMatchingThreshold}}`);
pattern = [...word].map((c) => escapeStringRegexp(c)).join(`[\\s\\-_.,!?]{0,${looseMatchingThreshold}}`);
} else {
pattern = escapeStringRegexp(word);
}
Expand All @@ -62,10 +60,7 @@ export const MatchWordsTrigger = automodTrigger<MatchResultType>()({
return pattern;
});

const mergedRegex = new RegExp(
patterns.map((p) => `(${p})`).join("|"),
trigger.case_sensitive ? "" : "i"
);
const mergedRegex = new RegExp(patterns.map((p) => `(${p})`).join("|"), trigger.case_sensitive ? "" : "i");

regexCache.set(trigger, [mergedRegex]);
}
Expand All @@ -84,7 +79,7 @@ export const MatchWordsTrigger = automodTrigger<MatchResultType>()({
for (const regex of regexes) {
const match = regex.exec(str);
if (match) {
const matchedWordIndex = match.slice(1).findIndex(group => group !== undefined);
const matchedWordIndex = match.slice(1).findIndex((group) => group !== undefined);
const matchedWord = trigger.words[matchedWordIndex];

return {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/plugins/Cases/functions/getCaseSummary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { GuildPluginData } from "knub";
import { splitMessageIntoChunks } from "knub/helpers";
import moment from "moment-timezone";
import { Case } from "../../../data/entities/Case.js";
import { convertDelayStringToMS, DBDateFormat, disableLinkPreviews, messageLink } from "../../../utils.js";
import { convertDelayStringToMS, DBDateFormat, messageLink } from "../../../utils.js";
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin.js";
import { caseAbbreviations } from "../caseAbbreviations.js";
import { CasesPluginType } from "../types.js";
Expand Down
22 changes: 14 additions & 8 deletions backend/src/plugins/Cases/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,21 @@ import { zColor } from "../../utils/zColor.js";

const caseKeys = keys(CaseNameToType) as U.ListOf<keyof typeof CaseNameToType>;

const caseColorsTypeMap = caseKeys.reduce((map, key) => {
map[key] = zColor;
return map;
}, {} as Record<typeof caseKeys[number], typeof zColor>);
const caseColorsTypeMap = caseKeys.reduce(
(map, key) => {
map[key] = zColor;
return map;
},
{} as Record<(typeof caseKeys)[number], typeof zColor>,
);

const caseIconsTypeMap = caseKeys.reduce((map, key) => {
map[key] = zBoundedCharacters(0, 100);
return map;
}, {} as Record<typeof caseKeys[number], z.ZodString>);
const caseIconsTypeMap = caseKeys.reduce(
(map, key) => {
map[key] = zBoundedCharacters(0, 100);
return map;
},
{} as Record<(typeof caseKeys)[number], z.ZodString>,
);

export const zCasesConfig = z.strictObject({
log_automatic_actions: z.boolean().default(true),
Expand Down
2 changes: 1 addition & 1 deletion backend/src/plugins/Common/CommonPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const CommonPlugin = guildPlugin<CommonPluginType>()({
storeAttachmentsAsMessage: async (attachments: Attachment[], backupChannel?: TextBasedChannel | null) => {
const attachmentChannelId = pluginData.config.get().attachment_storing_channel;
const channel = attachmentChannelId
? (pluginData.guild.channels.cache.get(attachmentChannelId) as TextBasedChannel) ?? backupChannel
? ((pluginData.guild.channels.cache.get(attachmentChannelId) as TextBasedChannel) ?? backupChannel)
: backupChannel;

if (!channel) {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/plugins/Common/functions/getEmoji.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { GuildPluginData } from "knub";
import { CommonPluginType } from "../types.js";
import { env } from "../../../env.js";
import { CommonPluginType } from "../types.js";

export function getSuccessEmoji(pluginData: GuildPluginData<CommonPluginType>) {
return pluginData.config.get().success_emoji ?? env.DEFAULT_SUCCESS_EMOJI;
Expand Down
13 changes: 8 additions & 5 deletions backend/src/plugins/Logs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { GuildCases } from "../../data/GuildCases.js";
import { GuildLogs } from "../../data/GuildLogs.js";
import { GuildSavedMessages } from "../../data/GuildSavedMessages.js";
import { LogType } from "../../data/LogType.js";
import { keys, zBoundedCharacters, zEmbedInput, zMessageContent, zRegex, zSnowflake, zStrictMessageContent } from "../../utils.js";
import { keys, zBoundedCharacters, zMessageContent, zRegex, zSnowflake } from "../../utils.js";
import { MessageBuffer } from "../../utils/MessageBuffer.js";
import {
TemplateSafeCase,
Expand All @@ -30,10 +30,13 @@ const MAX_BATCH_TIME = 5000;
// A bit of a workaround so we can pass LogType keys to z.enum()
const zMessageContentWithDefault = zMessageContent.default("");
const logTypes = keys(LogType);
const logTypeProps = logTypes.reduce((map, type) => {
map[type] = zMessageContent.default(DefaultLogMessages[type] || "");
return map;
}, {} as Record<keyof typeof LogType, typeof zMessageContentWithDefault>);
const logTypeProps = logTypes.reduce(
(map, type) => {
map[type] = zMessageContent.default(DefaultLogMessages[type] || "");
return map;
},
{} as Record<keyof typeof LogType, typeof zMessageContentWithDefault>,
);
const zLogFormats = z.strictObject(logTypeProps);

const zLogChannel = z.strictObject({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export const ForceMuteMsgCmd = modActionsMsgCmd({
[...msg.attachments.values()],
mod,
ppId,
"time" in args ? args.time ?? undefined : undefined,
"time" in args ? (args.time ?? undefined) : undefined,
args.reason,
contactMethods,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const ForceMuteSlashCmd = modActionsSlashCmd({
ppId = interaction.user.id;
}

const convertedTime = options.time ? convertDelayStringToMS(options.time) ?? undefined : undefined;
const convertedTime = options.time ? (convertDelayStringToMS(options.time) ?? undefined) : undefined;
if (options.time && !convertedTime) {
pluginData.state.common.sendErrorMessage(interaction, `Could not convert ${options.time} to a delay`);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const ForceUnmuteMsgCmd = modActionsMsgCmd({
[...msg.attachments.values()],
mod,
ppId,
"time" in args ? args.time ?? undefined : undefined,
"time" in args ? (args.time ?? undefined) : undefined,
args.reason,
);
},
Expand Down
Loading