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; |
||
0 ignored issues
–
show
|
|||
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 | ]/*, |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
60% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
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']) ) |
|
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']) ) |
|
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']) ) |
|
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(); |
||
0 ignored issues
–
show
$transaction is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
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 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.