PluginProbe
Magic Login – Magic Link & Passwordless Authentication for WordPress – Login Without Password / trunk
Magic Login – Magic Link & Passwordless Authentication for WordPress – Login Without Password vtrunk
2.8.1 2.1 2.1.1 2.1.2 2.1.3 2.2 2.3 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.4 2.4.1 2.4.2 2.5 2.5.1 2.6 2.6.1 2.6.2 2.6.3 2.7 2.7.1 2.8 trunk All 48 releases
magic-login / includes / security.php

security.php in Magic Login – Magic Link & Passwordless Authentication for WordPress – Login Without Password trunk, at includes/security.php

110 lines 2.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Security functionality
4 *
5 * @package MagicLogin
6 */
7
8 namespace MagicLogin\Security;
9
10 use const MagicLogin\Constants\LOGIN_REQUEST_FAILSAFE_TRANSIENT_PREFIX;
11
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit; // Exit if accessed directly.
14 }
15
16 /**
17 * Default setup routine.
18 *
19 * @return void
20 */
21 function setup() {
22 add_filter( 'magic_login_pre_send_login_link', __NAMESPACE__ . '\\maybe_enforce_login_request_failsafe', 1, 2 );
23 add_action( 'magic_login_send_login_link', __NAMESPACE__ . '\\observe_login_request_failsafe', 10, 1 );
24 }
25
26 /**
27 * Apply a per-user failsafe for login emails.
28 *
29 * @param \WP_Error|null $result Current result.
30 * @param \WP_User|null $user User object.
31 *
32 * @return \WP_Error|null
33 */
34 function maybe_enforce_login_request_failsafe( $result, $user = null ) {
35 if ( ! is_null( $result ) ) {
36 return $result;
37 }
38
39 if ( ! is_a( $user, '\WP_User' ) ) {
40 return $result;
41 }
42
43 $limit = defined( 'MAGIC_LOGIN_REQUEST_FAILSAFE_LIMIT' ) ? absint( MAGIC_LOGIN_REQUEST_FAILSAFE_LIMIT ) : 60;
44 $limit = absint( apply_filters( 'magic_login_request_failsafe_limit', $limit, $user ) );
45
46 if ( $limit < 1 ) {
47 return $result;
48 }
49
50 $minute_time = (int) floor( time() / MINUTE_IN_SECONDS );
51 $transient_key = LOGIN_REQUEST_FAILSAFE_TRANSIENT_PREFIX . $user->ID;
52 $send_arr = get_site_transient( $transient_key );
53 $total_sent = 0;
54
55 if ( ! is_array( $send_arr ) ) {
56 $send_arr = [];
57 }
58
59 for ( $i = $minute_time; $i > $minute_time - 60; $i-- ) {
60 if ( isset( $send_arr[ $i ] ) ) {
61 $total_sent += absint( $send_arr[ $i ] );
62 }
63 }
64
65 if ( $total_sent >= $limit ) {
66 return new \WP_Error( 'magic_login_request_failsafe_block', esc_html__( 'We have already sent several login emails recently. Please check your inbox and spam folder before requesting another link.', 'magic-login' ) );
67 }
68
69 return $result;
70 }
71
72 /**
73 * Observe sent login emails for the per-user failsafe.
74 *
75 * @param \WP_User|null $user User object.
76 *
77 * @return void
78 */
79 function observe_login_request_failsafe( $user = null ) {
80 if ( ! is_a( $user, '\WP_User' ) ) {
81 return;
82 }
83
84 $limit = defined( 'MAGIC_LOGIN_REQUEST_FAILSAFE_LIMIT' ) ? absint( MAGIC_LOGIN_REQUEST_FAILSAFE_LIMIT ) : 60;
85 $limit = absint( apply_filters( 'magic_login_request_failsafe_limit', $limit, $user ) );
86
87 if ( $limit < 1 ) {
88 return;
89 }
90
91 $minute_time = (int) floor( time() / MINUTE_IN_SECONDS );
92 $transient_key = LOGIN_REQUEST_FAILSAFE_TRANSIENT_PREFIX . $user->ID;
93 $send_arr = get_site_transient( $transient_key );
94 $updated_send_arr = [];
95
96 if ( ! is_array( $send_arr ) ) {
97 $send_arr = [];
98 }
99
100 $send_arr[ $minute_time ] = isset( $send_arr[ $minute_time ] ) ? absint( $send_arr[ $minute_time ] ) + 1 : 1;
101
102 for ( $i = $minute_time; $i > $minute_time - 60; $i-- ) {
103 if ( isset( $send_arr[ $i ] ) ) {
104 $updated_send_arr[ $i ] = absint( $send_arr[ $i ] );
105 }
106 }
107
108 set_site_transient( $transient_key, $updated_send_arr, HOUR_IN_SECONDS );
109 }
110