ShopifySharp
ShopifySharp copied to clipboard
Validates web requests fails for bulk admin actions
Shopify admin has the option to add bulk action links in orders/products/customers... pages. For these cases the request query string looks like this:
hmac=XXXXXX&ids%5B%5D=2074861961283&ids%5B%5D=2074861830211&locale=en&shop=YYYYYYYYYYY×tamp=1552479578
These requests are not well documented in Shopify documentation, but as it is explained here https://community.shopify.com/c/Shopify-APIs-SDKs/Hmac-weirdness-when-working-with-Shop-admin-links-gt-Products/m-p/293628#M14200 , the query string used for hmac calculation looks like this
ids=["2074861961283", "2074861830211"]&locale=en&shop=YYYYYYYYYYY×tamp=1552479578
Adding this code at the beggining of PrepareQueryString within AuthorizationService.cs fix the validation for these cases:
private static string PrepareQuerystring(IEnumerable<KeyValuePair<string, StringValues>> querystring, string joinWith)
{
if (string.IsNullOrEmpty(querystring.FirstOrDefault(kvp => kvp.Key == "ids").Value))
{
var ids = string.Join(", ", querystring.FirstOrDefault(kvp => kvp.Key == "ids[]").Value.Select(id => $"\"{id}\""));
querystring = querystring.Concat(new[] { new KeyValuePair<string, StringValues>("ids", $"[{ids}]") });
querystring = querystring.Where(x => x.Key != "ids[]");
}
var kvps = querystring.Select(kvp => new
....
I want to make a PR to handle this case, but I don't have the API key used in tests to create similar ones. I could create it anyway but then someone should fix it:
[Fact]
public void Validates_Web_Bulk_Links_Requests()
{
// hmac=XXX&ids[]=2065145364547&ids[]=2065146314819&locale=en&shop=YYY×tamp=1551874047
var qs = new Dictionary<string, StringValues>()
{
{"hmac", "XXX"},
{"ids[]", new StringValues(new[] {"2065145364547", "2065146314819" }) },
{"locale", "en"},
{"shop", "YYY"},
{"timestamp", "1551874047"},
};
bool isValid = AuthorizationService.IsAuthenticRequest(qs, Utils.SecretKey);
Assert.True(isValid);
}
Thanks for the report! I'm actually a bit surprised that this isn't working for you, I'm pretty sure it's working for my own apps with admin actions. I'll try to get a unit test for this using the correct API key.