PluginProbe ʕ •ᴥ•ʔ
CloudSecure WP Security / 1.0.2
CloudSecure WP Security v1.0.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 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 unify-messages.php 2 years ago update-notice.php 2 years ago
disable-login.php
329 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' ); // 秒 .
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
145 $charset_collate = $wpdb->get_charset_collate();
146 $table_name = $this->get_table_name();
147
148 $sql = "CREATE TABLE IF NOT EXISTS {$table_name} ( ";
149 $sql .= " ip VARCHAR( 39 ) NOT NULL DEFAULT '', ";
150 $sql .= ' status INT NOT NULL DEFAULT 0, ';
151 $sql .= ' failed_count INT NOT NULL DEFAULT 0, ';
152 $sql .= ' login_at DATETIME, ';
153 $sql .= ' UNIQUE KEY index_ip ( ip ) ';
154 $sql .= " ) {$charset_collate};";
155
156 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
157 dbDelta( $sql );
158 }
159
160 /**
161 * 期限切れログイン�
162 報削除
163 *
164 * @return void
165 */
166 public function remove_expired_login(): void {
167 global $wpdb;
168
169 $expired_hour = self::LOGIN_EXPIRED_HOUR;
170 $sql = $wpdb->prepare( "DELETE FROM {$wpdb->prefix}cloudsecurewp_login WHERE login_at < SYSDATE() - INTERVAL %d HOUR", $expired_hour );
171
172 $wpdb->query( $sql );
173 }
174
175 /**
176 * ipアドレスでログイン�
177 報取得
178 *
179 * @param string $ip
180 * @return array $row
181 */
182 public function get_row_by_ip( string $ip ): array {
183 global $wpdb;
184
185 $sql = $wpdb->prepare( "SELECT * from {$wpdb->prefix}cloudsecurewp_login WHERE ip = %s", $ip );
186 $row = $wpdb->get_row( $sql, ARRAY_A );
187
188 return $row ?? array();
189 }
190
191 /**
192 * ログインステータスが成功のレコード�
193 �件取得
194 *
195 * @return array $row
196 */
197 public function get_rows_status_success(): array {
198 global $wpdb;
199
200 $sql = $wpdb->prepare( "SELECT * from {$wpdb->prefix}cloudsecurewp_login WHERE status = %d", $this->get_status_success() );
201 $row = $wpdb->get_results( $sql, ARRAY_A );
202
203 return $row ?? array();
204 }
205
206 /**
207 * wp_login_failed
208 *
209 * @param string $user_name
210 * @return void
211 */
212 public function wp_login_failed( $user_name ): void {
213 global $wpdb;
214
215 $this->set_login_status( self::LOGIN_STATUS_FAILED );
216
217 $ip = $this->get_client_ip();
218 $now_datetime = current_time( 'mysql' );
219 $now_time = strtotime( $now_datetime );
220 $data = array(
221 'ip' => $ip,
222 'status' => self::LOGIN_STATUS_FAILED,
223 'failed_count' => 1,
224 'login_at' => $now_datetime,
225 );
226
227 $wpdb->query( 'START TRANSACTION' );
228 $this->remove_expired_login();
229 $row = $this->get_row_by_ip( $ip );
230
231 if ( empty( $row ) ) {
232 $wpdb->insert( $this->get_table_name(), $data );
233
234 } else {
235 $row['status'] = (int) $row['status'];
236 $row['failed_count'] = (int) $row['failed_count'];
237
238 $this->set_login_status( $row['status'] );
239
240 if ( self::LOGIN_STATUS_FAILED === $row['status'] ) {
241 $now_failed_count = $row['failed_count'] + 1;
242 $interval_time = strtotime( $row['login_at'] ) + (int) $this->config->get( self::KEY_INTERVAL );
243
244 if ( (int) $this->config->get( self::KEY_LIMIT ) <= $now_failed_count ) {
245 $data['status'] = self::LOGIN_STATUS_DISABLED;
246 $data['failed_count'] = $now_failed_count;
247
248 } elseif ( $now_time <= $interval_time ) {
249 $data['failed_count'] = $now_failed_count;
250 $data['login_at'] = $row['login_at'];
251 }
252 } elseif ( self::LOGIN_STATUS_DISABLED === $row['status'] ) {
253 $duration_time = strtotime( $row['login_at'] ) + (int) $this->config->get( self::KEY_DURATION );
254
255 if ( $now_time <= $duration_time ) {
256 $data['status'] = $row['status'];
257 $data['login_at'] = $row['login_at'];
258 }
259 }
260 $wpdb->update( $this->get_table_name(), $data, array( 'ip' => $ip ) );
261
262 }
263 $wpdb->query( 'COMMIT' );
264 }
265
266 /**
267 * エラーコード追加
268 */
269 public function shake_error_codes( $error_codes ) {
270 array_push( $error_codes, self::ERROR_CODE );
271 return $error_codes;
272 }
273
274 /**
275 * 認証
276 *
277 * @param $user
278 * @param string $user_name
279 * @param string $password
280 */
281 public function authenticate( $user, $user_name, $password ) {
282 if ( $this->is_disable() ) {
283 return new WP_Error( self::ERROR_CODE, 'ログイン失敗回数が上限に達したためログインが無効化されました。' );
284 }
285 return $user;
286 }
287
288 /**
289 * ログイン無効判定
290 *
291 * @return bool
292 */
293 public function is_disable(): bool {
294 $ip = $this->get_client_ip();
295 $row = $this->get_row_by_ip( $ip );
296
297 if ( ! empty( $row ) && self::LOGIN_STATUS_DISABLED === (int) $row['status'] ) {
298 $now_time = strtotime( current_time( 'mysql' ) );
299 $duration_time = strtotime( $row['login_at'] ) + (int) $this->config->get( self::KEY_DURATION );
300
301 if ( $now_time <= $duration_time ) {
302 return true;
303 }
304 }
305
306 return false;
307 }
308
309 /**
310 * 有効化
311 *
312 * @return void
313 */
314 public function activate(): void {
315 $this->save_settings( $this->get_default() );
316 $this->create_table();
317 }
318
319 /**
320 * 無効化
321 *
322 * @return void
323 */
324 public function deactivate(): void {
325 $this->config->set( $this->get_feature_key(), 'f' );
326 $this->config->save();
327 }
328 }
329