Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ jobs:
- name: Test
env:
SHOPIFYNET_SHOP_ID: ${{ secrets.SHOPIFYNET_SHOP_ID }}
SHOPIFYNET_SHOP_TOKEN: ${{ secrets.SHOPIFYNET_SHOP_TOKEN }}
SHOPIFYNET_CLIENT_ID: ${{ secrets.SHOPIFYNET_CLIENT_ID }}
SHOPIFYNET_KEY_ID: ${{ secrets.SHOPIFYNET_KEY_ID }}
SHOPIFYNET_PRIVATE_KEY: ${{ secrets.SHOPIFYNET_PRIVATE_KEY }}
run: dotnet test --no-restore --verbosity normal

- name: Publish to nuget
Expand Down
12 changes: 10 additions & 2 deletions ShopifyNet.Tests/ShopifyClientAssertionAccessTokenRequestTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,15 @@ public async Task RejectsPublicOnlyKeysBeforeSending(string algorithm)
using AsymmetricAlgorithm key = algorithm == "ES256" ? ECDsa.Create(ECCurve.NamedCurves.nistP256) : RSA.Create(2048);
using var http = new TestHttpClient(_ => throw new AssertFailedException("Public-only key must not be sent."));
var client = new ShopifyOAuthClient("client-id", string.Empty, http);
await Assert.ThrowsExceptionAsync<CryptographicException>(() => client.RequestClientAssertionAccessTokenAsync(
"test.myshopify.com", "key", key.ExportSubjectPublicKeyInfoPem()));
try
{
await client.RequestClientAssertionAccessTokenAsync(
"test.myshopify.com", "key", key.ExportSubjectPublicKeyInfoPem());
Assert.Fail("A public-only key must fail signing.");
}
catch (CryptographicException)
{
// Accept platform-specific subclasses, including OpenSSL exceptions on Linux.
}
}
}
11 changes: 9 additions & 2 deletions ShopifyNet.Tests/ShopifyClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@ namespace ShopifyNet.Tests;
[TestClass]
public class ShopifyClientTests
{
private static string _accessToken;
private ShopifyClient _client;

[ClassInitialize]
public static async Task InitializeClass(TestContext context)
{
_accessToken = await TestHelper.GetAccessTokenAsync();
}

[TestInitialize]
public void Initialize()
{
Expand All @@ -18,7 +25,7 @@ public void Initialize()

private static ShopifyClientOptions GetClientOptions(bool throwOnGraphQLErrors = true, bool requestDetailedQueryCost = false)
{
return new ShopifyClientOptions(TestHelper.ShopId, TestHelper.Token)
return new ShopifyClientOptions(TestHelper.ShopId, _accessToken)
{
Interceptor = NoOpInterceptor<ShopifyGraphQLRequest, ShopifyClientOptions>.Instance,
ThrowOnGraphQLErrors = throwOnGraphQLErrors,
Expand Down Expand Up @@ -301,4 +308,4 @@ SYNTAX ERROR!!!
Assert.IsNotNull(response.errors);
Assert.IsTrue(response.errors.Count > 0);
}
}
}
16 changes: 13 additions & 3 deletions ShopifyNet.Tests/TestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ public class TestHelper
{
public static string ShopId => Environment.GetEnvironmentVariable("SHOPIFYNET_SHOP_ID", EnvironmentVariableTarget.User) ??
Environment.GetEnvironmentVariable("SHOPIFYNET_SHOP_ID");
public static string Token => Environment.GetEnvironmentVariable("SHOPIFYNET_SHOP_TOKEN", EnvironmentVariableTarget.User) ??
Environment.GetEnvironmentVariable("SHOPIFYNET_SHOP_TOKEN");
}
public static string ClientId => Environment.GetEnvironmentVariable("SHOPIFYNET_CLIENT_ID", EnvironmentVariableTarget.User) ??
Environment.GetEnvironmentVariable("SHOPIFYNET_CLIENT_ID");
public static string PrivateKey => Environment.GetEnvironmentVariable("SHOPIFYNET_PRIVATE_KEY", EnvironmentVariableTarget.User) ??
Environment.GetEnvironmentVariable("SHOPIFYNET_PRIVATE_KEY");
public static string KeyId => Environment.GetEnvironmentVariable("SHOPIFYNET_KEY_ID", EnvironmentVariableTarget.User) ??
Environment.GetEnvironmentVariable("SHOPIFYNET_KEY_ID");
public static async Task<string> GetAccessTokenAsync()
{
var oauthClient = new ShopifyOAuthClient(ClientId, null);
var token = await oauthClient.RequestClientAssertionAccessTokenAsync(ShopId, KeyId, PrivateKey);
return token.access_token;
}
}
23 changes: 10 additions & 13 deletions ShopifyNet.Tests/TokenBucket/TokenBucketInterceptorTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Net;
using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using GraphQLSharp;
Expand All @@ -14,21 +14,18 @@ public class TokenBucketInterceptorTests

private ShopifyClientOptions CreateClientOptions(HttpStatusCode status, object response, IInterceptor<ShopifyGraphQLRequest, ShopifyClientOptions> interceptor, bool throwOnGraphQLErrors = true)
{
return new ShopifyClientOptions(TestHelper.ShopId, TestHelper.Token)
var httpClient = new TestHttpClient(_ => new HttpResponseMessage
{
Interceptor = interceptor,
ThrowOnGraphQLErrors = throwOnGraphQLErrors,
HttpClient = new TestHttpClient(msg => new HttpResponseMessage
{
StatusCode = status,
Content = JsonContent.Create(response)
})
};
StatusCode = status,
Content = JsonContent.Create(response)
});

return CreateClientOptions(httpClient, interceptor, throwOnGraphQLErrors);
}

private ShopifyClientOptions CreateClientOptions(HttpClient httpClient, IInterceptor<ShopifyGraphQLRequest, ShopifyClientOptions> interceptor, bool throwOnGraphQLErrors = true)
{
return new ShopifyClientOptions(TestHelper.ShopId, TestHelper.Token)
return new ShopifyClientOptions("test.myshopify.com", "test-token")
{
Interceptor = interceptor,
ThrowOnGraphQLErrors = throwOnGraphQLErrors,
Expand Down Expand Up @@ -270,7 +267,7 @@ public async Task ShouldProcessInPriorityOrder()
int cost = 962;
int priority = 0;
var interceptor = new TokenBucketInterceptor(r => priority);
var options = new ShopifyClientOptions(TestHelper.ShopId, TestHelper.Token)
var options = new ShopifyClientOptions(TestHelper.ShopId, await TestHelper.GetAccessTokenAsync())
{
Interceptor = interceptor,
};
Expand All @@ -292,4 +289,4 @@ public async Task ShouldProcessInPriorityOrder()
var responsesByPriority = responses.OrderBy(i => i.reqPriority).ToArray();
Assert.IsTrue(responsesByPriority.SequenceEqual(responsesByElapsed));
}
}
}
15 changes: 11 additions & 4 deletions ShopifyNet.TypeGenerator/TypeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@
var generator = new GraphQLTypeGenerator();
string csharpCode = await generator.GenerateTypesAsync(options, async query =>
{
string shopId = Environment.GetEnvironmentVariable("SHOPIFYNET_SHOP_ID", EnvironmentVariableTarget.User)!;
string token = Environment.GetEnvironmentVariable("SHOPIFYNET_SHOP_TOKEN", EnvironmentVariableTarget.User)!;
string shopId = GetRequiredEnvironmentVariable("SHOPIFYNET_SHOP_ID");
var oauthClient = new ShopifyOAuthClient(GetRequiredEnvironmentVariable("SHOPIFYNET_CLIENT_ID"), null);
var token = await oauthClient.RequestClientAssertionAccessTokenAsync(shopId,
GetRequiredEnvironmentVariable("SHOPIFYNET_KEY_ID"), GetRequiredEnvironmentVariable("SHOPIFYNET_PRIVATE_KEY"));

var shopifyOptions = new ShopifyClientOptions(shopId, token) as IGraphQLClientOptions<ShopifyClientOptions, ShopifyGraphQLRequest>;
var shopifyOptions = new ShopifyClientOptions(shopId, token.access_token) as IGraphQLClientOptions<ShopifyClientOptions, ShopifyGraphQLRequest>;

var options = new GraphQLClientOptions(shopifyOptions.Uri)
{
Expand All @@ -57,4 +59,9 @@

File.WriteAllText($@"{GetDir()}/../ShopifyNet/Generated.cs", csharpCode);

static string GetDir([CallerFilePath] string filePath = "") => Path.GetDirectoryName(filePath)!;
static string GetDir([CallerFilePath] string filePath = "") => Path.GetDirectoryName(filePath)!;

static string GetRequiredEnvironmentVariable(string name) =>
Environment.GetEnvironmentVariable(name) ??
Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.User) ??
throw new InvalidOperationException($"Set {name} before running the type generator.");
10 changes: 9 additions & 1 deletion ShopifyNet/OAuth/ShopifyOAuthClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ public class ShopifyOAuthClient
public ShopifyOAuthClient(string clientId, string clientSecret, HttpClient httpClient = null)
{
_clientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
_clientSecret = clientSecret ?? throw new ArgumentNullException(nameof(clientSecret));
// The client secret can be null for certain flows, such as client assertion.
_clientSecret = clientSecret;
_httpClient = httpClient ?? _defaultHttpClient;
}

Expand Down Expand Up @@ -113,6 +114,9 @@ public static bool IsValidShopDomain(string myShopifyDomain)
/// </summary>
public bool IsValidHmac(IEnumerable<KeyValuePair<string, string>> queryParameters)
{
if (_clientSecret == null)
throw new ArgumentNullException(nameof(_clientSecret));

if (queryParameters == null)
return false;

Expand Down Expand Up @@ -389,7 +393,11 @@ private async Task<T> RequestAccessTokenAsync<T>(string myShopifyDomain, Diction

parameters[CLIENT_ID_KEY] = _clientId;
if (includeClientSecret)
{
if (_clientSecret == null)
throw new ArgumentNullException(nameof(_clientSecret));
parameters[CLIENT_SECRET_KEY] = _clientSecret;
}

using var request = new HttpRequestMessage(HttpMethod.Post, $"https://{myShopifyDomain}/admin/oauth/access_token")
{
Expand Down
2 changes: 1 addition & 1 deletion ShopifyNet/ShopifyNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<PackageProjectUrl>https://github.com/Wish-Org/ShopifyNet</PackageProjectUrl>
<RepositoryUrl>https://github.com/Wish-Org/ShopifyNet</RepositoryUrl>
<Description>.NET utilities for Shopify GraphQL</Description>
<Version>2.19.0</Version>
<Version>2.20.0</Version>
<PackageTags>shopify graphql types classes schema generator strongly typed</PackageTags>

<!-- Ensure the XML doc file is generated -->
Expand Down
Loading