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