| @@ -9,10 +9,10 @@ | ||
| 9 | 9 | $this->auth(); |
| 10 | 10 | } |
| 11 | 11 | |
| 12 | 12 | public function auth(){ |
| 13 | - if(self::getOption('authorized') === false){ | |
| 14 | - wp_safe_redirect(wtsec_getUrl('login')); | |
| 13 | + if(self::getOption('authorized') === false && (defined('WTSEC_DEACTIVATED') && !WTSEC_DEACTIVATED)){ | |
| 14 | + wp_safe_redirect(admin_url('admin.php?page=' . WTSEC_PAGE_PREFIX . 'login')); | |
| 15 | 15 | exit; |
| 16 | 16 | } |
| 17 | 17 | } |
| 18 | 18 | |
| @@ -20,19 +20,18 @@ | ||
| 20 | 20 | return (boolean) self::getOption('authorized'); |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | 23 | public static function login($token){ |
| 24 | + define("WTSEC_DEACTIVATED", false); | |
| 24 | 25 | self::_set('authorized', true); |
| 25 | 26 | self::_set('authToken', $token); |
| 26 | 27 | } |
| 27 | 28 | |
| 28 | 29 | public static function logout(){ |
| 29 | - self::_set('authorized', false); | |
| 30 | - self::_set('authToken', ""); | |
| 30 | + self::_delete(['authToken','authorized','api_key']); | |
| 31 | + //self::_set('am_installed', false); | |
| 31 | 32 | } |
| 32 | 33 | |
| 33 | - | |
| 34 | - | |
| 35 | 34 | public function getLocalDomains(){ |
| 36 | 35 | return []; |
| 37 | 36 | } |
| 38 | 37 | |
| @@ -43,8 +42,19 @@ | ||
| 43 | 42 | public static function _get($name){ |
| 44 | 43 | return get_option(WTSEC_PLUGIN_PREFIX.$name); |
| 45 | 44 | } |
| 46 | 45 | |
| 46 | + public static function _delete($options){ | |
| 47 | + if(is_array($options)){ | |
| 48 | + foreach ($options as $option) { | |
| 49 | + if ( ! delete_option(WTSEC_PLUGIN_PREFIX.$option)) | |
| 50 | + return FALSE; | |
| 51 | + } | |
| 52 | + } else{ | |
| 53 | + delete_option(WTSEC_PLUGIN_PREFIX.$options); | |
| 54 | + } | |
| 55 | + } | |
| 56 | + | |
| 47 | 57 | public function set($name,$value){ |
| 48 | 58 | return update_option(WTSEC_PLUGIN_PREFIX.$name,$value); |
| 49 | 59 | } |
| 50 | 60 | |
| @@ -66,5 +76,117 @@ | ||
| 66 | 76 | |
| 67 | 77 | public static function getName(){ |
| 68 | 78 | return self::getOption('username'); |
| 69 | 79 | } |
| 80 | + | |
| 81 | + | |
| 82 | + // Limit login attempt | |
| 83 | + public function wtsec_login_check(){ | |
| 84 | + | |
| 85 | + if( ! $this->wtsec_is_need_check() ) | |
| 86 | + return; | |
| 87 | + | |
| 88 | + $massage = wtsec_locale('login_attempt_message'); | |
| 89 | + | |
| 90 | + $options = (object) [ | |
| 91 | + // время снятия блокировки в секудах | |
| 92 | + 'lock_time' => 1800, // 1800 | |
| 93 | + // Количество попыток авторизоваться | |
| 94 | + 'lock_num' => 5, | |
| 95 | + // Сообщение о блокировке | |
| 96 | + 'massage' => $massage, | |
| 97 | + // время полной очистки файла - 4 дня | |
| 98 | + 'expire_time' => 3600 * 24 * 4, | |
| 99 | + // добавить в названия файлов запрос REQUEST_URI - может пригодится для дебага | |
| 100 | + 'add_uri' => false, | |
| 101 | + // использовать ли мякгий метод получения IP? | |
| 102 | + 'soft_get_ip' => false, | |
| 103 | + ]; | |
| 104 | + | |
| 105 | + // чтобы установить имя файла | |
| 106 | + $action = @ $_GET['action']; | |
| 107 | + if( ! in_array( $action, array( 'postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login' ), true ) ) | |
| 108 | + $action = 'login'; | |
| 109 | + | |
| 110 | + // создаем директорию кэша если надо | |
| 111 | + $cache_dir = plugin_dir_path(__FILE__) . 'cache'; | |
| 112 | + if( ! file_exists($cache_dir) ) | |
| 113 | + mkdir( $cache_dir, 0777 ); | |
| 114 | + | |
| 115 | + // оперделим название файла | |
| 116 | + $REQUEST_URI = $options->add_uri ? ( '___'. preg_replace('/[^a-zA-Z0-9:=?_-]/', '-', $_SERVER['REQUEST_URI'] ) /*все на -*/ ) : ''; | |
| 117 | + $domen = str_replace('www.', '', $_SERVER['HTTP_HOST'] ); | |
| 118 | + $file_path = $cache_dir . "/{$domen}___{$action}{$REQUEST_URI}.ini"; | |
| 119 | + | |
| 120 | + // оперделим ip | |
| 121 | + if( ! $ip = $this->wtsec_get_ip( $options->soft_get_ip ) ) | |
| 122 | + die( 'No IP...' ); | |
| 123 | + | |
| 124 | + // парсим данные | |
| 125 | + $data = @ parse_ini_file( $file_path ); | |
| 126 | + $data = (!$data) ? [] : $data; | |
| 127 | + $attempts = array_key_exists($ip,$data) ? count($data[$ip]) + 1 : 1; | |
| 128 | + $last_access_time = array_key_exists($ip,$data) ? max( $data[$ip] ) : 0; | |
| 129 | + $blocked_time = $last_access_time + ($options->lock_time * floor( $attempts / $options->lock_num) ); | |
| 130 | + | |
| 131 | + if ( $data['status'][$ip] == 'blocked' && $blocked_time > time() ){ | |
| 132 | + $blocked_time = ($blocked_time - time()) / 60; | |
| 133 | + //return new WP_Error('incorrect_password', $options->massage); | |
| 134 | + die( sprintf($options->massage, $options->lock_num, $blocked_time) ); // блокируем | |
| 135 | + } else{ | |
| 136 | + file_put_contents( $file_path, sprintf("{$ip}[] = %d\n", time()), FILE_APPEND ); // добавляем ip и время | |
| 137 | + | |
| 138 | + if ($data['status'][$ip] == 'blocked'){ | |
| 139 | + $new_content = preg_replace("~status\[" . $ip . "\] = [a-z]+\n~", '', file_get_contents($file_path) ); | |
| 140 | + file_put_contents( $file_path, $new_content ); // снимает блокировку | |
| 141 | + } | |
| 142 | + | |
| 143 | + if($attempts >= $options->lock_num && ( $attempts % $options->lock_num ) == 0) | |
| 144 | + file_put_contents( $file_path, "status[{$ip}] = blocked\n", FILE_APPEND); // добавляем блокировку | |
| 145 | + } | |
| 146 | + | |
| 147 | + // полная очистка файла | |
| 148 | + if( empty($data['expire']) ){ | |
| 149 | + file_put_contents( $file_path, 'expire = ' . time() . "\n", FILE_APPEND ); | |
| 150 | + } | |
| 151 | + elseif( $data['expire'] + $options->expire_time < time() ){ | |
| 152 | + $content = 'expire = '. time() . "\n"; | |
| 153 | + file_put_contents( $file_path, $content ); // очищаем файл полностью | |
| 154 | + } | |
| 155 | + } | |
| 156 | + | |
| 157 | + | |
| 158 | + protected function wtsec_is_need_check(){ | |
| 159 | + | |
| 160 | + // работает только для POST запросов. | |
| 161 | + if( empty($_POST) ) | |
| 162 | + return false; | |
| 163 | + | |
| 164 | + $need_check = false; | |
| 165 | + $settings_value = self::_get('check_login_attempt'); | |
| 166 | + | |
| 167 | + // для страницы '/wp-login.php' | |
| 168 | + if( false !== strpos($_SERVER['REQUEST_URI'], '/wp-login.php') && $settings_value ) | |
| 169 | + $need_check = true; | |
| 170 | + | |
| 171 | + | |
| 172 | + return $need_check; | |
| 173 | + } | |
| 174 | + | |
| 175 | + protected function wtsec_get_ip( $soft = false ){ | |
| 176 | + | |
| 177 | + if( $soft ){ | |
| 178 | + $ip = isset($_SERVER['HTTP_CF_CONNECTING_IP']) ? $_SERVER['HTTP_CF_CONNECTING_IP'] : ''; // cloudflare IP support | |
| 179 | + if( ! filter_var($ip, FILTER_VALIDATE_IP) ) $ip = isset($_SERVER['HTTP_CLIENT_IP']) ? $_SERVER['HTTP_CLIENT_IP'] : ''; | |
| 180 | + if( ! filter_var($ip, FILTER_VALIDATE_IP) ) $ip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : ''; | |
| 181 | + if( ! filter_var($ip, FILTER_VALIDATE_IP) ) $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : ''; | |
| 182 | + } | |
| 183 | + else { | |
| 184 | + $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : ''; | |
| 185 | + } | |
| 186 | + | |
| 187 | + return $ip; | |
| 188 | + } | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 70 | 192 | } |