This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | use Omnipay\Omnipay; |
||
4 | use Omnipay\Common\Exception\InvalidResponseException; |
||
5 | use Omnipay\Common\Exception\OmnipayException; |
||
6 | |||
7 | if ( !defined('ABSPATH') ) exit; |
||
8 | |||
9 | /** |
||
10 | * WC_Gateway_FirstAtlanticCommerce class |
||
11 | * |
||
12 | * @extends WC_Payment_Gateway |
||
13 | */ |
||
14 | class WC_Gateway_FirstAtlanticCommerce extends WC_Payment_Gateway |
||
15 | { |
||
16 | /** |
||
17 | * Constructor |
||
18 | */ |
||
19 | public function __construct() |
||
20 | { |
||
21 | $this->id = 'fac'; |
||
22 | $this->method_title = __('First Atlantic Commerce', 'wc-gateway-fac'); |
||
23 | $this->method_description = __('First Atlantic Commerce works by adding credit card fields on the checkout and then sending the details to First Atlantic Commerce for verification.', 'wc-gateway-fac'); |
||
24 | $this->has_fields = true; |
||
25 | $this->supports = [ |
||
26 | //'subscriptions', |
||
27 | 'products', |
||
28 | 'refunds', |
||
29 | //'subscription_cancellation', |
||
30 | //'subscription_reactivation', |
||
31 | //'subscription_suspension', |
||
32 | //'subscription_amount_changes', |
||
33 | //'subscription_payment_method_change', |
||
34 | //'subscription_date_changes', |
||
35 | //'pre-orders', |
||
36 | 'default_credit_card_form' |
||
37 | ]; |
||
38 | |||
39 | // Load the form fields |
||
40 | $this->init_form_fields(); |
||
41 | |||
42 | // Load the settings |
||
43 | $this->init_settings(); |
||
44 | |||
45 | // User defined settings |
||
46 | $this->title = $this->get_option('title'); |
||
47 | $this->description = $this->get_option('description'); |
||
48 | $this->enabled = $this->get_option('enabled'); |
||
49 | $this->testmode = 'yes' === $this->get_option('testmode', 'no'); |
||
50 | $this->capture = $this->get_option('capture', "yes") === "yes" ? true : false; |
||
51 | //$this->saved_cards = $this->get_option( 'saved_cards' ) === "yes" ? true : false; |
||
52 | $this->merchant_id = $this->testmode ? $this->get_option('test_merchant_id') : $this->get_option('merchant_id'); |
||
53 | $this->merchant_password = $this->testmode ? $this->get_option('test_merchant_password') : $this->get_option('merchant_password'); |
||
54 | |||
55 | // Hooks |
||
56 | add_action('admin_notices', [$this, 'admin_notices']); |
||
57 | add_action('woocommerce_update_options_payment_gateways_' . $this->id, [$this, 'process_admin_options']); |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * Notify of issues in wp-admin |
||
62 | */ |
||
63 | public function admin_notices() |
||
64 | { |
||
65 | if ($this->enabled == 'no') |
||
66 | { |
||
67 | return; |
||
68 | } |
||
69 | |||
70 | // Check required fields |
||
71 | if (!$this->merchant_id) |
||
72 | { |
||
73 | echo '<div class="error"><p>' . sprintf( __( 'First Atlantic Commerce error: Please enter your merchant id <a href="%s">here</a>', 'woocommerce-gateway-fac' ), admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=wc_gateway_fac' ) ) . '</p></div>'; |
||
74 | return; |
||
75 | } |
||
76 | elseif (!$this->merchant_password) |
||
77 | { |
||
78 | echo '<div class="error"><p>' . sprintf( __( 'First Atlantic Commerce error: Please enter your merchant password <a href="%s">here</a>', 'woocommerce-gateway-fac' ), admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=wc_gateway_fac' ) ) . '</p></div>'; |
||
79 | return; |
||
80 | } |
||
81 | |||
82 | // Check if enabled and force SSL is disabled |
||
83 | if ( get_option('woocommerce_force_ssl_checkout') == 'no' ) { |
||
84 | echo '<div class="error"><p>' . sprintf( __( 'First Atlantic Commerce is enabled, but the <a href="%s">force SSL option</a> is disabled; your checkout may not be secure! Please enable SSL and ensure your server has a valid SSL certificate - First Atlantic Commerce will only work in test mode.', 'woocommerce-gateway-fac' ), admin_url( 'admin.php?page=wc-settings&tab=checkout' ) ) . '</p></div>'; |
||
85 | return; |
||
86 | } |
||
87 | } |
||
88 | |||
89 | /** |
||
90 | * Logging method |
||
91 | * |
||
92 | * @param string $message |
||
93 | * |
||
94 | * @return void |
||
95 | */ |
||
96 | public function log($message) |
||
97 | { |
||
98 | if ( empty($this->log) ) |
||
99 | { |
||
100 | $this->log = new WC_Logger(); |
||
101 | } |
||
102 | |||
103 | $this->log->add($this->id, $message); |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * Check if the gateway is available for use |
||
108 | * |
||
109 | * @return bool |
||
110 | */ |
||
111 | public function is_available() |
||
112 | { |
||
113 | $is_available = parent::is_available(); |
||
114 | |||
115 | // Only allow unencrypted connections when testing |
||
116 | if (!is_ssl() && !$this->testmode) |
||
117 | { |
||
118 | $is_available = false; |
||
119 | } |
||
120 | |||
121 | // Required fields check |
||
122 | if (!$this->merchant_id || !$this->merchant_password) |
||
123 | { |
||
124 | $is_available = false; |
||
125 | } |
||
126 | |||
127 | return $is_available; |
||
128 | } |
||
129 | |||
130 | /** |
||
131 | * Initialise Gateway Settings Form Fields |
||
132 | */ |
||
133 | public function init_form_fields() |
||
134 | { |
||
135 | $this->form_fields = apply_filters('wc_fac_settings', [ |
||
136 | 'enabled' => [ |
||
137 | 'title' => __('Enable/Disable', 'woocommerce-gateway-fac'), |
||
138 | 'label' => __('Enable FAC', 'woocommerce-gateway-fac'), |
||
139 | 'type' => 'checkbox', |
||
140 | 'description' => '', |
||
141 | 'default' => 'no' |
||
142 | ], |
||
143 | 'title' => [ |
||
144 | 'title' => __('Title', 'woocommerce-gateway-fac'), |
||
145 | 'type' => 'text', |
||
146 | 'description' => __('This controls the title which the user sees during checkout.', 'woocommerce-gateway-fac'), |
||
147 | 'default' => __('Credit card', 'woocommerce-gateway-fac') |
||
148 | ], |
||
149 | 'description' => [ |
||
150 | 'title' => __('Description', 'woocommerce-gateway-fac'), |
||
151 | 'type' => 'textarea', |
||
152 | 'description' => __('This controls the description which the user sees during checkout.', 'woocommerce-gateway-fac'), |
||
153 | 'default' => __('Pay with your credit card.', 'woocommerce-gateway-fac') |
||
154 | ], |
||
155 | 'testmode' => [ |
||
156 | 'title' => __('Test mode', 'woocommerce-gateway-fac'), |
||
157 | 'label' => __('Enable Test Mode', 'woocommerce-gateway-fac'), |
||
158 | 'type' => 'checkbox', |
||
159 | 'description' => __('Place the payment gateway in test mode using test API credentials.', 'woocommerce-gateway-fac'), |
||
160 | 'default' => 'yes' |
||
161 | ], |
||
162 | 'merchant_id' => [ |
||
163 | 'title' => __('Live Merchant ID', 'woocommerce-gateway-fac'), |
||
164 | 'type' => 'text', |
||
165 | 'description' => __('Get your API credentials from your merchant account.', 'woocommerce-gateway-fac'), |
||
166 | 'default' => '' |
||
167 | ], |
||
168 | 'merchant_password' => [ |
||
169 | 'title' => __('Live Merchant Password', 'woocommerce-gateway-fac'), |
||
170 | 'type' => 'text', |
||
171 | 'description' => __('Get your API credentials from your merchant account.', 'woocommerce-gateway-fac'), |
||
172 | 'default' => '' |
||
173 | ], |
||
174 | 'test_merchant_id' => [ |
||
175 | 'title' => __('Test Merchant ID', 'woocommerce-gateway-fac'), |
||
176 | 'type' => 'text', |
||
177 | 'description' => __('Get your API credentials from your merchant account.', 'woocommerce-gateway-fac'), |
||
178 | 'default' => '' |
||
179 | ], |
||
180 | 'test_merchant_password' => [ |
||
181 | 'title' => __('Test Merchant Password', 'woocommerce-gateway-fac'), |
||
182 | 'type' => 'text', |
||
183 | 'description' => __('Get your API credentials from your merchant account.', 'woocommerce-gateway-fac'), |
||
184 | 'default' => '' |
||
185 | ], |
||
186 | 'capture' => [ |
||
187 | 'title' => __('Capture', 'woocommerce-gateway-fac'), |
||
188 | 'label' => __('Capture charge immediately', 'woocommerce-gateway-fac'), |
||
189 | 'type' => 'checkbox', |
||
190 | 'description' => __('Whether or not to immediately capture the charge. When unchecked, the charge issues an authorization and will need to be captured later. Uncaptured charges expire in 7 days.', 'woocommerce-gateway-fac'), |
||
191 | 'default' => 'yes' |
||
192 | ]/*, |
||
193 | 'saved_cards' => [ |
||
194 | 'title' => __('Saved cards', 'woocommerce-gateway-fac'), |
||
195 | 'label' => __('Enable saved cards', 'woocommerce-gateway-fac'), |
||
196 | 'type' => 'checkbox', |
||
197 | 'description' => __('If enabled, users will be able to pay with a saved card during checkout. Card details are saved on FAC servers, not on your store.', 'woocommerce-gateway-fac'), |
||
198 | 'default' => 'no' |
||
199 | ]*/ |
||
200 | ]); |
||
201 | } |
||
202 | |||
203 | /** |
||
204 | * Setup the gateway object |
||
205 | */ |
||
206 | public function setup_gateway() |
||
207 | { |
||
208 | $gateway = Omnipay::create('FirstAtlanticCommerce'); |
||
209 | |||
210 | $gateway->setMerchantId($this->merchant_id); |
||
211 | $gateway->setMerchantPassword($this->merchant_password); |
||
212 | |||
213 | if ($this->testmode) |
||
214 | { |
||
215 | $gateway->setTestMode(true); |
||
216 | } |
||
217 | |||
218 | return $gateway; |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * Output payment fields |
||
223 | * |
||
224 | * @return void |
||
225 | */ |
||
226 | public function payment_fields() |
||
227 | { |
||
228 | // Default credit card form |
||
229 | $this->credit_card_form(); |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Validate form fields |
||
234 | * |
||
235 | * @return bool |
||
236 | */ |
||
237 | public function validate_fields() |
||
238 | { |
||
239 | $validated = true; |
||
240 | |||
241 | View Code Duplication | if ( empty($_POST['fac-card-number']) ) |
|
0 ignored issues
–
show
|
|||
242 | { |
||
243 | wc_add_notice( $this->get_validation_error( __('Card Number', 'woocommerce-gateway-fac'), $_POST['fac-card-number'] ), 'error' ); |
||
244 | $validated = false; |
||
245 | } |
||
246 | View Code Duplication | if ( empty($_POST['fac-card-expiry']) ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
247 | { |
||
248 | wc_add_notice( $this->get_validation_error( __('Card Expiry', 'woocommerce-gateway-fac'), $_POST['fac-card-number'] ), 'error' ); |
||
249 | $validated = false; |
||
250 | } |
||
251 | View Code Duplication | if ( empty($_POST['fac-card-cvc']) ) |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
252 | { |
||
253 | wc_add_notice( $this->get_validation_error( __('Card Code', 'woocommerce-gateway-fac'), $_POST['fac-card-number'] ), 'error' ); |
||
254 | $validated = false; |
||
255 | } |
||
256 | |||
257 | return $validated; |
||
258 | } |
||
259 | |||
260 | /** |
||
261 | * Get error message for form fields |
||
262 | * |
||
263 | * @param string $field |
||
264 | * @param string $type |
||
265 | * @return string |
||
266 | */ |
||
267 | protected function get_validation_error($field, $type = 'undefined') |
||
268 | { |
||
269 | if ( $type === 'invalid' ) |
||
270 | { |
||
271 | return sprintf( __( 'Please enter a valid %s.', 'woocommerce-gateway-fac' ), "<strong>$field</strong>" ); |
||
272 | } |
||
273 | else |
||
274 | { |
||
275 | return sprintf( __( '%s is a required field.', 'woocommerce-gateway-fac' ), "<strong>$field</strong>" ); |
||
276 | } |
||
277 | } |
||
278 | |||
279 | /** |
||
280 | * Can the order be processed? |
||
281 | * |
||
282 | * @param WC_Order $order |
||
283 | * |
||
284 | * @return bool |
||
285 | */ |
||
286 | public function can_process_order($order) |
||
287 | { |
||
288 | return $order && $order->payment_method == 'fac'; |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * Process the payment and return the result |
||
293 | * |
||
294 | * @param int $order_id |
||
295 | * |
||
296 | * @return array |
||
297 | */ |
||
298 | public function process_payment($order_id) |
||
299 | { |
||
300 | $order = new WC_Order($order_id); |
||
301 | |||
302 | if ( !$this->can_process_order($order) ) return; |
||
303 | |||
304 | $transaction = $order->get_transaction_id(); |
||
305 | $captured = get_post_meta($order_id, '_fac_captured', true); |
||
306 | |||
307 | // Skip already captured transactions |
||
308 | if ($captured) return; |
||
309 | |||
310 | try |
||
311 | { |
||
312 | $gateway = $this->setup_gateway(); |
||
313 | |||
314 | $data = [ |
||
315 | 'transactionId' => $order->get_order_number(), |
||
316 | 'amount' => $this->get_order_total(), |
||
317 | 'currency' => $order->order_currency |
||
318 | ]; |
||
319 | |||
320 | // Already authorized transactions should be captured |
||
321 | if ( $transaction && !$captured ) |
||
322 | { |
||
323 | $response = $gateway->capture($data)->send(); |
||
324 | } |
||
325 | else |
||
326 | { |
||
327 | $card_number = str_replace( [' ', '-'], '', wc_clean($_POST['fac-card-number']) ); |
||
328 | $card_cvv = wc_clean($_POST['fac-card-cvc']); |
||
329 | $card_expiry = preg_split('/\s?\/\s?/', wc_clean($_POST['fac-card-expiry']), 2); |
||
330 | |||
331 | $data['card'] = [ |
||
332 | 'firstName' => $order->billing_first_name, |
||
333 | 'lastName' => $order->billing_last_name, |
||
334 | 'number' => $card_number, |
||
335 | 'expiryMonth' => $card_expiry[0], |
||
336 | 'expiryYear' => $card_expiry[1], |
||
337 | 'cvv' => $card_cvv, |
||
338 | 'billingAddress1' => $order->billing_address_1, |
||
339 | 'billingAddress2' => $order->billing_address_2, |
||
340 | 'billingCity' => $order->billing_city, |
||
341 | 'billingPostcode' => $order->billing_postcode, |
||
342 | 'billingState' => $order->billing_state, |
||
343 | 'billingCountry' => $order->billing_country, |
||
344 | 'email' => $order->billing_email |
||
345 | ]; |
||
346 | |||
347 | // Capture in one pass if enabled, otherwise authorize |
||
348 | if ($this->capture) |
||
349 | { |
||
350 | $response = $gateway->purchase($data)->send(); |
||
351 | } |
||
352 | else |
||
353 | { |
||
354 | $response = $gateway->authorize($data)->send(); |
||
355 | } |
||
356 | } |
||
357 | |||
358 | if ( $response->isSuccessful() ) |
||
359 | { |
||
360 | $reference = $response->getTransactionReference(); |
||
361 | |||
362 | // Captured transaction |
||
363 | if ( ($transaction && !$captured) || (!$transaction && $this->capture) ) |
||
364 | { |
||
365 | // Store captured |
||
366 | update_post_meta($order_id, '_fac_captured', true); |
||
367 | |||
368 | // Complete payment |
||
369 | $order->payment_complete($reference); |
||
370 | |||
371 | // Add note to order |
||
372 | $order->add_order_note( sprintf( __('FAC transaction complete (ID: %s)', 'woocommerce-gateway-fac'), $reference ) ); |
||
373 | } |
||
374 | // Authorized transaction |
||
375 | else |
||
376 | { |
||
377 | // Store captured |
||
378 | update_post_meta($order_id, '_transaction_id', $reference, true); |
||
379 | update_post_meta($order_id, '_fac_captured', false); |
||
380 | |||
381 | // Mark order as on-hold and add note |
||
382 | $order->update_status( 'on-hold', sprintf( __('FAC charge authorized (ID: %s). Process the order to take payment, or cancel to remove the pre-authorization.', 'woocommerce-gateway-fac'), $reference ) ); |
||
383 | |||
384 | // Reduce stock level |
||
385 | $order->reduce_order_stock(); |
||
386 | } |
||
387 | |||
388 | // Clear cart |
||
389 | WC()->cart->empty_cart(); |
||
390 | |||
391 | // Return thank you page redirect |
||
392 | return [ |
||
393 | 'result' => 'success', |
||
394 | 'redirect' => $this->get_return_url($order) |
||
395 | ]; |
||
396 | } |
||
397 | else |
||
398 | { |
||
399 | throw new InvalidResponseException( $response->getMessage(), $response->getCode() ); |
||
400 | } |
||
401 | } |
||
402 | catch (OmnipayException $e) |
||
403 | { |
||
404 | $message = 'Transaction Failed: '. $e->getCode() .' – '. $e->getMessage(); |
||
405 | |||
406 | $this->log($message); |
||
407 | $order->add_order_note( __($message, 'woocommerce-gateway-fac') ); |
||
408 | |||
409 | // Friendly declined message |
||
410 | if ( in_array( $e->getCode(), [2, 3, 4, 35, 38, 39] ) ) |
||
411 | { |
||
412 | $message = __('Unfortunately your order cannot be processed as the originating bank/merchant has declined your transaction.', 'woocommerce') .' '. __('Please attempt your purchase again.', 'woocommerce'); |
||
413 | } |
||
414 | |||
415 | // Friendly error message |
||
416 | else |
||
417 | { |
||
418 | $message = __('Unfortunately your order cannot be processed as an error has occured.', 'woocommerce') .' '. __('Please attempt your purchase again.', 'woocommerce'); |
||
419 | } |
||
420 | |||
421 | if ( !is_admin() || ( defined('DOING_AJAX') && DOING_AJAX ) ) |
||
422 | { |
||
423 | wc_add_notice($message, 'error'); |
||
424 | } |
||
425 | |||
426 | return; |
||
427 | } |
||
428 | } |
||
429 | |||
430 | /** |
||
431 | * Can the order be refunded? |
||
432 | * |
||
433 | * @param WC_Order $order |
||
434 | * |
||
435 | * @return bool |
||
436 | */ |
||
437 | public function can_refund_order($order) |
||
438 | { |
||
439 | return $order && $order->payment_method == 'fac' && $order->get_transaction_id(); |
||
440 | } |
||
441 | |||
442 | /** |
||
443 | * Refund a charge |
||
444 | * |
||
445 | * @param int $order_id |
||
446 | * @param float $amount |
||
447 | * |
||
448 | * @return bool |
||
449 | */ |
||
450 | public function process_refund($order_id, $amount = null, $reason = '') |
||
451 | { |
||
452 | $order = wc_get_order($order_id); |
||
453 | |||
454 | if ( !$this->can_refund_order($order) ) |
||
455 | { |
||
456 | $this->log('Refund Failed: No transaction ID for FAC'); |
||
457 | return false; |
||
458 | } |
||
459 | |||
460 | $transaction = $order->get_transaction_id(); |
||
461 | $captured = get_post_meta($order_id, '_fac_captured', true); |
||
462 | |||
463 | if ( is_null($amount) ) |
||
464 | { |
||
465 | $amount = $order->get_total(); |
||
466 | } |
||
467 | |||
468 | try |
||
469 | { |
||
470 | $gateway = $this->setup_gateway(); |
||
471 | |||
472 | $data = [ |
||
473 | 'transactionId' => $order->get_order_number(), |
||
474 | 'amount' => $amount |
||
475 | ]; |
||
476 | |||
477 | if ($captured) |
||
478 | { |
||
479 | $response = $gateway->refund($data)->send(); |
||
480 | } |
||
481 | else |
||
482 | { |
||
483 | $response = $gateway->void($data)->send(); |
||
484 | } |
||
485 | |||
486 | if ( $response->isSuccessful() ) |
||
487 | { |
||
488 | $order->add_order_note( sprintf( __('Refunded %s', 'woocommerce-gateway-fac'), $data['amount'] ) ); |
||
489 | return true; |
||
490 | } |
||
491 | else |
||
492 | { |
||
493 | throw new InvalidResponseException( $response->getMessage(), $response->getCode() ); |
||
494 | } |
||
495 | } |
||
496 | catch (OmnipayException $e) |
||
497 | { |
||
498 | $message = 'Refund Failed: '. $e->getCode() .' – '. $e->getMessage(); |
||
499 | |||
500 | $this->log($message); |
||
501 | $order->add_order_note( __($message, 'woocommerce-gateway-fac') ); |
||
502 | |||
503 | return new WP_Error( 'fac-refund', __($e->getCode() .' – '.$e->getMessage(), 'woocommerce-gateway-fac') ); |
||
504 | } |
||
505 | } |
||
506 | } |
||
507 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.