Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/newsletters-lite/helpers/auth.php
+++ b/newsletters-lite/helpers/auth.php
@@ -20,8 +20,12 @@
if (!empty($subscriber_id) && $subscriber = $Db -> find(array('id' => $subscriber_id), false, false, true, true, false)) {
return $subscriber;
- } elseif (!empty($subscriberauth) && $subscriber = $Db -> find(array('cookieauth' => $subscriberauth), false, false, true, true, false)) {
- return $subscriber;
+ } elseif (!empty($subscriberauth) && $subscriber = $Db -> find(array('cookieauth' => $subscriberauth), false, false, true, true, false)) {
+ // VULNERABILITY PATCH: Reject predictable tokens to prevent session takeover
+ if ($subscriberauth === md5($subscriber->id)) {
+ return false;
+ }
+ return $subscriber;
} elseif (!empty($user_id) && $subscriber = $Db -> find(array('user_id' => $user_id))) {
return $subscriber;
}
--- a/newsletters-lite/includes/checkinit.php
+++ b/newsletters-lite/includes/checkinit.php
@@ -364,6 +364,7 @@
// Store the validation result and timestamp in transients
set_transient("wpml" . 'serial_valid_' . $host_hash, $is_serial_valid , 86400);
set_transient("wpml" . 'serial_validation_time_' . $host_hash, time(), 86400);
+ $valid_status = $is_serial_valid;
}
// Retrieve the validation result from the transients
@@ -487,4 +488,4 @@
}
}
-?>
No newline at end of file
+?>
--- a/newsletters-lite/views/admin/settings/view_logs.php
+++ b/newsletters-lite/views/admin/settings/view_logs.php
@@ -1,136 +1,136 @@
-<?php // phpcs:ignoreFile ?>
-<!-- API -->
-
-<?php
-
-$debugging = get_option('tridebugging');
-$this->debugging = (empty($debugging)) ? $this->debugging : true;
-
-if (!file_exists(NEWSLETTERS_LOG_FILE)) {
- esc_html_e('The log file does not exist yet.', 'wp-mailinglist');
- die();
-}
-
-if (empty(filesize(NEWSLETTERS_LOG_FILE))) {
- $info = [
- 'enabled' => $this->debugging,
- ];
-
- if (!file_exists(NEWSLETTERS_LOG_FILE)) {
- echo esc_html_e('The log file does not exist.', 'wp-mailinglist');
- die();
- }
-
- // File path.
- $info['filePath'] = NEWSLETTERS_LOG_FILE;
-
- $file_size = @filesize($info['filePath']);
-
- if (empty($file_size)) {
- $file_size = '0B';
- }
-
- echo esc_html_e('The log file is empty.', 'wp-mailinglist');
- die();
-}
-
-$lines = 500;
-// Open file.
-$f = @fopen(NEWSLETTERS_LOG_FILE, 'rb'); // phpcs:ignore
-
-if (false === $f) {
- echo esc_html_e('Could not open the log file', 'wp-mailinglist');
- die();
-}
-
-// Sets buffer size, according to the number of lines to retrieve.
-// This gives a performance boost when reading a few lines from the file.
-$buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096));
-
-// Jump to last character.
-fseek($f, -1, SEEK_END);
-
-// Read it and adjust line number if necessary.
-// (Otherwise the result would be wrong if file doesn't end with a blank line).
-if (fread($f, 1) != "n") $lines -= 1; // phpcs:ignore
-
-// Start reading.
-$output = '';
-$chunk = '';
-
-// While we would like more.
-while (ftell($f) > 0 && $lines >= 0) {
- // Figure out how far back we should jump.
- $seek = min(ftell($f), $buffer);
-
- // Do the jump (backwards, relative to where we are).
- fseek($f, -$seek, SEEK_CUR);
-
- // Read a chunk and prepend it to our output.
- $output = ($chunk = fread($f, $seek)) . $output; // phpcs:ignore
-
- // Jump back to where we started reading.
- fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR);
-
- // Decrease our line counter.
- $lines -= substr_count($chunk, "n");
-}
-
-// While we have too many lines.
-// (Because of buffer size we might have read too many).
-while ($lines++ < 0) {
- // Find first newline and remove all text before that.
- $output = substr($output, strpos($output, "n") + 1);
-}
-
-// Close file and return.
-fclose($f); // phpcs:ignore
-
-?>
-
-<div class="wrap newsletters">
- <h1><?php esc_html_e('View Logs', 'wp-mailinglist'); ?></h1>
-
- <?php $this->render('settings-navigation', false, true, 'admin'); ?>
-
- <p><?php esc_html_e('The debug log displays the last 500 lines and only shows certain logs such as when a cron job fires or when you face a specific issue. The logs are not the same as PHP error logs.', 'wp-mailinglist'); ?><br/>
- <?php _e('<a href="https://tribulant.com/docs/wordpress-mailing-list-plugin/3926/newsletters-debugging/" target="_blank" >Debugging documentation</a>. ', 'wp-mailinglist'); ?>
- </p>
- <?php if (!empty($log_protection_message)) : ?>
- <div class="notice <?php echo esc_attr($log_protection_message_class); ?>"><p><?php echo esc_html($log_protection_message); ?></p></div>
- <?php endif; ?>
- <textarea style="width: 100%; min-height: 600px;"><?php echo esc_textarea($output); ?></textarea>
- <?php if (empty($log_protected)) : ?>
- <form method="post" style="margin-top: 10px;">
- <?php wp_nonce_field('newsletters_protect_log_file'); ?>
- <p>
- <button type="submit" name="protect_log_file" class="button button-secondary"><?php esc_html_e('Protect Log File via .htaccess', 'wp-mailinglist'); ?></button>
- <span class="description"><?php esc_html_e('Add a .htaccess rule to block direct access to the log file.', 'wp-mailinglist'); ?></span>
- </p>
- </form>
- <?php //if (empty($log_htaccess_writable)) : ?>
- <div class="log-htaccess-manual" style="margin-top: 10px;">
- <a href="#" class="toggle-log-htaccess-rule" aria-expanded="false"><?php esc_html_e('Or add this to your htaccess to protect your log', 'wp-mailinglist'); ?></a>
- <div class="log-htaccess-rule" style="display: none; margin-top: 5px;">
- <pre><?php echo esc_html($log_htaccess_rule); ?></pre>
- </div>
- </div>
- <script type="text/javascript">
- (function($) {
- $(document).ready(function() {
- $('.toggle-log-htaccess-rule').on('click', function(event) {
- event.preventDefault();
-
- var $toggle = $(this);
- var $container = $toggle.closest('.log-htaccess-manual').find('.log-htaccess-rule');
- var expanded = $toggle.attr('aria-expanded') === 'true';
-
- $container.toggle(!expanded);
- $toggle.attr('aria-expanded', expanded ? 'false' : 'true');
- });
- });
- })(jQuery);
- </script>
- <?php //endif; ?>
- <?php endif; ?>
-</div>
+<?php // phpcs:ignoreFile ?>
+<!-- API -->
+
+<?php
+
+$debugging = get_option('tridebugging');
+$this->debugging = (empty($debugging)) ? $this->debugging : true;
+
+if (!file_exists(NEWSLETTERS_LOG_FILE)) {
+ esc_html_e('The log file does not exist yet.', 'wp-mailinglist');
+ die();
+}
+
+if (empty(filesize(NEWSLETTERS_LOG_FILE))) {
+ $info = [
+ 'enabled' => $this->debugging,
+ ];
+
+ if (!file_exists(NEWSLETTERS_LOG_FILE)) {
+ echo esc_html_e('The log file does not exist.', 'wp-mailinglist');
+ die();
+ }
+
+ // File path.
+ $info['filePath'] = NEWSLETTERS_LOG_FILE;
+
+ $file_size = @filesize($info['filePath']);
+
+ if (empty($file_size)) {
+ $file_size = '0B';
+ }
+
+ echo esc_html_e('The log file is empty.', 'wp-mailinglist');
+ die();
+}
+
+$lines = 500;
+// Open file.
+$f = @fopen(NEWSLETTERS_LOG_FILE, 'rb'); // phpcs:ignore
+
+if (false === $f) {
+ echo esc_html_e('Could not open the log file', 'wp-mailinglist');
+ die();
+}
+
+// Sets buffer size, according to the number of lines to retrieve.
+// This gives a performance boost when reading a few lines from the file.
+$buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096));
+
+// Jump to last character.
+fseek($f, -1, SEEK_END);
+
+// Read it and adjust line number if necessary.
+// (Otherwise the result would be wrong if file doesn't end with a blank line).
+if (fread($f, 1) != "n") $lines -= 1; // phpcs:ignore
+
+// Start reading.
+$output = '';
+$chunk = '';
+
+// While we would like more.
+while (ftell($f) > 0 && $lines >= 0) {
+ // Figure out how far back we should jump.
+ $seek = min(ftell($f), $buffer);
+
+ // Do the jump (backwards, relative to where we are).
+ fseek($f, -$seek, SEEK_CUR);
+
+ // Read a chunk and prepend it to our output.
+ $output = ($chunk = fread($f, $seek)) . $output; // phpcs:ignore
+
+ // Jump back to where we started reading.
+ fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR);
+
+ // Decrease our line counter.
+ $lines -= substr_count($chunk, "n");
+}
+
+// While we have too many lines.
+// (Because of buffer size we might have read too many).
+while ($lines++ < 0) {
+ // Find first newline and remove all text before that.
+ $output = substr($output, strpos($output, "n") + 1);
+}
+
+// Close file and return.
+fclose($f); // phpcs:ignore
+
+?>
+
+<div class="wrap newsletters">
+ <h1><?php esc_html_e('View Logs', 'wp-mailinglist'); ?></h1>
+
+ <?php $this->render('settings-navigation', false, true, 'admin'); ?>
+
+ <p><?php esc_html_e('The debug log displays the last 500 lines and only shows certain logs such as when a cron job fires or when you face a specific issue. The logs are not the same as PHP error logs.', 'wp-mailinglist'); ?><br/>
+ <?php _e('<a href="https://tribulant.com/docs/wordpress-mailing-list-plugin/3926/newsletters-debugging/" target="_blank" >Debugging documentation</a>. ', 'wp-mailinglist'); ?>
+ </p>
+ <?php if (!empty($log_protection_message)) : ?>
+ <div class="notice <?php echo esc_attr($log_protection_message_class); ?>"><p><?php echo esc_html($log_protection_message); ?></p></div>
+ <?php endif; ?>
+ <textarea style="width: 100%; min-height: 600px;"><?php echo esc_textarea($output); ?></textarea>
+ <?php if (empty($log_protected)) : ?>
+ <form method="post" style="margin-top: 10px;">
+ <?php wp_nonce_field('newsletters_protect_log_file'); ?>
+ <p>
+ <button type="submit" name="protect_log_file" class="button button-secondary"><?php esc_html_e('Protect Log File via .htaccess', 'wp-mailinglist'); ?></button>
+ <span class="description"><?php esc_html_e('Add a .htaccess rule to block direct access to the log file.', 'wp-mailinglist'); ?></span>
+ </p>
+ </form>
+ <?php //if (empty($log_htaccess_writable)) : ?>
+ <div class="log-htaccess-manual" style="margin-top: 10px;">
+ <a href="#" class="toggle-log-htaccess-rule" aria-expanded="false"><?php esc_html_e('Or add this to your htaccess to protect your log', 'wp-mailinglist'); ?></a>
+ <div class="log-htaccess-rule" style="display: none; margin-top: 5px;">
+ <pre><?php echo esc_html($log_htaccess_rule); ?></pre>
+ </div>
+ </div>
+ <script type="text/javascript">
+ (function($) {
+ $(document).ready(function() {
+ $('.toggle-log-htaccess-rule').on('click', function(event) {
+ event.preventDefault();
+
+ var $toggle = $(this);
+ var $container = $toggle.closest('.log-htaccess-manual').find('.log-htaccess-rule');
+ var expanded = $toggle.attr('aria-expanded') === 'true';
+
+ $container.toggle(!expanded);
+ $toggle.attr('aria-expanded', expanded ? 'false' : 'true');
+ });
+ });
+ })(jQuery);
+ </script>
+ <?php //endif; ?>
+ <?php endif; ?>
+</div>
--- a/newsletters-lite/views/admin/submitserial.php
+++ b/newsletters-lite/views/admin/submitserial.php
@@ -12,7 +12,7 @@
<h1><i class="fa fa-envelope fa-fw"></i> <?php echo sprintf(__('%s Serial Key', 'wp-mailinglist'), $this -> name); ?></h1>
-<?php if (empty($success) || $success == false) : ?>
+<?php if (empty($success) || $success == false) : ?>
<?php
$validation_status = $this -> ci_serial_valid();
@@ -105,11 +105,24 @@
<?php
}
?>
-<?php else : ?>
- <p><?php esc_html_e('The serial key is valid and you can now continue using the Newsletter plugin. Thank you for your business and support!', 'wp-mailinglist'); ?></p>
- <p>
- <button value="1" type="button" onclick="jQuery.colorbox.close(); parent.location = '<?php echo esc_url_raw(rtrim(get_admin_url(), '/')); ?>/admin.php?page=newsletters';" class="button-primary" name="close">
- <i class="fa fa-check fa-fw"></i> <?php esc_html_e('Apply Serial and Close Window', 'wp-mailinglist'); ?>
- </button>
- </p>
-<?php endif; ?>
No newline at end of file
+<?php elseif ($success == 'expired') : ?>
+ <p><?php esc_html_e('The serial key is valid but expired.', 'wp-mailinglist'); ?></p>
+ <p style="width:400px;">
+ <?php echo sprintf(__('To access PRO features, download our paid version from your %s, then deactivate and delete the LITE version before installing and activating the paid version. You will not lose any data.', 'wp-mailinglist'), '<a href="https://tribulant.com/downloads/" target="_blank">' . __('Downloads page', 'wp-mailinglist') . '</a>'); ?>
+ </p>
+ <p>
+ <button value="1" type="button" onclick="jQuery.colorbox.close(); parent.location = '<?php echo esc_url_raw(rtrim(get_admin_url(), '/')); ?>/plugins.php';" class="button-primary" name="close">
+ <i class="fa fa-check fa-fw"></i> <?php esc_html_e('Apply Serial and Close Window', 'wp-mailinglist'); ?>
+ </button>
+ </p>
+<?php else : ?>
+ <p><?php esc_html_e('The serial key is valid and you can now continue using the Newsletter plugin. Thank you for your business and support!', 'wp-mailinglist'); ?></p>
+ <p style="width:400px;">
+ <?php echo sprintf(__('To access PRO features, download our paid version from your %s, then deactivate and delete the LITE version before installing and activating the paid version. You will not lose any data.', 'wp-mailinglist'), '<a href="https://tribulant.com/downloads/" target="_blank">' . __('Downloads page', 'wp-mailinglist') . '</a>'); ?>
+ </p>
+ <p>
+ <button value="1" type="button" onclick="jQuery.colorbox.close(); parent.location = '<?php echo esc_url_raw(rtrim(get_admin_url(), '/')); ?>/plugins.php';" class="button-primary" name="close">
+ <i class="fa fa-check fa-fw"></i> <?php esc_html_e('Apply Serial and Close Window', 'wp-mailinglist'); ?>
+ </button>
+ </p>
+<?php endif; ?>
--- a/newsletters-lite/views/admin/subscribers/unsubscribes.php
+++ b/newsletters-lite/views/admin/subscribers/unsubscribes.php
@@ -151,7 +151,7 @@
<?php if (!empty($unsubscribe -> user_id)) : ?>
<a href="<?php echo get_edit_user_link($unsubscribe -> userdata -> ID); ?>"><?php echo esc_html( $unsubscribe -> userdata -> display_name); ?></a>
<div class="row-actions">
- <span class="delete"><a href="<?php echo esc_url_raw( admin_url('admin.php?page=' . $this -> sections -> subscribers . '&method=deleteuser&user_id=' . $unsubscribe -> user_id)) ?>" class="submitdelete" onclick="if (!confirm('<?php esc_html_e('Are you sure you want to delete this user?', 'wp-mailinglist'); ?>')) { return false; }"><?php esc_html_e('Delete User', 'wp-mailinglist'); ?></a></span>
+ <span class="delete"><a href="<?php echo esc_url_raw( wp_nonce_url(admin_url('admin.php?page=' . $this -> sections -> subscribers . '&method=deleteuser&user_id=' . $unsubscribe -> user_id), $this -> sections -> subscribers . '_deleteuser')) ?>" class="submitdelete" onclick="if (!confirm('<?php esc_html_e('Are you sure you want to delete this user?', 'wp-mailinglist'); ?>')) { return false; }"><?php esc_html_e('Delete User', 'wp-mailinglist'); ?></a></span>
</div>
<?php else : ?>
<?php esc_html_e('None', 'wp-mailinglist'); ?>
--- a/newsletters-lite/wp-mailinglist-plugin.php
+++ b/newsletters-lite/wp-mailinglist-plugin.php
@@ -8,7 +8,7 @@
var $name = 'Newsletters';
var $plugin_base;
var $pre = 'wpml';
- var $version = '4.13';
+ var $version = '4.14';
var $dbversion = '1.2.3';
var $debugging = false; //set to "true" to turn on debugging
var $debug_level = 2; //set to 1 for only database errors and var dump; 2 for PHP errors as well
@@ -2390,7 +2390,7 @@
$subscribers = (object) stripslashes_deep($_REQUEST['subscribers']);
if (!empty($subscribers)) {
- $historyquery = "SELECT id, message, subject FROM " . $wpdb -> prefix . $this -> History() -> table . " WHERE id = '" . esc_sql($_REQUEST['history_id']) . "' LIMIT 1";
+ $historyquery = $wpdb->prepare("SELECT id, message, subject FROM " . $wpdb -> prefix . $this -> History() -> table . " WHERE id = %d LIMIT 1", intval($_REQUEST['history_id']));
$history = $wpdb -> get_row($historyquery);
if (!empty($history)) {
@@ -2469,7 +2469,7 @@
$this -> qp_reset_data();
if (!empty($subscribers)) {
- $historyquery = "SELECT id, message, subject FROM " . $wpdb -> prefix . $this -> History() -> table . " WHERE id = '" . esc_sql($_REQUEST['history_id']) . "' LIMIT 1";
+ $historyquery = $wpdb->prepare("SELECT id, message, subject FROM " . $wpdb -> prefix . $this -> History() -> table . " WHERE id = %d LIMIT 1", intval($_REQUEST['history_id']));
$history = $wpdb -> get_row($historyquery);
if (!empty($history)) {
@@ -4807,11 +4807,12 @@
check_ajax_referer('serialkey', 'security');
if (current_user_can('newsletters_welcome')) {
- if (!empty($_GET['delete'])) {
- $this -> delete_option('serialkey');
- $host = sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST']));
- $host_hash = md5($host);
- if (!empty($host)) {
+ if (!empty($_GET['delete'])) {
+ $this -> delete_option('serialkey');
+ $this -> delete_all_cache('all');
+ $host = sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST']));
+ $host_hash = md5($host);
+ if (!empty($host)) {
$time_key = 'wpmlserial_validation_time_' . $host_hash;
$valid_key = 'wpmlserial_valid_' . $host_hash;
@@ -4820,11 +4821,12 @@
if ( is_multisite() ) {
delete_site_transient( $time_key );
- delete_site_transient( $valid_key );
- }
- }
- $errors[] = __('Serial key has been deleted.', 'wp-mailinglist');
- } else {
+ delete_site_transient( $valid_key );
+ }
+ }
+ delete_transient($this -> pre . 'update_info');
+ $errors[] = __('Serial key has been deleted.', 'wp-mailinglist');
+ } else {
if (!empty($_POST)) {
if (empty($_REQUEST['serialkey'])) { $errors[] = __('Please fill in a serial key.', 'wp-mailinglist'); }
else {
@@ -4839,14 +4841,13 @@
}
$serial_validation_status = $this->ci_serial_valid();
- if (!is_array($serial_validation_status) && !$serial_validation_status) {
- $errors[] = __('Serial key is invalid, please try again.', 'wp-mailinglist');
- }
- else if(is_array($serial_validation_status) && !$serial_validation_status) {
- $errors[] = __('Serial key is expired. You can still work with it, but it is limited', 'wp-mailinglist');
- delete_transient($this -> pre . 'update_info');
- $success = true;
- }
+ if (!is_array($serial_validation_status) && !$serial_validation_status) {
+ $errors[] = __('Serial key is invalid, please try again.', 'wp-mailinglist');
+ }
+ else if (is_array($serial_validation_status) && !empty($serial_validation_status['expired'])) {
+ delete_transient($this -> pre . 'update_info');
+ $success = 'expired';
+ }
else if (!is_array($serial_validation_status) && $serial_validation_status)
{
$host = sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST']));
@@ -5582,7 +5583,7 @@
if ($subscriber = $Db -> find(array('id' => (int) $_POST['subscriber_id']), false, false, true, true, false)) {
if ($subscriber -> id == (int) $_POST['subscriber_id']) {
$Db -> model = $Mailinglist -> model;
- $query = "SELECT * FROM " . $wpdb -> prefix . $Mailinglist -> table . " WHERE `id` = '" . esc_sql((int)$_POST['mailinglist_id']) . "'";
+ $query = $wpdb->prepare("SELECT * FROM " . $wpdb -> prefix . $Mailinglist -> table . " WHERE `id` = %d", intval($_POST['mailinglist_id']));
$mailinglist = $wpdb -> get_row($query);
$paid = $mailinglist -> paid;
@@ -6079,7 +6080,7 @@
$success = true;
$Authnews -> set_emailcookie($subscriber -> email, "+30 days");
- if (empty($subscriber -> cookieauth)) {
+ if (empty($subscriber -> cookieauth) || $subscriber -> cookieauth === md5($subscriber->id)) {
$subscriberauth = $Authnews -> gen_subscriberauth();
$Db -> model = $Subscriber -> model;
$Db -> save_field('cookieauth', $subscriberauth, array('id' => $subscriber -> id));
@@ -6124,7 +6125,7 @@
$success = true;
$Authnews -> set_emailcookie($subscriber -> email, "+30 days");
- if (empty($subscriber -> cookieauth)) {
+ if (empty($subscriber -> cookieauth) || $subscriber -> cookieauth === md5($subscriber->id)) {
$subscriberauth = $Authnews -> gen_subscriberauth();
$Db -> model = $Subscriber -> model;
$Db -> save_field('cookieauth', $subscriberauth, array('id' => $subscriber -> id));
@@ -6166,7 +6167,7 @@
}
if (!empty($data[$this -> pre . 'subscriber_id'])) {
- $subscriber_query = "SELECT * FROM " . $wpdb -> prefix . $Subscriber -> table . " WHERE id = '" . $data[$this -> pre . 'subscriber_id'] . "'";
+ $subscriber_query = $wpdb->prepare("SELECT * FROM " . $wpdb -> prefix . $Subscriber -> table . " WHERE id = %d", intval($data[$this -> pre . 'subscriber_id']));
$subscriber = $wpdb -> get_row($subscriber_query);
@@ -9132,7 +9133,9 @@
global $Db, $Subscriber, $SubscribersList;
$Db -> model = $Subscriber -> model;
$subscriber = $Db -> find(array('id' => $subscriber_id));
- $authkey = (empty($subscriber -> authkey)) ? md5($subscriber_id) : $subscriber -> authkey;
+ $new_authkey = function_exists('wp_generate_password') ? wp_generate_password(32, false) : md5(uniqid(rand(), true));
+ $new_authkey = function_exists('wp_generate_password') ? wp_generate_password(32, false) : md5(uniqid(rand(), true));
+ $authkey = (empty($subscriber -> authkey) || $subscriber -> authkey === md5($subscriber_id)) ? $new_authkey : $subscriber -> authkey;
if (!empty($mailinglist_id)) {
$Db -> model = $SubscribersList -> model;
@@ -9148,7 +9151,7 @@
}
} else {
if (!empty($subscriber)) {
- if ($subscriber -> authinprog == "Y" && !empty($subscriber -> authkey)) {
+ if ($subscriber -> authinprog == "Y" && !empty($subscriber -> authkey) && $subscriber -> authkey !== md5($subscriber_id)) {
$authkey = $subscriber -> authkey;
} else {
$Db -> model = $Subscriber -> model;
@@ -9299,7 +9302,7 @@
if (!empty($subscriber)) {
$linktext = esc_html($this -> get_option('managelinktext'));
- if (empty($subscriber -> cookieauth)) {
+ if (empty($subscriber -> cookieauth) || $subscriber -> cookieauth === md5($subscriber->id)) {
$subscriberauth = $Authnews -> gen_subscriberauth();
$Db -> model = $Subscriber -> model;
$Db -> save_field('cookieauth', $subscriberauth, array('id' => $subscriber -> id));
@@ -14841,4 +14844,4 @@
}*/
}
-?>
No newline at end of file
+?>
--- a/newsletters-lite/wp-mailinglist.php
+++ b/newsletters-lite/wp-mailinglist.php
@@ -3,7 +3,7 @@
/*
Plugin Name: Newsletters
Plugin URI: https://tribulant.com/plugins/view/1/
-Version: 4.13
+Version: 4.14
Description: This newsletter software by Tribulant allows users to subscribe to multiple mailing lists on your WordPress website. Send newsletters manually or from posts, manage newsletter templates, view a complete history with tracking, import/export subscribers, accept paid subscriptions and much more. Remove limits by buying PRO. Once purchased, to avoid future issues, remove this version and install and use the paid version in its stead. No data will be lost.
Author: Tribulant
Author URI: https://tribulant.com
@@ -7122,7 +7122,7 @@
// Save authentication string to subscriber record
$Db->model = $Subscriber->model;
- if (empty($subscriber->cookieauth)) {
+ if (empty($subscriber->cookieauth) || $subscriber->cookieauth === md5($subscriber->id)) {
$Db->save_field('cookieauth', $subscriberauth, array('id' => $subscriber->id));
} else {
$subscriberauth = $subscriber->cookieauth;
@@ -7343,7 +7343,7 @@
// Save authentication string to subscriber record
$Db->model = $Subscriber->model;
- if (empty($subscriber->cookieauth)) {
+ if (empty($subscriber->cookieauth) || $subscriber->cookieauth === md5($subscriber->id)) {
$Db->save_field('cookieauth', $subscriberauth, array('id' => $subscriber->id));
} else {
$subscriberauth = $subscriber->cookieauth;
@@ -7648,8 +7648,14 @@
$this -> redirect($this -> referer, $msgtype, $message);
break;
case 'deleteuser' :
+ check_admin_referer($this->sections->subscribers . '_deleteuser');
if (!empty($_GET['user_id'])) {
- if (wp_delete_user((int) $_GET['user_id']) && !user_can( $_GET['user_id'], 'manage_options' )) {
+ $user_id = (int) $_GET['user_id'];
+ $current_user_id = get_current_user_id();
+ if ($user_id === $current_user_id) {
+ $msgtype = 'error';
+ $message = __('You cannot delete your own user account', 'wp-mailinglist');
+ } elseif (!user_can($user_id, 'manage_options') && wp_delete_user($user_id)) {
$msgtype = 'message';
$message = __('User has been deleted', 'wp-mailinglist');
} else {