6
6
use Assert \AssertionFailedException ;
7
7
use Funeralzone \ValueObjects \Scalars \StringTrait ;
8
8
use Illuminate \Support \Carbon ;
9
+ use Illuminate \Support \Str ;
9
10
use Osiset \ShopifyApp \Contracts \Objects \Values \SessionToken as SessionTokenValue ;
10
11
use Osiset \ShopifyApp \Contracts \Objects \Values \ShopDomain as ShopDomainValue ;
12
+ use Osiset \ShopifyApp \Objects \Enums \SessionTokenSource ;
11
13
use Osiset \ShopifyApp \Util ;
12
14
13
15
/**
@@ -129,6 +131,13 @@ final class SessionToken implements SessionTokenValue
129
131
*/
130
132
protected $ shopDomain ;
131
133
134
+ /**
135
+ * Shopify has multiple session tokens, slightly differing in format.
136
+ *
137
+ * @var string
138
+ */
139
+ protected $ tokenSource = SessionTokenSource::APP ;
140
+
132
141
/**
133
142
* Constructor.
134
143
*
@@ -167,32 +176,38 @@ protected function decodeToken(): void
167
176
$ this ->parts = explode ('. ' , $ this ->string );
168
177
$ body = json_decode (Util::base64UrlDecode ($ this ->parts [1 ]), true );
169
178
179
+ $ this ->tokenSource = $ this ->determineTokenSource ($ body );
180
+
170
181
// Confirm token is not malformed
171
182
Assert::thatAll ([
172
- $ body ['iss ' ],
173
183
$ body ['dest ' ],
174
184
$ body ['aud ' ],
175
- $ body ['sub ' ],
176
185
$ body ['exp ' ],
177
186
$ body ['nbf ' ],
178
187
$ body ['iat ' ],
179
188
$ body ['jti ' ],
180
- $ body ['sid ' ],
189
+ ... $ this ->tokenSource === SessionTokenSource::APP
190
+ ? [
191
+ $ body ['iss ' ],
192
+ $ body ['sub ' ],
193
+ $ body ['sid ' ],
194
+ ]
195
+ : [],
181
196
])->notNull (self ::EXCEPTION_MALFORMED );
182
197
183
198
// Format the values
184
- $ this ->iss = $ body ['iss ' ];
199
+ $ this ->iss = $ body ['iss ' ] ?? '' ;
185
200
$ this ->dest = $ body ['dest ' ];
186
201
$ this ->aud = $ body ['aud ' ];
187
- $ this ->sub = $ body ['sub ' ];
202
+ $ this ->sub = $ body ['sub ' ] ?? '' ;
188
203
$ this ->jti = $ body ['jti ' ];
189
- $ this ->sid = SessionId::fromNative ($ body ['sid ' ]);
204
+ $ this ->sid = SessionId::fromNative ($ body ['sid ' ] ?? '' );
190
205
$ this ->exp = new Carbon ($ body ['exp ' ]);
191
206
$ this ->nbf = new Carbon ($ body ['nbf ' ]);
192
207
$ this ->iat = new Carbon ($ body ['iat ' ]);
193
208
194
209
// Parse the shop domain from the destination
195
- $ host = parse_url ($ body ['dest ' ], PHP_URL_HOST );
210
+ $ host = $ this -> findHost ($ body ['dest ' ]);
196
211
$ this ->shopDomain = NullableShopDomain::fromNative ($ host );
197
212
}
198
213
@@ -357,7 +372,10 @@ protected function verifySignature(): void
357
372
*/
358
373
protected function verifyValidity (): void
359
374
{
360
- Assert::that ($ this ->iss )->contains ($ this ->dest , self ::EXCEPTION_INVALID );
375
+ if ($ this ->tokenSource === SessionTokenSource::APP ) {
376
+ Assert::that ($ this ->iss )->contains ($ this ->dest , self ::EXCEPTION_INVALID );
377
+ }
378
+
361
379
Assert::that ($ this ->aud )->eq (Util::getShopifyConfig ('api_key ' , $ this ->getShopDomain ()), self ::EXCEPTION_INVALID );
362
380
}
363
381
@@ -377,4 +395,20 @@ protected function verifyExpiration(): void
377
395
$ now ->lessThan ($ this ->getLeewayIssuedAt ()),
378
396
])->false (self ::EXCEPTION_EXPIRED );
379
397
}
398
+
399
+ protected function determineTokenSource (array $ body ): int
400
+ {
401
+ if (!isset ($ body ['iss ' ]) && !isset ($ body ['sid ' ])) {
402
+ return SessionTokenSource::CHECKOUT_EXTENSION ;
403
+ }
404
+
405
+ return SessionTokenSource::APP ;
406
+ }
407
+
408
+ protected function findHost (string $ destination ): ?string
409
+ {
410
+ return Str::startsWith ($ destination , 'https ' )
411
+ ? parse_url ($ destination , PHP_URL_HOST )
412
+ : $ destination ;
413
+ }
380
414
}
0 commit comments