PluginProbe ʕ •ᴥ•ʔ
CloudSecure WP Security / 1.4.9
CloudSecure WP Security v1.4.9
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 / login-log.php
cloudsecure-wp-security / modules Last commit date
admin 1 month ago cli 2 months ago lib 3 months ago captcha.php 3 months ago cloudsecure-wp.php 1 month ago common.php 2 months ago config.php 2 years ago disable-access-system-file.php 4 months ago disable-author-query.php 2 years ago disable-login.php 2 months ago disable-restapi.php 2 months ago disable-xmlrpc.php 1 year ago htaccess.php 3 months ago login-log.php 2 months ago login-notification.php 1 year ago rename-login-page.php 3 months ago restrict-admin-page.php 3 months ago server-error-notification.php 2 months ago two-factor-authentication.php 1 month ago unify-messages.php 2 years ago update-notice.php 7 months ago waf-engine.php 1 month ago waf.php 1 month ago
login-log.php
289 lines
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit;
5 }
6
7 class CloudSecureWP_Login_Log extends CloudSecureWP_Common {
8 private const KEY_FEATURE = 'login_log';
9 private const KEY_CONDITIONS = self::KEY_FEATURE . '_conditions';
10 private const TABLE_NAME = 'cloudsecurewp_' . self::KEY_FEATURE;
11 private const COLUMN_ID = 'id';
12 private const COLUMN_NAME = 'name';
13 private const COLUMN_IP = 'ip';
14 private const COLUMN_STATUS = 'status';
15 private const COLUMN_METHOD = 'method';
16 private const COLUMN_LOGIN_AT = 'login_at';
17 private const COLUMNS = array(
18 self::COLUMN_ID => 'ID',
19 self::COLUMN_NAME => 'ユーザー名',
20 self::COLUMN_IP => 'IPアドレス',
21 self::COLUMN_STATUS => 'ログイン判定',
22 self::COLUMN_METHOD => 'ログイン種別',
23 self::COLUMN_LOGIN_AT => '日時',
24 );
25
26 private const MAX_LOG = 10000;
27 private $config;
28 private $disable_login;
29
30 function __construct( array $info, CloudSecureWP_Config $config, CloudSecureWP_Disable_Login $disable_login ) {
31 parent::__construct( $info );
32 $this->config = $config;
33 $this->disable_login = $disable_login;
34 }
35
36 /**
37 * 機能毎のKEY取得
38 *
39 * @return string
40 */
41 public function get_feature_key(): string {
42 return self::KEY_FEATURE;
43 }
44
45 /**
46 * テーブル名取得
47 *
48 * @return string
49 */
50 public function get_table_name(): string {
51 global $wpdb;
52 return $wpdb->prefix . self::TABLE_NAME;
53 }
54
55 /**
56 * LoginLogテーブルカラム�
57 報取得
58 */
59 public function get_cloumns(): array {
60 return self::COLUMNS;
61 }
62
63 /**
64 * ログイン種別取得
65 */
66 public function get_methods(): array {
67 return self::METHODS;
68 }
69
70 /**
71 * Xmlrpc判定
72 *
73 * @return bool
74 */
75 public function is_xmlrpc(): bool {
76 if ( 'xmlrpc.php' === basename( sanitize_text_field( $_SERVER['SCRIPT_NAME'] ) ) ) {
77 return true;
78 }
79 return false;
80 }
81
82 /**
83 * ログインログ登録
84 *
85 * @param string $name
86 * @param string $ip
87 * @param int $status
88 * @param int $method
89 * @return void
90 */
91 public function write_log( string $name, string $ip, int $status, int $method ): void {
92 global $wpdb;
93 $table_name = $wpdb->prefix . self::TABLE_NAME;
94 $max_log = self::MAX_LOG;
95
96 $data = array(
97 'name' => $name,
98 'ip' => $ip,
99 'status' => $status,
100 'method' => $method,
101 'login_at' => current_time( 'mysql' ),
102 );
103
104 try {
105 $wpdb->query( 'START TRANSACTION' );
106
107 $result = $wpdb->insert( $table_name, $data );
108 if ( $result === false || ! empty( $wpdb->last_error ) ) {
109 throw new Exception( 'Failed to insert login log.' );
110 }
111
112 $row = $wpdb->get_row( $wpdb->prepare( "SELECT id FROM {$wpdb->prefix}cloudsecurewp_login_log ORDER BY id DESC LIMIT 1 OFFSET %d", $max_log ), ARRAY_A );
113
114 if ( ! empty( $row ?? array() ) ) {
115 $result = $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}cloudsecurewp_login_log WHERE id <= %d", $row['id'] ) );
116 if ( $result === false || ! empty( $wpdb->last_error ) ) {
117 throw new Exception( 'Failed to delete old login logs.' );
118 }
119 }
120
121 $wpdb->query( 'COMMIT' );
122 } catch ( Exception $e ) {
123 $wpdb->query( 'ROLLBACK' );
124 }
125 }
126
127 /**
128 * ログインページログイン成功時
129 */
130 public function wp_login( $user_login ) {
131
132 global $wpdb;
133 $ip = $this->get_client_ip();
134
135 $this->disable_login->remove_expired_login();
136
137 $data = array(
138 'ip' => $ip,
139 'status' => $this->disable_login->get_status_success(),
140 'failed_count' => 0,
141 'login_at' => current_time( 'mysql' ),
142 );
143
144 $row = $this->disable_login->get_row_by_ip( $ip );
145 if ( empty( $row ) ) {
146 $wpdb->insert( $this->disable_login->get_table_name(), $data );
147 } else {
148 $wpdb->update( $this->disable_login->get_table_name(), $data, array( 'ip' => $ip ) );
149 }
150
151 $this->write_log( $user_login, $ip, self::LOGIN_STATUS_SUCCESS, self::METHOD_PAGE );
152 }
153
154 /**
155 * XML-RPCログイン成功時
156 */
157 public function xmlrpc_call() {
158 $user = wp_get_current_user();
159
160 if ( empty( $user->ID ) ) {
161 return;
162 }
163
164 $user_login = $user->user_login;
165 $ip = $this->get_client_ip();
166 $this->write_log( $user_login, $ip, self::LOGIN_STATUS_SUCCESS, self::METHOD_XMLRPC );
167 }
168
169 /**
170 * ログイン失敗時
171 */
172 public function wp_login_failed( $user_login, $error = null ) {
173 $ip = $this->get_client_ip();
174
175 if ( is_wp_error( $error ) && $error->get_error_code() === 'xmlrpc_login_denied' ) {
176 $status = self::LOGIN_STATUS_DISABLED;
177 } else {
178 $status = $this->disable_login->get_login_status();
179 }
180
181 $method = $this->is_xmlrpc() ? self::METHOD_XMLRPC : self::METHOD_PAGE;
182 $this->write_log( $user_login, $ip, $status, $method );
183 }
184
185 /**
186 * ログインログ取得
187 *
188 * @param array $conditions
189 * @return array
190 */
191 public function get_login_history( array $conditions ): array {
192 global $wpdb;
193 $table_name = $wpdb->prefix . self::TABLE_NAME;
194 $prepare = array();
195
196 $sql = 'SELECT ';
197 $sql .= '* ';
198 $sql .= "FROM {$table_name} ";
199 $sql .= 'WHERE %d ';
200
201 $prepare[] = 1;
202
203 if ( ! empty( $conditions['condition_status'] ?? '' ) ) {
204 $sql .= 'AND status = %d ';
205 $prepare[] = (int) $conditions['condition_status'];
206 }
207
208 if ( ! empty( $conditions['condition_method'] ?? '' ) ) {
209 $sql .= 'AND method = %d ';
210 $prepare[] = (int) $conditions['condition_method'];
211 }
212
213 if ( ! empty( $conditions['condition_ip'] ?? '' ) ) {
214 if ( ! empty( $conditions['condition_ip_other_than'] ?? '' ) && 't' === $conditions['condition_ip_other_than'] ) {
215 $sql .= 'AND ip <> %s ';
216 } else {
217 $sql .= 'AND ip = %s ';
218 }
219 $prepare[] = $conditions['condition_ip'];
220 }
221
222 if ( ! empty( $conditions['condition_name'] ?? '' ) ) {
223 if ( ! empty( $conditions['condition_name_other_than'] ?? '' ) && 't' === $conditions['condition_name_other_than'] ) {
224 $sql .= 'AND `name` <> %s ';
225 } else {
226 $sql .= 'AND `name` = %s ';
227 }
228 $prepare[] = $conditions['condition_name'];
229 }
230
231 array_unshift( $prepare, $sql );
232 $rows = $wpdb->get_results( call_user_func_array( array( $wpdb, 'prepare' ), $prepare ), ARRAY_A );
233
234 return $rows ?? array();
235 }
236
237 /**
238 * 絞込み条件保存
239 *
240 * @param array $conditions
241 * @return void
242 */
243 public function save_conditions( $conditions ): void {
244 $this->config->set( self::KEY_CONDITIONS, $conditions );
245 $this->config->save();
246 }
247
248 /**
249 * 絞込み条件取得
250 *
251 * @return array $conditions
252 */
253 public function get_conditions(): array {
254 $conditions = $this->config->get( self::KEY_CONDITIONS ) ?? '';
255 if ( ! empty( $conditions ) ) {
256 return $conditions;
257 }
258 return array();
259 }
260
261 /**
262 * 有効化
263 *
264 * @return void
265 */
266 public function activate(): void {
267 global $wpdb;
268 $table_name = $this->get_table_name();
269 $table = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table_name ) ) );
270
271 if ( is_null( $table ) ) {
272 $charset_collate = $wpdb->get_charset_collate();
273
274 $sql = "CREATE TABLE {$table_name} (
275 id BIGINT( 20 ) UNSIGNED NOT NULL AUTO_INCREMENT,
276 name VARCHAR( 60 ) NOT NULL DEFAULT '',
277 ip VARCHAR( 39 ) NOT NULL DEFAULT '',
278 status INT NOT NULL DEFAULT 0,
279 method INT NOT NULL DEFAULT 0,
280 login_at DATETIME,
281 UNIQUE KEY id ( id )
282 ) {$charset_collate}";
283
284 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
285 dbDelta( $sql );
286 }
287 }
288 }
289