22
33namespace Danielz \SettleApi ;
44
5- use Exception ;
6-
75class SettleApiClient
86{
97 protected string $ merchantId ;
@@ -15,10 +13,12 @@ class SettleApiClient
1513 const BASE_URL_PRODUCTION = 'https://api.settle.eu/merchant/v1/ ' ;
1614 const BASE_URL_SANDBOX = 'https://api.sandbox.settle.eu/merchant/v1/ ' ;
1715
16+ const PUBLIC_KEY_PRODUCTION = "-----BEGIN PUBLIC KEY----- \nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9iglTBPG1poCw3qFPlxT0MSHO \nt6kgRmpVrLBY9Fx8Zn+zAoY89ZeFhwwnRR8IDQcj4yEAjsoXCxtH3bbh/OdvlFG6 \nxdSsAeph6/MSk9YAVKWRWU5ber9cgoQ89KJ14goLUnhhegynUjnz+hdgAET5k9Uc \nsxnmfU7XeT78FP02JQIDAQAB \n-----END PUBLIC KEY----- " ;
17+ const PUBLIC_KEY_SANDBOX = "-----BEGIN PUBLIC KEY----- \nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDS92fCQmAPDpmcgraqPRXgz4Nd \nd/biPxIH5aG1dAQ8dMMcEjGCn7Sm5VcX1iV8L5oW+MlcnHFaZdVyy1Lcqed/8+r0 \nQM9cFqQWif35C+eOr/s7/CCY/WXMApqO6YihtHvP+jgjrXltw0LHrUwMWO718udN \nhlg22QkpjhG90kvf3QIDAQAB \n-----END PUBLIC KEY----- " ;
1818
1919 const SETTLE_LINK = 'https://settle.eu ' ;
20- const PAYMENT_LINK = 'https ://settle.eu/p/:payment_request_id/ ' ;
21- const PAYMENT_LINK_MOBILE = 'https ://settle.eu/p/:payment_request_id/ ' ;
20+ const PAYMENT_LINK = 'http ://settle.eu/p/:payment_request_id/ ' ;
21+ const PAYMENT_LINK_MOBILE = 'http ://settle.eu/p/:payment_request_id/ ' ;
2222 const PAYMENT_LINK_MOBILE_SANDBOX = 'https://settledemo.page.link/?apn=eu.settle.app.sandbox&ibi=eu.settle.app.sandbox&isi=1453180781&ius=eu.settle.app.firebaselink&link=https://settle-demo://qr/http://settle.eu/p/:payment_request_id/ ' ;
2323
2424 /**
@@ -46,6 +46,14 @@ public function getIsSandbox()
4646 return $ this ->isSandbox ;
4747 }
4848
49+ /**
50+ * @return string
51+ */
52+ public function getSettlePublicKey ()
53+ {
54+ return $ this ->isSandbox ? self ::PUBLIC_KEY_SANDBOX : self ::PUBLIC_KEY_PRODUCTION ;
55+ }
56+
4957 /**
5058 * @param $isSandbox
5159 */
@@ -151,6 +159,74 @@ protected function getHeaders(string $method, string $url, array $postFields): a
151159 return $ headers ;
152160 }
153161
162+
163+ /**
164+ * @param string $callbackUrl
165+ * @param string $method
166+ * @return false|mixed
167+ * @throws SettleApiException
168+ */
169+ public function getCallbackData ($ callbackUrl = '' , $ method = 'POST ' )
170+ {
171+ $ body = file_get_contents ('php://input ' );
172+ if (empty ($ callbackUrl )) {
173+ $ callbackUrl = $ _SERVER ['REQUEST_SCHEME ' ] . ':// ' . $ _SERVER ['HTTP_HOST ' ] . $ _SERVER ['REQUEST_URI ' ];
174+ }
175+
176+ $ is_valid_request = $ this ->isValidCallback ($ callbackUrl , $ body , $ _SERVER , $ method );
177+
178+ return $ is_valid_request ? json_decode ($ body , true ) : false ;
179+ }
180+
181+ /**
182+ * @param string $callbackUrl
183+ * @param string|array $body
184+ * @param array $headers
185+ * @param string $method
186+ * @return bool
187+ * @throws SettleApiException
188+ */
189+ public function isValidCallback ($ callbackUrl , $ body , $ headers , $ method = 'POST ' )
190+ {
191+ $ data = is_string ($ body ) ? $ body : json_encode ($ body );
192+ $ content_digest = base64_encode (hash ('sha256 ' , $ data , true ));
193+
194+ $ expected_signature = false ;
195+ $ expected_content_digest = false ;
196+ $ settle_headers = [];
197+ foreach ($ headers as $ header => $ value ) {
198+ $ normalized_header = str_replace (['http_ ' , '_ ' ], ['' , '- ' ], strtolower ($ header ));
199+ switch ($ normalized_header ) {
200+ case 'authorization ' :
201+ list ($ algo , $ authorization ) = explode (' ' , $ value , 2 );
202+ if ($ algo == 'RSA-SHA256 ' ) {
203+ $ expected_signature = base64_decode ($ authorization );
204+ }
205+ break ;
206+ case 'x-settle-timestamp ' :
207+ $ settle_headers [] = 'X-SETTLE-TIMESTAMP= ' . $ value ;
208+ break ;
209+ case 'x-settle-content-digest ' :
210+ list ($ algo , $ digest ) = explode ('= ' , $ value , 2 );
211+ if ($ algo == 'SHA256 ' ) {
212+ $ settle_headers [] = 'X-SETTLE-CONTENT-DIGEST= ' . $ value ;
213+ $ expected_content_digest = $ digest ;
214+ }
215+ break ;
216+ }
217+ }
218+ sort ($ settle_headers );
219+
220+ if (!$ expected_signature ) {
221+ throw new SettleApiException ("Authorization header is missing. " );
222+ }
223+
224+ $ fingerprint = join ('| ' , [strtoupper ($ method ), $ callbackUrl , join ('& ' , $ settle_headers )]);
225+ $ valid_signature = openssl_verify ($ fingerprint , $ expected_signature , $ this ->getSettlePublicKey (), OPENSSL_ALGO_SHA256 );
226+
227+ return ($ expected_content_digest == $ content_digest ) && $ valid_signature ;
228+ }
229+
154230 public function createLink ($ template , array $ data = [])
155231 {
156232 switch ($ template ) {
0 commit comments