PluginProbe ʕ •ᴥ•ʔ
CloudSecure WP Security / 1.2.2
CloudSecure WP Security v1.2.2
1.4.10 1.4.9 trunk 0.9.0 1.0.2 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.19 1.3.2 1.3.20 1.3.21 1.3.22 1.3.23 1.3.24 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8
cloudsecure-wp-security / modules / disable-login.php
cloudsecure-wp-security / modules Last commit date
admin 2 years ago lib 2 years ago captcha.php 2 years ago cloudsecure-wp.php 2 years ago common.php 2 years ago config.php 2 years ago disable-author-query.php 2 years ago disable-login.php 2 years ago disable-restapi.php 2 years ago disable-xmlrpc.php 2 years ago htaccess.php 2 years ago login-log.php 2 years ago login-notification.php 2 years ago rename-login-page.php 2 years ago restrict-admin-page.php 2 years ago server-error-notification.php 2 years ago two-factor-authentication.php 2 years ago unify-messages.php 2 years ago update-notice.php 2 years ago
disable-login.php
333 lines
1 <?php
2 class CloudSecureWP_Disable_Login extends CloudSecureWP_Common {
3 private const KEY_FEATURE = 'disable_login';
4 private const KEY_INTERVAL = self::KEY_FEATURE . '_interval';
5 private const KEY_LIMIT = self::KEY_FEATURE . '_limit';
6 private const KEY_DURATION = self::KEY_FEATURE . '_duration';
7 private const INTERVAL_VALUES = array( '5', '15', '30' ); // 秒 .
8 private const LIMIT_VALUES = array( '5', '15', '30' ); // 回 .
9 private const DURATION_VALUES = array( '60', '180', '300', '600', '3600' ); // 秒 .
10 private const LOGIN_EXPIRED_HOUR = 24;
11 private const TABLE_NAME = 'cloudsecurewp_login';
12 private const ERROR_CODE = 'cloudsecurewp_disable_login_error';
13 private $login_status = self::LOGIN_STATUS_FAILED;
14 private $config;
15
16 function __construct( array $info, CloudSecureWP_Config $config ) {
17 parent::__construct( $info );
18 $this->config = $config;
19 }
20
21 /**
22 * 機能毎のKEY取得
23 *
24 * @return string
25 */
26 public function get_feature_key(): string {
27 return self::KEY_FEATURE;
28 }
29
30 /**
31 * 有効無効判定
32 *
33 * @return bool
34 */
35 public function is_enabled(): bool {
36 return $this->config->get( $this->get_feature_key() ) === 't' ? true : false;
37 }
38
39 /**
40 * 初期設定値取得
41 *
42 * @return array
43 */
44 public function get_default(): array {
45 $ret = array(
46 self::KEY_FEATURE => $this->check_environment() ? 't' : 'f',
47 self::KEY_INTERVAL => self::INTERVAL_VALUES[0],
48 self::KEY_LIMIT => self::LIMIT_VALUES[0],
49 self::KEY_DURATION => self::DURATION_VALUES[0],
50 );
51 return $ret;
52 }
53
54 /**
55 * 設定値取得
56 */
57 public function get_settings(): array {
58 $settings = array();
59 $default = $this->get_default();
60
61 foreach ( $default as $key => $val ) {
62 $settings[ $key ] = $this->config->get( $key );
63 }
64
65 return $settings;
66 }
67
68 /**
69 * 設定値保存
70 *
71 * @param array $settings
72 * @return void
73 */
74 public function save_settings( $settings ): void {
75 $default = $this->get_default();
76
77 foreach ( $default as $key => $val ) {
78 $this->config->set( $key, $settings[ $key ] ?? '' );
79 }
80 $this->config->save();
81 }
82
83 /**
84 * 設定定義値取得
85 *
86 * @return array
87 */
88 public function get_constant_settings(): array {
89 $ret = array(
90 self::KEY_INTERVAL => self::INTERVAL_VALUES,
91 self::KEY_LIMIT => self::LIMIT_VALUES,
92 self::KEY_DURATION => self::DURATION_VALUES,
93 );
94 return $ret;
95 }
96
97 /**
98 * ステータス定義値取得
99 *
100 * @return array
101 */
102 public function get_constant_status(): array {
103 $ret = array(
104 self::LOGIN_STATUS_SUCCESS => 'ログイン成功',
105 self::LOGIN_STATUS_FAILED => 'ログイン失敗',
106 self::LOGIN_STATUS_DISABLED => '無効化',
107 );
108 return $ret;
109 }
110
111 /**
112 * ログイン成功ステータス取得
113 */
114 public function get_status_success(): int {
115 return self::LOGIN_STATUS_SUCCESS;
116 }
117
118 /**
119 * ログインステータス取得
120 */
121 public function get_login_status(): int {
122 return $this->login_status;
123 }
124
125 public function set_login_status( int $status ): void {
126 $this->login_status = $status;
127 }
128
129 /**
130 * テーブル名取得
131 *
132 * @return string
133 */
134 public function get_table_name(): string {
135 global $wpdb;
136 return $wpdb->prefix . self::TABLE_NAME;
137 }
138
139 /**
140 * テーブル作成
141 */
142 public function create_table(): void {
143 global $wpdb;
144 $table_name = $this->get_table_name();
145 $table = $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
146
147 if( is_null( $table ) ) {
148 $charset_collate = $wpdb->get_charset_collate();
149
150 $sql = "CREATE TABLE {$table_name} (
151 ip VARCHAR( 39 ) NOT NULL DEFAULT '',
152 status INT NOT NULL DEFAULT 0,
153 failed_count INT NOT NULL DEFAULT 0,
154 login_at DATETIME,
155 UNIQUE KEY index_ip ( ip )
156 ) {$charset_collate}";
157
158 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
159 dbDelta( $sql );
160 }
161 }
162
163 /**
164 * 期限切れログイン�
165 報削除
166 *
167 * @return void
168 */
169 public function remove_expired_login(): void {
170 global $wpdb;
171
172 $table_name = $this->get_table_name();
173 $expired_hour = self::LOGIN_EXPIRED_HOUR;
174 $sql = "DELETE FROM {$table_name} WHERE login_at < SYSDATE() - INTERVAL {$expired_hour} HOUR;";
175
176 $wpdb->query( $sql );
177 }
178
179 /**
180 * ipアドレスでログイン�
181 報取得
182 *
183 * @param string $ip
184 * @return array $row
185 */
186 public function get_row_by_ip( string $ip ): array {
187 global $wpdb;
188
189 $sql = $wpdb->prepare( "SELECT * from {$wpdb->prefix}cloudsecurewp_login WHERE ip = %s", $ip );
190 $row = $wpdb->get_row( $sql, ARRAY_A );
191
192 return $row ?? array();
193 }
194
195 /**
196 * ログインステータスが成功のレコード�
197 �件取得
198 *
199 * @return array $row
200 */
201 public function get_rows_status_success(): array {
202 global $wpdb;
203
204 $sql = $wpdb->prepare( "SELECT * from {$wpdb->prefix}cloudsecurewp_login WHERE status = %d", $this->get_status_success() );
205 $row = $wpdb->get_results( $sql, ARRAY_A );
206
207 return $row ?? array();
208 }
209
210 /**
211 * wp_login_failed
212 *
213 * @param string $user_name
214 * @return void
215 */
216 public function wp_login_failed( $user_name ): void {
217 global $wpdb;
218
219 $this->set_login_status( self::LOGIN_STATUS_FAILED );
220
221 $ip = $this->get_client_ip();
222 $now_datetime = current_time( 'mysql' );
223 $now_time = strtotime( $now_datetime );
224 $data = array(
225 'ip' => $ip,
226 'status' => self::LOGIN_STATUS_FAILED,
227 'failed_count' => 1,
228 'login_at' => $now_datetime,
229 );
230
231 $wpdb->query( 'START TRANSACTION' );
232 $this->remove_expired_login();
233 $row = $this->get_row_by_ip( $ip );
234
235 if ( empty( $row ) ) {
236 $wpdb->insert( $this->get_table_name(), $data );
237
238 } else {
239 $row['status'] = (int) $row['status'];
240 $row['failed_count'] = (int) $row['failed_count'];
241
242 $this->set_login_status( $row['status'] );
243
244 if ( self::LOGIN_STATUS_FAILED === $row['status'] ) {
245 $now_failed_count = $row['failed_count'] + 1;
246 $interval_time = strtotime( $row['login_at'] ) + (int) $this->config->get( self::KEY_INTERVAL );
247
248 if ( (int) $this->config->get( self::KEY_LIMIT ) <= $now_failed_count ) {
249 $data['status'] = self::LOGIN_STATUS_DISABLED;
250 $data['failed_count'] = $now_failed_count;
251
252 } elseif ( $now_time <= $interval_time ) {
253 $data['failed_count'] = $now_failed_count;
254 $data['login_at'] = $row['login_at'];
255 }
256 } elseif ( self::LOGIN_STATUS_DISABLED === $row['status'] ) {
257 $duration_time = strtotime( $row['login_at'] ) + (int) $this->config->get( self::KEY_DURATION );
258
259 if ( $now_time <= $duration_time ) {
260 $data['status'] = $row['status'];
261 $data['login_at'] = $row['login_at'];
262 }
263 }
264 $wpdb->update( $this->get_table_name(), $data, array( 'ip' => $ip ) );
265
266 }
267 $wpdb->query( 'COMMIT' );
268 }
269
270 /**
271 * エラーコード追加
272 */
273 public function shake_error_codes( $error_codes ) {
274 array_push( $error_codes, self::ERROR_CODE );
275 return $error_codes;
276 }
277
278 /**
279 * 認証
280 *
281 * @param $user
282 * @param string $user_name
283 * @param string $password
284 */
285 public function authenticate( $user, $user_name, $password ) {
286 if ( $this->is_disable() ) {
287 return new WP_Error( self::ERROR_CODE, 'ログイン失敗回数が上限に達したためログインが無効化されました。' );
288 }
289 return $user;
290 }
291
292 /**
293 * ログイン無効判定
294 *
295 * @return bool
296 */
297 public function is_disable(): bool {
298 $ip = $this->get_client_ip();
299 $row = $this->get_row_by_ip( $ip );
300
301 if ( ! empty( $row ) && self::LOGIN_STATUS_DISABLED === (int) $row['status'] ) {
302 $now_time = strtotime( current_time( 'mysql' ) );
303 $duration_time = strtotime( $row['login_at'] ) + (int) $this->config->get( self::KEY_DURATION );
304
305 if ( $now_time <= $duration_time ) {
306 return true;
307 }
308 }
309
310 return false;
311 }
312
313 /**
314 * 有効化
315 *
316 * @return void
317 */
318 public function activate(): void {
319 $this->save_settings( $this->get_default() );
320 $this->create_table();
321 }
322
323 /**
324 * 無効化
325 *
326 * @return void
327 */
328 public function deactivate(): void {
329 $this->config->set( $this->get_feature_key(), 'f' );
330 $this->config->save();
331 }
332 }
333