@@ -23,44 +23,78 @@ class Request implements Requestable
23
23
/**
24
24
* @var string
25
25
*/
26
- protected $ apiKey = '' ;
27
-
26
+ protected $ apiKey ;
27
+ /**
28
+ * @var string
29
+ */
30
+ private $ apiSecret = '' ;
31
+ /**
32
+ * @var string
33
+ */
34
+ private $ encryptionMethod = '' ;
35
+ /**
36
+ * @var string
37
+ */
38
+ private $ encryptionPassword = '' ;
28
39
/**
29
40
* Request constructor.
30
41
*
31
42
* @param $apiKey
32
43
*/
33
44
function __construct ($ apiKey )
34
45
{
35
- $ this ->apiKey = $ apiKey ;
46
+ $ apiSecret = '' ;
47
+ $ encryptionMethod = '' ;
48
+ $ encryptionPassword = '' ;
49
+ $ asApiKey =$ apiKey ;
50
+
51
+ if (is_array ($ apiKey )) {
52
+ if (array_key_exists ('api_secret ' , $ apiKey )) {
53
+ $ apiSecret = $ apiKey ['api_secret ' ];
54
+ }
55
+ if (array_key_exists ('encryption_method ' , $ apiKey )) {
56
+ $ encryptionMethod = $ apiKey ['encryption_method ' ];
57
+ }
58
+ if (array_key_exists ('encryption_password ' , $ apiKey )) {
59
+ $ encryptionPassword = $ apiKey ['encryption_password ' ];
60
+ }
61
+ if (array_key_exists ('api_key ' , $ apiKey )) {
62
+ $ asApiKey = $ apiKey ['api_key ' ];
63
+ }
64
+ }
65
+
66
+ $ this ->apiKey = $ asApiKey ;
67
+ $ this ->apiSecret = $ apiSecret ;
68
+ $ this ->encryptionMethod = $ encryptionMethod ;
69
+ $ this ->encryptionPassword = $ encryptionPassword ;
36
70
}
37
71
38
72
/**
39
- * @param $url
73
+ * @param $path
40
74
* @param $method
41
75
* @param array $data
42
76
*
43
77
* @return mixed
44
78
*/
45
- public function send ($ method , $ url , array $ data = [])
79
+ public function send ($ method , $ path , array $ data = [])
46
80
{
81
+ $ url = self ::API_URL . '/ ' . self ::API_VERSION . '/ ' . $ path ;
47
82
$ methodUpper = strtoupper ($ method );
48
- $ headers = [
49
- 'aftership-api-key ' => $ this ->apiKey ,
50
- 'content-type ' => 'application/json '
51
- ];
52
83
$ parameters = [
53
- 'url ' => self ::API_URL . '/ ' . self ::API_VERSION . '/ ' . $ url ,
54
- 'headers ' => array_map (function ($ key , $ value ) {
55
- return "$ key: $ value " ;
56
- }, array_keys ($ headers ), $ headers )
84
+ 'url ' => $ url ,
57
85
];
86
+
58
87
if ($ methodUpper == 'GET ' && $ data > 0 ) {
59
88
$ parameters ['url ' ] = $ parameters ['url ' ] . '? ' . http_build_query ($ data );
60
89
} else if ($ methodUpper != 'GET ' ) {
61
90
$ parameters ['body ' ] = $ this ->safeJsonEncode ($ data );
62
91
}
63
92
93
+ $ headers = $ this ->getHeaders ($ method , $ parameters ['url ' ], $ data );
94
+ $ parameters ['headers ' ] = array_map (function ($ key , $ value ) {
95
+ return "$ key: $ value " ;
96
+ }, array_keys ($ headers ), $ headers );
97
+
64
98
return $ this ->call ($ methodUpper , $ parameters );
65
99
}
66
100
@@ -153,4 +187,113 @@ private function handleHttpStatusError($response, $curl, $code)
153
187
curl_close ($ curl );
154
188
throw new AfterShipException ("$ errType: $ errCode - $ errMessage " , $ errCode );
155
189
}
190
+
191
+ function getCanonicalizedHeaders ($ headers )
192
+ {
193
+ $ filtered_headers = [];
194
+
195
+ foreach ($ headers as $ key => $ value ) {
196
+ // Check if the header key starts with "as-"
197
+ if (strpos ($ key , 'as- ' ) === 0 ) {
198
+ // Convert header key to lowercase and trim leading/trailing spaces
199
+ $ key = strtolower (trim ($ key ));
200
+
201
+ // Trim leading/trailing spaces from header value
202
+ $ value = trim ($ value );
203
+
204
+ // Concatenate header key and value
205
+ $ filtered_headers [] = "{$ key }: {$ value }" ;
206
+ }
207
+ }
208
+
209
+ // Sort headers in ASCII code order
210
+ sort ($ filtered_headers , SORT_STRING );
211
+
212
+ // Concatenate header pairs with new line character
213
+ $ header_string = implode ("\n" , $ filtered_headers );
214
+
215
+ return $ header_string ;
216
+ }
217
+
218
+ function getCanonicalizedResource ($ url )
219
+ {
220
+ $ path = "" ;
221
+ $ query = "" ;
222
+ $ parse_url = parse_url ($ url );
223
+ if (array_key_exists ('path ' , $ parse_url )) {
224
+ $ path = $ parse_url ['path ' ];
225
+ }
226
+ if (array_key_exists ('query ' , $ parse_url )) {
227
+ $ query = $ parse_url ['query ' ];
228
+ }
229
+ if ($ query === "" ) {
230
+ return $ path ;
231
+ }
232
+
233
+ $ params = explode ("& " , $ query );
234
+ sort ($ params );
235
+ $ queryStr = implode ("& " , $ params );
236
+ $ path .= "? " . $ queryStr ;
237
+
238
+ return $ path ;
239
+ }
240
+
241
+ function getSignString ($ method , $ url , $ data , $ headers )
242
+ {
243
+ $ contentMD5 = "" ;
244
+ $ contentType = "" ;
245
+ if (!empty ($ data ) && $ method != "GET " ) {
246
+ $ contentMD5 = strtoupper (md5 ($ this ->safeJsonEncode ($ data )));
247
+ $ contentType = "application/json " ;
248
+ }
249
+
250
+ $ canonicalizedHeaders = $ this ->getCanonicalizedHeaders ($ headers );
251
+ $ canonicalizedResource = $ this ->getCanonicalizedResource ($ url );
252
+ return mb_convert_encoding ($ method ."\n" .$ contentMD5 ."\n" .$ contentType ."\n" .$ headers ['date ' ]."\n" .$ canonicalizedHeaders ."\n" .$ canonicalizedResource , 'UTF-8 ' );
253
+ }
254
+
255
+ private function getHeaders ($ method , $ url , $ data )
256
+ {
257
+ $ isRSAEncryptionMethod = strcmp ($ this ->encryptionMethod , Encryption::ENCRYPTION_RSA ) == 0 ;
258
+ $ isAESEncryptionMethod = strcmp ($ this ->encryptionMethod , Encryption::ENCRYPTION_AES ) == 0 ;
259
+
260
+ // if not RSA or AES encryption, just return the legacy headers
261
+ if (!$ isRSAEncryptionMethod && !$ isAESEncryptionMethod ) {
262
+ return [
263
+ 'aftership-api-key ' => $ this ->apiKey ,
264
+ 'content-type ' => 'application/json '
265
+ ];
266
+ }
267
+
268
+ $ encryption = new Encryption ($ this ->apiSecret , $ this ->encryptionMethod , $ this ->encryptionPassword );
269
+ // get the header `date`
270
+ date_default_timezone_set ('UTC ' );
271
+ $ date = gmdate ('D, d M Y H:i:s \G\M\T ' , time ());
272
+ $ contentType = "" ;
273
+
274
+ // get the header `content-type`
275
+ if (!empty ($ data ) && $ method != "GET " ) {
276
+ $ contentType = "application/json " ;
277
+ }
278
+
279
+ $ headers = [
280
+ 'as-api-key ' => $ this ->apiKey ,
281
+ 'date ' => $ date ,
282
+ 'content-type ' => $ contentType ,
283
+ ];
284
+ $ signString = $ this ->getSignString ($ method , $ url , $ data , $ headers );
285
+
286
+ if ($ isRSAEncryptionMethod ) {
287
+ $ rsa = $ encryption ->rsaPSSSha256Encrypt ($ signString );
288
+ $ headers ['as-signature-rsa-sha256 ' ] = $ rsa ;
289
+
290
+ return $ headers ;
291
+ }
292
+ if ($ isAESEncryptionMethod ) {
293
+ $ rsa = $ encryption ->hmacSha256Encrypt ($ signString );
294
+ $ headers ['as-signature-hmac-sha256 ' ] = $ rsa ;
295
+
296
+ return $ headers ;
297
+ }
298
+ }
156
299
}
0 commit comments