From 407c2bd2ae52491fb676a100fd519ce735b1f5e7 Mon Sep 17 00:00:00 2001 From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com> Date: Sat, 19 Feb 2022 00:03:17 +0200 Subject: [PATCH] Don't crash on invalid mentions Fixes #816 --- .../MarkdownVisitors/HtmlMarkdownVisitor.cs | 21 ++++++++++++------- .../PlainTextMarkdownVisitor.cs | 15 ++++++++----- .../Markdown/MentionKind.cs | 3 ++- .../Markdown/MentionNode.cs | 3 ++- .../Markdown/Parsing/MarkdownParser.cs | 12 +++++------ .../Markdown/UnixTimestampNode.cs | 2 +- 6 files changed, 35 insertions(+), 21 deletions(-) diff --git a/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/HtmlMarkdownVisitor.cs b/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/HtmlMarkdownVisitor.cs index 634f2316..c9e98ace 100644 --- a/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/HtmlMarkdownVisitor.cs +++ b/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/HtmlMarkdownVisitor.cs @@ -107,27 +107,34 @@ internal partial class HtmlMarkdownVisitor : MarkdownVisitor protected override MarkdownNode VisitMention(MentionNode mention) { - if (mention.Kind == MentionKind.Meta) + if (mention.Kind == MentionKind.Everyone) { _buffer .Append("") - .Append("@").Append(HtmlEncode(mention.Id.ToString())) + .Append("@everyone") + .Append(""); + } + else if (mention.Kind == MentionKind.Here) + { + _buffer + .Append("") + .Append("@here") .Append(""); } else if (mention.Kind == MentionKind.User) { - var member = _context.TryGetMember(mention.Id); + var member = mention.TargetId?.Pipe(_context.TryGetMember); var fullName = member?.User.FullName ?? "Unknown"; var nick = member?.Nick ?? "Unknown"; _buffer .Append($"") - .Append("@").Append(HtmlEncode(nick)) + .Append('@').Append(HtmlEncode(nick)) .Append(""); } else if (mention.Kind == MentionKind.Channel) { - var channel = _context.TryGetChannel(mention.Id); + var channel = mention.TargetId?.Pipe(_context.TryGetChannel); var symbol = channel?.IsVoiceChannel == true ? "🔊" : "#"; var name = channel?.Name ?? "deleted-channel"; @@ -138,7 +145,7 @@ internal partial class HtmlMarkdownVisitor : MarkdownVisitor } else if (mention.Kind == MentionKind.Role) { - var role = _context.TryGetRole(mention.Id); + var role = mention.TargetId?.Pipe(_context.TryGetRole); var name = role?.Name ?? "deleted-role"; var color = role?.Color; @@ -148,7 +155,7 @@ internal partial class HtmlMarkdownVisitor : MarkdownVisitor _buffer .Append($"") - .Append("@").Append(HtmlEncode(name)) + .Append('@').Append(HtmlEncode(name)) .Append(""); } diff --git a/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/PlainTextMarkdownVisitor.cs b/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/PlainTextMarkdownVisitor.cs index a44a08ee..842ba1aa 100644 --- a/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/PlainTextMarkdownVisitor.cs +++ b/DiscordChatExporter.Core/Exporting/Writers/MarkdownVisitors/PlainTextMarkdownVisitor.cs @@ -1,6 +1,7 @@ using System.Text; using DiscordChatExporter.Core.Markdown; using DiscordChatExporter.Core.Markdown.Parsing; +using DiscordChatExporter.Core.Utils.Extensions; namespace DiscordChatExporter.Core.Exporting.Writers.MarkdownVisitors; @@ -34,20 +35,24 @@ internal partial class PlainTextMarkdownVisitor : MarkdownVisitor protected override MarkdownNode VisitMention(MentionNode mention) { - if (mention.Kind == MentionKind.Meta) + if (mention.Kind == MentionKind.Everyone) { - _buffer.Append($"@{mention.Id}"); + _buffer.Append("@everyone"); + } + else if (mention.Kind == MentionKind.Here) + { + _buffer.Append("@here"); } else if (mention.Kind == MentionKind.User) { - var member = _context.TryGetMember(mention.Id); + var member = mention.TargetId?.Pipe(_context.TryGetMember); var name = member?.User.Name ?? "Unknown"; _buffer.Append($"@{name}"); } else if (mention.Kind == MentionKind.Channel) { - var channel = _context.TryGetChannel(mention.Id); + var channel =mention.TargetId?.Pipe(_context.TryGetChannel); var name = channel?.Name ?? "deleted-channel"; _buffer.Append($"#{name}"); @@ -58,7 +63,7 @@ internal partial class PlainTextMarkdownVisitor : MarkdownVisitor } else if (mention.Kind == MentionKind.Role) { - var role = _context.TryGetRole(mention.Id); + var role = mention.TargetId?.Pipe(_context.TryGetRole); var name = role?.Name ?? "deleted-role"; _buffer.Append($"@{name}"); diff --git a/DiscordChatExporter.Core/Markdown/MentionKind.cs b/DiscordChatExporter.Core/Markdown/MentionKind.cs index 5fb66dbc..d7512363 100644 --- a/DiscordChatExporter.Core/Markdown/MentionKind.cs +++ b/DiscordChatExporter.Core/Markdown/MentionKind.cs @@ -2,7 +2,8 @@ internal enum MentionKind { - Meta, + Everyone, + Here, User, Channel, Role diff --git a/DiscordChatExporter.Core/Markdown/MentionNode.cs b/DiscordChatExporter.Core/Markdown/MentionNode.cs index cc6458e1..609bf042 100644 --- a/DiscordChatExporter.Core/Markdown/MentionNode.cs +++ b/DiscordChatExporter.Core/Markdown/MentionNode.cs @@ -2,4 +2,5 @@ namespace DiscordChatExporter.Core.Markdown; -internal record MentionNode(Snowflake Id, MentionKind Kind) : MarkdownNode; \ No newline at end of file +// Null ID means it's a meta mention or an invalid mention +internal record MentionNode(Snowflake? TargetId, MentionKind Kind) : MarkdownNode; \ No newline at end of file diff --git a/DiscordChatExporter.Core/Markdown/Parsing/MarkdownParser.cs b/DiscordChatExporter.Core/Markdown/Parsing/MarkdownParser.cs index 2229402b..7ee1c887 100644 --- a/DiscordChatExporter.Core/Markdown/Parsing/MarkdownParser.cs +++ b/DiscordChatExporter.Core/Markdown/Parsing/MarkdownParser.cs @@ -124,31 +124,31 @@ internal static partial class MarkdownParser // Capture @everyone private static readonly IMatcher EveryoneMentionNodeMatcher = new StringMatcher( "@everyone", - _ => new MentionNode(Snowflake.Zero, MentionKind.Meta) + _ => new MentionNode(null, MentionKind.Everyone) ); // Capture @here private static readonly IMatcher HereMentionNodeMatcher = new StringMatcher( "@here", - _ => new MentionNode(Snowflake.Zero, MentionKind.Meta) + _ => new MentionNode(null, MentionKind.Here) ); // Capture <@123456> or <@!123456> private static readonly IMatcher UserMentionNodeMatcher = new RegexMatcher( new Regex("<@!?(\\d+)>", DefaultRegexOptions), - (_, m) => new MentionNode(Snowflake.Parse(m.Groups[1].Value), MentionKind.User) + (_, m) => new MentionNode(Snowflake.TryParse(m.Groups[1].Value), MentionKind.User) ); // Capture <#123456> private static readonly IMatcher ChannelMentionNodeMatcher = new RegexMatcher( new Regex("<#!?(\\d+)>", DefaultRegexOptions), - (_, m) => new MentionNode(Snowflake.Parse(m.Groups[1].Value), MentionKind.Channel) + (_, m) => new MentionNode(Snowflake.TryParse(m.Groups[1].Value), MentionKind.Channel) ); // Capture <@&123456> private static readonly IMatcher RoleMentionNodeMatcher = new RegexMatcher( new Regex("<@&(\\d+)>", DefaultRegexOptions), - (_, m) => new MentionNode(Snowflake.Parse(m.Groups[1].Value), MentionKind.Role) + (_, m) => new MentionNode(Snowflake.TryParse(m.Groups[1].Value), MentionKind.Role) ); /* Emoji */ @@ -179,7 +179,7 @@ internal static partial class MarkdownParser private static readonly IMatcher CustomEmojiNodeMatcher = new RegexMatcher( new Regex("<(a)?:(.+?):(\\d+?)>", DefaultRegexOptions), (_, m) => new EmojiNode( - Snowflake.Parse(m.Groups[3].Value), + Snowflake.TryParse(m.Groups[3].Value), m.Groups[2].Value, !string.IsNullOrWhiteSpace(m.Groups[1].Value) ) diff --git a/DiscordChatExporter.Core/Markdown/UnixTimestampNode.cs b/DiscordChatExporter.Core/Markdown/UnixTimestampNode.cs index 82a81c2c..23991c7c 100644 --- a/DiscordChatExporter.Core/Markdown/UnixTimestampNode.cs +++ b/DiscordChatExporter.Core/Markdown/UnixTimestampNode.cs @@ -2,5 +2,5 @@ namespace DiscordChatExporter.Core.Markdown; -// Null means invalid date +// Null date means invalid timestamp internal record UnixTimestampNode(DateTimeOffset? Date) : MarkdownNode; \ No newline at end of file