Skip to content

Commit 47e3e08

Browse files
Merge pull request #12 from Shape-and-Shift/feature/add-app-id
V2.0 Drop primary key from `shop_id` of `sw_shop` and Add `app_id` as primary key
2 parents 8021126 + 4ea4ff7 commit 47e3e08

11 files changed

+93
-53
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
### 2.0.0
2+
- Drop primary key from `shop_id` of `sw_shop`
3+
- Add `app_id` as primary in `sw_shop`
4+
- Change behavior of middleware (using `app_name` and `app_id`)
5+
16
### 1.3.2
27
- Add get middleware for Iframe
38

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ Your app is now ready to install by a Shopware application!
4747
## Usage
4848
- Context, ShopRepository auto-binding
4949
- SwAppMiddleware _(alias: 'sas.app.auth')_: A middleware to verify incoming webhook requests
50-
- SwAppIframeMiddleware _(alias: 'sas.app.auth.iframe')_: A middleware to verify incoming requests from Iframe Shopware
50+
- SwAppIframeMiddleware _(alias: 'sas.app.auth.iframe:?app_name')_: A middleware to verify incoming requests from Iframe Shopware (`app_name` is the name of the App)
51+
- SwAppHeaderMiddleware _(alias: 'sas.app.auth.header')_: A middleware to verify incoming requests from Headers requests
5152

5253
## Change log
5354
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "sas/shopware-laravel-sdk",
33
"description": "Shopware SDK for Laravel 8",
44
"type": "library",
5-
"version": "1.3.2",
5+
"version": "2.0.0",
66
"require": {
77
"php": "^7.4 || ^8.0",
88
"ext-json": "*",

src/Http/Middleware/SwAppHeaderMiddleware.php

+11-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Illuminate\Support\Facades\Auth;
88
use Sas\ShopwareLaravelSdk\Models\SwShop;
99
use Sas\ShopwareLaravelSdk\Repositories\ShopRepository;
10+
use Sas\ShopwareLaravelSdk\Utils\AppHelper;
1011
use Symfony\Component\HttpFoundation\HeaderBag;
1112
use Vin\ShopwareSdk\Data\Webhook\ShopRequest;
1213
use Vin\ShopwareSdk\Exception\AuthorizationFailedException;
@@ -27,11 +28,10 @@ public function __construct(ShopRepository $shopRepository)
2728
*
2829
* @param Request $request
2930
* @param Closure $next
30-
* @param string|null ...$guards
3131
* @return mixed
3232
* @throws AuthorizationFailedException
3333
*/
34-
public function handle(Request $request, Closure $next, ...$guards)
34+
public function handle(Request $request, Closure $next)
3535
{
3636
$shop = $this->authenticateHeaderRequest($request);
3737

@@ -44,8 +44,12 @@ protected function authenticateHeaderRequest(Request $request): SwShop
4444
{
4545
$headers = $request->headers;
4646
$shopId = $headers->get(ShopRequest::SHOP_ID_REQUEST_PARAMETER);
47+
$appId = $headers->get(AppHelper::APP_ID_REQUEST_PARAMETER);
48+
if ($headers->has(AppHelper::APP_ID_REQUEST_PARAMETER) && empty($appId)) {
49+
throw new AuthorizationFailedException(sprintf('%s in headers is invalid', AppHelper::APP_ID_REQUEST_PARAMETER));
50+
}
4751

48-
$shop = $this->shopRepository->getShopById($shopId);
52+
$shop = $this->shopRepository->getShopById($shopId, ['app_id' => $appId]);
4953

5054
$authenticated = $shop && $this->checkHeaderRequests($headers, $shop);
5155

@@ -60,12 +64,12 @@ protected function checkHeaderRequests(HeaderBag $headers, SwShop $shop): bool
6064
{
6165
$queries = [];
6266

63-
if ($headers->has('location-id')) {
64-
$queries['location-id'] = $headers->get('location-id');
67+
if ($headers->has(AppHelper::LOCATION_ID_REQUEST_PARAMETER)) {
68+
$queries[AppHelper::LOCATION_ID_REQUEST_PARAMETER] = $headers->get(AppHelper::LOCATION_ID_REQUEST_PARAMETER);
6569
}
6670

67-
if ($headers->has('privileges')) {
68-
$queries['privileges'] = urlencode((string)$headers->get('privileges'));
71+
if ($headers->has(AppHelper::PRIVILEGES_REQUEST_PARAMETER)) {
72+
$queries[AppHelper::PRIVILEGES_REQUEST_PARAMETER] = urlencode((string)$headers->get(AppHelper::PRIVILEGES_REQUEST_PARAMETER));
6973
}
7074

7175
if ($headers->has(ShopRequest::SHOP_ID_REQUEST_PARAMETER)) {

src/Http/Middleware/SwAppIframeMiddleware.php

+20-21
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Http\Request;
66
use Sas\ShopwareLaravelSdk\Models\SwShop;
7+
use Sas\ShopwareLaravelSdk\Utils\AppHelper;
78
use Symfony\Component\HttpFoundation\InputBag;
89
use Vin\ShopwareSdk\Data\Webhook\ShopRequest;
910
use Vin\ShopwareSdk\Exception\AuthorizationFailedException;
@@ -18,10 +19,24 @@ protected function authenticatePostRequest(Request $request): SwShop
1819
$sourceRequest = $requestContent['source'];
1920
$shopId = $sourceRequest[ShopRequest::SHOP_ID_REQUEST_PARAMETER];
2021

21-
$shop = $this->shopRepository->getShopById($shopId);
22+
$shop = $this->shopRepository->getShopById($shopId, ['app_name' => $this->appName]);
2223

2324
$authenticated = $shop && $this->checkPostRequest($sourceRequest, $shop->shop_secret);
25+
if (!$authenticated) {
26+
throw new AuthorizationFailedException($request->getMethod() . ' is not supported or the data is invalid');
27+
}
28+
29+
return $shop;
30+
}
31+
32+
protected function authenticateGetRequest(Request $request): SwShop
33+
{
34+
$queries = $request->query;
35+
$shopId = (string)$queries->get(ShopRequest::SHOP_ID_REQUEST_PARAMETER);
2436

37+
$shop = $this->shopRepository->getShopById($shopId, ['app_name' => $this->appName]);
38+
39+
$authenticated = $shop && $this->checkGetRequests($queries, $shop);
2540
if (!$authenticated) {
2641
throw new AuthorizationFailedException($request->getMethod() . ' is not supported or the data is invalid');
2742
}
@@ -50,32 +65,16 @@ private function checkPostRequest(array $sourceRequests, string $shopSecret): bo
5065
return hash_equals($hmac, $shopwareShopSignature);
5166
}
5267

53-
protected function authenticateGetRequest(Request $request): SwShop
54-
{
55-
$queries = $request->query;
56-
$shopId = (string)$queries->get(ShopRequest::SHOP_ID_REQUEST_PARAMETER);
57-
58-
$shop = $this->shopRepository->getShopById($shopId);
59-
60-
$authenticated = $shop && $this->checkGetRequests($queries, $shop);
61-
62-
if (!$authenticated) {
63-
throw new AuthorizationFailedException($request->getMethod() . ' is not supported or the data is invalid');
64-
}
65-
66-
return $shop;
67-
}
68-
6968
protected function checkGetRequests(InputBag $inputBag, SwShop $shop): bool
7069
{
7170
$queries = [];
7271

73-
if ($inputBag->has('location-id')) {
74-
$queries['location-id'] = $inputBag->get('location-id');
72+
if ($inputBag->has(AppHelper::LOCATION_ID_REQUEST_PARAMETER)) {
73+
$queries[AppHelper::LOCATION_ID_REQUEST_PARAMETER] = $inputBag->get(AppHelper::LOCATION_ID_REQUEST_PARAMETER);
7574
}
7675

77-
if ($inputBag->has('privileges')) {
78-
$queries['privileges'] = urlencode((string)$inputBag->get('privileges'));
76+
if ($inputBag->has(AppHelper::PRIVILEGES_REQUEST_PARAMETER)) {
77+
$queries[AppHelper::PRIVILEGES_REQUEST_PARAMETER] = urlencode((string)$inputBag->get(AppHelper::PRIVILEGES_REQUEST_PARAMETER));
7978
}
8079

8180
if ($inputBag->has(ShopRequest::SHOP_ID_REQUEST_PARAMETER)) {

src/Http/Middleware/SwAppMiddleware.php

+5-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
class SwAppMiddleware
1515
{
16+
protected ?string $appName = null;
17+
1618
public const REQUIRED_KEYS = [
1719
ShopRequest::SHOP_ID_REQUEST_PARAMETER,
1820
ShopRequest::SHOP_URL_REQUEST_PARAMETER,
@@ -33,12 +35,13 @@ public function __construct(ShopRepository $shopRepository)
3335
*
3436
* @param Request $request
3537
* @param Closure $next
36-
* @param string|null ...$guards
38+
* @param ?string $appName
3739
* @return mixed
3840
* @throws AuthorizationFailedException
3941
*/
40-
public function handle(Request $request, Closure $next, ...$guards)
42+
public function handle(Request $request, Closure $next, ?string $appName)
4143
{
44+
$this->appName = $appName;
4245
$shop = null;
4346

4447
if ($request->getMethod() === 'POST' && $this->supportsPostRequest($request)) {

src/Models/SwShop.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
use Vin\ShopwareSdk\Data\AccessToken;
99

1010
/**
11+
* @property string $app_id
1112
* @property string $shop_id
1213
* @property string $shop_url
14+
* @property string $shop_name
1315
* @property string $shop_secret
1416
* @property string $api_key
1517
* @property string $secret_key
@@ -28,7 +30,7 @@ class SwShop extends Model implements AuthenticatableContract
2830
*/
2931
protected $table = 'sw_shops';
3032

31-
protected $primaryKey = 'shop_id';
33+
protected $primaryKey = 'app_id';
3234

3335
protected $keyType = 'string';
3436

src/Repositories/ShopRepository.php

+32-16
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Exception;
66
use Illuminate\Database\Eloquent\Model;
7+
use Ramsey\Uuid\Uuid;
78
use Sas\ShopwareLaravelSdk\Models\SwShop;
89
use Vin\ShopwareSdk\Client\AdminAuthenticator;
910
use Vin\ShopwareSdk\Client\GrantType\ClientCredentialsGrantType;
@@ -36,18 +37,24 @@ public function updateAccessKeysForShop(string $shopId, string $apiKey, string $
3637
]);
3738
}
3839

39-
public function createShop(Shop $shop): void
40+
public function createShop(Shop $shop, array $condition = [], array $update = []): void
4041
{
41-
$this->shopModel->updateOrCreate(['shop_id' => $shop->getShopId()], [
42-
'shop_url' => $shop->getShopUrl(),
43-
'shop_secret' => $shop->getShopSecret(),
44-
'access_token' => null,
45-
'api_key' => null,
46-
'secret_key' => null
47-
]);
42+
$this->shopModel->updateOrCreate(
43+
array_merge([
44+
'shop_id' => $shop->getShopId()
45+
], $condition),
46+
array_merge([
47+
'app_id' => Uuid::uuid4()->toString(),
48+
'shop_url' => $shop->getShopUrl(),
49+
'shop_secret' => $shop->getShopSecret(),
50+
'access_token' => null,
51+
'api_key' => null,
52+
'secret_key' => null
53+
], $update)
54+
);
4855
}
4956

50-
public function getShopById(?string $shopId): ?SwShop
57+
public function getShopById(?string $shopId, array $queries = []): ?SwShop
5158
{
5259
if (!$shopId) {
5360
return null;
@@ -57,26 +64,35 @@ public function getShopById(?string $shopId): ?SwShop
5764
return $this->shops[$shopId];
5865
}
5966

60-
$shop = $this->shopModel->find($shopId);
67+
$query = $this->shopModel->where('shop_id', $shopId);
68+
foreach ($queries as $column => $value) {
69+
if (empty($value) || empty($column)) {
70+
continue;
71+
}
72+
73+
$query = $query->where($column, $value);
74+
}
75+
76+
$shop = $query->first();
6177
if (!$shop) {
6278
return null;
6379
}
6480

6581
return $this->shops[$shopId] = $shop;
6682
}
6783

68-
public function removeShop(string $shopId): void
84+
public function removeShop(string $shopId, array $queries = []): void
6985
{
70-
$shop = $this->getShopById($shopId);
86+
$shop = $this->getShopById($shopId, $queries);
7187

7288
$shop->delete();
7389

7490
unset($this->shops[$shopId]);
7591
}
7692

77-
public function getSecretByShopId(string $shopId): string
93+
public function getSecretByShopId(string $shopId, array $queries = []): string
7894
{
79-
$shop = $this->getShopById($shopId);
95+
$shop = $this->getShopById($shopId, $queries);
8096

8197
if (!$shop) {
8298
throw new Exception('Shop not found');
@@ -85,9 +101,9 @@ public function getSecretByShopId(string $shopId): string
85101
return $shop->shop_secret;
86102
}
87103

88-
public function getShopContext(string $shopId): Context
104+
public function getShopContext(string $shopId, array $queries = []): Context
89105
{
90-
$shop = $this->getShopById($shopId);
106+
$shop = $this->getShopById($shopId, $queries);
91107
if (!$shop) {
92108
throw new Exception('Shop not found');
93109
}

src/ServiceProvider/ContextServiceProvider.php

+7-3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
namespace Sas\ShopwareLaravelSdk\ServiceProvider;
44

5+
use Sas\ShopwareLaravelSdk\Utils\AppHelper;
56
use Vin\ShopwareSdk\Data\Webhook\ShopRequest;
67
use Sas\ShopwareLaravelSdk\Models\SwShop;
78
use Illuminate\Contracts\Support\DeferrableProvider;
8-
use Illuminate\Foundation\Application;
9+
use Illuminate\Contracts\Foundation\Application;
910
use Symfony\Component\HttpFoundation\Request;
1011
use Illuminate\Support\ServiceProvider;
1112
use Sas\ShopwareLaravelSdk\Repositories\ShopRepository;
@@ -36,20 +37,23 @@ public function register(): void
3637

3738
if ($request->headers->has(ShopRequest::SHOP_ID_REQUEST_PARAMETER)) {
3839
$shopId = $request->headers->get(ShopRequest::SHOP_ID_REQUEST_PARAMETER);
40+
$appId = (string) $request->headers->get(AppHelper::APP_ID_REQUEST_PARAMETER);
3941
} else {
4042
if ($request->getMethod() === 'POST') {
4143
$requestContent = \json_decode($request->getContent(), true);
4244
$shopId = $requestContent['source']['shopId'];
4345
} else {
4446
$shopId = $request->query->get(ShopRequest::SHOP_ID_REQUEST_PARAMETER);
4547
}
48+
49+
$appId = (string)$request->query->get(AppHelper::APP_ID_REQUEST_PARAMETER);
4650
}
4751

4852
if (!$shopId) {
4953
return null;
5054
}
5155

52-
return $shopRepository->getShopContext($shopId);
56+
return $shopRepository->getShopContext($shopId, ['app_id' => $appId]);
5357
});
5458

5559
$this->app->singleton(AppAction::class, function (Application $app) {
@@ -83,7 +87,7 @@ public function register(): void
8387
*
8488
* @return array
8589
*/
86-
public function provides()
90+
public function provides(): array
8791
{
8892
return [Context::class, AppAction::class, ShopRepository::class, Event::class, IFrameRequest::class];
8993
}

src/Utils/AppHelper.php

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111

1212
class AppHelper
1313
{
14+
const PRIVILEGES_REQUEST_PARAMETER = 'privileges';
15+
const LOCATION_ID_REQUEST_PARAMETER = 'location-id';
16+
const APP_ID_REQUEST_PARAMETER = 'app-id';
17+
1418
private Request $request;
1519

1620
public function __construct(Request $request)

src/database/migrations/2021_07_16_161755_create_sw_shops_table.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ class CreateSwShopsTable extends Migration
1515
public function up(): void
1616
{
1717
Schema::create('sw_shops', function (Blueprint $table): void {
18-
$table->string('shop_id')->primary();
18+
$table->string('app_id')->primary();
19+
$table->string('shop_id');
1920
$table->string('shop_url', 255);
2021
$table->string('shop_secret', 255);
22+
$table->string('app_name', 255)->nullable();
2123
$table->string('api_key', 255)->nullable();
2224
$table->string('secret_key', 255)->nullable();
2325
$table->longText('access_token')->nullable();

0 commit comments

Comments
 (0)