Convert Sentry enrichers

This commit is contained in:
Ske 2021-01-31 14:50:10 +01:00
parent e06a6ecf85
commit 5a52abed77
3 changed files with 45 additions and 92 deletions

View File

@ -9,6 +9,7 @@ namespace Myriad.Gateway
public Optional<User> Author { get; init; }
public Optional<GuildMemberPartial> Member { get; init; }
public Optional<Message.Attachment[]> Attachments { get; init; }
public Optional<ulong?> GuildId { get; init; }
// TODO: lots of partials
}
}

View File

@ -30,9 +30,7 @@ namespace PluralKit.Bot
public const uint Green = 0x00cc78;
public const uint Red = 0xef4b3d;
public const uint Gray = 0x979c9f;
public static Permissions DM_PERMISSIONS = (Permissions) 0b00000_1000110_1011100110000_000000;
private static readonly Regex USER_MENTION = new Regex("<@!?(\\d{17,19})>");
private static readonly Regex ROLE_MENTION = new Regex("<@&(\\d{17,19})>");
private static readonly Regex EVERYONE_HERE_MENTION = new Regex("@(everyone|here)");
@ -44,60 +42,11 @@ namespace PluralKit.Bot
// corresponding to: https://github.com/Khan/simple-markdown/blob/master/src/index.js#L1489
// I added <? and >? at the start/end; they need to be handled specially later...
private static readonly Regex UNBROKEN_LINK_REGEX = new Regex("<?(https?:\\/\\/[^\\s<]+[^<.,:;\"')\\]\\s])>?");
private static readonly FieldInfo _roleIdsField =
typeof(DiscordMember).GetField("_role_ids", BindingFlags.NonPublic | BindingFlags.Instance);
public static string NameAndMention(this User user)
{
return $"{user.Username}#{user.Discriminator} ({user.Mention()})";
}
// We funnel all "permissions from DiscordMember" calls through here
// This way we can ensure we do the read permission correction everywhere
private static Permissions PermissionsInGuild(DiscordChannel channel, DiscordMember member)
{
ValidateCachedRoles(member);
var permissions = channel.PermissionsFor(member);
// This method doesn't account for channels without read permissions
// If we don't have read permissions in the channel, we don't have *any* permissions
if ((permissions & Permissions.AccessChannels) != Permissions.AccessChannels)
return Permissions.None;
return permissions;
}
// Workaround for DSP internal error
private static void ValidateCachedRoles(DiscordMember member)
{
var roleIdCache = _roleIdsField.GetValue(member) as List<ulong>;
var currentRoleIds = member.Roles.Where(x => x != null).Select(x => x.Id);
var invalidRoleIds = roleIdCache.Where(x => !currentRoleIds.Contains(x)).ToList();
roleIdCache.RemoveAll(x => invalidRoleIds.Contains(x));
}
// Same as PermissionsIn, but always synchronous. DiscordUser must be a DiscordMember if channel is in guild.
public static Permissions PermissionsInSync(this DiscordChannel channel, DiscordUser user)
{
if (channel.Guild != null && !(user is DiscordMember))
throw new ArgumentException("Function was passed a guild channel but a non-member DiscordUser");
if (user is DiscordMember m) return PermissionsInGuild(channel, m);
if (channel.Type == ChannelType.Private) return DM_PERMISSIONS;
return Permissions.None;
}
public static Permissions BotPermissions(this DiscordChannel channel)
{
// TODO: can we get a CurrentMember somehow without a guild context?
// at least, without somehow getting a DiscordClient reference as an arg(which I don't want to do)
if (channel.Guild != null)
return PermissionsInSync(channel, channel.Guild.CurrentMember);
if (channel.Type == ChannelType.Private) return DM_PERMISSIONS;
return Permissions.None;
}
public static Instant SnowflakeToInstant(ulong snowflake) =>
Instant.FromUtc(2015, 1, 1, 0, 0, 0) + Duration.FromMilliseconds(snowflake >> 22);

View File

@ -1,9 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using DSharpPlus;
using DSharpPlus.EventArgs;
using Myriad.Extensions;
using Myriad.Gateway;
using Sentry;
@ -15,82 +12,88 @@ namespace PluralKit.Bot
void Enrich(Scope scope, Shard shard, T evt);
}
public class SentryEnricher //:
// TODO!!!
// ISentryEnricher<MessageCreateEventArgs>,
// ISentryEnricher<MessageDeleteEventArgs>,
// ISentryEnricher<MessageUpdateEventArgs>,
// ISentryEnricher<MessageBulkDeleteEventArgs>,
// ISentryEnricher<MessageReactionAddEventArgs>
public class SentryEnricher:
ISentryEnricher<MessageCreateEvent>,
ISentryEnricher<MessageDeleteEvent>,
ISentryEnricher<MessageUpdateEvent>,
ISentryEnricher<MessageDeleteBulkEvent>,
ISentryEnricher<MessageReactionAddEvent>
{
private readonly Bot _bot;
public SentryEnricher(Bot bot)
{
_bot = bot;
}
// TODO: should this class take the Scope by dependency injection instead?
// Would allow us to create a centralized "chain of handlers" where this class could just be registered as an entry in
public void Enrich(Scope scope, Shard shard, MessageCreateEventArgs evt)
public void Enrich(Scope scope, Shard shard, MessageCreateEvent evt)
{
scope.AddBreadcrumb(evt.Message.Content, "event.message", data: new Dictionary<string, string>
scope.AddBreadcrumb(evt.Content, "event.message", data: new Dictionary<string, string>
{
{"user", evt.Author.Id.ToString()},
{"channel", evt.Channel.Id.ToString()},
{"guild", evt.Channel.GuildId.ToString()},
{"message", evt.Message.Id.ToString()},
{"channel", evt.ChannelId.ToString()},
{"guild", evt.GuildId.ToString()},
{"message", evt.Id.ToString()},
});
scope.SetTag("shard", shard.ShardInfo?.ShardId.ToString());
scope.SetTag("shard", shard.ShardInfo.ShardId.ToString());
// Also report information about the bot's permissions in the channel
// We get a lot of permission errors so this'll be useful for determining problems
var perms = evt.Channel.BotPermissions();
var perms = _bot.PermissionsIn(evt.ChannelId);
scope.AddBreadcrumb(perms.ToPermissionString(), "permissions");
}
public void Enrich(Scope scope, Shard shard, MessageDeleteEventArgs evt)
public void Enrich(Scope scope, Shard shard, MessageDeleteEvent evt)
{
scope.AddBreadcrumb("", "event.messageDelete",
data: new Dictionary<string, string>()
{
{"channel", evt.Channel.Id.ToString()},
{"guild", evt.Channel.GuildId.ToString()},
{"message", evt.Message.Id.ToString()},
{"channel", evt.ChannelId.ToString()},
{"guild", evt.GuildId.ToString()},
{"message", evt.Id.ToString()},
});
scope.SetTag("shard", shard.ShardInfo?.ShardId.ToString());
scope.SetTag("shard", shard.ShardInfo.ShardId.ToString());
}
public void Enrich(Scope scope, Shard shard, MessageUpdateEventArgs evt)
public void Enrich(Scope scope, Shard shard, MessageUpdateEvent evt)
{
scope.AddBreadcrumb(evt.Message.Content ?? "<unknown>", "event.messageEdit",
scope.AddBreadcrumb(evt.Content.Value ?? "<unknown>", "event.messageEdit",
data: new Dictionary<string, string>()
{
{"channel", evt.Channel.Id.ToString()},
{"guild", evt.Channel.GuildId.ToString()},
{"message", evt.Message.Id.ToString()}
{"channel", evt.ChannelId.ToString()},
{"guild", evt.GuildId.Value.ToString()},
{"message", evt.Id.ToString()}
});
scope.SetTag("shard", shard.ShardInfo?.ShardId.ToString());
scope.SetTag("shard", shard.ShardInfo.ShardId.ToString());
}
public void Enrich(Scope scope, Shard shard, MessageBulkDeleteEventArgs evt)
public void Enrich(Scope scope, Shard shard, MessageDeleteBulkEvent evt)
{
scope.AddBreadcrumb("", "event.messageDelete",
data: new Dictionary<string, string>()
{
{"channel", evt.Channel.Id.ToString()},
{"guild", evt.Channel.Id.ToString()},
{"messages", string.Join(",", evt.Messages.Select(m => m.Id))},
{"channel", evt.ChannelId.ToString()},
{"guild", evt.GuildId.ToString()},
{"messages", string.Join(",", evt.Ids)},
});
scope.SetTag("shard", shard.ShardInfo?.ShardId.ToString());
scope.SetTag("shard", shard.ShardInfo.ShardId.ToString());
}
public void Enrich(Scope scope, Shard shard, MessageReactionAddEventArgs evt)
public void Enrich(Scope scope, Shard shard, MessageReactionAddEvent evt)
{
scope.AddBreadcrumb("", "event.reaction",
data: new Dictionary<string, string>()
{
{"user", evt.User.Id.ToString()},
{"channel", (evt.Channel?.Id ?? 0).ToString()},
{"guild", (evt.Channel?.GuildId ?? 0).ToString()},
{"message", evt.Message.Id.ToString()},
{"user", evt.UserId.ToString()},
{"channel", evt.ChannelId.ToString()},
{"guild", (evt.GuildId ?? 0).ToString()},
{"message", evt.MessageId.ToString()},
{"reaction", evt.Emoji.Name}
});
scope.SetTag("shard", shard.ShardInfo?.ShardId.ToString());
scope.SetTag("shard", shard.ShardInfo.ShardId.ToString());
}
}
}