Skip to content

Commit

Permalink
API key validation
Browse files Browse the repository at this point in the history
  • Loading branch information
ob-stripe committed Feb 17, 2019
1 parent 8069bd3 commit 12506e3
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 10 deletions.
10 changes: 2 additions & 8 deletions src/Stripe.net/Infrastructure/Public/StripeConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,7 @@ public static string ApiKey
return apiKey;
}

set
{
apiKey = value;
}
set => apiKey = StringUtils.ValidateApiKey(value);
}

/// <summary>Gets or sets the base URL for Stripe's OAuth API.</summary>
Expand Down Expand Up @@ -126,10 +123,7 @@ public static IStripeClient StripeClient
return stripeClient;
}

set
{
stripeClient = value;
}
set => stripeClient = value;
}

/// <summary>Gets the version of the Stripe.net client library.</summary>
Expand Down
23 changes: 23 additions & 0 deletions src/Stripe.net/Infrastructure/StringUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ namespace Stripe.Infrastructure

internal static class StringUtils
{
private static Regex apiKeyRegex
= new Regex(@"\A\w*\z", RegexOptions.Singleline | RegexOptions.CultureInvariant);

/// <summary>Converts the string to snake case.</summary>
/// <param name="str">The string to convert.</param>
/// <returns>A string with the contents of the input string converted to snake_case.</returns>
Expand Down Expand Up @@ -52,5 +55,25 @@ public static bool SecureEquals(string a, string b)

return result == 0;
}

/// <summary>
/// Validates that the API key only contains valid characters (alphanumeric or underscores).
/// </summary>
/// <param name="apiKey">The API key.</param>
/// <returns>The API key, if valid.</returns>
/// <exception name="StripeException">
/// Thrown if the API key contains invalid characters.
/// </exception>
public static string ValidateApiKey(string apiKey)
{
if (!apiKeyRegex.IsMatch(apiKey ?? string.Empty))
{
var message = $"Invalid API key: \"{apiKey}\". API keys may only contain alphanumeric "
+ "characters and underscores.";
throw new StripeException(message);
}

return apiKey;
}
}
}
2 changes: 1 addition & 1 deletion src/Stripe.net/Services/_base/Service.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ protected Service()

protected Service(string apiKey)
{
this.ApiKey = apiKey;
this.ApiKey = StringUtils.ValidateApiKey(apiKey);
}

public string ApiKey { get; set; }
Expand Down
10 changes: 9 additions & 1 deletion src/Stripe.net/Services/_common/RequestOptions.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
namespace Stripe
{
using Stripe.Infrastructure;

public class RequestOptions
{
private string apiKey;

/// <summary>The API key to use for the request.</summary>
public string ApiKey { get; set; }
public string ApiKey
{
get => this.apiKey;
set => this.apiKey = StringUtils.ValidateApiKey(value);
}

/// <summary>Idempotency key for safely retrying requests.</summary>
public string IdempotencyKey { get; set; }
Expand Down
14 changes: 14 additions & 0 deletions src/StripeTests/Infrastructure/Public/StripeConfigurationTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace StripeTests
{
using Stripe;
using Xunit;

public class StripeConfigurationTest : BaseStripeTest
{
[Fact]
public void ApiKey_Set_ThrowsOnInvalidKey()
{
Assert.Throws<StripeException>(() => StripeConfiguration.ApiKey = "sk_test_123\n");
}
}
}
32 changes: 32 additions & 0 deletions src/StripeTests/Infrastructure/StringUtilsTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace StripeTests
{
using Stripe;
using Stripe.Infrastructure;
using Xunit;

Expand Down Expand Up @@ -48,5 +49,36 @@ public void SecureEquals()
StringUtils.SecureEquals(testCase.data.a, testCase.data.b));
}
}

[Fact]
public void ValidateApiKey()
{
var testCases = new[]
{
new { data = "sk_test_123", throws = false },
new { data = "sk_test_4eC39HqLyjWDarjtT1zdp7dc", throws = false },
new { data = "abc", throws = false },
new { data = string.Empty, throws = false },
new { data = (string)null, throws = false },
new { data = "sk_test_123\n", throws = true },
new { data = "\nsk_test_123", throws = true },
new { data = "sk_test_\n123", throws = true },
new { data = "sk_test_123 ", throws = true },
new { data = " sk_test_123", throws = true },
new { data = "sk_test_ 123", throws = true },
};

foreach (var testCase in testCases)
{
if (testCase.throws)
{
Assert.Throws<StripeException>(() => StringUtils.ValidateApiKey(testCase.data));
}
else
{
Assert.Equal(testCase.data, StringUtils.ValidateApiKey(testCase.data));
}
}
}
}
}
16 changes: 16 additions & 0 deletions src/StripeTests/Services/_base/ServiceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ namespace StripeTests

public class ServiceTest : BaseStripeTest
{
[Fact]
public void Ctor_ThrowsOnInvalidApiKey()
{
Assert.Throws<StripeException>(() => new TestService("sk_test_123\n"));
}

[Fact]
public void Get_ExpandProperties()
{
Expand Down Expand Up @@ -65,6 +71,16 @@ private class TestService : Service<TestEntity>,
IListable<TestEntity, ListOptions>,
IRetrievable<TestEntity>
{
public TestService()
: base(null)
{
}

public TestService(string apiKey)
: base(apiKey)
{
}

public override string BasePath => "/v1/test_entities";

public bool ExpandSimple { get; set; }
Expand Down
14 changes: 14 additions & 0 deletions src/StripeTests/Services/_common/RequestOptionsTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace StripeTests
{
using Stripe;
using Xunit;

public class RequestOptionsTest : BaseStripeTest
{
[Fact]
public void ApiKey_Set_ThrowsOnInvalidKey()
{
Assert.Throws<StripeException>(() => new RequestOptions { ApiKey = "sk_test_123\n" });
}
}
}

0 comments on commit 12506e3

Please sign in to comment.