From 501276ce72417f7a7f66cc727fafaa3d0f353b8b Mon Sep 17 00:00:00 2001 From: Hussein Alzein Date: Sat, 31 Jul 2021 13:45:05 -0400 Subject: [PATCH] Fixed url validation to be neater and not utilize IsWellFormatted (#66) * Error handling on URL additions in embeds and components. * Wording on exception comment * Wording on exceptions * changed IsWellFormatted to validating urls start with protocol. May not keep all url validation, may just keep image-based url validation as those definitely only require http/s. * Helper utility made for url validation * xml Co-authored-by: Quin Lynch <49576606+quinchs@users.noreply.github.com> --- src/Discord.Net.Core/Discord.Net.Core.xml | 8 +++++ .../Message Components/ComponentBuilder.cs | 12 ++++---- .../Entities/Messages/EmbedBuilder.cs | 29 +++++++++++-------- src/Discord.Net.Core/Utils/UrlValidation.cs | 22 ++++++++++++++ 4 files changed, 53 insertions(+), 18 deletions(-) create mode 100644 src/Discord.Net.Core/Utils/UrlValidation.cs diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml index 5213edd3c..b351ad49d 100644 --- a/src/Discord.Net.Core/Discord.Net.Core.xml +++ b/src/Discord.Net.Core/Discord.Net.Core.xml @@ -11643,5 +11643,13 @@ Thrown when the supplied token string is null, empty, or contains only whitespace. Thrown when the supplied or token value is invalid. + + + Not full URL validation right now. Just ensures protocol is present and that it's either http or https + + url to validate before sending to Discord + A URL must include a protocol (http or https). + true if url is valid by our standard, false if null, throws an error upon invalid + diff --git a/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs b/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs index ff2c99a6c..bb2f80a81 100644 --- a/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs +++ b/src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Discord.Utils; namespace Discord { @@ -535,12 +536,11 @@ namespace Discord if (this.Style == ButtonStyle.Link) { - if (string.IsNullOrEmpty(this.Url)) - throw new InvalidOperationException("Link buttons must have a link associated with them"); - else if (!Uri.IsWellFormedUriString(this.Url, UriKind.Absolute)) - throw new InvalidOperationException("Urls must be well formatted and include their protocol (either HTTP or HTTPS)"); - } - + if (string.IsNullOrEmpty(this.Url)) + throw new InvalidOperationException("Link buttons must have a link associated with them"); + else + UrlValidation.Validate(this.Url); + } else if (string.IsNullOrEmpty(this.CustomId)) throw new InvalidOperationException("Non-link buttons must have a custom id associated with them"); diff --git a/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs b/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs index b7dd6ed02..2ab2699a6 100644 --- a/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs +++ b/src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using Discord.Utils; namespace Discord { @@ -401,25 +402,29 @@ namespace Discord /// The built embed object. /// /// Total embed length exceeds . - /// Any Url must be well formatted include its protocols (i.e http:// or https://). + /// Any Url must include its protocols (i.e http:// or https://). public Embed Build() { if (Length > MaxEmbedLength) throw new InvalidOperationException($"Total embed length must be less than or equal to {MaxEmbedLength}."); - if (!string.IsNullOrEmpty(Url) && !Uri.IsWellFormedUriString(Url, UriKind.Absolute)) - throw new InvalidOperationException("Url must be well formatted and include its protocol (either HTTP or HTTPS)"); - if (!string.IsNullOrEmpty(ThumbnailUrl) && !Uri.IsWellFormedUriString(ThumbnailUrl, UriKind.Absolute)) - throw new InvalidOperationException("Thumbnail Url must be well formatted and include its protocol (either HTTP or HTTPS)"); - if (!string.IsNullOrEmpty(ImageUrl) && !Uri.IsWellFormedUriString(ImageUrl, UriKind.Absolute)) - throw new InvalidOperationException("Image Url must be well formatted and include its protocol (either HTTP or HTTPS)"); + if (!string.IsNullOrEmpty(Url)) + UrlValidation.Validate(Url); + if (!string.IsNullOrEmpty(ThumbnailUrl)) + UrlValidation.Validate(ThumbnailUrl); + if (!string.IsNullOrEmpty(ImageUrl)) + UrlValidation.Validate(ImageUrl); if (Author != null) { - if(!string.IsNullOrEmpty(Author.Url) && !Uri.IsWellFormedUriString(Author.Url, UriKind.Absolute)) - throw new InvalidOperationException("Author Url must be well formatted and include its protocol (either HTTP or HTTPS)"); - if (!string.IsNullOrEmpty(Author.IconUrl) && !Uri.IsWellFormedUriString(Author.IconUrl, UriKind.Absolute)) - throw new InvalidOperationException("Author Icon Url must be well formatted and include its protocol (either HTTP or HTTPS)"); + if (!string.IsNullOrEmpty(Author.Url)) + UrlValidation.Validate(Author.Url); + if (!string.IsNullOrEmpty(Author.IconUrl)) + UrlValidation.Validate(Author.IconUrl); + } + if(Footer != null) + { + if (!string.IsNullOrEmpty(Footer.IconUrl)) + UrlValidation.Validate(Footer.IconUrl); } - var fields = ImmutableArray.CreateBuilder(Fields.Count); for (int i = 0; i < Fields.Count; i++) fields.Add(Fields[i].Build()); diff --git a/src/Discord.Net.Core/Utils/UrlValidation.cs b/src/Discord.Net.Core/Utils/UrlValidation.cs new file mode 100644 index 000000000..7cc9bd8bd --- /dev/null +++ b/src/Discord.Net.Core/Utils/UrlValidation.cs @@ -0,0 +1,22 @@ +using System; + +namespace Discord.Utils +{ + static class UrlValidation + { + /// + /// Not full URL validation right now. Just ensures protocol is present and that it's either http or https + /// + /// url to validate before sending to Discord + /// A URL must include a protocol (http or https). + /// true if url is valid by our standard, false if null, throws an error upon invalid + public static bool Validate(string url) + { + if (string.IsNullOrEmpty(url)) + return false; + if(!(url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || (url.StartsWith("https://", StringComparison.OrdinalIgnoreCase)))) + throw new InvalidOperationException($"Url {url} must be include its protocol (either HTTP or HTTPS)"); + return true; + } + } +}