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-email-functions.php (5 issues)

1
<?php
2
/**
3
 * Contains email functions.
4
 *
5
 * Most of this functions are deprecated and will be removed soon.
6
 * Please use GetPaid_Notification_Email_Sender
7
 */
8
9
defined( 'ABSPATH' ) || exit;
10
11
/*
12
|--------------------------------------------------------------------------
13
| Email Template functions.
14
|--------------------------------------------------------------------------
15
*/
16
17
/**
18
 * Generates the email header.
19
 */
20
function wpinv_email_header( $email_heading ) {
21
    wpinv_get_template( 'emails/wpinv-email-header.php', compact( 'email_heading' ) );
22
}
23
add_action( 'wpinv_email_header', 'wpinv_email_header' );
24
25
26
/**
27
 * Generates the email footer.
28
 */
29
function wpinv_email_footer() {
30
    wpinv_get_template( 'emails/wpinv-email-footer.php' );
31
}
32
add_action( 'wpinv_email_footer', 'wpinv_email_footer' );
33
34
35
/**
36
 * Display invoice details in emails.
37
 *
38
 * @param WPInv_Invoice $invoice
39
 * @param string $email_type
40
 * @param bool $sent_to_admin
41
 */
42
function wpinv_email_invoice_details( $invoice, $email_type, $sent_to_admin ) {
43
44
    $args = compact( 'invoice', 'email_type', 'sent_to_admin' );
45
    wpinv_get_template( 'emails/invoice-details.php', $args );
46
47
}
48
add_action( 'wpinv_email_invoice_details', 'wpinv_email_invoice_details', 10, 3 );
49
50
/**
51
 * Display line items in emails.
52
 *
53
 * @param WPInv_Invoice $invoice
54
 * @param string $email_type
55
 * @param bool $sent_to_admin
56
 */
57
function wpinv_email_invoice_items( $invoice, $email_type, $sent_to_admin ) {
58
59
    // Prepare line items.
60
    $columns = getpaid_invoice_item_columns( $invoice );
61
    $columns = apply_filters( 'getpaid_invoice_line_items_table_columns', $columns, $invoice );
62
63
    // Load the template.
64
    wpinv_get_template( 'emails/invoice-items.php', compact( 'invoice', 'columns', 'email_type', 'sent_to_admin' ) );
65
66
}
67
add_action( 'wpinv_email_invoice_items', 'wpinv_email_invoice_items', 10, 3 );
68
69
70
/**
71
 * Display billing details in emails.
72
 *
73
 * @param WPInv_Invoice $invoice
74
 * @param string $email_type
75
 * @param bool $sent_to_admin
76
 */
77
function wpinv_email_billing_details( $invoice, $email_type, $sent_to_admin ) {
78
79
    $args = compact( 'invoice', 'email_type', 'sent_to_admin' );
80
    wpinv_get_template( 'emails/wpinv-email-billing-details.php', $args );
81
82
}
83
add_action( 'wpinv_email_billing_details', 'wpinv_email_billing_details', 10, 3 );
84
85
/**
86
 * Returns email css.
87
 *
88
 */
89
function getpaid_get_email_css() {
90
91
    $css = wpinv_get_template_html( 'emails/wpinv-email-styles.php' );
92
    return apply_filters( 'wpinv_email_styles', $css );
93
94
}
95
96
/**
97
 * Inline styles to email content.
98
 *
99
 * @param string $content
100
 * @return string
101
 *
102
 */
103
function wpinv_email_style_body( $content ) {
104
105
    if ( ! class_exists( 'DOMDocument' ) ) {
106
        return $content;
107
    }
108
109
    $css = getpaid_get_email_css();
110
111
    // include css inliner
112
	if ( ! class_exists( 'Emogrifier' ) ) {
113
		include_once WPINV_PLUGIN_DIR . 'includes/libraries/class-emogrifier.php';
114
    }
115
116
    // Inline the css.
117
    try {
118
        $emogrifier = new Emogrifier( $content, $css );
119
        $_content   = $emogrifier->emogrify();
120
        $content    = $_content;
121
    } catch ( Exception $e ) {
122
        wpinv_error_log( $e->getMessage(), 'emogrifier' );
123
    }
124
125
    return $content;
126
}
127
128
129
// Backwards compatibility.
130
function wpinv_init_transactional_emails() {
131
    foreach ( apply_filters( 'wpinv_email_actions', array() ) as $action ) {
132
        add_action( $action, 'wpinv_send_transactional_email', 10, 10 );
133
    }
134
}
135
add_action( 'init', 'wpinv_init_transactional_emails' );
136
137
function wpinv_send_transactional_email() {
138
    $args       = func_get_args();
139
    $function   = current_filter() . '_notification';
140
    do_action_ref_array( $function, $args );
141
}
142
143
function wpinv_mail_get_from_address() {
144
    $from_address = apply_filters( 'wpinv_mail_from_address', wpinv_get_option( 'email_from', get_option( 'admin_email' ) ) );
145
    return sanitize_email( $from_address );
146
}
147
148
function wpinv_mail_get_from_name() {
149
    $from_name = apply_filters( 'wpinv_mail_from_name', wpinv_get_option( 'email_from_name', get_bloginfo( 'name', 'display' ) ) );
150
    return wp_specialchars_decode( esc_html( $from_name ), ENT_QUOTES );
151
}
152
153
function wpinv_mail_admin_bcc_active( $mail_type = '' ) {
154
    $active = apply_filters( 'wpinv_mail_admin_bcc_active', wpinv_get_option( 'email_' . $mail_type . '_admin_bcc' ) );
155
    return ( $active ? true : false );
156
}
157
158
function wpinv_mail_get_content_type( $content_type = 'text/html', $email_type = 'html' ) {
159
    $email_type = apply_filters( 'wpinv_mail_content_type', $email_type );
160
161
    switch ( $email_type ) {
162
        case 'html':
163
            $content_type = 'text/html';
164
            break;
165
        case 'multipart':
166
            $content_type = 'multipart/alternative';
167
            break;
168
        default:
169
            $content_type = 'text/plain';
170
            break;
171
    }
172
173
    return $content_type;
174
}
175
176
/**
177
 * Sends a single email.
178
 *
179
 * @param string|array $to The recipient's email or an array of recipient emails.
180
 * @param string       $subject The email subject.
181
 * @param string       $message The email content.
182
 * @param mixed        $deprecated
183
 * @param array        $attachments Any files to attach to the email.
184
 * @param string|array $cc An email or array of extra emails to send a copy of the email to.
185
 */
186
function wpinv_mail_send( $to, $subject, $message, $deprecated, $attachments = array(), $cc = array() ) {
187
188
    $mailer  = new GetPaid_Notification_Email_Sender();
189
    $message = wpinv_email_style_body( $message );
190
    $to      = array_merge( wpinv_parse_list( $to ), wpinv_parse_list( $cc ) );
191
192
	return $mailer->send(
193
        $to,
194
        $subject,
195
        $message,
196
        $attachments
197
    );
198
199
}
200
201
/**
202
 * Returns an array of email settings.
203
 *
204
 * @return array
205
 */
206
function wpinv_get_emails() {
207
    return apply_filters( 'wpinv_get_emails', wpinv_get_data( 'email-settings' ) );
208
}
209
210
/**
211
 * Filter email settings.
212
 *
213
 * @param array $settings
214
 * @return array
215
 */
216
function wpinv_settings_emails( $settings = array() ) {
217
    $settings = array_merge( $settings, wpinv_get_emails() );
218
    return apply_filters( 'wpinv_settings_get_emails', $settings );
219
}
220
add_filter( 'wpinv_settings_emails', 'wpinv_settings_emails', 10, 1 );
221
222
/**
223
 * Filter email section names.
224
 *
225
 */
226
function wpinv_settings_sections_emails( $settings ) {
227
    foreach ( wpinv_get_emails() as $key => $email ) {
228
        $settings[ $key ] = ! empty( $email[ 'email_' . $key . '_header' ]['name'] ) ? strip_tags( $email[ 'email_' . $key . '_header' ]['name'] ) : strip_tags( $key );
229
    }
230
231
    return $settings;
232
}
233
add_filter( 'wpinv_settings_sections_emails', 'wpinv_settings_sections_emails', 10, 1 );
234
235
function wpinv_email_is_enabled( $email_type ) {
236
    $emails = wpinv_get_emails();
237
    $enabled = isset( $emails[ $email_type ] ) && wpinv_get_option( 'email_' . $email_type . '_active', 0 ) ? true : false;
238
239
    return apply_filters( 'wpinv_email_is_enabled', $enabled, $email_type );
240
}
241
242
function wpinv_email_get_recipient( $email_type = '', $invoice_id = 0, $invoice = array() ) {
243
    switch ( $email_type ) {
244
        case 'new_invoice':
245
        case 'cancelled_invoice':
246
        case 'failed_invoice':
247
            $recipient  = wpinv_get_admin_email();
248
            break;
249
        default:
250
            $invoice    = ! empty( $invoice ) && is_object( $invoice ) ? $invoice : ( $invoice_id > 0 ? wpinv_get_invoice( $invoice_id ) : null );
251
            $recipient  = ! empty( $invoice ) ? $invoice->get_email() : '';
252
            break;
253
    }
254
255
    return apply_filters( 'wpinv_email_recipient', $recipient, $email_type, $invoice_id, $invoice );
256
}
257
258
/**
259
 * Returns invoice CC recipients
260
 */
261
function wpinv_email_get_cc_recipients( $email_type = '', $invoice_id = 0, $invoice = array() ) {
262
    switch ( $email_type ) {
263
        case 'new_invoice':
264
        case 'cancelled_invoice':
265
        case 'failed_invoice':
266
            return array();
267
        break;
268
        default:
269
            $invoice    = ! empty( $invoice ) && is_object( $invoice ) ? $invoice : ( $invoice_id > 0 ? wpinv_get_invoice( $invoice_id ) : null );
270
            $recipient  = empty( $invoice ) ? '' : get_post_meta( $invoice->ID, 'wpinv_email_cc', true );
271
            if ( empty( $recipient ) ) {
272
                return array();
273
            }
274
            return array_filter( array_map( 'trim', explode( ',', $recipient ) ) );
275
        break;
276
    }
277
278
}
279
280
function wpinv_email_get_subject( $email_type = '', $invoice_id = 0, $invoice = array() ) {
281
    $subject    = wpinv_get_option( 'email_' . $email_type . '_subject' );
282
    $subject    = __( $subject, 'invoicing' );
0 ignored issues
show
It seems like $subject can also be of type false; however, parameter $text of __() 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

282
    $subject    = __( /** @scrutinizer ignore-type */ $subject, 'invoicing' );
Loading history...
283
284
    $subject    = wpinv_email_format_text( $subject, $invoice );
285
286
    return apply_filters( 'wpinv_email_subject', $subject, $email_type, $invoice_id, $invoice );
287
}
288
289
function wpinv_email_get_heading( $email_type = '', $invoice_id = 0, $invoice = array() ) {
290
    $email_heading = wpinv_get_option( 'email_' . $email_type . '_heading' );
291
    $email_heading = __( $email_heading, 'invoicing' );
0 ignored issues
show
It seems like $email_heading can also be of type false; however, parameter $text of __() 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

291
    $email_heading = __( /** @scrutinizer ignore-type */ $email_heading, 'invoicing' );
Loading history...
292
293
    $email_heading = wpinv_email_format_text( $email_heading, $invoice );
294
295
    return apply_filters( 'wpinv_email_heading', $email_heading, $email_type, $invoice_id, $invoice );
296
}
297
298
function wpinv_email_get_content( $email_type = '', $invoice_id = 0, $invoice = array() ) {
299
    $content    = wpinv_get_option( 'email_' . $email_type . '_body' );
300
    $content    = __( $content, 'invoicing' );
0 ignored issues
show
It seems like $content can also be of type false; however, parameter $text of __() 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

300
    $content    = __( /** @scrutinizer ignore-type */ $content, 'invoicing' );
Loading history...
301
302
    $content    = wpinv_email_format_text( $content, $invoice );
303
304
    return apply_filters( 'wpinv_email_content', $content, $email_type, $invoice_id, $invoice );
305
}
306
307
function wpinv_email_get_headers( $email_type = '', $invoice_id = 0, $invoice = array() ) {
308
    $from_name = wpinv_mail_get_from_address();
309
    $from_email = wpinv_mail_get_from_address();
310
311
    $invoice    = ! empty( $invoice ) && is_object( $invoice ) ? $invoice : ( $invoice_id > 0 ? wpinv_get_invoice( $invoice_id ) : null );
312
313
    $headers    = 'From: ' . stripslashes_deep( html_entity_decode( $from_name, ENT_COMPAT, 'UTF-8' ) ) . " <$from_email>\r\n";
314
    $headers    .= 'Reply-To: ' . $from_email . "\r\n";
315
    $headers    .= 'Content-Type: ' . wpinv_mail_get_content_type() . "\r\n";
316
317
    return apply_filters( 'wpinv_email_headers', $headers, $email_type, $invoice_id, $invoice );
318
}
319
320
function wpinv_email_get_attachments( $email_type = '', $invoice_id = 0, $invoice = array() ) {
321
    $attachments = array();
322
323
    return apply_filters( 'wpinv_email_attachments', $attachments, $email_type, $invoice_id, $invoice );
324
}
325
326
/**
327
 * Searches for and replaces certain placeholders in an email.
328
 */
329
function wpinv_email_format_text( $content, $invoice ) {
330
331
    $replace_array = array(
332
        '{site_title}' => wpinv_get_blogname(),
333
        '{date}'       => getpaid_format_date( current_time( 'mysql' ) ),
334
    );
335
336
    $invoice = new WPInv_Invoice( $invoice );
337
338
    if ( $invoice->get_id() ) {
339
340
        $replace_array = array_merge(
341
            $replace_array,
342
            array(
343
                '{name}'             => sanitize_text_field( $invoice->get_user_full_name() ),
344
                '{full_name}'        => sanitize_text_field( $invoice->get_user_full_name() ),
345
                '{first_name}'       => sanitize_text_field( $invoice->get_first_name() ),
346
                '{last_name}'        => sanitize_text_field( $invoice->get_last_name() ),
347
                '{email}'            => sanitize_email( $invoice->get_email() ),
348
                '{invoice_number}'   => sanitize_text_field( $invoice->get_number() ),
349
                '{invoice_total}'    => sanitize_text_field( wpinv_price( $invoice->get_total( true ), $invoice->get_currency() ) ),
350
                '{invoice_link}'     => esc_url( $invoice->get_view_url() ),
351
                '{invoice_pay_link}' => esc_url( $invoice->get_checkout_payment_url() ),
352
                '{invoice_date}'     => date( get_option( 'date_format' ), strtotime( $invoice->get_date_created(), current_time( 'timestamp' ) ) ),
353
                '{invoice_due_date}' => date( get_option( 'date_format' ), strtotime( $invoice->get_due_date(), current_time( 'timestamp' ) ) ),
354
                '{invoice_quote}'    => sanitize_text_field( $invoice->get_invoice_quote_type() ),
355
                '{invoice_label}'    => sanitize_text_field( ucfirst( $invoice->get_invoice_quote_type() ) ),
356
                '{is_was}'           => strtotime( $invoice->get_due_date() ) < current_time( 'timestamp' ) ? __( 'was', 'invoicing' ) : __( 'is', 'invoicing' ),
357
            )
358
        );
359
360
    }
361
362
    // Let third party plugins filter the arra.
363
    $replace_array = apply_filters( 'wpinv_email_format_text', $replace_array, $content, $invoice );
364
365
    foreach ( $replace_array as $key => $value ) {
366
        $content = str_replace( $key, $value, $content );
367
    }
368
369
    return apply_filters( 'wpinv_email_content_replace', $content );
370
}
371
372
373
function wpinv_email_wrap_message( $message ) {
374
    // Buffer
375
    ob_start();
376
377
    do_action( 'wpinv_email_header' );
378
379
    echo wp_kses_post( wpautop( wptexturize( $message ) ) );
380
381
    do_action( 'wpinv_email_footer' );
382
383
    // Get contents
384
    $message = ob_get_clean();
385
386
    return $message;
387
}
388
389
function wpinv_add_notes_to_invoice_email( $invoice, $email_type ) {
390
    if ( ! empty( $invoice ) && $email_type == 'user_invoice' && $invoice_notes = wpinv_get_invoice_notes( $invoice->get_id(), true ) ) {
0 ignored issues
show
true of type true is incompatible with the type string expected by parameter $type of wpinv_get_invoice_notes(). ( Ignorable by Annotation )

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

390
    if ( ! empty( $invoice ) && $email_type == 'user_invoice' && $invoice_notes = wpinv_get_invoice_notes( $invoice->get_id(), /** @scrutinizer ignore-type */ true ) ) {
Loading history...
391
        $date_format = get_option( 'date_format' );
392
        $time_format = get_option( 'time_format' );
393
        ?>
394
        <div id="wpinv-email-notes">
395
            <h3 class="wpinv-notes-t"><?php echo esc_html( apply_filters( 'wpinv_email_invoice_notes_title', __( 'Invoice Notes', 'invoicing' ) ) ); ?></h3>
396
            <ol class="wpinv-notes-lists">
397
        <?php
398
        foreach ( $invoice_notes as $note ) {
399
            $note_time = strtotime( $note->comment_date );
400
            ?>
401
            <li class="comment wpinv-note">
402
            <p class="wpinv-note-date meta"><?php printf( esc_html__( '%2$s at %3$s', 'invoicing' ), esc_html( $note->comment_author ), esc_html( date_i18n( $date_format, $note_time ) ), esc_html( date_i18n( $time_format, $note_time ) ), esc_html( $note_time ) ); ?></p>
0 ignored issues
show
It seems like $date_format can also be of type false; however, parameter $format of date_i18n() 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

402
            <p class="wpinv-note-date meta"><?php printf( esc_html__( '%2$s at %3$s', 'invoicing' ), esc_html( $note->comment_author ), esc_html( date_i18n( /** @scrutinizer ignore-type */ $date_format, $note_time ) ), esc_html( date_i18n( $time_format, $note_time ) ), esc_html( $note_time ) ); ?></p>
Loading history...
403
            <div class="wpinv-note-desc description"><?php echo wp_kses_post( wpautop( wptexturize( $note->comment_content ) ) ); ?></div>
404
            </li>
405
            <?php
406
        }
407
        ?>
408
          </ol>
409
        </div>
410
        <?php
411
    }
412
}
413
add_action( 'wpinv_email_billing_details', 'wpinv_add_notes_to_invoice_email', 10, 3 );
414