Skip to content

Commit 3d5b478

Browse files
author
Tyler King
authored
bugfix/593 (gnikyt#732)
* Fix for issue gnikyt#742 * AuthShopify middleware: moved implode of data sources to own function * AuthShopify middleware: implode of data sources now handles array and nested arrays * SyleCI fix * Ignore data if no HMAC in AuthShopify middleware
1 parent f9cc5ba commit 3d5b478

File tree

1 file changed

+79
-32
lines changed

1 file changed

+79
-32
lines changed

src/ShopifyApp/Http/Middleware/AuthShopify.php

Lines changed: 79 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
use Closure;
66
use Illuminate\Http\RedirectResponse;
77
use Illuminate\Http\Request;
8-
use Illuminate\Support\Facades\Auth;
9-
use Illuminate\Support\Facades\Log;
108
use Illuminate\Support\Facades\Redirect;
119
use Illuminate\Support\Facades\Session;
1210
use Osiset\ShopifyApp\Contracts\ApiHelper as IApiHelper;
@@ -68,7 +66,7 @@ public function __construct(IApiHelper $apiHelper, ShopSession $shopSession)
6866
public function handle(Request $request, Closure $next)
6967
{
7068
// Grab the domain and check the HMAC (if present)
71-
$domain = $this->getShopDomainFromData($request);
69+
$domain = $this->getShopDomainFromRequest($request);
7270
$hmac = $this->verifyHmac($request);
7371

7472
$checks = [];
@@ -230,6 +228,51 @@ private function getHmac(Request $request): ?array
230228
return null;
231229
}
232230

231+
/**
232+
* Grab the shop, if present, and how it was found.
233+
* Order of precedence is:.
234+
*
235+
* - GET/POST Variable
236+
* - Headers
237+
* - Referer
238+
*
239+
* @param Request $request The request object.
240+
*
241+
* @return ShopDomainValue
242+
*/
243+
private function getShopDomainFromRequest(Request $request): ShopDomainValue
244+
{
245+
// All possible methods
246+
$options = [
247+
// GET/POST
248+
DataSource::INPUT()->toNative() => $request->input('shop'),
249+
// Headers
250+
DataSource::HEADER()->toNative() => $request->header('X-Shop-Domain'),
251+
// Headers: Referer
252+
DataSource::REFERER()->toNative() => function () use ($request): ?string {
253+
$url = parse_url($request->header('referer'), PHP_URL_QUERY);
254+
parse_str($url, $refererQueryParams);
255+
if (! $refererQueryParams || ! isset($refererQueryParams['shop'])) {
256+
return null;
257+
}
258+
259+
return $refererQueryParams['shop'];
260+
},
261+
];
262+
263+
// Loop through each until we find the HMAC
264+
foreach ($options as $method => $value) {
265+
$result = is_callable($value) ? $value() : $value;
266+
if ($result !== null) {
267+
// Found a shop
268+
return ShopDomain::fromNative($result);
269+
}
270+
}
271+
272+
// No shop domain found in any source
273+
return NullShopDomain::fromNative(null);
274+
}
275+
233276
/**
234277
* Grab the data.
235278
*
@@ -247,7 +290,7 @@ private function getData(Request $request, string $source): array
247290
// Verify
248291
$verify = [];
249292
foreach ($request->query() as $key => $value) {
250-
$verify[$key] = is_array($value) ? '["'.implode('", "', $value).'"]' : $value;
293+
$verify[$key] = $this->parseDataSourceValue($value);
251294
}
252295

253296
return $verify;
@@ -274,7 +317,7 @@ private function getData(Request $request, string $source): array
274317

275318
foreach (compact('code', 'locale', 'state', 'id', 'ids') as $key => $value) {
276319
if ($value) {
277-
$verify[$key] = is_array($value) ? '["'.implode('", "', $value).'"]' : $value;
320+
$verify[$key] = $this->parseDataSourceValue($value);
278321
}
279322
}
280323

@@ -288,7 +331,7 @@ private function getData(Request $request, string $source): array
288331
// Verify
289332
$verify = [];
290333
foreach ($refererQueryParams as $key => $value) {
291-
$verify[$key] = is_array($value) ? '["'.implode('", "', $value).'"]' : $value;
334+
$verify[$key] = $this->parseDataSourceValue($value);
292335
}
293336

294337
return $verify;
@@ -298,32 +341,6 @@ private function getData(Request $request, string $source): array
298341
return $options[$source]();
299342
}
300343

301-
/**
302-
* Gets the shop domain from the data.
303-
*
304-
* @param Request $request The request object.
305-
*
306-
* @return ShopDomainValue
307-
*/
308-
private function getShopDomainFromData(Request $request): ShopDomainValue
309-
{
310-
$options = [
311-
DataSource::INPUT()->toNative(),
312-
DataSource::HEADER()->toNative(),
313-
DataSource::REFERER()->toNative(),
314-
];
315-
foreach ($options as $option) {
316-
$result = $this->getData($request, $option);
317-
if (isset($result['shop'])) {
318-
// Found a shop
319-
return ShopDomain::fromNative($result['shop']);
320-
}
321-
}
322-
323-
// No shop domain found in any source
324-
return NullShopDomain::fromNative(null);
325-
}
326-
327344
/**
328345
* Handle bad verification by killing the session and redirecting to auth.
329346
*
@@ -353,4 +370,34 @@ private function handleBadVerification(Request $request, ShopDomainValue $domain
353370
['shop' => $domain->toNative()]
354371
);
355372
}
373+
374+
/**
375+
* Parse the data source value.
376+
* Handle simple key/values, arrays, and nested arrays.
377+
*
378+
* @param mixed $value
379+
*
380+
* @return string
381+
*/
382+
private function parseDataSourceValue($value): string
383+
{
384+
/**
385+
* Format the value.
386+
*
387+
* @param mixed $val
388+
*
389+
* @return string
390+
*/
391+
$formatValue = function ($val): string {
392+
return is_array($val) ? '["'.implode('", "', $val).'"]' : $val;
393+
};
394+
395+
// Nested array
396+
if (is_array($value) && is_array(current($value))) {
397+
return implode(', ', array_map($formatValue, $value));
398+
}
399+
400+
// Array or basic value
401+
return $formatValue($value);
402+
}
356403
}

0 commit comments

Comments
 (0)