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-tax-functions.php (1 issue)

1
<?php
2
/**
3
 * Contains the tax functions.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * Returns an array of eu states.
11
 *
12
 * @return array
13
 */
14
function getpaid_get_eu_states() {
15
    return wpinv_get_data( 'eu-states' );
16
}
17
18
/**
19
 * Checks if a given country is an EU state.
20
 *
21
 * @return bool
22
 */
23
function getpaid_is_eu_state( $country ) {
24
    return ! empty( $country ) && in_array( strtoupper( $country ), getpaid_get_eu_states(), true ) ? true : false;
25
}
26
27
/**
28
 * Returns an array of gst states.
29
 *
30
 * @return array
31
 */
32
function getpaid_get_gst_states() {
33
    return array( 'AU', 'NZ', 'CA', 'CN' );
34
}
35
36
/**
37
 * Checks if a given country is GST country.
38
 *
39
 * @return bool
40
 */
41
function getpaid_is_gst_country( $country ) {
42
    return ! empty( $country ) && in_array( strtoupper( $country ), getpaid_get_gst_states(), true ) ? true : false;
43
}
44
45
/**
46
 * Checks whether or not taxes are enabled.
47
 *
48
 * @return bool
49
 */
50
function wpinv_use_taxes() {
51
52
    $ret = wpinv_get_option( 'enable_taxes', false );
53
    return (bool) apply_filters( 'wpinv_use_taxes', ! empty( $ret ) );
54
55
}
56
57
/**
58
 * Checks whether or not an invoice is taxable.
59
 *
60
 * @param WPInv_Invoice $invoice
61
 * @return bool
62
 */
63
function wpinv_is_invoice_taxable( $invoice ) {
64
    return $invoice->is_taxable();
65
}
66
67
/**
68
 * Checks whether or not a given country is taxable.
69
 *
70
 * @param string $country
71
 * @return bool
72
 */
73
function wpinv_is_country_taxable( $country ) {
74
    $is_eu     = getpaid_is_eu_state( $country );
75
    $is_exempt = ! $is_eu && wpinv_is_base_country( $country ) && wpinv_same_country_exempt_vat();
76
77
    return (bool) apply_filters( 'wpinv_is_country_taxable', ! $is_exempt, $country );
78
79
}
80
81
/**
82
 * Checks whether or not an item is taxable.
83
 *
84
 * @param WPInv_Item|GetPaid_Form_Item $item
85
 * @return bool
86
 */
87
function wpinv_is_item_taxable( $item ) {
88
    return '_exempt' !== $item->get_vat_rule();
89
}
90
91
/**
92
 * Checks whether or not taxes are calculated based on the store address.
93
 *
94
 * @return bool
95
 */
96
function wpinv_use_store_address_as_tax_base( $tax_rule = false ) {
97
    $use_base = wpinv_get_option( 'tax_base', 'billing' ) === 'base';
98
99
    if ( $tax_rule ) {
100
        $rules    = getpaid_get_tax_rules( 'tax_base' );
101
        $use_base = isset( $rules[ $tax_rule ] ) ? 'base' === $rules[ $tax_rule ] : $use_base;
102
    }
103
104
    return (bool) apply_filters( 'wpinv_use_store_address_as_tax_base', $use_base, $tax_rule );
105
}
106
107
/**
108
 * Retrieves the same country rule.
109
 *
110
 * @return bool
111
 */
112
function wpinv_get_vat_same_country_rule( $tax_rule = false ) {
113
    $rule = wpinv_get_option( 'vat_same_country_rule', 'vat_too' );
114
115
    if ( $tax_rule ) {
116
        $rules = getpaid_get_tax_rules( 'same_country_rule' );
117
        $rule  = isset( $rules[ $tax_rule ] ) ? $rules[ $tax_rule ] : $rule;
118
    }
119
120
    return (bool) apply_filters( 'wpinv_get_vat_same_country_rule', $rule, $tax_rule );
121
}
122
123
/**
124
 * Checks whether or not prices include tax.
125
 *
126
 * @return bool
127
 */
128
function wpinv_prices_include_tax() {
129
    $is_inclusive = wpinv_get_option( 'prices_include_tax', 'no' ) === 'yes';
130
    return (bool) apply_filters( 'wpinv_prices_include_tax', $is_inclusive );
131
}
132
133
/**
134
 * Checks whether we should round per rate or per subtotal
135
 *
136
 * @return bool
137
 */
138
function wpinv_round_tax_per_tax_rate() {
139
    $subtotal_rounding = wpinv_get_option( 'tax_subtotal_rounding', 1 );
140
    return (bool) apply_filters( 'wpinv_round_tax_per_tax_rate', empty( $subtotal_rounding ) );
141
}
142
143
/**
144
 * Checks whether we should display individual tax rates.
145
 *
146
 * @return bool
147
 */
148
function wpinv_display_individual_tax_rates() {
149
    $individual = wpinv_get_option( 'tax_display_totals', 'single' ) === 'individual';
150
    return (bool) apply_filters( 'wpinv_display_individual_tax_rates', $individual );
151
}
152
153
/**
154
 * Retrieves the default tax rate.
155
 *
156
 * @return float
157
 */
158
function wpinv_get_default_tax_rate() {
159
    $rate = wpinv_get_option( 'tax_rate', 0 );
160
    return (float) apply_filters( 'wpinv_get_default_tax_rate', floatval( $rate ) );
161
}
162
163
/**
164
 * Checks if we should exempt same country vat.
165
 *
166
 * @return bool
167
 */
168
function wpinv_same_country_exempt_vat() {
169
    return 'no' === wpinv_get_option( 'vat_same_country_rule', 'vat_too' );
170
}
171
172
/**
173
 * Retrieves an array of all tax rates.
174
 *
175
 * @return array
176
 */
177
function wpinv_get_tax_rates() {
178
    return GetPaid_Tax::get_all_tax_rates();
179
}
180
181
/**
182
 * Retrieves an item's tax rates.
183
 *
184
 * @param WPInv_Item|GetPaid_Form_Item $item
185
 * @param string $country
186
 * @param string $state
187
 * @return array
188
 */
189
function getpaid_get_item_tax_rates( $item, $country = '', $state = '' ) {
190
191
    // Abort if the item is not taxable.
192
    if ( ! wpinv_is_item_taxable( $item ) ) {
193
        return array();
194
    }
195
196
    // Maybe use the store address.
197
    if ( wpinv_use_store_address_as_tax_base( $item->get_vat_rule() ) ) {
198
        $country = wpinv_get_default_country();
199
        $state   = wpinv_get_default_state();
200
    }
201
202
    // Retrieve tax rates.
203
    $tax_rates = GetPaid_Tax::get_address_tax_rates( $country, $state );
204
205
    // Fallback to the default tax rates if non were found.
206
    if ( empty( $tax_rates ) ) {
207
        $tax_rates = GetPaid_Tax::get_default_tax_rates();
208
    }
209
210
    return apply_filters( 'getpaid_get_item_tax_rates', $tax_rates, $item, $country, $state );
211
}
212
213
/**
214
 * Filters an item's tax rate.
215
 *
216
 * @param WPInv_Item|GetPaid_Form_Item $item
217
 * @param array $rates
218
 * @return array
219
 */
220
function getpaid_filter_item_tax_rates( $item, $rates ) {
221
222
    $tax_class = $item->get_vat_class();
223
224
    foreach ( $rates as $i => $rate ) {
225
226
        if ( '_reduced' === $tax_class ) {
227
            $rates[ $i ]['rate'] = empty( $rate['reduced_rate'] ) ? 0 : $rate['reduced_rate'];
228
        }
229
230
        if ( '_exempt' === $tax_class ) {
231
            $rates[ $i ]['rate'] = 0;
232
        }
233
    }
234
235
    return apply_filters( 'getpaid_filter_item_tax_rates', $rates, $item );
236
}
237
238
/**
239
 * Retrieves an item's taxes.
240
 *
241
 * @param float $amount
242
 * @param array $rates
243
 * @return array
244
 */
245
function getpaid_calculate_item_taxes( $amount, $rates ) {
246
247
    $is_inclusive = wpinv_prices_include_tax();
248
    $taxes        = GetPaid_Tax::calc_tax( $amount, $rates, $is_inclusive );
249
250
    return apply_filters( 'getpaid_calculate_taxes', $taxes, $amount, $rates );
251
}
252
253
/**
254
 * Prepares an item's tax.
255
 *
256
 * @param WPInv_Item|GetPaid_Form_Item $item
257
 * @param string $tax_name
258
 * @param float $tax_amount
259
 * @param float $recurring_tax_amount
260
 * @return array
261
 */
262
function getpaid_prepare_item_tax( $item, $tax_name, $tax_amount, $recurring_tax_amount ) {
263
264
    $initial_tax   = $tax_amount;
265
	$recurring_tax = 0;
266
267
    if ( $item->is_recurring() ) {
268
		$recurring_tax = $recurring_tax_amount;
269
	}
270
271
	return array(
272
		'name'          => sanitize_text_field( $tax_name ),
273
		'initial_tax'   => $initial_tax,
274
		'recurring_tax' => $recurring_tax,
275
    );
276
277
}
278
279
/**
280
 * Sanitizes a VAT number.
281
 *
282
 * @param string $vat_number
283
 * @return string
284
 */
285
function wpinv_sanitize_vat_number( $vat_number ) {
286
    return str_replace( array( ' ', '.', '-', '_', ',' ), '', strtoupper( trim( $vat_number ) ) );
287
}
288
289
/**
290
 * Validates a vat number via a REGEX.
291
 *
292
 * @param string $vat_number
293
 * @return bool
294
 */
295
function wpinv_regex_validate_vat_number( $vat_number ) {
296
297
    $country    = substr( $vat_number, 0, 2 );
298
    $vatin      = substr( $vat_number, 2 );
299
    $regexes    = wpinv_get_data( 'vat-number-regexes' );
300
301
    if ( isset( $regexes[ $country ] ) ) {
302
303
        $regex = $regexes[ $country ];
304
        $regex = '/^(?:' . $regex . ')$/';
305
        return 1 === preg_match( $regex, $vatin );
306
307
    }
308
309
    // Not an EU state, use filters to validate the number.
310
    return apply_filters( 'wpinv_regex_validate_vat_number', true, $vat_number );
311
}
312
313
/**
314
 * Validates a vat number via a VIES.
315
 *
316
 * @param string $vat_number
317
 * @return bool
318
 */
319
function wpinv_vies_validate_vat_number( $vat_number ) {
320
321
    $country    = substr( $vat_number, 0, 2 );
322
    $vatin      = substr( $vat_number, 2 );
323
324
    $url        = add_query_arg(
325
        array(
326
            'ms'  => rawurlencode( $country ),
327
            'iso' => rawurlencode( $country ),
328
            'vat' => rawurlencode( $vatin ),
329
        ),
330
        'http://ec.europa.eu/taxation_customs/vies/viesquer.do'
331
    );
332
333
    $response   = wp_remote_get( $url );
334
    $response   = wp_remote_retrieve_body( $response );
335
336
    // Fallback gracefully if the VIES website is down.
337
    if ( empty( $response ) ) {
338
        return true;
339
    }
340
341
    return 1 !== preg_match( '/invalid VAT number/i', $response );
342
343
}
344
345
/**
346
 * Validates a vat number.
347
 *
348
 * @param string $vat_number
349
 * @param string $country
350
 * @return bool
351
 */
352
function wpinv_validate_vat_number( $vat_number, $country ) {
353
354
    // In case the vat number does not have a country code...
355
    $vat_number = wpinv_sanitize_vat_number( $vat_number );
356
    $_country   = substr( $vat_number, 0, 2 );
357
358
    if ( wpinv_country_name( $_country ) === $_country ) {
359
        $vat_number = strtoupper( $country ) . $vat_number;
360
    }
361
362
    return wpinv_regex_validate_vat_number( $vat_number ) && wpinv_vies_validate_vat_number( $vat_number );
363
}
364
365
/**
366
 * Checks whether or not we should validate vat numbers.
367
 *
368
 * @return bool
369
 */
370
function wpinv_should_validate_vat_number() {
371
    $validate = wpinv_get_option( 'validate_vat_number' );
372
	return ! empty( $validate );
373
}
374
375
function wpinv_sales_tax_for_year( $year = null ) {
376
    return wpinv_price( wpinv_get_sales_tax_for_year( $year ) );
377
}
378
379
function wpinv_get_sales_tax_for_year( $year = null ) {
380
    global $wpdb;
381
382
    // Start at zero
383
    $tax = 0;
384
385
    if ( ! empty( $year ) ) {
386
        $args = array(
387
            'post_type'      => 'wpi_invoice',
388
            'post_status'    => array( 'publish' ),
389
            'posts_per_page' => -1,
390
            'year'           => $year,
391
            'fields'         => 'ids',
392
        );
393
394
        $payments    = get_posts( $args );
395
        $payment_ids = implode( ',', $payments );
396
397
        if ( count( $payments ) > 0 ) {
398
            $sql = "SELECT SUM( meta_value ) FROM $wpdb->postmeta WHERE meta_key = '_wpinv_tax' AND post_id IN( $payment_ids )";
399
            $tax = $wpdb->get_var( $sql );
400
        }
401
}
402
403
    return apply_filters( 'wpinv_get_sales_tax_for_year', $tax, $year );
404
}
405
406
function wpinv_is_cart_taxed() {
407
    return wpinv_use_taxes();
408
}
409
410
function wpinv_prices_show_tax_on_checkout() {
411
    return false; // TODO
412
    $ret = ( wpinv_get_option( 'checkout_include_tax', false ) === 'yes' && wpinv_use_taxes() );
413
414
    return apply_filters( 'wpinv_taxes_on_prices_on_checkout', $ret );
415
}
416
417
function wpinv_display_tax_rate() {
418
    $ret = wpinv_use_taxes() && wpinv_get_option( 'display_tax_rate', false );
419
420
    return apply_filters( 'wpinv_display_tax_rate', $ret );
421
}
422
423
function wpinv_cart_needs_tax_address_fields() {
424
    if ( ! wpinv_is_cart_taxed() ) {
425
        return false;
426
    }
427
428
    return ! did_action( 'wpinv_after_cc_fields', 'wpinv_default_cc_address_fields' );
0 ignored issues
show
The call to did_action() has too many arguments starting with 'wpinv_default_cc_address_fields'. ( Ignorable by Annotation )

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

428
    return ! /** @scrutinizer ignore-call */ did_action( 'wpinv_after_cc_fields', 'wpinv_default_cc_address_fields' );

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...
429
}
430
431
function wpinv_item_is_tax_exclusive( $item_id = 0 ) {
432
    $ret = (bool)get_post_meta( $item_id, '_wpinv_tax_exclusive', false );
433
    return apply_filters( 'wpinv_is_tax_exclusive', $ret, $item_id );
434
}
435
436
function wpinv_currency_decimal_filter( $decimals = 2 ) {
437
    $currency = wpinv_get_currency();
438
439
    switch ( $currency ) {
440
        case 'RIAL':
441
        case 'JPY':
442
        case 'TWD':
443
        case 'HUF':
444
            $decimals = 0;
445
            break;
446
    }
447
448
    return apply_filters( 'wpinv_currency_decimal_count', $decimals, $currency );
449
}
450
451
function wpinv_tax_amount() {
452
    $output = 0.00;
453
454
    return apply_filters( 'wpinv_tax_amount', $output );
455
}
456
457
/**
458
 * Filters the VAT rules to ensure that each item has a VAT rule.
459
 *
460
 * @param string|bool|null $vat_rule
461
 */
462
function getpaid_filter_vat_rule( $vat_rule ) {
463
464
    if ( empty( $vat_rule ) ) {
465
        return 'digital';
466
    }
467
468
    return $vat_rule;
469
}
470
add_filter( 'wpinv_get_item_vat_rule', 'getpaid_filter_vat_rule' );
471
472
/**
473
 * Filters the VAT class to ensure that each item has a VAT class.
474
 *
475
 * @param string|bool|null $vat_rule
476
 */
477
function getpaid_filter_vat_class( $vat_class ) {
478
    return empty( $vat_class ) ? '_standard' : $vat_class;
479
}
480
add_filter( 'wpinv_get_item_vat_class', 'getpaid_filter_vat_class' );
481
482
/**
483
 * Returns a list of all tax classes.
484
 *
485
 * @return array
486
 */
487
function getpaid_get_tax_classes() {
488
489
    return apply_filters(
490
        'getpaid_tax_classes',
491
        array(
492
            '_standard' => __( 'Standard Tax Rate', 'invoicing' ),
493
            '_reduced'  => __( 'Reduced Tax Rate', 'invoicing' ),
494
            '_exempt'   => __( 'Tax Exempt', 'invoicing' ),
495
        )
496
    );
497
498
}
499
500
/**
501
 * Returns a list of all tax rules.
502
 *
503
 * @return array
504
 */
505
function getpaid_get_tax_rules( $return = 'label' ) {
506
    return wp_list_pluck( GetPaid_Tax::get_all_tax_rules(), $return, 'key' );
507
}
508
509
/**
510
 * Returns the label of a tax class.
511
 *
512
 * @param string $tax_class
513
 * @return string
514
 */
515
function getpaid_get_tax_class_label( $tax_class ) {
516
517
    $classes = getpaid_get_tax_classes();
518
519
    if ( isset( $classes[ $tax_class ] ) ) {
520
        return sanitize_text_field( $classes[ $tax_class ] );
521
    }
522
523
    return sanitize_text_field( $tax_class );
524
525
}
526
527
/**
528
 * Returns the label of a tax rule.
529
 *
530
 * @param string $tax_rule
531
 * @return string
532
 */
533
function getpaid_get_tax_rule_label( $tax_rule ) {
534
535
    $rules = getpaid_get_tax_rules();
536
537
    if ( isset( $rules[ $tax_rule ] ) ) {
538
        return sanitize_text_field( $rules[ $tax_rule ] );
539
    }
540
541
    return sanitize_text_field( $tax_rule );
542
543
}
544
545
/**
546
 * Returns the taxable amount
547
 *
548
 * @param GetPaid_Form_Item $item
549
 * @param string $recurring
550
 * @return string
551
 */
552
function getpaid_get_taxable_amount( $item, $recurring = false ) {
553
554
    $taxable_amount  = $recurring ? $item->get_recurring_sub_total() : $item->get_sub_total();
555
    $taxable_amount -= $recurring ? $item->recurring_item_discount : $item->item_discount;
556
    $taxable_amount  = max( 0, $taxable_amount );
557
    return apply_filters( 'getpaid_taxable_amount', $taxable_amount, $item, $recurring );
558
559
}
560