Issues (850)

Security Analysis    4 potential vulnerabilities

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection (1)
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection (2)
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting (1)
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

gateways/class-getpaid-bank-transfer-gateway.php (4 issues)

1
<?php
2
/**
3
 * Bank transfer payment gateway
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * Bank transfer Payment Gateway class.
11
 *
12
 */
13
class GetPaid_Bank_Transfer_Gateway extends GetPaid_Payment_Gateway {
14
15
    /**
16
	 * Payment method id.
17
	 *
18
	 * @var string
19
	 */
20
    public $id = 'bank_transfer';
21
22
	/**
23
	 * An array of features that this gateway supports.
24
	 *
25
	 * @var array
26
	 */
27
	protected $supports = array(
28
		'subscription',
29
		'addons',
30
		'single_subscription_group',
31
		'multiple_subscription_groups',
32
		'subscription_date_change',
33
		'subscription_bill_times_change',
34
	);
35
36
    /**
37
	 * Payment method order.
38
	 *
39
	 * @var int
40
	 */
41
	public $order = 8;
42
43
	/**
44
	 * Bank transfer instructions.
45
	 */
46
	public $instructions;
47
48
	/**
49
	 * Locale array.
50
	 */
51
	public $locale;
52
53
    /**
54
	 * Class constructor.
55
	 */
56
	public function __construct() {
57
        parent::__construct();
58
59
        $this->title                = __( 'Direct bank transfer', 'invoicing' );
60
        $this->method_title         = __( 'Bank transfer', 'invoicing' );
61
        $this->checkout_button_text = __( 'Proceed', 'invoicing' );
62
        $this->instructions         = apply_filters( 'wpinv_bank_instructions', $this->get_option( 'info' ) );
63
64
		add_action( 'wpinv_receipt_end', array( $this, 'thankyou_page' ) );
65
		add_action( 'getpaid_invoice_line_items', array( $this, 'thankyou_page' ), 40 );
66
		add_action( 'wpinv_pdf_content_billing', array( $this, 'thankyou_page' ), 11 );
67
		add_action( 'wpinv_email_invoice_details', array( $this, 'email_instructions' ), 10, 3 );
68
		add_action( 'getpaid_should_renew_subscription', array( $this, 'maybe_renew_subscription' ), 12, 2 );
69
		add_action( 'getpaid_invoice_status_publish', array( $this, 'invoice_paid' ), 20 );
70
71
		add_filter( 'wpinv_' . $this->id . '_support_subscription', array( $this, 'supports_subscription' ), 20, 1 );
72
		add_filter( 'getpaid_' . $this->id . '_support_subscription', array( $this, 'supports_subscription' ), 20, 1 );
73
		add_filter( 'getpaid_' . $this->id . '_supports_subscription', array( $this, 'supports_subscription' ), 20, 1 );
74
	}
75
76
	/**
77
	 * Check gateway supports for subscription.
78
	 *
79
	 * @since 2.8.24
80
	 *
81
	 * @param bool $supports True if supports else False.
82
	 * @return bool True if supports else False.
83
	 */
84
	public function supports_subscription( $supports ) {
85
		if ( $supports && (int) $this->get_option( 'no_subscription' ) ) {
86
			$supports = false;
87
		}
88
89
		return $supports;
90
	}
91
92
	/**
93
	 * Process Payment.
94
	 *
95
	 * @param WPInv_Invoice $invoice Invoice.
96
	 * @param array $submission_data Posted checkout fields.
97
	 * @param GetPaid_Payment_Form_Submission $submission Checkout submission.
98
	 * @return array
99
	 */
100
	public function process_payment( $invoice, $submission_data, $submission ) {
101
102
        // Add a transaction id.
103
        $invoice->set_transaction_id( $invoice->generate_key( 'bt_' ) );
104
105
        // Set it as pending payment.
106
        if ( ! $invoice->needs_payment() ) {
107
            $invoice->mark_paid();
108
        } elseif ( ! $invoice->is_paid() ) {
109
            $invoice->set_status( 'wpi-onhold' );
110
        }
111
112
        // Save it.
113
        $invoice->save();
114
115
        // Send to the success page.
116
        wpinv_send_to_success_page( array( 'invoice_key' => $invoice->get_key() ) );
117
118
    }
119
120
    /**
121
	 * Output for the order received page.
122
	 *
123
	 * @param WPInv_Invoice $invoice Invoice.
124
	 */
125
	public function thankyou_page( $invoice ) {
126
127
        if ( 'bank_transfer' === $invoice->get_gateway() && $invoice->needs_payment() ) {
128
129
			echo '<div class="mt-4 mb-2 getpaid-bank-transfer-details">' . PHP_EOL;
130
131
            if ( ! empty( $this->instructions ) ) {
132
                echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) );
133
			}
134
135
			$this->bank_details( $invoice );
136
137
			echo '</div>';
138
139
        }
140
141
	}
142
143
    /**
144
	 * Add content to the WPI emails.
145
	 *
146
	 * @param WPInv_Invoice $invoice Invoice.
147
	 * @param string     $email_type Email format: plain text or HTML.
148
	 * @param bool     $sent_to_admin Sent to admin.
149
	 */
150
	public function email_instructions( $invoice, $email_type, $sent_to_admin ) {
151
152
		if ( ! $sent_to_admin && 'bank_transfer' === $invoice->get_gateway() && $invoice->needs_payment() ) {
153
154
			echo '<div class="wpi-email-row getpaid-bank-transfer-details">';
155
156
			if ( $this->instructions ) {
157
				echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) . PHP_EOL );
0 ignored issues
show
It seems like $this->instructions can also be of type true; however, parameter $text of wptexturize() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

157
				echo wp_kses_post( wpautop( wptexturize( /** @scrutinizer ignore-type */ $this->instructions ) ) . PHP_EOL );
Loading history...
158
            }
159
160
			$this->bank_details( $invoice );
161
162
			echo '</div>';
163
164
		}
165
166
    }
167
168
    /**
169
	 * Get bank details and place into a list format.
170
	 *
171
	 * @param WPInv_Invoice $invoice Invoice.
172
	 */
173
	protected function bank_details( $invoice ) {
174
175
		// Get the invoice country and country $locale.
176
		$country = $invoice->get_country();
177
		$locale  = $this->get_country_locale();
178
179
		// Get shortcode label in the $locale array and use appropriate one.
180
		$sortcode = isset( $locale[ $country ]['sortcode']['label'] ) ? $locale[ $country ]['sortcode']['label'] : __( 'Sort code', 'invoicing' );
181
182
        $bank_fields = array(
183
            'ac_name'   => __( 'Account Name', 'invoicing' ),
184
            'ac_no'     => __( 'Account Number', 'invoicing' ),
185
            'bank_name' => __( 'Bank Name', 'invoicing' ),
186
            'ifsc'      => __( 'IFSC code', 'invoicing' ),
187
            'iban'      => __( 'IBAN', 'invoicing' ),
188
            'bic'       => __( 'BIC/Swift code', 'invoicing' ),
189
            'sort_code' => $sortcode,
190
        );
191
192
        $bank_info = array();
193
194
        foreach ( $bank_fields as $field => $label ) {
195
            $value = $this->get_option( $field );
196
197
            if ( ! empty( $value ) ) {
198
                $bank_info[ $field ] = array(
199
					'label' => $label,
200
					'value' => $value,
201
				);
202
            }
203
		}
204
205
        $bank_info = apply_filters( 'wpinv_bank_info', $bank_info, $invoice );
206
207
        if ( empty( $bank_info ) ) {
208
            return;
209
        }
210
211
		echo '<h3 class="getpaid-bank-transfer-title"> ' . esc_html( apply_filters( 'wpinv_receipt_bank_details_title', __( 'Bank Details', 'invoicing' ), $invoice ) ) . '</h3>' . PHP_EOL;
212
213
		echo '<table class="table table-bordered getpaid-bank-transfer-details">' . PHP_EOL;
214
215
		foreach ( $bank_info as $key => $data ) {
216
			echo "<tr class='getpaid-bank-transfer-" . esc_attr( $key ) . "'><th class='font-weight-bold'>" . wp_kses_post( $data['label'] ) . "</th><td class='w-75'>" . wp_kses_post( wptexturize( $data['value'] ) ) . '</td></tr>' . PHP_EOL;
217
		}
218
219
		echo '</table>';
220
221
    }
222
223
    /**
224
	 * Get country locale if localized.
225
	 *
226
	 * @return array
227
	 */
228
	public function get_country_locale() {
229
230
		if ( empty( $this->locale ) ) {
231
232
			// Locale information to be used - only those that are not 'Sort Code'.
233
			$this->locale = apply_filters(
234
				'getpaid_get_bank_transfer_locale',
235
				array(
236
					'AU' => array(
237
						'sortcode' => array(
238
							'label' => __( 'BSB', 'invoicing' ),
239
						),
240
					),
241
					'CA' => array(
242
						'sortcode' => array(
243
							'label' => __( 'Bank transit number', 'invoicing' ),
244
						),
245
					),
246
					'IN' => array(
247
						'sortcode' => array(
248
							'label' => __( 'IFSC', 'invoicing' ),
249
						),
250
					),
251
					'IT' => array(
252
						'sortcode' => array(
253
							'label' => __( 'Branch sort', 'invoicing' ),
254
						),
255
					),
256
					'NZ' => array(
257
						'sortcode' => array(
258
							'label' => __( 'Bank code', 'invoicing' ),
259
						),
260
					),
261
					'SE' => array(
262
						'sortcode' => array(
263
							'label' => __( 'Bank code', 'invoicing' ),
264
						),
265
					),
266
					'US' => array(
267
						'sortcode' => array(
268
							'label' => __( 'Routing number', 'invoicing' ),
269
						),
270
					),
271
					'ZA' => array(
272
						'sortcode' => array(
273
							'label' => __( 'Branch code', 'invoicing' ),
274
						),
275
					),
276
				)
277
			);
278
279
		}
280
281
		return $this->locale;
282
283
	}
284
285
	/**
286
	 * Filters the gateway settings.
287
	 *
288
	 * @param array $admin_settings
289
	 */
290
	public function admin_settings( $admin_settings ) {
291
		$admin_settings['bank_transfer_desc']['std']    = __( "Make your payment directly into our bank account. Please use your Invoice Number as the payment reference. Your invoice won't be processed until the funds have cleared in our account.", 'invoicing' );
292
		$admin_settings['bank_transfer_active']['desc'] = __( 'Enable bank transfer', 'invoicing' );
293
294
		$_settings = array();
295
296
		foreach ( $admin_settings as $key => $setting ) {
297
			$_settings[ $key ] = $setting;
298
299
			if ( $key == 'bank_transfer_active' ) {
300
				// Enable/disable subscriptions setting.
301
				$_settings['bank_transfer_no_subscription'] = array(
302
					'id' => 'bank_transfer_no_subscription',
303
					'type' => 'checkbox',
304
					'name' => __( 'Disable Subscriptions', 'invoicing' ),
305
					'desc' => __( 'Tick to disable support for recurring items.', 'invoicing' ),
306
					'std' => 0
307
				);
308
			}
309
		}
310
311
		$admin_settings = $_settings;
312
313
		$locale  = $this->get_country_locale();
314
315
		// Get sortcode label in the $locale array and use appropriate one.
316
		$country  = wpinv_default_billing_country();
317
		$sortcode = isset( $locale[ $country ]['sortcode']['label'] ) ? $locale[ $country ]['sortcode']['label'] : __( 'Sort code', 'invoicing' );
318
319
		$admin_settings['bank_transfer_ac_name'] = array(
320
			'type' => 'text',
321
			'id'   => 'bank_transfer_ac_name',
322
			'name' => __( 'Account Name', 'invoicing' ),
323
		);
324
325
		$admin_settings['bank_transfer_ac_no'] = array(
326
			'type' => 'text',
327
			'id'   => 'bank_transfer_ac_no',
328
			'name' => __( 'Account Number', 'invoicing' ),
329
		);
330
331
		$admin_settings['bank_transfer_bank_name'] = array(
332
			'type' => 'text',
333
			'id'   => 'bank_transfer_bank_name',
334
			'name' => __( 'Bank Name', 'invoicing' ),
335
		);
336
337
		$admin_settings['bank_transfer_ifsc'] = array(
338
			'type' => 'text',
339
			'id'   => 'bank_transfer_ifsc',
340
			'name' => __( 'IFSC Code', 'invoicing' ),
341
		);
342
343
		$admin_settings['bank_transfer_iban'] = array(
344
			'type' => 'text',
345
			'id'   => 'bank_transfer_iban',
346
			'name' => __( 'IBAN', 'invoicing' ),
347
		);
348
349
		$admin_settings['bank_transfer_bic'] = array(
350
			'type' => 'text',
351
			'id'   => 'bank_transfer_bic',
352
			'name' => __( 'BIC/Swift Code', 'invoicing' ),
353
		);
354
355
		$admin_settings['bank_transfer_sort_code'] = array(
356
			'type' => 'text',
357
			'id'   => 'bank_transfer_sort_code',
358
			'name' => $sortcode,
359
		);
360
361
		$admin_settings['bank_transfer_info'] = array(
362
			'id'   => 'bank_transfer_info',
363
			'name' => __( 'Instructions', 'invoicing' ),
364
			'desc' => __( 'Instructions that will be added to the thank you page and emails.', 'invoicing' ),
365
			'type' => 'textarea',
366
			'std'  => __( "Make your payment directly into our bank account. Please use your Invoice Number as the payment reference. Your invoice won't be processed until the funds have cleared in our account.", 'invoicing' ),
367
			'cols' => 50,
368
			'rows' => 5,
369
		);
370
371
		return $admin_settings;
372
	}
373
374
	/**
375
	 * Processes invoice addons.
376
	 *
377
	 * @param WPInv_Invoice $invoice
378
	 * @param GetPaid_Form_Item[] $items
379
	 * @return WPInv_Invoice
380
	 */
381
	public function process_addons( $invoice, $items ) {
382
383
        foreach ( $items as $item ) {
384
            $invoice->add_item( $item );
385
        }
386
387
        $invoice->recalculate_total();
388
        $invoice->save();
389
	}
390
391
	/**
392
	 * (Maybe) renews a bank transfer subscription profile.
393
	 *
394
	 *
395
	 * @param WPInv_Subscription $subscription
396
	 */
397
	public function maybe_renew_subscription( $subscription, $parent_invoice ) {
398
		// Ensure its our subscription && it's active.
399
		if ( ! empty( $parent_invoice ) && $this->id === $parent_invoice->get_gateway() && $subscription->has_status( 'active trialling' ) ) {
400
			add_filter( 'getpaid_invoice_notifications_is_payment_form_invoice', array( $this, 'force_is_payment_form_invoice' ), 10, 2 );
401
402
			$invoice = $subscription->create_payment();
403
404
			if ( ! empty( $invoice ) ) {
405
				$is_logged_in = is_user_logged_in();
406
407
				// Cron run.
408
				if ( ! $is_logged_in ) {
409
					$note = wp_sprintf( __( 'Renewal %1$s created with the status "%2$s".', 'invoicing' ), $invoice->get_invoice_quote_type(), wpinv_status_nicename( $invoice->get_status(), $invoice ) );
410
411
					$invoice->add_note( $note, false, $is_logged_in, ! $is_logged_in );
412
				}
413
			}
414
415
			remove_filter( 'getpaid_invoice_notifications_is_payment_form_invoice', array( $this, 'force_is_payment_form_invoice' ), 10, 2 );
0 ignored issues
show
The call to remove_filter() has too many arguments starting with 2. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

415
			/** @scrutinizer ignore-call */ 
416
   remove_filter( 'getpaid_invoice_notifications_is_payment_form_invoice', array( $this, 'force_is_payment_form_invoice' ), 10, 2 );

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
416
		}
417
	}
418
419
	/**
420
	 * Process a bank transfer payment.
421
	 *
422
	 *
423
     * @param WPInv_Invoice $invoice
424
	 */
425
	public function invoice_paid( $invoice ) {
426
427
		// Abort if not paid by bank transfer.
428
		if ( $this->id !== $invoice->get_gateway() || ! $invoice->is_recurring() ) {
429
			return;
430
		}
431
432
		// Is it a parent payment?
433
		if ( 0 == $invoice->get_parent_id() ) {
434
435
			// (Maybe) activate subscriptions.
436
			$subscriptions = getpaid_get_invoice_subscriptions( $invoice );
437
438
			if ( ! empty( $subscriptions ) ) {
439
				$subscriptions = is_array( $subscriptions ) ? $subscriptions : array( $subscriptions );
0 ignored issues
show
The condition is_array($subscriptions) is always false.
Loading history...
440
441
				foreach ( $subscriptions as $subscription ) {
442
					if ( $subscription->exists() ) {
443
						$duration = strtotime( $subscription->get_expiration() ) - strtotime( $subscription->get_date_created() );
444
						$expiry   = gmdate( 'Y-m-d H:i:s', ( current_time( 'timestamp' ) + $duration ) );
445
446
						$subscription->set_next_renewal_date( $expiry );
447
						$subscription->set_date_created( current_time( 'mysql' ) );
448
						$subscription->set_profile_id( 'bt_sub_' . $invoice->get_id() . '_' . $subscription->get_id() );
449
						$subscription->activate();
450
					}
451
				}
452
			}
453
		} else {
454
455
			$subscription = getpaid_get_subscription( $invoice->get_subscription_id() );
456
457
			// Renew the subscription.
458
			if ( $subscription && $subscription->exists() ) {
459
				$subscription->add_payment( array(), $invoice );
460
				$subscription->renew( strtotime( $invoice->get_date_created() ) );
461
			}
462
		}
463
464
    }
465
466
	/**
467
	 * Force created from payment false to allow email for auto renewal generation invoice.
468
	 *
469
	 * @since 2.8.11
470
	 *
471
	 * @param bool $is_payment_form_invoice True when invoice created via payment form else false.
472
	 * @param int  $invoice Invoice ID.
473
	 * @return bool True when invoice created via payment form else false.
474
	 */
475
	public function force_is_payment_form_invoice( $is_payment_form_invoice, $invoice ) {
0 ignored issues
show
The parameter $invoice is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

475
	public function force_is_payment_form_invoice( $is_payment_form_invoice, /** @scrutinizer ignore-unused */ $invoice ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
476
		if ( $is_payment_form_invoice ) {
477
			$is_payment_form_invoice = false;
478
		}
479
480
		return $is_payment_form_invoice;
481
	}
482
483
}
484