Browse Source

feature: Check for whitespace or newline characters in tokens (#1305)

* Trim whitespace from tokens before logging in

This change trims whitespace characters from the supplied token before it is used to log in. Users can encounter this accidentally if they read their token from a file that ends with a blank line.

Leading whitespace will make the token invalid. Trailing whitespace or \n (not \r\n) will also fail to log in. \r\n (CRLF) doesn't fail because of the line break style for http request headers.

* revert trimming api token

* add check for whitespace or newline characters to existing token validation

Checks to see if a token contains any illegal characters, like whitespace or a newline. If it is, throws an ArgumentException warning the user that their token may be invalid.

I considered only checking the first and last character, but given that a token containing whitespace or a newline wouldn't work either I figured this made sense.

* removed unused usings

These were leftover from a previous approach using an ImmutableHashSet
tags/2.1.0
Chris Johnston Christopher F 6 years ago
parent
commit
bb61efabf3
2 changed files with 32 additions and 0 deletions
  1. +22
    -0
      src/Discord.Net.Core/Utils/TokenUtils.cs
  2. +10
    -0
      test/Discord.Net.Tests/Tests.TokenUtils.cs

+ 22
- 0
src/Discord.Net.Core/Utils/TokenUtils.cs View File

@@ -119,6 +119,25 @@ namespace Discord
return DecodeBase64UserId(segments[0]).HasValue; return DecodeBase64UserId(segments[0]).HasValue;
} }


/// <summary>
/// The set of all characters that are not allowed inside of a token.
/// </summary>
internal static char[] IllegalTokenCharacters = new char[]
{
' ', '\t', '\r', '\n'
};

/// <summary>
/// Checks if the given token contains a whitespace or newline character
/// that would fail to log in.
/// </summary>
/// <param name="token"> The token to validate. </param>
/// <returns>
/// True if the token contains a whitespace or newline character.
/// </returns>
internal static bool CheckContainsIllegalCharacters(string token)
=> token.IndexOfAny(IllegalTokenCharacters) != -1;

/// <summary> /// <summary>
/// Checks the validity of the supplied token of a specific type. /// Checks the validity of the supplied token of a specific type.
/// </summary> /// </summary>
@@ -131,6 +150,9 @@ namespace Discord
// A Null or WhiteSpace token of any type is invalid. // A Null or WhiteSpace token of any type is invalid.
if (string.IsNullOrWhiteSpace(token)) if (string.IsNullOrWhiteSpace(token))
throw new ArgumentNullException(paramName: nameof(token), message: "A token cannot be null, empty, or contain only whitespace."); throw new ArgumentNullException(paramName: nameof(token), message: "A token cannot be null, empty, or contain only whitespace.");
// ensure that there are no whitespace or newline characters
if (CheckContainsIllegalCharacters(token))
throw new ArgumentException(message: "The token contains a whitespace or newline character. Ensure that the token has been properly trimmed.", paramName: nameof(token));


switch (tokenType) switch (tokenType)
{ {


+ 10
- 0
test/Discord.Net.Tests/Tests.TokenUtils.cs View File

@@ -99,6 +99,16 @@ namespace Discord
[InlineData("937it3ow87i4ery69876wqire")] [InlineData("937it3ow87i4ery69876wqire")]
// 57 char bot token // 57 char bot token
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kK")] [InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kK")]
// ends with invalid characters
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k ")]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k\n")]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k\t")]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k\r\n")]
// starts with invalid characters
[InlineData(" MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k")]
[InlineData("\nMTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k")]
[InlineData("\tMTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k")]
[InlineData("\r\nMTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k")]
[InlineData("This is an invalid token, but it passes the check for string length.")] [InlineData("This is an invalid token, but it passes the check for string length.")]
// valid token, but passed in twice // valid token, but passed in twice
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWsMTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")] [InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWsMTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")]


Loading…
Cancel
Save