diff --git a/src/Discord.Net.Core/Utils/TokenUtils.cs b/src/Discord.Net.Core/Utils/TokenUtils.cs
index d53b5d3f1..68aad5d96 100644
--- a/src/Discord.Net.Core/Utils/TokenUtils.cs
+++ b/src/Discord.Net.Core/Utils/TokenUtils.cs
@@ -17,6 +17,40 @@ namespace Discord
///
internal const int MinBotTokenLength = 58;
+ ///
+ /// Decodes a base 64 encoded string into a ulong value.
+ ///
+ /// A base 64 encoded string containing a User Id.
+ /// A ulong containing the decoded value of the string, or null if the value was invalid.
+ internal static ulong? DecodeBase64UserId(string encoded)
+ {
+ if (string.IsNullOrWhiteSpace(encoded))
+ return null;
+
+ try
+ {
+ // decode the base64 string
+ var bytes = Convert.FromBase64String(encoded);
+ var idStr = Encoding.UTF8.GetString(bytes);
+ // try to parse a ulong from the resulting string
+ if (ulong.TryParse(idStr, out var id))
+ return id;
+ }
+ catch (DecoderFallbackException)
+ {
+ // ignore exception, can be thrown by GetString
+ }
+ catch (FormatException)
+ {
+ // ignore exception, can be thrown if base64 string is invalid
+ }
+ catch (ArgumentException)
+ {
+ // ignore exception, can be thrown by BitConverter
+ }
+ return null;
+ }
+
///
/// Checks the validity of a bot token by attempting to decode a ulong userid
/// from the bot token.
@@ -38,30 +72,8 @@ namespace Discord
// ensure that there are three parts
if (segments.Length != 3)
return false;
-
- try
- {
- // decode the first segment as base64
- var bytes = Convert.FromBase64String(segments[0]);
- var idStr = Encoding.UTF8.GetString(bytes);
- // discard id
- return ulong.TryParse(idStr, out var id);
- }
- catch (DecoderFallbackException)
- {
- // can be thrown by GetString
- return false;
- }
- catch (FormatException)
- {
- // ignore exception, if contains invalid base64 characters return false
- return false;
- }
- catch (ArgumentException)
- {
- // ignore exceptions thrown by BitConverter
- return false;
- }
+ // return true if the user id could be determined
+ return DecodeBase64UserId(segments[0]).HasValue;
}
///
diff --git a/test/Discord.Net.Tests/Tests.TokenUtils.cs b/test/Discord.Net.Tests/Tests.TokenUtils.cs
index 317b8c719..9a1102ec5 100644
--- a/test/Discord.Net.Tests/Tests.TokenUtils.cs
+++ b/test/Discord.Net.Tests/Tests.TokenUtils.cs
@@ -146,5 +146,23 @@ namespace Discord
{
Assert.Equal(expected, TokenUtils.CheckBotTokenValidity(token));
}
+
+ [Theory]
+ // cannot pass a ulong? as a param in InlineData, so have to have a separate param
+ // indicating if a value is null
+ [InlineData("NDI4NDc3OTQ0MDA5MTk1NTIw", false, 428477944009195520)]
+ // should return null w/o throwing other exceptions
+ [InlineData("", true, 0)]
+ [InlineData(" ", true, 0)]
+ [InlineData(null, true, 0)]
+ [InlineData("these chars aren't allowed @U#)*@#!)*", true, 0)]
+ public void TestDecodeBase64UserId(string encodedUserId, bool isNull, ulong expectedUserId)
+ {
+ var result = TokenUtils.DecodeBase64UserId(encodedUserId);
+ if (isNull)
+ Assert.Null(result);
+ else
+ Assert.Equal(expectedUserId, result);
+ }
}
}