Issues (51)

Security Analysis    not enabled

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
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
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
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.

include/Addon/Addon.php (9 issues)

Labels
1
<?php namespace EmailLog\Addon;
2
3
use EmailLog\Addon\License\AddonLicense;
4
5
defined( 'ABSPATH' ) || exit; // Exit if accessed directly.
6
7
/**
8
 * Encapsulate Add-on Data.
9
 *
10
 * @since 2.0.0
11
 *
12
 * @property-read string $name
13
 * @property-read string $version
14
 * @property-read string $thumbnail
15
 * @property-read string $description
16
 * @property-read string $link
17
 * @property-read string $slug
18
 * @property-read string $file
19
 * @property-read string $author
20
 */
21
class Addon {
22
23
	private $name;
24
	private $version;
25
	private $thumbnail;
26
	private $description;
27
	private $link;
28
	private $slug;
29
	private $file;
30
	private $author;
31
32
	protected $email_log;
33
	protected $license;
34
35
	/**
36
	 * Construct Addon object from data array.
37
	 *
38
	 * @param array                                     $data      Data array.
39
	 * @param \EmailLog\Addon\License\AddonLicense|null $license   Add-on License.
40
	 * @param \EmailLog\Core\EmailLog|null              $email_log Email Log instance.
41
	 */
42
	public function __construct( $data, $license = null, $email_log = null ) {
43
		$this->parse_data( $data );
44
45
		if ( null === $license ) {
46
			$license = new AddonLicense();
47
			$license->set_addon_name( $this->name );
48
			$license->load();
49
		}
50
		$this->license = $license;
51
52
		if ( null === $email_log ) {
53
			$email_log = email_log();
54
		}
55
		$this->email_log = $email_log;
56
	}
57
58
	/**
59
	 * Render the add-on in Addon list page.
60
	 */
61
	public function render() {
62
		?>
63
		<div class="el-addon">
64
			<h3 class="el-addon-title"> <?php echo esc_html( $this->name ); ?> </h3>
65
66
			<a rel="noopener" target="_blank" href="<?php echo esc_url( $this->link ); ?>?utm_campaign=Upsell&utm_medium=wpadmin&utm_source=addon-grid&utm_content=<?php echo $this->name; ?>"
67
			   title="<?php echo esc_attr( $this->name ); ?>">
68
				<img src="<?php echo esc_url( $this->thumbnail ); ?>" class="el-addon-image" alt="<?php echo esc_attr( $this->name ); ?>" title="<?php echo esc_attr( $this->name ); ?>">
69
			</a>
70
71
			<p> <?php echo esc_html( $this->description ); ?> </p>
72
73
			<?php $this->print_actions(); ?>
74
		</div> <!-- .el-addon -->
75
76
		<?php
77
	}
78
79
	/**
80
	 * Have a magic getter instead of having individual getters.
81
	 *
82
	 * @param string $property Property.
83
	 *
84
	 * @return string Value for the property.
85
	 */
86
	public function __get( $property ) {
87
		if ( isset( $this->{$property} ) ) {
88
			return $this->{$property};
89
		}
90
91
		return false;
92
	}
93
94
	/**
95
	 * Get Add-on License object.
96
	 *
97
	 * @return \EmailLog\Addon\License\AddonLicense License object.
98
	 */
99
	public function get_license() {
100
		return $this->license;
101
	}
102
103
	/**
104
	 * Get action links for add-ons.
105
	 */
106
	protected function print_actions() {
107
		if ( $this->has_valid_bundle_license() ) {
108
			$this->print_valid_actions();
109
110
			return;
111
		}
112
113
		if ( ! $this->has_valid_addon_license() ) {
114
			$this->print_invalid_actions();
115
		} else {
116
			$this->print_valid_actions();
117
		}
118
119
		$this->render_individual_license();
120
	}
121
122
	/**
123
	 * Print actions that are available when the license is valid.
124
	 */
125
	protected function print_valid_actions() {
126
		$actions = '';
127
128
		if ( $this->is_installed() ) {
129
			$actions = '<a disabled class="button button-secondary">' . _x( 'Installed', 'Installed on website but not activated', 'email-log' );
130
131
			if ( $this->is_active() ) {
132
				$actions .= ' &amp; ' . _x( 'Activated', 'Installed and activated on website', 'email-log' ) . '</a>';
133
			} else {
134
				$actions .= sprintf( '</a> <a class="button button-primary" href="%s">%s</a>', $this->get_activate_url(), _x( 'Activate', 'Enable addon so it may be used', 'email-log' ) );
135
			}
136
		}
137
138
		$actions .= sprintf(
139
			' <a class="button button-secondary" rel="noopener" target="_blank" onclick="%s" href="%s">%s</a>',
140
			$this->get_download_button_js(),
141
			$this->get_download_url(),
142
			_x( 'Download', 'Download to your computer', 'email-log' )
143
		);
144
145
		echo $actions;
146
	}
147
148
	/**
149
	 * Return the JavaScript that shows the message when the Download button is clicked.
150
	 *
151
	 * @since 2.2.4
152
	 *
153
	 * @return string JavaScript.
154
	 */
155
	protected function get_download_button_js() {
156
		ob_start();
157
		?>
158
		javascript:alert( "The zip file download will start now. Once the zip file is downloaded, upload it from the plugin page to install the add-on. WordPress plugin repo guidelines prevent us from automatically installing the add-on and that's why you have to do this manual step once." );
159
		<?php
160
		return ob_get_clean();
161
	}
162
163
	/**
164
	 * Print actions that are available when the license is not valid.
165
	 */
166
	protected function print_invalid_actions() {
167
		$label = _x( 'Activate License to Download', 'Download add-on', 'email-log' );
168
169
		if ( $this->is_installed() ) {
170
			$label = _x( 'Activate License to Use', 'Download and activate addon', 'email-log' );
171
		}
172
173
		printf(
174
			'<a disabled class="button-secondary disabled" title="%s" href="#">%s</a>',
175
			__( 'You need an active license to use the add-on', 'email-log' ),
176
			$label
177
		);
178
	}
179
180
	/**
181
	 * Render Individual license form.
182
	 */
183
	protected function render_individual_license() {
184
		$action         = 'el_license_activate';
185
		$action_text    = __( 'Activate License', 'email-log' );
186
		$button_class   = 'button-primary';
187
		$dashicon       = 'down';
188
		$license_wrap   = 'hidden';
189
		$expiry_details = '';
190
191
		if ( $this->has_valid_addon_license() ) {
192
			$action       = 'el_license_deactivate';
193
			$action_text  = __( 'Deactivate License', 'email-log' );
194
			$button_class = '';
195
			$dashicon     = 'up';
196
			$license_wrap = '';
197
198
			$expiry_date = date( 'F d, Y', strtotime( $this->get_license()->get_expiry_date() ) );
0 ignored issues
show
It seems like $this->get_license()->get_expiry_date() can also be of type false; however, parameter $datetime of strtotime() 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

198
			$expiry_date = date( 'F d, Y', strtotime( /** @scrutinizer ignore-type */ $this->get_license()->get_expiry_date() ) );
Loading history...
199
200
			if ( $this->get_license()->has_expired() ) {
201
				/* translators: 1 License expiry date, 2 License Renewal link */
202
				$expiry_details = sprintf( __( 'Your license has expired on %1$s. Please <a href="%2$s">renew it</a> to receive automatic updates and support.', 'email-log' ), $expiry_date, esc_url( $this->get_license()->get_renewal_link() ) );
203
			} else {
204
				/* translators: 1 License expiry date */
205
				$expiry_details = sprintf( __( 'Your license is valid till %s', 'email-log' ), $expiry_date );
206
			}
207
		}
208
		?>
209
210
		<span class="el-expander dashicons dashicons-arrow-<?php echo sanitize_html_class( $dashicon ); ?>"
211
			title="<?php _e( 'Individual add-on license', 'email-log' ); ?>"></span>
212
213
		<div class="individual-license <?php echo sanitize_html_class( $license_wrap ); ?>">
214
			<form method="post">
215
				<input type="text" name="el-license" class="el-license" size="40"
216
				       title="<?php _e( 'Email Log License Key', 'email-log' ); ?>"
217
				       placeholder="<?php echo esc_attr( sprintf( __( '%s Add-on License Key', 'email-log' ), $this->name ) ); ?>"
218
				       value="<?php echo esc_attr( $this->get_addon_license_key() ); ?>">
219
220
				<input type="submit" class="button <?php echo sanitize_html_class( $button_class ); ?>"
221
				       value="<?php echo esc_attr( $action_text ); ?>">
222
223
				<p class="expires"><?php echo $expiry_details; ?></p>
224
225
				<input type="hidden" name="el-addon" value="<?php echo esc_attr( $this->name ); ?>">
226
				<input type="hidden" name="el-action" value="<?php echo esc_attr( $action ); ?>">
227
228
				<?php wp_nonce_field( $action, $action . '_nonce' ); ?>
229
			</form>
230
		</div>
231
		<?php
232
	}
233
234
	/**
235
	 * Is the add-on installed?
236
	 *
237
	 * @return bool True, if installed. False otherwise.
238
	 */
239
	public function is_installed() {
240
		$installed_plugins = array_keys( get_plugins() );
241
242
		return in_array( $this->file, $installed_plugins, true );
243
	}
244
245
	/**
246
	 * Get the version of the add-on.
247
	 * If the add-on is installed then it returns the installed version,
248
	 * otherwise returns the latest add-on version from server.
249
	 *
250
	 * @return string Add-on version.
251
	 */
252
	public function get_version() {
253
		if ( ! $this->is_installed() ) {
254
			return $this->version;
255
		}
256
257
		$plugins_data = get_plugins();
258
259
		return $plugins_data[ $this->file ]['Version'];
260
	}
261
262
	/**
263
	 * Is the add-on active?
264
	 *
265
	 * @return bool True if the add-on is active, False otherwise.
266
	 */
267
	public function is_active() {
268
		return is_plugin_active( $this->file );
269
	}
270
271
	/**
272
	 * Get the activate url for the add-on.
273
	 *
274
	 * @return string Activate url with nonce.
275
	 */
276
	protected function get_activate_url() {
277
		return wp_nonce_url( network_admin_url( 'plugins.php?action=activate&amp;plugin=' . $this->file ), 'activate-plugin_' . $this->file );
278
	}
279
280
	/**
281
	 * Get the install url for the add-on.
282
	 *
283
	 * @return string Install url with nonce.
284
	 */
285
	protected function get_install_url() {
286
		return wp_nonce_url( network_admin_url( 'update.php?action=install-plugin&plugin=' . $this->slug ), 'install-plugin_' . $this->slug );
287
	}
288
289
	/**
290
	 * Get the download url for add-on.
291
	 *
292
	 * @return string Download url for add-on.
293
	 */
294
	public function get_download_url() {
295
		$licenser = $this->email_log->get_licenser();
296
297
		if ( is_null( $licenser ) ) {
298
			return '';
299
		}
300
301
		return $licenser->get_addon_download_url( $this->slug );
302
	}
303
304
	/**
305
	 * Is there a valid bundle license?
306
	 *
307
	 * @return bool True if valid, False otherwise.
308
	 */
309
	protected function has_valid_bundle_license() {
310
		$licenser = $this->email_log->get_licenser();
311
312
		if ( is_null( $licenser ) ) {
313
			return false;
314
		}
315
316
		return $licenser->is_bundle_license_valid();
317
	}
318
319
	/**
320
	 * Is the license of this add-on valid?
321
	 *
322
	 * @return bool True if valid, False otherwise.
323
	 */
324
	protected function has_valid_addon_license() {
325
		return $this->get_license()->is_valid();
326
	}
327
328
	/**
329
	 * Get license key if the add-on has a valid license.
330
	 *
331
	 * @return string|null License key if found, null otherwise.
332
	 */
333
	public function get_addon_license_key() {
334
		return $this->get_license()->get_license_key();
335
	}
336
337
	/**
338
	 * Parse and store add-on data from data array.
339
	 *
340
	 * @param array $data Data array.
341
	 */
342
	protected function parse_data( $data ) {
343
		$this->name        = $data['info']['title'];
0 ignored issues
show
The property name is declared read-only in EmailLog\Addon\Addon.
Loading history...
344
		$this->version     = $data['info']['version'];
0 ignored issues
show
The property version is declared read-only in EmailLog\Addon\Addon.
Loading history...
345
		$this->thumbnail   = $data['info']['thumbnail'];
0 ignored issues
show
The property thumbnail is declared read-only in EmailLog\Addon\Addon.
Loading history...
346
		$this->description = $data['info']['excerpt'];
0 ignored issues
show
The property description is declared read-only in EmailLog\Addon\Addon.
Loading history...
347
		$this->link        = $data['info']['permalink'];
0 ignored issues
show
The property link is declared read-only in EmailLog\Addon\Addon.
Loading history...
348
		$this->slug        = 'email-log-' . $data['info']['slug'];
0 ignored issues
show
The property slug is declared read-only in EmailLog\Addon\Addon.
Loading history...
349
		$this->file        = sprintf( '%1$s/%1$s.php', $this->slug );
0 ignored issues
show
The property file is declared read-only in EmailLog\Addon\Addon.
Loading history...
350
		$this->author      = 'Sudar Muthu';
0 ignored issues
show
The property author is declared read-only in EmailLog\Addon\Addon.
Loading history...
351
	}
352
}
353