Add bot alerts for missing audit log permissions; ignore internal server errors on discord's side when fetching audit logs

This commit is contained in:
Dragory 2019-07-22 13:50:24 +03:00
parent fb481aa583
commit ee58769460
3 changed files with 52 additions and 18 deletions

View file

@ -1,16 +1,15 @@
import { decorators as d, IPluginOptions, logger } from "knub";
import { GuildLogs } from "../data/GuildLogs";
import { LogType } from "../data/LogType";
import { Attachment, Channel, Constants as ErisConstants, Embed, Member, TextChannel, User } from "eris";
import { Attachment, Channel, Constants as ErisConstants, Embed, Guild, Member, TextChannel, User } from "eris";
import DiscordRESTError from "eris/lib/errors/DiscordRESTError"; // tslint:disable-line
import {
createChunkedMessage,
deactivateMentions,
disableCodeBlocks,
disableLinkPreviews,
findRelevantAuditLogEntry,
noop,
stripObjectToScalars,
trimLines,
UnknownUser,
useMediaUrls,
} from "../utils";
@ -249,6 +248,20 @@ export class LogsPlugin extends ZeppelinPlugin<TConfigSchema> {
}
}
async findRelevantAuditLogEntry(actionType: number, userId: string, attempts?: number, attemptDelay?: number) {
try {
return await findRelevantAuditLogEntry(this.guild, actionType, userId, attempts, attemptDelay);
} catch (e) {
if (e instanceof DiscordRESTError && e.code === 50013) {
this.guildLogs.log(LogType.BOT_ALERT, {
body: "Missing permissions to read audit log",
});
} else {
throw e;
}
}
}
@d.event("guildMemberAdd")
async onMemberJoin(_, member) {
const newThreshold = moment().valueOf() - 1000 * 60 * 60;
@ -299,8 +312,7 @@ export class LogsPlugin extends ZeppelinPlugin<TConfigSchema> {
@d.event("guildBanAdd")
async onMemberBan(_, user) {
const relevantAuditLogEntry = await findRelevantAuditLogEntry(
this.guild,
const relevantAuditLogEntry = await this.findRelevantAuditLogEntry(
ErisConstants.AuditLogActions.MEMBER_BAN_ADD,
user.id,
);
@ -318,8 +330,7 @@ export class LogsPlugin extends ZeppelinPlugin<TConfigSchema> {
@d.event("guildBanRemove")
async onMemberUnban(_, user) {
const relevantAuditLogEntry = await findRelevantAuditLogEntry(
this.guild,
const relevantAuditLogEntry = await this.findRelevantAuditLogEntry(
ErisConstants.AuditLogActions.MEMBER_BAN_REMOVE,
user.id,
);
@ -351,8 +362,7 @@ export class LogsPlugin extends ZeppelinPlugin<TConfigSchema> {
const addedRoles = diff(member.roles, oldMember.roles);
const removedRoles = diff(oldMember.roles, member.roles);
const relevantAuditLogEntry = await findRelevantAuditLogEntry(
this.guild,
const relevantAuditLogEntry = await this.findRelevantAuditLogEntry(
ErisConstants.AuditLogActions.MEMBER_ROLE_UPDATE,
member.id,
);

View file

@ -1,5 +1,6 @@
import { decorators as d, IPluginOptions, logger, waitForReaction, waitForReply } from "knub";
import { Attachment, Constants as ErisConstants, Guild, Member, Message, TextChannel, User } from "eris";
import DiscordRESTError from "eris/lib/errors/DiscordRESTError"; // tslint:disable-line
import humanizeDuration from "humanize-duration";
import { GuildCases } from "../data/GuildCases";
import {
@ -164,6 +165,20 @@ export class ModActionsPlugin extends ZeppelinPlugin<TConfigSchema> {
return bans.some(b => b.user.id === userId);
}
async findRelevantAuditLogEntry(actionType: number, userId: string, attempts?: number, attemptDelay?: number) {
try {
return await findRelevantAuditLogEntry(this.guild, actionType, userId, attempts, attemptDelay);
} catch (e) {
if (e instanceof DiscordRESTError && e.code === 50013) {
this.serverLogs.log(LogType.BOT_ALERT, {
body: "Missing permissions to read audit log",
});
} else {
throw e;
}
}
}
/**
* Add a BAN action automatically when a user is banned.
* Attempts to find the ban's details in the audit log.
@ -175,8 +190,7 @@ export class ModActionsPlugin extends ZeppelinPlugin<TConfigSchema> {
return;
}
const relevantAuditLogEntry = await findRelevantAuditLogEntry(
this.guild,
const relevantAuditLogEntry = await this.findRelevantAuditLogEntry(
ErisConstants.AuditLogActions.MEMBER_BAN_ADD,
user.id,
);
@ -214,8 +228,7 @@ export class ModActionsPlugin extends ZeppelinPlugin<TConfigSchema> {
return;
}
const relevantAuditLogEntry = await findRelevantAuditLogEntry(
this.guild,
const relevantAuditLogEntry = await this.findRelevantAuditLogEntry(
ErisConstants.AuditLogActions.MEMBER_BAN_REMOVE,
user.id,
);
@ -273,8 +286,7 @@ export class ModActionsPlugin extends ZeppelinPlugin<TConfigSchema> {
return;
}
const kickAuditLogEntry = await findRelevantAuditLogEntry(
this.guild,
const kickAuditLogEntry = await this.findRelevantAuditLogEntry(
ErisConstants.AuditLogActions.MEMBER_KICK,
member.id,
);

View file

@ -3,12 +3,14 @@ import {
EmbedOptions,
Emoji,
Guild,
GuildAuditLog,
GuildAuditLogEntry,
Member,
TextableChannel,
TextChannel,
User,
} from "eris";
import DiscordHTTPError from "eris/lib/errors/DiscordHTTPError"; // tslint:disable-line
import url from "url";
import tlds from "tlds";
import emojiRegex from "emoji-regex";
@ -129,9 +131,19 @@ export async function findRelevantAuditLogEntry(
attempts: number = 3,
attemptDelay: number = 3000,
): Promise<GuildAuditLogEntry> {
const auditLogEntries = await guild.getAuditLogs(5, null, actionType);
let auditLogs: GuildAuditLog;
try {
auditLogs = await guild.getAuditLogs(5, null, actionType);
} catch (e) {
// Ignore internal server errors which seem to be pretty common with audit log requests
if (!(e instanceof DiscordHTTPError) || e.code !== 500) {
throw e;
}
}
auditLogEntries.entries.sort((a, b) => {
const entries = auditLogs ? auditLogs.entries : [];
entries.sort((a, b) => {
if (a.createdAt > b.createdAt) return -1;
if (a.createdAt > b.createdAt) return 1;
return 0;
@ -139,7 +151,7 @@ export async function findRelevantAuditLogEntry(
const cutoffTS = Date.now() - 1000 * 60 * 2;
const relevantEntry = auditLogEntries.entries.find(entry => {
const relevantEntry = entries.find(entry => {
return entry.targetID === userId && entry.createdAt >= cutoffTS;
});