From 646030a9aa88a0d5befd947312269cf505b5e6ce Mon Sep 17 00:00:00 2001 From: jaswsinc Date: Mon, 20 Jul 2015 22:09:50 -0800 Subject: [PATCH 1/2] Improving login_redirect security. --- .../classes/login-redirects-r.inc.php | 57 ++++++++++--------- .../includes/classes/login-redirects.inc.php | 53 ++++++++++------- 2 files changed, 65 insertions(+), 45 deletions(-) diff --git a/s2member/includes/classes/login-redirects-r.inc.php b/s2member/includes/classes/login-redirects-r.inc.php index f6031d0c..f2179483 100644 --- a/s2member/includes/classes/login-redirects-r.inc.php +++ b/s2member/includes/classes/login-redirects-r.inc.php @@ -15,9 +15,9 @@ * @since 3.5 */ if(!defined('WPINC')) // MUST have WordPress. - exit("Do not access this file directly."); + exit('Do not access this file directly.'); -if (!class_exists ("c_ws_plugin__s2member_login_redirects_r")) +if (!class_exists ('c_ws_plugin__s2member_login_redirects_r')) { /** * Login redirect removals. @@ -30,65 +30,70 @@ class c_ws_plugin__s2member_login_redirects_r /** * Handles completely empty ``login_redirect`` values. * - * @attaches-to ``add_filter("login_redirect");`` + * @attaches-to ``add_filter('login_redirect');`` * * @package s2Member\Login_Redirects * @since 110926 * - * @param string $redirect_to Expects the current ``$redirect_to`` value, passed in by the Filter. + * @param string $redirect_to Expects the current ``$redirect_to`` passed in by the Filter. * @return string A non-empty string value. s2Member will NEVER allow this to be completely empty. */ - public static function _empty_login_redirect_filter ($redirect_to) + public static function _empty_login_redirect_filter($redirect_to) { - return (!$redirect_to) ? admin_url () : $redirect_to; + return $redirect_to ? $redirect_to : admin_url (); } + /** * Handles HTTP/HTTPS ``login_redirect`` values. * - * @attaches-to ``add_filter("login_redirect");`` + * @attaches-to ``add_filter('login_redirect');`` * * @package s2Member\Login_Redirects * @since 130819 * - * @param string $redirect_to Expects the current ``$redirect_to`` value, passed in by the Filter. + * @param string $redirect_to Expects the current ``$redirect_to`` passed in by the Filter. * @return string Updated `redirect_to` value. */ - public static function _http_login_redirect_filter ($redirect_to) + public static function _http_login_redirect_filter($redirect_to) { - if($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["login_redirection_always_http"]) - if($redirect_to && is_string ($redirect_to) && strpos($redirect_to, "wp-admin") === FALSE) + $ci = $GLOBALS['WS_PLUGIN__']['s2member']['o']['ruris_case_sensitive'] ? '' : 'i'; + + if($GLOBALS['WS_PLUGIN__']['s2member']['o']['login_redirection_always_http']) + if($redirect_to && is_string($redirect_to) && strpos($redirect_to, 'wp-admin') === FALSE) { - $redirect_to = preg_replace("/^https\:\/\//i", "http://", $redirect_to); - if(stripos($redirect_to, "http://") !== 0) // Force absolute. + $redirect_to = preg_replace('/^https\:\/\//i', 'http://', $redirect_to); + if(stripos($redirect_to, 'http://') !== 0) // Force full URL. { - $home_path = trim((string)@parse_url(home_url('/'), PHP_URL_PATH), '/'); - $http_home_base = trim(preg_replace('/\/'.preg_quote($home_path, '/').'\/$/', '', home_url('/', 'http')), '/'); - $redirect_to = $http_home_base.'/'.ltrim($redirect_to, '/'); + $redirect_uri = $redirect_to; // e.g., `/path/with/?query=args` + $home_path = trim((string)@parse_url(home_url('/'), PHP_URL_PATH), '/'); + $http_home_base = trim(preg_replace('/\/'.preg_quote($home_path, '/').'\/$/'.$ci, '', home_url('/', 'http')), '/'); + $redirect_to = $http_home_base.'/'.ltrim($redirect_uri, '/'); } } return $redirect_to; } + /** * Removes all other ``login_redirect`` Filters to prevent conflicts with s2Member. * - * @attaches-to ``add_action("init");`` + * @attaches-to ``add_action('init');`` * * @package s2Member\Login_Redirects * @since 3.5 */ - public static function remove_login_redirect_filters () + public static function remove_login_redirect_filters() { - do_action("ws_plugin__s2member_before_remove_login_redirect_filters", get_defined_vars ()); + do_action('ws_plugin__s2member_before_remove_login_redirect_filters', get_defined_vars ()); - if (!apply_filters("ws_plugin__s2member_allow_other_login_redirect_filters", false, get_defined_vars ())) + if (!apply_filters('ws_plugin__s2member_allow_other_login_redirect_filters', false, get_defined_vars ())) { - remove_all_filters("login_redirect"); - add_filter ("login_redirect", "c_ws_plugin__s2member_login_redirects_r::_empty_login_redirect_filter"); - add_filter ("login_redirect", "c_ws_plugin__s2member_login_redirects_r::_http_login_redirect_filter"); - - do_action("ws_plugin__s2member_during_remove_login_redirect_filters", get_defined_vars ()); + remove_all_filters('login_redirect'); // Remove all others. + do_action('ws_plugin__s2member_during_remove_login_redirect_filters', get_defined_vars ()); } - do_action("ws_plugin__s2member_after_remove_login_redirect_filters", get_defined_vars ()); + add_filter('login_redirect', 'c_ws_plugin__s2member_login_redirects_r::_empty_login_redirect_filter'); + add_filter('login_redirect', 'c_ws_plugin__s2member_login_redirects_r::_http_login_redirect_filter'); + + do_action('ws_plugin__s2member_after_remove_login_redirect_filters', get_defined_vars ()); } } } diff --git a/s2member/includes/classes/login-redirects.inc.php b/s2member/includes/classes/login-redirects.inc.php index 11b935df..d9534a8c 100644 --- a/s2member/includes/classes/login-redirects.inc.php +++ b/s2member/includes/classes/login-redirects.inc.php @@ -52,17 +52,20 @@ public static function login_redirect($username = '', $user = NULL) { update_user_option($user_id, 's2member_last_login_time', time()); + $logins = (int)get_user_option('s2member_login_counter', $user_id) + 1; + update_user_option($user_id, 's2member_login_counter', $logins); + if(!get_user_option('s2member_registration_ip', $user_id)) update_user_option($user_id, 's2member_registration_ip', $_SERVER['REMOTE_ADDR']); - if(($logins = (int)get_user_option('s2member_login_counter', $user_id) + 1) >= 1 || ($logins = 1)) - update_user_option($user_id, 's2member_login_counter', $logins); - if($GLOBALS['WS_PLUGIN__']['s2member']['o']['custom_reg_password']) - delete_user_setting('default_password_nag').update_user_option($user_id, 'default_password_nag', FALSE, TRUE); - - if(($ok = TRUE) && !is_super_admin($user_id) && $username !== 'demo' // Exclude super admins, the `demo` user, and anyone who can edit posts. - && !apply_filters('ws_plugin__s2member_disable_login_ip_restrictions', (($user->has_cap('edit_posts')) ? TRUE : FALSE), get_defined_vars()) + { + delete_user_setting('default_password_nag'); + update_user_option($user_id, 'default_password_nag', FALSE, TRUE); + } + $ok = TRUE; // Initialize IP restriction being OK here. This is for filters. + if($username !== 'demo' && !is_super_admin($user_id) // Exclude the `demo` user, super admins, and anyone who can edit posts. + && !apply_filters('ws_plugin__s2member_disable_login_ip_restrictions', $user->has_cap('edit_posts') ? TRUE : FALSE, get_defined_vars()) ) $ok = c_ws_plugin__s2member_ip_restrictions::ip_restrictions_ok($_SERVER['REMOTE_ADDR'], strtolower($username)); if($GLOBALS['WS_PLUGIN__']['s2member']['o']['login_redirection_always_http']) // Alter value of `redirect_to`? @@ -71,12 +74,13 @@ public static function login_redirect($username = '', $user = NULL) $_REQUEST['redirect_to'] = preg_replace('/^https\:\/\//i', 'http://', $_REQUEST['redirect_to']); if(stripos($_REQUEST['redirect_to'], 'http://') !== 0) // Force an absolute URL in this case. { + $redirect_uri = $_REQUEST['redirect_to']; // e.g., `/path/with/?query=args` $home_path = trim((string)@parse_url(home_url('/'), PHP_URL_PATH), '/'); $http_home_base = trim(preg_replace('/\/'.preg_quote($home_path, '/').'\/$/'.$ci, '', home_url('/', 'http')), '/'); - $_REQUEST['redirect_to'] = $http_home_base.'/'.ltrim($_REQUEST['redirect_to'], '/'); + $_REQUEST['redirect_to'] = $http_home_base.'/'.ltrim($redirect_uri, '/'); } } - if(($redirect = apply_filters('ws_plugin__s2member_login_redirect', (($user->has_cap('edit_posts')) ? FALSE : TRUE), get_defined_vars()))) + if(($redirect = apply_filters('ws_plugin__s2member_login_redirect', $user->has_cap('edit_posts') ? FALSE : TRUE, get_defined_vars()))) { $obey_redirect_to = apply_filters('ws_plugin__s2member_obey_login_redirect_to', TRUE, get_defined_vars()); @@ -93,15 +97,21 @@ public static function login_redirect($username = '', $user = NULL) do_action('ws_plugin__s2member_during_login_redirect', get_defined_vars()); unset($__refs, $__v); // Housekeeping. - if($redirect && is_string($redirect)) $redirect = $redirect; + $is_lwp = FALSE; // Initialize LWP detection flag. - else if($redirection_url = c_ws_plugin__s2member_login_redirects::login_redirection_url($user)) - $redirect = $redirection_url; // Special redirection URL (overrides LWP). + if($redirect && is_string($redirect)) + $redirect = $redirect; + else if(($login_redirection_url = c_ws_plugin__s2member_login_redirects::login_redirection_url($user))) + { + $is_lwp = TRUE; // Flag as being a hard-coded LWP URL in this case. + $redirect = $login_redirection_url; // Special redirection URL. + } else if($GLOBALS['WS_PLUGIN__']['s2member']['o']['login_welcome_page']) - // Else we use the Login Welcome Page configured for s2Member. - $redirect = get_page_link($GLOBALS['WS_PLUGIN__']['s2member']['o']['login_welcome_page']); - + { + $is_lwp = TRUE; // Flag as being a hard-coded LWP URL in this case. + $redirect = get_page_link($GLOBALS['WS_PLUGIN__']['s2member']['o']['login_welcome_page']); + } else $redirect = home_url('/'); // Default to the home page. if($GLOBALS['WS_PLUGIN__']['s2member']['o']['login_redirection_always_http']) @@ -109,12 +119,17 @@ public static function login_redirect($username = '', $user = NULL) $redirect = preg_replace('/^https\:\/\//i', 'http://', $redirect); if(stripos($redirect, 'http://') !== 0) // Force absolute. { - $home_path = trim((string)@parse_url(home_url('/'), PHP_URL_PATH), '/'); - $http_home_base = trim(preg_replace('/\/'.preg_quote($home_path, '/').'\/$/'.$ci, '', home_url('/', 'http')), '/'); - $redirect = $http_home_base.'/'.ltrim($redirect, '/'); + $redirect_uri = $redirect; // e.g., `/path/with/?query=args` + $home_path = trim((string)@parse_url(home_url('/'), PHP_URL_PATH), '/'); + $http_home_base = trim(preg_replace('/\/'.preg_quote($home_path, '/').'\/$/'.$ci, '', home_url('/', 'http')), '/'); + $redirect = $http_home_base.'/'.ltrim($redirect_uri, '/'); } } - wp_redirect($redirect).exit(); + if($is_lwp) // Allow offsite redirection? + wp_redirect($redirect); // Perhaps an offsite location. + else wp_safe_redirect($redirect); // Default behavior. + + exit(); // Stop here; redirecting now. } } } From 9ad13330180c300f899e54b884d834773e97dbe9 Mon Sep 17 00:00:00 2001 From: jaswsinc Date: Wed, 22 Jul 2015 01:08:40 -0800 Subject: [PATCH 2/2] Wrappers. See: https://github.com/websharks/s2member/issues/645 --- s2member/includes/classes/sc-eots-in.inc.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/s2member/includes/classes/sc-eots-in.inc.php b/s2member/includes/classes/sc-eots-in.inc.php index 75460d6b..a26519c3 100644 --- a/s2member/includes/classes/sc-eots-in.inc.php +++ b/s2member/includes/classes/sc-eots-in.inc.php @@ -153,6 +153,11 @@ public static function sc_eot_details($attr = array(), $content = '', $shortcode $details = $attr['empty_format']; // Empty this. $eot['debug'] = 'No more payments needed from this user.'; } + // Wrapper and debug info... + + if($details) // Wrapper for CSS styling. + $details = ''.$details.''; + if(filter_var($attr['debug'], FILTER_VALIDATE_BOOLEAN)) $details .= '
'.esc_html($eot['debug'] ? $eot['debug'] : 'Unknown error.').'
';