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.

includes/wpinv-general-functions.php (3 issues)

1
<?php
2
/**
3
 * Contains functions related to Invoicing plugin.
4
 *
5
 * @since 1.0.0
6
 * @package Invoicing
7
 */
8
9
// MUST have WordPress.
10
if ( ! defined( 'WPINC' ) ) {
11
    exit;
12
}
13
14
function wpinv_is_checkout() {
15
    global $wp_query;
16
17
    $is_object_set    = isset( $wp_query->queried_object );
18
    $is_object_id_set = isset( $wp_query->queried_object_id );
19
    $checkout_page    = wpinv_get_option( 'checkout_page' );
20
    $is_checkout      = ! empty( $checkout_page ) && is_page( $checkout_page );
21
22
    if ( ! $is_object_set ) {
23
        unset( $wp_query->queried_object );
24
    }
25
26
    if ( ! $is_object_id_set ) {
27
        unset( $wp_query->queried_object_id );
28
    }
29
30
    return apply_filters( 'wpinv_is_checkout', $is_checkout );
31
}
32
33
function wpinv_can_checkout() {
34
	$can_checkout = true; // Always true for now
35
36
	return (bool) apply_filters( 'wpinv_can_checkout', $can_checkout );
37
}
38
39
function wpinv_get_success_page_uri() {
40
	$page_id = wpinv_get_option( 'success_page', 0 );
41
	$page_id = absint( $page_id );
42
43
	return apply_filters( 'wpinv_get_success_page_uri', get_permalink( $page_id ) );
44
}
45
46
/**
47
 * Retrieves the invoice/quote history page URL.
48
 *
49
 * @param string $post_type The post type or invoice type.
50
 * @return string The history page URL.
51
 */
52
function wpinv_get_history_page_uri( $post_type = 'wpi_invoice' ) {
53
    $post_type = sanitize_key( str_replace( 'wpi_', '', $post_type ) );
54
	$page_id   = wpinv_get_option( "{$post_type}_history_page", 0 );
55
	$page_id   = absint( $page_id );
56
	return apply_filters( 'wpinv_get_history_page_uri', get_permalink( $page_id ), $post_type );
57
}
58
59
function wpinv_is_success_page() {
60
	$is_success_page = wpinv_get_option( 'success_page', false );
61
	$is_success_page = ! empty( $is_success_page ) ? is_page( $is_success_page ) : false;
62
63
	return apply_filters( 'wpinv_is_success_page', $is_success_page );
64
}
65
66
function wpinv_is_invoice_history_page() {
67
	$ret = wpinv_get_option( 'invoice_history_page', false );
68
	$ret = $ret ? is_page( $ret ) : false;
69
	return apply_filters( 'wpinv_is_invoice_history_page', $ret );
70
}
71
72
function wpinv_is_subscriptions_history_page() {
73
    $ret = wpinv_get_option( 'invoice_subscription_page', false );
74
    $ret = $ret ? is_page( $ret ) : false;
75
    return apply_filters( 'wpinv_is_subscriptions_history_page', $ret );
76
}
77
78
/**
79
 * Redirects a user the success page.
80
 */
81
function wpinv_send_to_success_page( $args = array() ) {
82
83
    $args = wp_parse_args( $args );
84
85
    if ( ! empty( $args['invoice_key'] ) ) {
86
        $invoice = wpinv_get_invoice( $args['invoice_key'] );
87
88
        if ( $invoice && $invoice->exists() ) {
89
            $success_page = $invoice->get_receipt_url();
90
        }
91
    }
92
93
    if ( empty( $success_page ) ) {
94
        $success_page = wpinv_get_success_page_uri();
95
    }
96
97
    $args['wpinv-notice'] = current( array_keys( wpinv_get_errors() ) );
98
99
    $redirect = add_query_arg( $args, $success_page );
100
101
    $redirect = apply_filters( 'wpinv_send_to_success_page_url', $redirect, $args, $success_page );
102
103
    wp_redirect( $redirect );
104
    exit;
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
105
}
106
107
function wpinv_send_to_failed_page( $args = null ) {
108
	$redirect = wpinv_get_failed_transaction_uri();
109
110
    if ( ! empty( $args ) ) {
111
        // Check for backward compatibility
112
        if ( is_string( $args ) ) {
113
            $args = str_replace( '?', '', $args );
114
        }
115
116
        $args = wp_parse_args( $args );
117
118
        $redirect = add_query_arg( $args, $redirect );
119
    }
120
121
    $gateway = isset( $_REQUEST['wpi-gateway'] ) ? $_REQUEST['wpi-gateway'] : '';
122
123
    $redirect = apply_filters( 'wpinv_failed_page_redirect', $redirect, $gateway, $args );
124
    wp_redirect( $redirect );
125
    exit;
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
126
}
127
128
function wpinv_get_checkout_uri( $args = array() ) {
129
	$uri = wpinv_get_option( 'checkout_page', false );
130
	$uri = isset( $uri ) ? get_permalink( $uri ) : null;
131
132
	if ( ! empty( $args ) ) {
133
		// Check for backward compatibility
134
		if ( is_string( $args ) ) {
135
			$args = str_replace( '?', '', $args );
136
        }
137
138
		$args = wp_parse_args( $args );
139
140
		$uri = add_query_arg( $args, $uri );
141
	}
142
143
	$scheme = defined( 'FORCE_SSL_ADMIN' ) && FORCE_SSL_ADMIN ? 'https' : 'admin';
144
145
	$ajax_url = admin_url( 'admin-ajax.php', $scheme );
146
147
	if ( ( ! preg_match( '/^https/', $uri ) && preg_match( '/^https/', $ajax_url ) ) || wpinv_is_ssl_enforced() ) {
148
		$uri = preg_replace( '/^http:/', 'https:', $uri );
149
	}
150
151
	return apply_filters( 'wpinv_get_checkout_uri', $uri );
152
}
153
154
function wpinv_get_success_page_url( $query_string = null ) {
155
	$success_page = wpinv_get_option( 'success_page', 0 );
156
	$success_page = get_permalink( $success_page );
157
158
	if ( $query_string ) {
159
		$success_page .= $query_string;
160
    }
161
162
	return apply_filters( 'wpinv_success_page_url', $success_page );
163
}
164
165
function wpinv_get_failed_transaction_uri( $extras = false ) {
166
	$uri = wpinv_get_option( 'failure_page', '' );
167
	$uri = ! empty( $uri ) ? trailingslashit( get_permalink( $uri ) ) : home_url();
168
169
	if ( $extras ) {
170
		$uri .= $extras;
171
    }
172
173
	return apply_filters( 'wpinv_get_failed_transaction_uri', $uri );
174
}
175
176
function wpinv_is_failed_transaction_page() {
177
	$ret = wpinv_get_option( 'failure_page', false );
178
	$ret = isset( $ret ) ? is_page( $ret ) : false;
179
180
	return apply_filters( 'wpinv_is_failure_page', $ret );
181
}
182
183
function wpinv_transaction_query( $type = 'start' ) {
184
    global $wpdb;
185
186
    $wpdb->hide_errors();
187
188
    if ( ! defined( 'WPINV_USE_TRANSACTIONS' ) ) {
189
        define( 'WPINV_USE_TRANSACTIONS', true );
190
    }
191
192
    if ( WPINV_USE_TRANSACTIONS ) {
193
        switch ( $type ) {
194
            case 'commit':
195
                $wpdb->query( 'COMMIT' );
196
                break;
197
            case 'rollback':
198
                $wpdb->query( 'ROLLBACK' );
199
                break;
200
            default:
201
                $wpdb->query( 'START TRANSACTION' );
202
                break;
203
        }
204
    }
205
}
206
207
function wpinv_get_prefix() {
208
    $invoice_prefix = 'INV-';
209
210
    return apply_filters( 'wpinv_get_prefix', $invoice_prefix );
211
}
212
213
function wpinv_get_business_logo() {
214
    $business_logo = wpinv_get_option( 'logo' );
215
    return apply_filters( 'wpinv_get_business_logo', $business_logo );
216
}
217
218
function wpinv_get_business_name() {
219
    $name = wpinv_get_option( 'store_name', wpinv_get_blogname() );
220
221
    if ( empty( $name ) ) {
222
        $name = wpinv_get_blogname();
223
    }
224
225
    return apply_filters( 'wpinv_get_business_name', $name );
226
}
227
228
function wpinv_get_blogname() {
229
    return wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
230
}
231
232
function wpinv_get_admin_email() {
233
    $admin_email = wpinv_get_option( 'admin_email', get_option( 'admin_email' ) );
234
    return apply_filters( 'wpinv_admin_email', $admin_email );
235
}
236
237
function wpinv_get_business_website() {
238
    $business_website = home_url( '/' );
239
    return apply_filters( 'wpinv_get_business_website', $business_website );
240
}
241
242
function wpinv_get_terms_text( $invoice_id = 0 ) {
243
    $terms_text = '';
244
    return apply_filters( 'wpinv_get_terms_text', $terms_text, $invoice_id );
245
}
246
247
function wpinv_get_business_footer() {
248
    $site_link = '<a target="_blank" href="' . esc_url( wpinv_get_business_website() ) . '">' . esc_html( wpinv_get_business_name() ) . '</a>';
249
    $business_footer = wp_sprintf( __( 'Thanks for using %s', 'invoicing' ), $site_link );
250
    return apply_filters( 'wpinv_get_business_footer', $business_footer );
251
}
252
253
function wpinv_checkout_required_fields() {
254
    $required_fields = array();
255
256
    // Let payment gateways and other extensions determine if address fields should be required
257
    $require_billing_details = apply_filters( 'wpinv_checkout_required_billing_details', wpinv_use_taxes() );
258
259
    if ( $require_billing_details ) {
260
		if ( (bool)wpinv_get_option( 'fname_mandatory' ) ) {
261
			$required_fields['first_name'] = array(
262
				'error_id'      => 'invalid_first_name',
263
				'error_message' => __( 'Please enter your first name', 'invoicing' ),
264
			);
265
		}
266
		if ( (bool)wpinv_get_option( 'address_mandatory' ) ) {
267
			$required_fields['address'] = array(
268
				'error_id'      => 'invalid_address',
269
				'error_message' => __( 'Please enter your address', 'invoicing' ),
270
			);
271
		}
272
		if ( (bool)wpinv_get_option( 'city_mandatory' ) ) {
273
			$required_fields['city'] = array(
274
				'error_id'      => 'invalid_city',
275
				'error_message' => __( 'Please enter your billing city', 'invoicing' ),
276
			);
277
		}
278
		if ( (bool)wpinv_get_option( 'state_mandatory' ) ) {
279
			$required_fields['state'] = array(
280
				'error_id'      => 'invalid_state',
281
				'error_message' => __( 'Please enter billing state / province', 'invoicing' ),
282
			);
283
		}
284
		if ( (bool)wpinv_get_option( 'country_mandatory' ) ) {
285
			$required_fields['country'] = array(
286
				'error_id'      => 'invalid_country',
287
				'error_message' => __( 'Please select your billing country', 'invoicing' ),
288
			);
289
		}
290
    }
291
292
    return apply_filters( 'wpinv_checkout_required_fields', $required_fields );
293
}
294
295
function wpinv_is_ssl_enforced() {
296
    $ssl_enforced = wpinv_get_option( 'enforce_ssl', false );
297
    return (bool) apply_filters( 'wpinv_is_ssl_enforced', $ssl_enforced );
298
}
299
300
function wpinv_schedule_event_twicedaily() {
301
    wpinv_email_payment_reminders();
0 ignored issues
show
Deprecated Code introduced by
The function wpinv_email_payment_reminders() has been deprecated. ( Ignorable by Annotation )

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

301
    /** @scrutinizer ignore-deprecated */ wpinv_email_payment_reminders();
Loading history...
302
}
303
add_action( 'wpinv_register_schedule_event_daily', 'wpinv_schedule_event_twicedaily' );
304
305
function wpinv_require_login_to_checkout() {
306
    $return = wpinv_get_option( 'login_to_checkout', false );
307
    return (bool) apply_filters( 'wpinv_require_login_to_checkout', $return );
308
}
309
310
function wpinv_sequential_number_active( $type = '' ) {
311
    $check = apply_filters( 'wpinv_pre_check_sequential_number_active', null, $type );
312
    if ( null !== $check ) {
313
        return $check;
314
    }
315
316
    return wpinv_get_option( 'sequential_invoice_number' );
317
}
318
319
function wpinv_switch_to_locale( $locale = null ) {
320
    global $invoicing, $wpi_switch_locale;
321
322
    if ( ! empty( $invoicing ) && function_exists( 'switch_to_locale' ) ) {
323
        $locale = empty( $locale ) ? get_locale() : $locale;
324
325
        switch_to_locale( $locale );
326
327
        $wpi_switch_locale = $locale;
328
329
        add_filter( 'plugin_locale', 'get_locale' );
330
331
        $invoicing->load_textdomain();
332
333
        do_action( 'wpinv_switch_to_locale', $locale );
334
    }
335
}
336
337
function wpinv_restore_locale() {
338
    global $invoicing, $wpi_switch_locale;
339
340
    if ( ! empty( $invoicing ) && function_exists( 'restore_previous_locale' ) && $wpi_switch_locale ) {
341
        restore_previous_locale();
342
343
        $wpi_switch_locale = null;
344
345
        remove_filter( 'plugin_locale', 'get_locale' );
346
347
        $invoicing->load_textdomain();
348
349
        do_action( 'wpinv_restore_locale' );
350
    }
351
}
352
353
/**
354
 * Returns the default form's id.
355
 */
356
function wpinv_get_default_payment_form() {
357
    $form = get_option( 'wpinv_default_payment_form' );
358
359
    if ( empty( $form ) || 'publish' != get_post_status( $form ) ) {
360
        $form = wp_insert_post(
361
            array(
362
                'post_type'   => 'wpi_payment_form',
363
                'post_title'  => __( 'Checkout (default)', 'invoicing' ),
364
                'post_status' => 'publish',
365
                'meta_input'  => array(
366
                    'wpinv_form_elements' => wpinv_get_data( 'default-payment-form' ),
367
                    'wpinv_form_items'    => array(),
368
                ),
369
            )
370
        );
371
372
        update_option( 'wpinv_default_payment_form', $form );
373
    }
374
375
    // WPML support.
376
    return (int) wpinv_translate_post_id( $form );
377
}
378
379
/**
380
 * Translates a post id.
381
 *
382
 * @param int $post_id
383
 */
384
function wpinv_translate_post_id( $post_id ) {
385
386
    // Abort if no post id is given.
387
    if ( empty( $post_id ) ) {
388
        return $post_id;
389
    }
390
391
    // WPML.
392
    $post_id = apply_filters( 'wpml_object_id', $post_id, 'wpi_payment_form', true );
393
394
    // Polylang.
395
    if ( function_exists( 'pll_get_post' ) ) {
396
        $translated = pll_get_post( $post_id );
397
398
        if ( ! empty( $translated ) ) {
399
            $post_id = $translated;
400
        }
401
    }
402
403
    return $post_id;
404
}
405
406
/**
407
 * Retrieves a given payment form's elements.
408
 *
409
 * @param int $payment_form
410
 */
411
function getpaid_get_payment_form_elements( $payment_form ) {
412
413
    if ( empty( $payment_form ) ) {
414
        return wpinv_get_data( 'sample-payment-form' );
415
    }
416
417
    $form_elements = get_post_meta( $payment_form, 'wpinv_form_elements', true );
418
419
    if ( is_array( $form_elements ) ) {
420
        return $form_elements;
421
    }
422
423
    return wpinv_get_data( 'sample-payment-form' );
424
425
}
426
427
/**
428
 * Returns an array of items for the given form.
429
 *
430
 * @param int $payment_form
431
 */
432
function gepaid_get_form_items( $id ) {
433
    $form = new GetPaid_Payment_Form( $id );
434
435
    // Is this a default form?
436
    if ( $form->is_default() ) {
437
        return array();
438
    }
439
440
    return $form->get_items( 'view', 'arrays' );
441
}
442
443
/**
444
 * Trims each line in a paragraph.
445
 *
446
 */
447
function gepaid_trim_lines( $content ) {
448
    return implode( "\n", array_map( 'trim', explode( "\n", $content ) ) );
449
}
450
451
452
function wpinv_add_elementor_widget_categories( $elements_manager ) {
453
    $elements_manager->add_category(
454
        'getpaid',
455
        array(
456
            'title' => esc_html__( 'GetPaid', 'invoicing' ),
457
            'icon'  => 'fa fa-plug',
458
        )
459
    );
460
}
461
add_filter( 'elementor/elements/categories_registered', 'wpinv_add_elementor_widget_categories' );
462
463
function wpinv_alter_elementor_widget_config( $config ) {
464
465
    if ( ! empty( $config['initial_document']['widgets'] ) ) {
466
        foreach ( $config['initial_document']['widgets'] as $key => $widget ) {
467
            if ( substr( $key, 0, 16 ) === 'wp-widget-wpinv_' || $key === 'wp-widget-getpaid' ) {
468
                $config['initial_document']['widgets'][ $key ]['categories'][] = 'getpaid';
469
                $config['initial_document']['widgets'][ $key ]['hide_on_search'] = false;
470
                $config['initial_document']['widgets'][ $key ]['icon'] = 'eicon-globe'; //@todo if no icons use on page then font-awesome is not loaded, wif we can fifure out how to force load we can use icons. <i class="fas fa-globe-americas"></i><i class="fa-solid fa-earth-americas"></i>
471
            }
472
        }
473
    } 
474
475
    return $config;
476
}
477
add_filter( 'elementor/editor/localize_settings', 'wpinv_alter_elementor_widget_config' );
478
479
function wpinv_get_report_graphs() {
480
481
    return apply_filters(
482
        'getpaid_report_graphs',
483
        array(
484
            'sales'    => __( 'Earnings', 'invoicing' ),
485
            'refunds'  => __( 'Refunds', 'invoicing' ),
486
            'tax'      => __( 'Taxes', 'invoicing' ),
487
            'fees'     => __( 'Fees', 'invoicing' ),
488
            'discount' => __( 'Discounts', 'invoicing' ),
489
            'invoices' => __( 'Invoices', 'invoicing' ),
490
            'items'    => __( 'Purchased Items', 'invoicing' ),
491
        )
492
    );
493
494
}
495