From 35a1fcab554209cce82d50be57ae8305d617fd46 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Fri, 30 Nov 2018 20:36:41 -0800 Subject: [PATCH] Refactor token conversion logic into it's own testable method --- src/Discord.Net.Core/Utils/TokenUtils.cs | 60 +++++++++++++--------- test/Discord.Net.Tests/Tests.TokenUtils.cs | 18 +++++++ 2 files changed, 54 insertions(+), 24 deletions(-) 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); + } } }