Newsletter - Version 6.4.2

Version Description

  • Improved the antispam check on subscription
Download this release

Release Info

Developer satollo
Plugin Icon 128x128 Newsletter
Version 6.4.2
Comparing to
See all releases

Code changes from version 6.4.1 to 6.4.2

includes/controls.php CHANGED
@@ -412,7 +412,7 @@ class NewsletterControls {
412
  if (!$current_language) {
413
  return;
414
  }
415
- $this->warnings[] = 'You are configuring the language <strong>' . $newsletter->get_language_label($current_language) . '</strong>. Switch to "all languages" to see every options.';
416
  }
417
 
418
  function hint($text, $url = '') {
412
  if (!$current_language) {
413
  return;
414
  }
415
+ $this->warnings[] = 'You are configuring the language <strong>' . $newsletter->get_language_label($current_language) . '</strong>. Switch to "all languages" to see all options.';
416
  }
417
 
418
  function hint($text, $url = '') {
plugin.php CHANGED
@@ -4,7 +4,7 @@
4
  Plugin Name: Newsletter
5
  Plugin URI: https://www.thenewsletterplugin.com/plugins/newsletter
6
  Description: Newsletter is a cool plugin to create your own subscriber list, to send newsletters, to build your business. <strong>Before update give a look to <a href="https://www.thenewsletterplugin.com/category/release">this page</a> to know what's changed.</strong>
7
- Version: 6.4.1
8
  Author: Stefano Lissa & The Newsletter Team
9
  Author URI: https://www.thenewsletterplugin.com
10
  Disclaimer: Use at your own risk. No warranty expressed or implied is provided.
@@ -28,7 +28,7 @@
28
 
29
  */
30
 
31
- define('NEWSLETTER_VERSION', '6.4.1');
32
 
33
  global $newsletter, $wpdb;
34
 
4
  Plugin Name: Newsletter
5
  Plugin URI: https://www.thenewsletterplugin.com/plugins/newsletter
6
  Description: Newsletter is a cool plugin to create your own subscriber list, to send newsletters, to build your business. <strong>Before update give a look to <a href="https://www.thenewsletterplugin.com/category/release">this page</a> to know what's changed.</strong>
7
+ Version: 6.4.2
8
  Author: Stefano Lissa & The Newsletter Team
9
  Author URI: https://www.thenewsletterplugin.com
10
  Disclaimer: Use at your own risk. No warranty expressed or implied is provided.
28
 
29
  */
30
 
31
+ define('NEWSLETTER_VERSION', '6.4.2');
32
 
33
  global $newsletter, $wpdb;
34
 
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Tags: email, email marketing, newsletter, newsletter subscribers, welcome email, signup forms, contact, lead generation, popup, marketing automation
3
  Requires at least: 3.4.0
4
  Tested up to: 5.3.2
5
- Stable tag: 6.4.1
6
  Requires PHP: 5.6
7
  Contributors: satollo,webagile,michael-travan
8
 
@@ -109,6 +109,10 @@ Thank you, The Newsletter Team
109
 
110
  == Changelog ==
111
 
 
 
 
 
112
  = 6.4.1 =
113
 
114
  * Added statistics shortcut for sent newsletters
2
  Tags: email, email marketing, newsletter, newsletter subscribers, welcome email, signup forms, contact, lead generation, popup, marketing automation
3
  Requires at least: 3.4.0
4
  Tested up to: 5.3.2
5
+ Stable tag: 6.4.2
6
  Requires PHP: 5.6
7
  Contributors: satollo,webagile,michael-travan
8
 
109
 
110
  == Changelog ==
111
 
112
+ = 6.4.2 =
113
+
114
+ * Improved the antispam check on subscription
115
+
116
  = 6.4.1 =
117
 
118
  * Added statistics shortcut for sent newsletters
subscription/antibot.php CHANGED
@@ -52,9 +52,10 @@ if ($controls->is_action()) {
52
 
53
  <table class="form-table">
54
  <tr>
55
- <th><?php _e('Disable antibot/antispam?', 'newsletter') ?></th>
56
  <td>
57
  <?php $controls->yesno('disabled'); ?>
 
58
  <p class="description">
59
  <?php _e('Disable for ajax form submission', 'newsletter'); ?>
60
  </p>
52
 
53
  <table class="form-table">
54
  <tr>
55
+ <th><?php _e('Disable antibot', 'newsletter') ?></th>
56
  <td>
57
  <?php $controls->yesno('disabled'); ?>
58
+ <?php $controls->help('https://www.thenewsletterplugin.com/documentation/antiflood') ?>
59
  <p class="description">
60
  <?php _e('Disable for ajax form submission', 'newsletter'); ?>
61
  </p>
subscription/lists.php CHANGED
@@ -30,6 +30,8 @@ for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
30
  }
31
  }
32
 
 
 
33
 
34
  $status = array(0 => 'Disabled/Private use', 1 => 'Only on profile page', 2 => 'Even on subscription forms', '3' => 'Hidden');
35
  ?>
@@ -87,7 +89,12 @@ $status = array(0 => 'Disabled/Private use', 1 => 'Only on profile page', 2 => '
87
  ?>
88
  <tr>
89
  <td><?php echo $i; ?></td>
90
- <td><?php $controls->text('list_' . $i, 50); ?></td>
 
 
 
 
 
91
  <?php if ($is_all_languages) { ?>
92
  <td><?php $controls->select('list_' . $i . '_status', $status); ?></td>
93
  <td><?php $controls->select('list_' . $i . '_checked', array(0 => 'No', 1 => 'Yes')); ?></td>
@@ -98,8 +105,12 @@ $status = array(0 => 'Disabled/Private use', 1 => 'Only on profile page', 2 => '
98
  <?php } ?>
99
 
100
  <td><?php echo $wpdb->get_var("select count(*) from " . NEWSLETTER_USERS_TABLE . " where list_" . $i . "=1 and status='C'"); ?></td>
101
- <td><?php $controls->button_confirm('unlink', __('Unlink everyone', 'newsletter'), '', $i); ?></td>
102
-
 
 
 
 
103
  <td>
104
  <?php $notes = apply_filters('newsletter_lists_notes', array(), $i); ?>
105
  <?php
30
  }
31
  }
32
 
33
+ $all_lang_options = $module->get_options('lists');
34
+
35
 
36
  $status = array(0 => 'Disabled/Private use', 1 => 'Only on profile page', 2 => 'Even on subscription forms', '3' => 'Hidden');
37
  ?>
89
  ?>
90
  <tr>
91
  <td><?php echo $i; ?></td>
92
+ <td>
93
+ <?php $controls->text('list_' . $i, 50); ?>
94
+ <?php if (!$is_all_languages) { ?>
95
+ <p class="description">Main name: <?php echo esc_html($all_lang_options['list_' . $i])?></p>
96
+ <?php } ?>
97
+ </td>
98
  <?php if ($is_all_languages) { ?>
99
  <td><?php $controls->select('list_' . $i . '_status', $status); ?></td>
100
  <td><?php $controls->select('list_' . $i . '_checked', array(0 => 'No', 1 => 'Yes')); ?></td>
105
  <?php } ?>
106
 
107
  <td><?php echo $wpdb->get_var("select count(*) from " . NEWSLETTER_USERS_TABLE . " where list_" . $i . "=1 and status='C'"); ?></td>
108
+
109
+ <td>
110
+ <?php if ($is_all_languages) { ?>
111
+ <?php $controls->button_confirm('unlink', __('Unlink everyone', 'newsletter'), '', $i); ?>
112
+ <?php } ?>
113
+ </td>
114
  <td>
115
  <?php $notes = apply_filters('newsletter_lists_notes', array(), $i); ?>
116
  <?php
subscription/subscription.php CHANGED
@@ -1,9 +1,6 @@
1
  <?php
2
 
3
- if (!defined('ABSPATH'))
4
- exit;
5
-
6
- require_once NEWSLETTER_INCLUDES_DIR . '/module.php';
7
 
8
  class NewsletterSubscription extends NewsletterModule {
9
 
@@ -162,7 +159,7 @@ class NewsletterSubscription extends NewsletterModule {
162
  global $wpdb;
163
  // TODO: Optimize!
164
  $options = $this->get_options('antibot');
165
-
166
  if (empty($options['antiflood'])) {
167
  return false;
168
  }
@@ -191,7 +188,7 @@ class NewsletterSubscription extends NewsletterModule {
191
  function is_spam_by_akismet($email, $name, $ip, $agent, $referrer) {
192
  // TODO: Optimize!
193
  $options = $this->get_options('antibot');
194
-
195
  if (empty($options['akismet'])) {
196
  return false;
197
  }
@@ -217,6 +214,61 @@ class NewsletterSubscription extends NewsletterModule {
217
  return false;
218
  }
219
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  /**
221
  *
222
  * @global wpdb $wpdb
@@ -274,88 +326,27 @@ class NewsletterSubscription extends NewsletterModule {
274
  case 's':
275
  case 'subscribe':
276
 
277
- $ip = $this->get_remote_ip();
278
- $email = $this->normalize_email($_REQUEST['ne']);
279
- $first_name = '';
280
- if (isset($_REQUEST['nn']))
281
- $first_name = $this->normalize_name($_REQUEST['nn']);
282
-
283
- $last_name = '';
284
- if (isset($_REQUEST['ns']))
285
- $last_name = $this->normalize_name($_REQUEST['ns']);
286
-
287
- $full_name = trim($first_name . ' ' . $last_name);
288
-
289
- $antibot_logger = new NewsletterLogger('antibot');
290
-
291
  if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
292
- $antibot_logger->fatal($email . ' - ' . $ip . ' - HTTP method invalid');
293
  die('Invalid');
294
  }
295
-
296
  $options_antibot = $this->get_options('antibot');
297
 
298
  $captcha = !empty($options_antibot['captcha']);
299
 
300
  if (!empty($options_antibot['disabled']) || $this->antibot_form_check($captcha)) {
301
 
 
302
 
303
- if ($this->is_spam_text($full_name)) {
304
- $antibot_logger->fatal($email . ' - ' . $ip . ' - Name with http: ' . $full_name);
305
- header("HTTP/1.0 404 Not Found");
306
- die();
307
- }
308
-
309
- // Cannot check for administrator here, too early.
310
- if (true) {
311
-
312
- $this->logger->debug('Subscription of: ' . $email);
313
-
314
- // 404 is returned to attempt to make the bot believe the url has been changed
315
-
316
- if ($this->is_missing_domain_mx($email)) {
317
- $antibot_logger->fatal($email . ' - ' . $ip . ' - MX check failed');
318
- header("HTTP/1.0 404 Not Found");
319
- die();
320
- }
321
-
322
- if ($this->is_ip_blacklisted($ip)) {
323
- $antibot_logger->fatal($email . ' - ' . $ip . ' - IP blacklisted');
324
- header("HTTP/1.0 404 Not Found");
325
- die();
326
- }
327
-
328
- if ($this->is_address_blacklisted($email)) {
329
- $antibot_logger->fatal($email . ' - ' . $ip . ' - Address blacklisted');
330
- header("HTTP/1.0 404 Not Found");
331
- die();
332
- }
333
-
334
- // Akismet check
335
- if ($this->is_spam_by_akismet($email, $full_name, $ip, $_SERVER['HTTP_USER_AGENT'], $_SERVER['HTTP_REFERER'])) {
336
- $antibot_logger->fatal($email . ' - ' . $ip . ' - Akismet blocked');
337
- header("HTTP/1.0 404 Not Found");
338
- die();
339
- }
340
-
341
- // Flood check
342
- if ($this->is_flood($email, $ip)) {
343
- $antibot_logger->fatal($email . ' - ' . $ip . ' - Antiflood triggered');
344
- header("HTTP/1.0 404 Not Found");
345
- die('Too quick');
346
- }
347
-
348
- $user = $this->subscribe();
349
-
350
- if ($user->status == 'E')
351
- $this->show_message('error', $user);
352
- if ($user->status == 'C')
353
- $this->show_message('confirmed', $user);
354
- if ($user->status == 'A')
355
- $this->show_message('already_confirmed', $user);
356
- if ($user->status == 'S')
357
- $this->show_message('confirmation', $user);
358
- }
359
  } else {
360
  // Temporary store data
361
  //$data_key = wp_generate_password(16, false, false);
@@ -367,7 +358,14 @@ class NewsletterSubscription extends NewsletterModule {
367
 
368
  // AJAX subscription
369
  case 'ajaxsub':
 
 
 
 
 
 
370
  $user = $this->subscribe();
 
371
  if ($user->status == 'E')
372
  $key = 'error';
373
  if ($user->status == 'C')
@@ -376,10 +374,11 @@ class NewsletterSubscription extends NewsletterModule {
376
  $key = 'already_confirmed';
377
  if ($user->status == 'S')
378
  $key = 'confirmation';
379
- $module = NewsletterSubscription::instance();
380
- $message = $newsletter->replace($module->options[$key . '_text'], $user);
381
- if (isset($module->options[$key . '_tracking'])) {
382
- $message .= $module->options[$key . '_tracking'];
 
383
  }
384
  echo $message;
385
  die();
@@ -466,36 +465,12 @@ class NewsletterSubscription extends NewsletterModule {
466
  $this->save_options($this->options);
467
  }
468
 
469
- if ($this->old_version < '2.0.0') {
470
- if (!isset($this->options['url']) && !empty($newsletter->options['url'])) {
471
- $this->options['url'] = $newsletter->options['url'];
472
- $this->save_options($this->options);
473
- }
474
-
475
- $options_template = $this->get_options('template');
476
- if (empty($options_template) && isset($this->options['template'])) {
477
- $options_template['enabled'] = isset($this->options['template_enabled']) ? 1 : 0;
478
- $options_template['template'] = $this->options['template'];
479
- add_option('newsletter_subscription_template', $options_template, null, 'no');
480
- }
481
-
482
- if (isset($this->options['template'])) {
483
- unset($this->options['template']);
484
- unset($this->options['template_enabled']);
485
- $this->save_options($this->options);
486
- }
487
- }
488
-
489
  $this->init_options('template', false);
490
 
491
-
492
-
493
  global $wpdb, $charset_collate;
494
 
495
  require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
496
 
497
-
498
-
499
  $sql = "CREATE TABLE `" . $wpdb->prefix . "newsletter_user_logs` (
500
  `id` int(11) NOT NULL AUTO_INCREMENT,
501
  `user_id` int(11) NOT NULL DEFAULT 0,
@@ -622,13 +597,31 @@ class NewsletterSubscription extends NewsletterModule {
622
  }
623
 
624
  /**
625
- * Return the subscribed user.
626
- *
627
- * @param bool $registration If invoked from the registration process
628
- * @global Newsletter $newsletter
 
629
  */
630
  function subscribe($status = null, $emails = true) {
631
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
632
  $opt_in = (int) $this->options['noconfirmation']; // 0 - double, 1 - single
633
  if (!empty($this->options['optin_override']) && isset($_REQUEST['optin'])) {
634
  switch ($_REQUEST['optin']) {
@@ -650,13 +643,6 @@ class NewsletterSubscription extends NewsletterModule {
650
  }
651
  }
652
 
653
- $email = $this->normalize_email(stripslashes($_REQUEST['ne']));
654
-
655
- // Shound never reach this point without a valid email address
656
- if ($email == null) {
657
- die('Wrong email');
658
- }
659
-
660
  $user = $this->get_user($email);
661
 
662
  if ($user != null) {
@@ -729,7 +715,6 @@ class NewsletterSubscription extends NewsletterModule {
729
 
730
 
731
  $user['token'] = $this->get_token();
732
- $ip = $this->get_remote_ip();
733
  $ip = $this->process_ip($ip);
734
  $user['ip'] = $ip;
735
  $user['geo'] = 0;
1
  <?php
2
 
3
+ defined('ABSPATH') || exit;
 
 
 
4
 
5
  class NewsletterSubscription extends NewsletterModule {
6
 
159
  global $wpdb;
160
  // TODO: Optimize!
161
  $options = $this->get_options('antibot');
162
+
163
  if (empty($options['antiflood'])) {
164
  return false;
165
  }
188
  function is_spam_by_akismet($email, $name, $ip, $agent, $referrer) {
189
  // TODO: Optimize!
190
  $options = $this->get_options('antibot');
191
+
192
  if (empty($options['akismet'])) {
193
  return false;
194
  }
214
  return false;
215
  }
216
 
217
+ /**
218
+ * $email must be cleaned using the is_email() function.
219
+ *
220
+ * @param type $email
221
+ * @param type $full_name
222
+ * @param type $ip
223
+ */
224
+ function valid_subscription_or_die($email, $full_name, $ip) {
225
+ $antibot_logger = new NewsletterLogger('antibot');
226
+
227
+ if (empty($email)) {
228
+ echo 'Wrong email';
229
+ header("HTTP/1.0 400 Bad request");
230
+ die();
231
+ }
232
+
233
+ if ($this->is_spam_text($full_name)) {
234
+ $antibot_logger->fatal($email . ' - ' . $ip . ' - Name with http: ' . $full_name);
235
+ header("HTTP/1.0 404 Not Found");
236
+ die();
237
+ }
238
+
239
+ if ($this->is_missing_domain_mx($email)) {
240
+ $antibot_logger->fatal($email . ' - ' . $ip . ' - MX check failed');
241
+ header("HTTP/1.0 404 Not Found");
242
+ die();
243
+ }
244
+
245
+ if ($this->is_ip_blacklisted($ip)) {
246
+ $antibot_logger->fatal($email . ' - ' . $ip . ' - IP blacklisted');
247
+ header("HTTP/1.0 404 Not Found");
248
+ die();
249
+ }
250
+
251
+ if ($this->is_address_blacklisted($email)) {
252
+ $antibot_logger->fatal($email . ' - ' . $ip . ' - Address blacklisted');
253
+ header("HTTP/1.0 404 Not Found");
254
+ die();
255
+ }
256
+
257
+ // Akismet check
258
+ if ($this->is_spam_by_akismet($email, $full_name, $ip, $_SERVER['HTTP_USER_AGENT'], $_SERVER['HTTP_REFERER'])) {
259
+ $antibot_logger->fatal($email . ' - ' . $ip . ' - Akismet blocked');
260
+ header("HTTP/1.0 404 Not Found");
261
+ die();
262
+ }
263
+
264
+ // Flood check
265
+ if ($this->is_flood($email, $ip)) {
266
+ $antibot_logger->fatal($email . ' - ' . $ip . ' - Antiflood triggered');
267
+ header("HTTP/1.0 404 Not Found");
268
+ die('Too quick');
269
+ }
270
+ }
271
+
272
  /**
273
  *
274
  * @global wpdb $wpdb
326
  case 's':
327
  case 'subscribe':
328
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
330
+ $antibot_logger->fatal('HTTP method invalid');
331
  die('Invalid');
332
  }
333
+
334
  $options_antibot = $this->get_options('antibot');
335
 
336
  $captcha = !empty($options_antibot['captcha']);
337
 
338
  if (!empty($options_antibot['disabled']) || $this->antibot_form_check($captcha)) {
339
 
340
+ $user = $this->subscribe();
341
 
342
+ if ($user->status == 'E')
343
+ $this->show_message('error', $user);
344
+ if ($user->status == 'C')
345
+ $this->show_message('confirmed', $user);
346
+ if ($user->status == 'A')
347
+ $this->show_message('already_confirmed', $user);
348
+ if ($user->status == 'S')
349
+ $this->show_message('confirmation', $user);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
  } else {
351
  // Temporary store data
352
  //$data_key = wp_generate_password(16, false, false);
358
 
359
  // AJAX subscription
360
  case 'ajaxsub':
361
+
362
+ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
363
+ $antibot_logger->fatal('HTTP method invalid');
364
+ die('Invalid');
365
+ }
366
+
367
  $user = $this->subscribe();
368
+
369
  if ($user->status == 'E')
370
  $key = 'error';
371
  if ($user->status == 'C')
374
  $key = 'already_confirmed';
375
  if ($user->status == 'S')
376
  $key = 'confirmation';
377
+
378
+
379
+ $message = $newsletter->replace($this->options[$key . '_text'], $user);
380
+ if (isset($this->options[$key . '_tracking'])) {
381
+ $message .= $this->options[$key . '_tracking'];
382
  }
383
  echo $message;
384
  die();
465
  $this->save_options($this->options);
466
  }
467
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
  $this->init_options('template', false);
469
 
 
 
470
  global $wpdb, $charset_collate;
471
 
472
  require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
473
 
 
 
474
  $sql = "CREATE TABLE `" . $wpdb->prefix . "newsletter_user_logs` (
475
  `id` int(11) NOT NULL AUTO_INCREMENT,
476
  `user_id` int(11) NOT NULL DEFAULT 0,
597
  }
598
 
599
  /**
600
+ * Create a subscription using the $_REQUEST data. Does security checks.
601
+ *
602
+ * @param string $status The status to use for this subscription (confirmed, not confirmed, ...)
603
+ * @param bool $emails If the confirmation/welcome email should be sent or the subscription should be silent
604
+ * @return TNP_User
605
  */
606
  function subscribe($status = null, $emails = true) {
607
 
608
+ // Validation
609
+ $ip = $this->get_remote_ip();
610
+ $email = $this->normalize_email(stripslashes($_REQUEST['ne']));
611
+ $first_name = '';
612
+ if (isset($_REQUEST['nn'])) {
613
+ $first_name = $this->normalize_name($_REQUEST['nn']);
614
+ }
615
+
616
+ $last_name = '';
617
+ if (isset($_REQUEST['ns'])) {
618
+ $last_name = $this->normalize_name($_REQUEST['ns']);
619
+ }
620
+
621
+ $full_name = trim($first_name . ' ' . $last_name);
622
+
623
+ $this->valid_subscription_or_die($email, $full_name, $ip);
624
+
625
  $opt_in = (int) $this->options['noconfirmation']; // 0 - double, 1 - single
626
  if (!empty($this->options['optin_override']) && isset($_REQUEST['optin'])) {
627
  switch ($_REQUEST['optin']) {
643
  }
644
  }
645
 
 
 
 
 
 
 
 
646
  $user = $this->get_user($email);
647
 
648
  if ($user != null) {
715
 
716
 
717
  $user['token'] = $this->get_token();
 
718
  $ip = $this->process_ip($ip);
719
  $user['ip'] = $ip;
720
  $user['geo'] = 0;