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.

class-getpaid-subscription-notification-emails.php (3 issues)

Labels
1
<?php
2
/**
3
 * Contains the subscriptions notification emails management class.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * This class handles subscription notificaiton emails.
11
 *
12
 */
13
class GetPaid_Subscription_Notification_Emails {
14
15
    /**
16
	 * The array of subscription email actions.
17
	 *
18
	 * @param array
19
	 */
20
	public $subscription_actions;
21
22
    /**
23
	 * Class constructor
24
     *
25
	 */
26
	public function __construct() {
27
28
		$this->subscription_actions = apply_filters(
29
			'getpaid_notification_email_subscription_triggers',
30
			array(
31
				'getpaid_subscription_active'    => 'subscription_active',
32
				'getpaid_subscription_trialling' => 'subscription_trial',
33
				'getpaid_subscription_cancelled' => 'subscription_cancelled',
34
				'getpaid_subscription_expired'   => 'subscription_expired',
35
				'getpaid_subscription_completed' => 'subscription_complete',
36
				'getpaid_daily_maintenance'      => 'renewal_reminder'
37
			)
38
		);
39
40
		add_action( 'init', array( $this, 'init_hooks' ) );
41
	}
42
43
    /**
44
	 * Registers email hooks.
45
	 */
46
	public function init_hooks() {
47
48
		add_filter( 'getpaid_get_email_merge_tags', array( $this, 'subscription_merge_tags' ), 10, 2 );
49
		foreach ( $this->subscription_actions as $hook => $email_type ) {
50
51
			$email = new GetPaid_Notification_Email( $email_type );
52
53
			if ( ! $email->is_active() ) {
54
				continue;
55
			}
56
57
			if ( method_exists( $this, $email_type ) ) {
58
				add_action( $hook, array( $this, $email_type ), 100, 2 );
59
				continue;
60
			}
61
62
			do_action( 'getpaid_subscription_notification_email_register_hook', $email_type, $hook );
63
64
		}
65
66
	}
67
68
	/**
69
	 * Filters subscription merge tags.
70
	 *
71
	 * @param array $merge_tags
72
	 * @param mixed|WPInv_Invoice|WPInv_Subscription $object
73
	 */
74
	public function subscription_merge_tags( $merge_tags, $object ) {
75
76
		if ( is_a( $object, 'WPInv_Subscription' ) ) {
77
			$merge_tags = array_merge(
78
				$merge_tags,
79
				$this->get_subscription_merge_tags( $object )
80
			);
81
		}
82
83
		return $merge_tags;
84
85
	}
86
87
	/**
88
	 * Generates subscription merge tags.
89
	 *
90
	 * @param WPInv_Subscription $subscription
91
	 * @return array
92
	 */
93
	public function get_subscription_merge_tags( $subscription ) {
94
95
		// Abort if it does not exist.
96
		if ( ! $subscription->get_id() ) {
97
			return array();
98
		}
99
100
		$invoice    = $subscription->get_parent_invoice();
101
		return array(
102
			'{subscription_renewal_date}'     => getpaid_format_date_value( $subscription->get_next_renewal_date(), __( 'Never', 'invoicing' ) ),
103
			'{subscription_created}'          => getpaid_format_date_value( $subscription->get_date_created() ),
104
			'{subscription_status}'           => sanitize_text_field( $subscription->get_status_label() ),
105
			'{subscription_profile_id}'       => sanitize_text_field( $subscription->get_profile_id() ),
106
			'{subscription_id}'               => absint( $subscription->get_id() ),
107
			'{subscription_recurring_amount}' => sanitize_text_field( wpinv_price( $subscription->get_recurring_amount(), $invoice->get_currency() ) ),
108
			'{subscription_initial_amount}'   => sanitize_text_field( wpinv_price( $subscription->get_initial_amount(), $invoice->get_currency() ) ),
109
			'{subscription_recurring_period}' => getpaid_get_subscription_period_label( $subscription->get_period(), $subscription->get_frequency(), '' ),
110
			'{subscription_bill_times}'       => $subscription->get_bill_times(),
111
			'{subscription_url}'              => esc_url( $subscription->get_view_url() ),
112
		);
113
114
	}
115
116
	/**
117
	 * Checks if we should send a notification for a subscription.
118
	 *
119
	 * @param WPInv_Invoice $invoice
120
	 * @return bool
121
	 */
122
	public function should_send_notification( $invoice ) {
123
		return 0 != $invoice->get_id();
124
	}
125
126
	/**
127
	 * Returns notification recipients.
128
	 *
129
	 * @param WPInv_Invoice $invoice
130
	 * @return array
131
	 */
132
	public function get_recipients( $invoice ) {
133
		$recipients = array( $invoice->get_email() );
134
135
		$cc = $invoice->get_email_cc();
136
137
		if ( ! empty( $cc ) ) {
138
			$cc = array_map( 'sanitize_email', wpinv_parse_list( $cc ) );
139
			$recipients = array_filter( array_unique( array_merge( $recipients, $cc ) ) );
140
		}
141
142
		return $recipients;
143
	}
144
145
	/**
146
	 * Helper function to send an email.
147
	 *
148
	 * @param WPInv_Subscription $subscription
149
	 * @param GetPaid_Notification_Email $email
150
	 * @param string $type
151
	 * @param array $extra_args Extra template args.
152
	 */
153
	public function send_email( $subscription, $email, $type, $extra_args = array() ) {
154
155
		if ( empty( $subscription ) ) {
156
			return;
157
		}
158
159
		if ( is_array( $subscription ) ) {
0 ignored issues
show
The condition is_array($subscription) is always false.
Loading history...
160
			$subscription = current( $subscription );
161
		}
162
163
		if ( ! $subscription instanceof WPInv_Subscription ) {
0 ignored issues
show
$subscription is always a sub-type of WPInv_Subscription.
Loading history...
164
			return;
165
		}
166
167
		// Abort in case the parent invoice does not exist.
168
		$invoice = $subscription->get_parent_invoice();
169
		if ( ! $this->should_send_notification( $invoice ) ) {
170
			return;
171
		}
172
173
		if ( apply_filters( 'getpaid_skip_subscription_email', false, $type, $subscription ) ) {
174
			return;
175
		}
176
177
		do_action( 'getpaid_before_send_subscription_notification', $type, $subscription, $email );
178
179
		$recipients  = $this->get_recipients( $invoice );
180
		$mailer      = new GetPaid_Notification_Email_Sender();
181
		$merge_tags  = $email->get_merge_tags();
182
		$content     = $email->get_content( $merge_tags, $extra_args );
183
		$subject     = $email->add_merge_tags( $email->get_subject(), $merge_tags );
184
		$attachments = $email->get_attachments();
185
186
		$result = $mailer->send(
187
			apply_filters( 'getpaid_subscription_email_recipients', wpinv_parse_list( $recipients ), $email ),
188
			$subject,
189
			$content,
190
			$attachments
191
		);
192
193
		// Maybe send a copy to the admin.
194
		if ( $email->include_admin_bcc() ) {
195
			$mailer->send(
196
				wpinv_get_admin_email(),
0 ignored issues
show
It seems like wpinv_get_admin_email() can also be of type false; however, parameter $to of GetPaid_Notification_Email_Sender::send() does only seem to accept array|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

196
				/** @scrutinizer ignore-type */ wpinv_get_admin_email(),
Loading history...
197
				$subject . __( ' - ADMIN BCC COPY', 'invoicing' ),
198
				$content,
199
				$attachments
200
			);
201
		}
202
203
		if ( $result ) {
204
			$invoice->add_system_note(
205
				sprintf(
206
					__( 'Successfully sent %1$s notification email to %2$s.', 'invoicing' ),
207
					sanitize_key( $type ),
208
					$email->is_admin_email() ? __( 'admin' ) : __( 'the customer' )
209
				)
210
			);
211
		} else {
212
			$invoice->add_system_note(
213
				sprintf(
214
					__( 'Failed sending %1$s notification email to %2$s.', 'invoicing' ),
215
					sanitize_key( $type ),
216
					$email->is_admin_email() ? __( 'admin' ) : __( 'the customer' )
217
				)
218
			);
219
		}
220
221
		do_action( 'getpaid_after_send_subscription_notification', $type, $subscription, $email );
222
223
	}
224
225
	/**
226
	 * Sends a subscription active.
227
	 *
228
	 * @since 2.8.4
229
	 *
230
	 * @param WPInv_Subscription $subscription
231
	 */
232
	public function subscription_active( $subscription ) {
233
		$email = new GetPaid_Notification_Email( __FUNCTION__, $subscription );
234
235
		$this->send_email( $subscription, $email, __FUNCTION__ );
236
	}
237
238
    /**
239
	 * Sends a new trial notification.
240
	 *
241
	 * @param WPInv_Subscription $subscription
242
	 */
243
	public function subscription_trial( $subscription ) {
244
245
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $subscription );
246
		$this->send_email( $subscription, $email, __FUNCTION__ );
247
248
	}
249
250
	/**
251
	 * Sends a cancelled subscription notification.
252
	 *
253
	 * @param WPInv_Subscription $subscription
254
	 */
255
	public function subscription_cancelled( $subscription ) {
256
257
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $subscription );
258
		$this->send_email( $subscription, $email, __FUNCTION__ );
259
260
	}
261
262
	/**
263
	 * Sends a subscription expired notification.
264
	 *
265
	 * @param WPInv_Subscription $subscription
266
	 */
267
	public function subscription_expired( $subscription ) {
268
269
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $subscription );
270
		$this->send_email( $subscription, $email, __FUNCTION__ );
271
272
	}
273
274
	/**
275
	 * Sends a completed subscription notification.
276
	 *
277
	 * @param WPInv_Subscription $subscription
278
	 */
279
	public function subscription_complete( $subscription ) {
280
281
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $subscription );
282
		$this->send_email( $subscription, $email, __FUNCTION__ );
283
284
	}
285
286
	/**
287
	 * Sends a subscription renewal reminder notification.
288
	 *
289
	 */
290
	public function renewal_reminder() {
291
292
		$email = new GetPaid_Notification_Email( __FUNCTION__ );
293
294
		// Fetch reminder days.
295
		$reminder_days = array_unique( wp_parse_id_list( $email->get_option( 'days' ) ) );
296
297
		// Abort if non is set.
298
		if ( empty( $reminder_days ) ) {
299
			return;
300
		}
301
302
		// Fetch matching subscriptions.
303
        $args  = array(
304
            'number'             => -1,
305
			'count_total'        => false,
306
			'status'             => 'trialling active',
307
            'date_expires_query' => array(
308
				'relation' => 'OR',
309
            ),
310
		);
311
312
		foreach ( $reminder_days as $days ) {
313
			$date = date_parse( date( 'Y-m-d', strtotime( "+$days days", current_time( 'timestamp' ) ) ) );
314
315
			$args['date_expires_query'][] = array(
316
				'year'  => $date['year'],
317
				'month' => $date['month'],
318
				'day'   => $date['day'],
319
			);
320
321
		}
322
323
		$subscriptions = new GetPaid_Subscriptions_Query( $args );
324
325
        foreach ( $subscriptions->get_results() as $subscription ) {
326
327
			// Skip packages.
328
			if ( apply_filters( 'getpaid_send_subscription_renewal_reminder_email', true ) ) {
329
				$email->object = $subscription;
330
            	$this->send_email( $subscription, $email, __FUNCTION__ );
331
			}
332
		}
333
334
	}
335
336
}
337