Version Description
Download this release
Release Info
Developer | paultgoodchild |
Plugin | Shield Security for WordPress |
Version | 16.1.3 |
Comparing to | |
See all releases |
Code changes from version 16.1.2 to 16.1.3
- cl.json +22 -0
- config/deprecated/data.php +1 -1
- config/deprecated/login_protect.php +18 -11
- config/login_protect.json +18 -11
- icwp-wpsf.php +2 -2
- plugin-spec.php +5 -5
- plugin.json +5 -5
- readme.txt +2 -2
- resources/css/plugin.css +1 -1
- resources/js/shield/login2fa.js +2 -4
- src/lib/src/Modules/Base/Strings.php +8 -2
- src/lib/src/Modules/Base/UI.php +1 -0
- src/lib/src/Modules/IPs/DB/IpRules/MergeAutoBlockRules.php +0 -6
- src/lib/src/Modules/IPs/Lib/CrowdSec/Api/DecisionsDownload.php +0 -5
- src/lib/src/Modules/IPs/UI.php +1 -1
- src/lib/src/Modules/LoginGuard/AjaxHandler.php +9 -10
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/{NoLoginIntentForUserException.php → InvalidLoginIntentException.php} +1 -1
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentRequestCapture.php +33 -34
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentRequestValidate.php +11 -18
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginRequestCapture.php +6 -6
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php +26 -3
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BackupCodes.php +1 -1
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php +9 -3
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php +44 -31
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/GoogleAuth.php +2 -2
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Sms.php +1 -1
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/U2F.php +1 -1
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Yubikey.php +1 -1
- src/lib/src/Modules/LoginGuard/Strings.php +17 -11
- src/lib/vendor/composer/autoload_classmap.php +1 -1
- src/lib/vendor/composer/autoload_static.php +1 -1
- src/lib/vendor/composer/installed.json +6 -6
- src/lib/vendor/composer/installed.php +9 -9
- src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/IpUtils.php +5 -3
- templates/twig/wpadmin_pages/base.twig +1 -2
- templates/twig/wpadmin_pages/components/page/nav_sidebar.twig +10 -1
cl.json
CHANGED
@@ -127,6 +127,28 @@
|
|
127 |
}
|
128 |
],
|
129 |
"patches": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
{
|
131 |
"version": "2",
|
132 |
"released_at": 1662985000,
|
127 |
}
|
128 |
],
|
129 |
"patches": [
|
130 |
+
{
|
131 |
+
"version": "3",
|
132 |
+
"released_at": 1663061215,
|
133 |
+
"items": [
|
134 |
+
{
|
135 |
+
"title": "Security fix for reported 2FA vulnerability. More info will be released after allowing time for client upgrades.",
|
136 |
+
"type": "fixed",
|
137 |
+
"description": [
|
138 |
+
"Note: sites are only vulnerable to this particular exploit IF it has an SQL-injection vulnerability caused by another plugin/theme.",
|
139 |
+
"As we always say, please ensure you keep ALL your plugins, themes and WordPress core up-to-date, particularly if they have known vulnerabilities!"
|
140 |
+
]
|
141 |
+
},
|
142 |
+
{
|
143 |
+
"title": "Reverted minimum WP version to 3.7 to allow for security patching.",
|
144 |
+
"type": "changes"
|
145 |
+
},
|
146 |
+
{
|
147 |
+
"title": "Bug: an error was generated when assessing some IP addresses.",
|
148 |
+
"type": "fixed"
|
149 |
+
}
|
150 |
+
]
|
151 |
+
},
|
152 |
{
|
153 |
"version": "2",
|
154 |
"released_at": 1662985000,
|
config/deprecated/data.php
CHANGED
@@ -54,7 +54,7 @@
|
|
54 |
"has_deleted_at": false,
|
55 |
"cols_custom": {
|
56 |
"req_id": {
|
57 |
-
"macro_type": "
|
58 |
"length": 10,
|
59 |
"attr": [
|
60 |
"UNIQUE"
|
54 |
"has_deleted_at": false,
|
55 |
"cols_custom": {
|
56 |
"req_id": {
|
57 |
+
"macro_type": "varchar",
|
58 |
"length": 10,
|
59 |
"attr": [
|
60 |
"UNIQUE"
|
config/deprecated/login_protect.php
CHANGED
@@ -536,14 +536,14 @@
|
|
536 |
"login_intent_timeout": 5,
|
537 |
"login_intent_max_attempts": 5,
|
538 |
"events": {
|
539 |
-
"2fa_verify_success":
|
540 |
"audit_params": [
|
541 |
"user_login",
|
542 |
"method"
|
543 |
],
|
544 |
"level": "notice"
|
545 |
},
|
546 |
-
"2fa_verify_fail":
|
547 |
"audit_params": [
|
548 |
"user_login",
|
549 |
"method"
|
@@ -551,18 +551,25 @@
|
|
551 |
"level": "warning",
|
552 |
"offense": true
|
553 |
},
|
554 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
555 |
"level": "warning",
|
556 |
"offense": true
|
557 |
},
|
558 |
-
"honeypot_fail":
|
559 |
"audit_params": [
|
560 |
"user_login",
|
561 |
"action"
|
562 |
],
|
563 |
"level": "warning"
|
564 |
},
|
565 |
-
"botbox_fail":
|
566 |
"audit_params": [
|
567 |
"user_login",
|
568 |
"action"
|
@@ -570,22 +577,22 @@
|
|
570 |
"level": "warning",
|
571 |
"offense": true
|
572 |
},
|
573 |
-
"login_block":
|
574 |
"level": "warning"
|
575 |
},
|
576 |
-
"block_register":
|
577 |
"level": "warning"
|
578 |
},
|
579 |
-
"block_lostpassword":
|
580 |
"level": "warning"
|
581 |
},
|
582 |
-
"block_checkout":
|
583 |
"level": "warning"
|
584 |
},
|
585 |
-
"hide_login_url":
|
586 |
"level": "notice"
|
587 |
},
|
588 |
-
"2fa_success":
|
589 |
"level": "info",
|
590 |
"recent": true
|
591 |
}
|
536 |
"login_intent_timeout": 5,
|
537 |
"login_intent_max_attempts": 5,
|
538 |
"events": {
|
539 |
+
"2fa_verify_success": {
|
540 |
"audit_params": [
|
541 |
"user_login",
|
542 |
"method"
|
543 |
],
|
544 |
"level": "notice"
|
545 |
},
|
546 |
+
"2fa_verify_fail": {
|
547 |
"audit_params": [
|
548 |
"user_login",
|
549 |
"method"
|
551 |
"level": "warning",
|
552 |
"offense": true
|
553 |
},
|
554 |
+
"2fa_nonce_verify_fail": {
|
555 |
+
"audit_params": [
|
556 |
+
"user_login"
|
557 |
+
],
|
558 |
+
"level": "alert",
|
559 |
+
"offense": true
|
560 |
+
},
|
561 |
+
"cooldown_fail": {
|
562 |
"level": "warning",
|
563 |
"offense": true
|
564 |
},
|
565 |
+
"honeypot_fail": {
|
566 |
"audit_params": [
|
567 |
"user_login",
|
568 |
"action"
|
569 |
],
|
570 |
"level": "warning"
|
571 |
},
|
572 |
+
"botbox_fail": {
|
573 |
"audit_params": [
|
574 |
"user_login",
|
575 |
"action"
|
577 |
"level": "warning",
|
578 |
"offense": true
|
579 |
},
|
580 |
+
"login_block": {
|
581 |
"level": "warning"
|
582 |
},
|
583 |
+
"block_register": {
|
584 |
"level": "warning"
|
585 |
},
|
586 |
+
"block_lostpassword": {
|
587 |
"level": "warning"
|
588 |
},
|
589 |
+
"block_checkout": {
|
590 |
"level": "warning"
|
591 |
},
|
592 |
+
"hide_login_url": {
|
593 |
"level": "notice"
|
594 |
},
|
595 |
+
"2fa_success": {
|
596 |
"level": "info",
|
597 |
"recent": true
|
598 |
}
|
config/login_protect.json
CHANGED
@@ -536,14 +536,14 @@
|
|
536 |
"login_intent_timeout": 5,
|
537 |
"login_intent_max_attempts": 5,
|
538 |
"events": {
|
539 |
-
"2fa_verify_success":
|
540 |
"audit_params": [
|
541 |
"user_login",
|
542 |
"method"
|
543 |
],
|
544 |
"level": "notice"
|
545 |
},
|
546 |
-
"2fa_verify_fail":
|
547 |
"audit_params": [
|
548 |
"user_login",
|
549 |
"method"
|
@@ -551,18 +551,25 @@
|
|
551 |
"level": "warning",
|
552 |
"offense": true
|
553 |
},
|
554 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
555 |
"level": "warning",
|
556 |
"offense": true
|
557 |
},
|
558 |
-
"honeypot_fail":
|
559 |
"audit_params": [
|
560 |
"user_login",
|
561 |
"action"
|
562 |
],
|
563 |
"level": "warning"
|
564 |
},
|
565 |
-
"botbox_fail":
|
566 |
"audit_params": [
|
567 |
"user_login",
|
568 |
"action"
|
@@ -570,22 +577,22 @@
|
|
570 |
"level": "warning",
|
571 |
"offense": true
|
572 |
},
|
573 |
-
"login_block":
|
574 |
"level": "warning"
|
575 |
},
|
576 |
-
"block_register":
|
577 |
"level": "warning"
|
578 |
},
|
579 |
-
"block_lostpassword":
|
580 |
"level": "warning"
|
581 |
},
|
582 |
-
"block_checkout":
|
583 |
"level": "warning"
|
584 |
},
|
585 |
-
"hide_login_url":
|
586 |
"level": "notice"
|
587 |
},
|
588 |
-
"2fa_success":
|
589 |
"level": "info",
|
590 |
"recent": true
|
591 |
}
|
536 |
"login_intent_timeout": 5,
|
537 |
"login_intent_max_attempts": 5,
|
538 |
"events": {
|
539 |
+
"2fa_verify_success": {
|
540 |
"audit_params": [
|
541 |
"user_login",
|
542 |
"method"
|
543 |
],
|
544 |
"level": "notice"
|
545 |
},
|
546 |
+
"2fa_verify_fail": {
|
547 |
"audit_params": [
|
548 |
"user_login",
|
549 |
"method"
|
551 |
"level": "warning",
|
552 |
"offense": true
|
553 |
},
|
554 |
+
"2fa_nonce_verify_fail": {
|
555 |
+
"audit_params": [
|
556 |
+
"user_login"
|
557 |
+
],
|
558 |
+
"level": "alert",
|
559 |
+
"offense": true
|
560 |
+
},
|
561 |
+
"cooldown_fail": {
|
562 |
"level": "warning",
|
563 |
"offense": true
|
564 |
},
|
565 |
+
"honeypot_fail": {
|
566 |
"audit_params": [
|
567 |
"user_login",
|
568 |
"action"
|
569 |
],
|
570 |
"level": "warning"
|
571 |
},
|
572 |
+
"botbox_fail": {
|
573 |
"audit_params": [
|
574 |
"user_login",
|
575 |
"action"
|
577 |
"level": "warning",
|
578 |
"offense": true
|
579 |
},
|
580 |
+
"login_block": {
|
581 |
"level": "warning"
|
582 |
},
|
583 |
+
"block_register": {
|
584 |
"level": "warning"
|
585 |
},
|
586 |
+
"block_lostpassword": {
|
587 |
"level": "warning"
|
588 |
},
|
589 |
+
"block_checkout": {
|
590 |
"level": "warning"
|
591 |
},
|
592 |
+
"hide_login_url": {
|
593 |
"level": "notice"
|
594 |
},
|
595 |
+
"2fa_success": {
|
596 |
"level": "info",
|
597 |
"recent": true
|
598 |
}
|
icwp-wpsf.php
CHANGED
@@ -3,12 +3,12 @@
|
|
3 |
* Plugin Name: Shield Security
|
4 |
* Plugin URI: https://shsec.io/2f
|
5 |
* Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
|
6 |
-
* Version: 16.1.
|
7 |
* Text Domain: wp-simple-firewall
|
8 |
* Domain Path: /languages
|
9 |
* Author: Shield Security
|
10 |
* Author URI: https://shsec.io/bv
|
11 |
-
* Requires at least:
|
12 |
* Requires PHP: 7.0
|
13 |
*/
|
14 |
|
3 |
* Plugin Name: Shield Security
|
4 |
* Plugin URI: https://shsec.io/2f
|
5 |
* Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
|
6 |
+
* Version: 16.1.3
|
7 |
* Text Domain: wp-simple-firewall
|
8 |
* Domain Path: /languages
|
9 |
* Author: Shield Security
|
10 |
* Author URI: https://shsec.io/bv
|
11 |
+
* Requires at least: 3.7
|
12 |
* Requires PHP: 7.0
|
13 |
*/
|
14 |
|
plugin-spec.php
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
{
|
2 |
"properties": {
|
3 |
-
"version": "16.1.
|
4 |
-
"release_timestamp":
|
5 |
-
"build": "202209.
|
6 |
"slug_parent": "icwp",
|
7 |
"slug_plugin": "wpsf",
|
8 |
"text_domain": "wp-simple-firewall",
|
@@ -18,7 +18,7 @@
|
|
18 |
},
|
19 |
"requirements": {
|
20 |
"php": "7.0",
|
21 |
-
"wordpress": "
|
22 |
"mysql": "5.6"
|
23 |
},
|
24 |
"reqs_rest": {
|
@@ -36,7 +36,7 @@
|
|
36 |
"wp": "3.7",
|
37 |
"mysql": "5.6"
|
38 |
},
|
39 |
-
"16.
|
40 |
"php": "7.0",
|
41 |
"wp": "4.7",
|
42 |
"mysql": "5.6"
|
1 |
{
|
2 |
"properties": {
|
3 |
+
"version": "16.1.3",
|
4 |
+
"release_timestamp": 1663061215,
|
5 |
+
"build": "202209.1301",
|
6 |
"slug_parent": "icwp",
|
7 |
"slug_plugin": "wpsf",
|
8 |
"text_domain": "wp-simple-firewall",
|
18 |
},
|
19 |
"requirements": {
|
20 |
"php": "7.0",
|
21 |
+
"wordpress": "3.7",
|
22 |
"mysql": "5.6"
|
23 |
},
|
24 |
"reqs_rest": {
|
36 |
"wp": "3.7",
|
37 |
"mysql": "5.6"
|
38 |
},
|
39 |
+
"16.2": {
|
40 |
"php": "7.0",
|
41 |
"wp": "4.7",
|
42 |
"mysql": "5.6"
|
plugin.json
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
{
|
2 |
"properties": {
|
3 |
-
"version": "16.1.
|
4 |
-
"release_timestamp":
|
5 |
-
"build": "202209.
|
6 |
"slug_parent": "icwp",
|
7 |
"slug_plugin": "wpsf",
|
8 |
"text_domain": "wp-simple-firewall",
|
@@ -18,7 +18,7 @@
|
|
18 |
},
|
19 |
"requirements": {
|
20 |
"php": "7.0",
|
21 |
-
"wordpress": "
|
22 |
"mysql": "5.6"
|
23 |
},
|
24 |
"reqs_rest": {
|
@@ -36,7 +36,7 @@
|
|
36 |
"wp": "3.7",
|
37 |
"mysql": "5.6"
|
38 |
},
|
39 |
-
"16.
|
40 |
"php": "7.0",
|
41 |
"wp": "4.7",
|
42 |
"mysql": "5.6"
|
1 |
{
|
2 |
"properties": {
|
3 |
+
"version": "16.1.3",
|
4 |
+
"release_timestamp": 1663061215,
|
5 |
+
"build": "202209.1301",
|
6 |
"slug_parent": "icwp",
|
7 |
"slug_plugin": "wpsf",
|
8 |
"text_domain": "wp-simple-firewall",
|
18 |
},
|
19 |
"requirements": {
|
20 |
"php": "7.0",
|
21 |
+
"wordpress": "3.7",
|
22 |
"mysql": "5.6"
|
23 |
},
|
24 |
"reqs_rest": {
|
36 |
"wp": "3.7",
|
37 |
"mysql": "5.6"
|
38 |
},
|
39 |
+
"16.2": {
|
40 |
"php": "7.0",
|
41 |
"wp": "4.7",
|
42 |
"mysql": "5.6"
|
readme.txt
CHANGED
@@ -4,11 +4,11 @@ Donate link: https://shsec.io/bw
|
|
4 |
License: GPLv3
|
5 |
License URI: http://www.gnu.org/licenses/gpl.html
|
6 |
Tags: limit login, malware scan, firewall, two factor authentication, login protection
|
7 |
-
Requires at least:
|
8 |
Requires PHP: 7.0
|
9 |
Recommended PHP: 7.4
|
10 |
Tested up to: 6.0
|
11 |
-
Stable tag: 16.1.
|
12 |
|
13 |
Bad Bots Are Your #1 Security Risk. Stop playing whack-a-mole with malware and vulnerabilities. Discover the advantage of putting real security before marketing.
|
14 |
|
4 |
License: GPLv3
|
5 |
License URI: http://www.gnu.org/licenses/gpl.html
|
6 |
Tags: limit login, malware scan, firewall, two factor authentication, login protection
|
7 |
+
Requires at least: 3.7
|
8 |
Requires PHP: 7.0
|
9 |
Recommended PHP: 7.4
|
10 |
Tested up to: 6.0
|
11 |
+
Stable tag: 16.1.3
|
12 |
|
13 |
Bad Bots Are Your #1 Security Risk. Stop playing whack-a-mole with malware and vulnerabilities. Discover the advantage of putting real security before marketing.
|
14 |
|
resources/css/plugin.css
CHANGED
@@ -547,7 +547,7 @@ a:focus .gravatar, a:focus, a:focus .media-icon img {
|
|
547 |
.table-success, .table-success > td, .table-success > th {
|
548 |
background-color: rgba(0, 128, 0, 0.20);
|
549 |
}
|
550 |
-
a[target="_blank"]:not(.option_link_info):not(.card-link):not(.table-link):not(.meter-analysis-link):not(.page-header-item)::after {
|
551 |
content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAQElEQVR42qXKwQkAIAxDUUdxtO6/RBQkQZvSi8I/pL4BoGw/XPkh4XigPmsUgh0626AjRsgxHTkUThsG2T/sIlzdTsp52kSS1wAAAABJRU5ErkJggg==);
|
552 |
margin: 0 3px;
|
553 |
}
|
547 |
.table-success, .table-success > td, .table-success > th {
|
548 |
background-color: rgba(0, 128, 0, 0.20);
|
549 |
}
|
550 |
+
a[target="_blank"]:not(.shield-footer-version):not(.option_link_info):not(.card-link):not(.table-link):not(.meter-analysis-link):not(.page-header-item)::after {
|
551 |
content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAQElEQVR42qXKwQkAIAxDUUdxtO6/RBQkQZvSi8I/pL4BoGw/XPkh4XigPmsUgh0626AjRsgxHTkUThsG2T/sIlzdTsp52kSS1wAAAABJRU5ErkJggg==);
|
552 |
margin: 0 3px;
|
553 |
}
|
resources/js/shield/login2fa.js
CHANGED
@@ -2,8 +2,6 @@ jQuery( document ).ready( function () {
|
|
2 |
|
3 |
let $body = jQuery( 'body' );
|
4 |
let $theForm = jQuery( 'form#loginform' );
|
5 |
-
let userID = jQuery( 'input[type=hidden]#wp_user_id' ).val();
|
6 |
-
let loginNonce = jQuery( 'input[type=hidden]#login_nonce' ).val();
|
7 |
let $u2fStart = jQuery( 'input#btn_u2f_start' );
|
8 |
|
9 |
jQuery( 'input[type=text]:first', $theForm ).focus();
|
@@ -57,8 +55,8 @@ jQuery( document ).ready( function () {
|
|
57 |
$this.attr( 'disabled', true );
|
58 |
|
59 |
let reqParams = $emailInput.data( 'ajax_intent_email_send' );
|
60 |
-
reqParams.wp_user_id =
|
61 |
-
reqParams.login_nonce =
|
62 |
$body.addClass( 'shield-busy' );
|
63 |
jQuery.post( reqParams.ajaxurl, reqParams, function ( response ) {
|
64 |
let msg = 'Communications error with site.';
|
2 |
|
3 |
let $body = jQuery( 'body' );
|
4 |
let $theForm = jQuery( 'form#loginform' );
|
|
|
|
|
5 |
let $u2fStart = jQuery( 'input#btn_u2f_start' );
|
6 |
|
7 |
jQuery( 'input[type=text]:first', $theForm ).focus();
|
55 |
$this.attr( 'disabled', true );
|
56 |
|
57 |
let reqParams = $emailInput.data( 'ajax_intent_email_send' );
|
58 |
+
reqParams.wp_user_id = jQuery( 'input[type=hidden]#wp_user_id' ).val();
|
59 |
+
reqParams.login_nonce = jQuery( 'input[type=hidden]#login_nonce' ).val();
|
60 |
$body.addClass( 'shield-busy' );
|
61 |
jQuery.post( reqParams.ajaxurl, reqParams, function ( response ) {
|
62 |
let msg = 'Communications error with site.';
|
src/lib/src/Modules/Base/Strings.php
CHANGED
@@ -126,9 +126,15 @@ class Strings {
|
|
126 |
'wphashes_token' => 'ShieldPRO API Token',
|
127 |
'is_opt_importexport' => __( 'Is this option included with import/export?', 'wp-simple-firewall' ),
|
128 |
|
129 |
-
'search_select'
|
130 |
'title' => ucwords( __( 'Search for a plugin option', 'wp-simple-firewall' ) ),
|
131 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
],
|
133 |
$this->getAdditionalDisplayStrings()
|
134 |
);
|
126 |
'wphashes_token' => 'ShieldPRO API Token',
|
127 |
'is_opt_importexport' => __( 'Is this option included with import/export?', 'wp-simple-firewall' ),
|
128 |
|
129 |
+
'search_select' => [
|
130 |
'title' => ucwords( __( 'Search for a plugin option', 'wp-simple-firewall' ) ),
|
131 |
+
],
|
132 |
+
'running_version' => sprintf( '%s %s', $con->getHumanName(),
|
133 |
+
Services::WpPlugins()->isUpdateAvailable( $con->base_file ) ?
|
134 |
+
sprintf( '<a href="%s" target="_blank" class="text-danger shield-footer-version">%s</a>',
|
135 |
+
Services::WpGeneral()->getAdminUrl_Updates(), $con->getVersion() )
|
136 |
+
: $con->getVersion()
|
137 |
+
),
|
138 |
],
|
139 |
$this->getAdditionalDisplayStrings()
|
140 |
);
|
src/lib/src/Modules/Base/UI.php
CHANGED
@@ -84,6 +84,7 @@ class UI {
|
|
84 |
'vars' => [
|
85 |
'mod_slug' => $mod->getModSlug(),
|
86 |
'unique_render_id' => uniqid(),
|
|
|
87 |
],
|
88 |
];
|
89 |
}
|
84 |
'vars' => [
|
85 |
'mod_slug' => $mod->getModSlug(),
|
86 |
'unique_render_id' => uniqid(),
|
87 |
+
'plugin_version' => $con->getVersion(),
|
88 |
],
|
89 |
];
|
90 |
}
|
src/lib/src/Modules/IPs/DB/IpRules/MergeAutoBlockRules.php
CHANGED
@@ -66,11 +66,6 @@ class MergeAutoBlockRules extends ExecOnceModConsumer {
|
|
66 |
}
|
67 |
|
68 |
if ( !empty( $toKeep ) && !empty( $idsToDelete ) ) {
|
69 |
-
error_log( var_export( $toKeep->ip, true ) );
|
70 |
-
error_log( var_export( $workingIP, true ) );
|
71 |
-
error_log( var_export( $idsToDelete, true ) );
|
72 |
-
error_log( var_export( $extraOffenses, true ) );
|
73 |
-
|
74 |
$mod->getDbH_IPRules()
|
75 |
->getQueryDeleter()
|
76 |
->addWhereIn( 'id', $idsToDelete )
|
@@ -88,7 +83,6 @@ class MergeAutoBlockRules extends ExecOnceModConsumer {
|
|
88 |
$updater->updateRecord( $toKeep, $updateData );
|
89 |
|
90 |
$toKeep = $mod->getDbH_IPRules()->getQuerySelector()->byId( $toKeep->id );
|
91 |
-
error_log( var_export( $toKeep, true ) );
|
92 |
}
|
93 |
|
94 |
return $toKeep;
|
66 |
}
|
67 |
|
68 |
if ( !empty( $toKeep ) && !empty( $idsToDelete ) ) {
|
|
|
|
|
|
|
|
|
|
|
69 |
$mod->getDbH_IPRules()
|
70 |
->getQueryDeleter()
|
71 |
->addWhereIn( 'id', $idsToDelete )
|
83 |
$updater->updateRecord( $toKeep, $updateData );
|
84 |
|
85 |
$toKeep = $mod->getDbH_IPRules()->getQuerySelector()->byId( $toKeep->id );
|
|
|
86 |
}
|
87 |
|
88 |
return $toKeep;
|
src/lib/src/Modules/IPs/Lib/CrowdSec/Api/DecisionsDownload.php
CHANGED
@@ -15,11 +15,6 @@ class DecisionsDownload extends BaseAuth {
|
|
15 |
$this->request_method = 'get';
|
16 |
$decisions = $this->sendReq();
|
17 |
if ( !is_array( $decisions ) || !isset( $decisions[ 'new' ] ) || !isset( $decisions[ 'deleted' ] ) ) {
|
18 |
-
error_log( var_export( $this->getApiRequestUrl(), true ) );
|
19 |
-
error_log( var_export( $this->getRequestParams(), true ) );
|
20 |
-
error_log( var_export( $this->params_body, true ) );
|
21 |
-
error_log( var_export( $this->params_query, true ) );
|
22 |
-
error_log( var_export( $this->headers, true ) );
|
23 |
throw new DownloadDecisionsStreamFailedException( sprintf( 'Failed to download decisions: %s',
|
24 |
var_export( $this->last_http_req->lastResponse->body, true ) ) );
|
25 |
}
|
15 |
$this->request_method = 'get';
|
16 |
$decisions = $this->sendReq();
|
17 |
if ( !is_array( $decisions ) || !isset( $decisions[ 'new' ] ) || !isset( $decisions[ 'deleted' ] ) ) {
|
|
|
|
|
|
|
|
|
|
|
18 |
throw new DownloadDecisionsStreamFailedException( sprintf( 'Failed to download decisions: %s',
|
19 |
var_export( $this->last_http_req->lastResponse->body, true ) ) );
|
20 |
}
|
src/lib/src/Modules/IPs/UI.php
CHANGED
@@ -41,7 +41,7 @@ class UI extends BaseShield\UI {
|
|
41 |
'label_help' => __( 'A helpful label to describe this IP rule.', 'wp-simple-firewall' ),
|
42 |
'label_help_max' => sprintf( '%s: %s', __( '255 characters max', 'wp-simple-firewall' ), 'a-z,0-9' ),
|
43 |
'ip_address' => __( 'IP Address or IP Range', 'wp-simple-firewall' ),
|
44 |
-
'ip_address_help' => __( 'IPv4 or
|
45 |
'add_rule' => __( 'Add New IP Rule', 'wp-simple-firewall' ),
|
46 |
'confirm' => __( "I fully understand the significance of this action", 'wp-simple-firewall' ),
|
47 |
],
|
41 |
'label_help' => __( 'A helpful label to describe this IP rule.', 'wp-simple-firewall' ),
|
42 |
'label_help_max' => sprintf( '%s: %s', __( '255 characters max', 'wp-simple-firewall' ), 'a-z,0-9' ),
|
43 |
'ip_address' => __( 'IP Address or IP Range', 'wp-simple-firewall' ),
|
44 |
+
'ip_address_help' => __( 'IPv4 or IPv6; Single Address or CIDR Range', 'wp-simple-firewall' ),
|
45 |
'add_rule' => __( 'Add New IP Rule', 'wp-simple-firewall' ),
|
46 |
'confirm' => __( "I fully understand the significance of this action", 'wp-simple-firewall' ),
|
47 |
],
|
src/lib/src/Modules/LoginGuard/AjaxHandler.php
CHANGED
@@ -232,19 +232,18 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
232 |
public function ajaxExec_IntentEmailSend() :array {
|
233 |
/** @var ModCon $mod */
|
234 |
$mod = $this->getMod();
|
235 |
-
$
|
236 |
|
237 |
$success = false;
|
238 |
-
$userID =
|
239 |
-
$
|
240 |
-
if ( !empty( $userID ) && !empty( $
|
241 |
$user = Services::WpUsers()->getUserById( $userID );
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
$success = !empty( $provider ) && $provider->sendEmailTwoFactorVerify( $loginNonce );
|
248 |
}
|
249 |
}
|
250 |
|
232 |
public function ajaxExec_IntentEmailSend() :array {
|
233 |
/** @var ModCon $mod */
|
234 |
$mod = $this->getMod();
|
235 |
+
$req = Services::Request();
|
236 |
|
237 |
$success = false;
|
238 |
+
$userID = $req->post( 'wp_user_id' );
|
239 |
+
$plainNonce = $req->post( 'login_nonce' );
|
240 |
+
if ( !empty( $userID ) && !empty( $plainNonce ) ) {
|
241 |
$user = Services::WpUsers()->getUserById( $userID );
|
242 |
+
if ( $user instanceof \WP_User ) {
|
243 |
+
/** @var TwoFactor\Provider\Email $p */
|
244 |
+
$p = $mod->getMfaController()
|
245 |
+
->getProvidersForUser( $user, true )[ TwoFactor\Provider\Email::SLUG ] ?? null;
|
246 |
+
$success = !empty( $p ) && $p->sendEmailTwoFactorVerify( $plainNonce );
|
|
|
247 |
}
|
248 |
}
|
249 |
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/{NoLoginIntentForUserException.php → InvalidLoginIntentException.php}
RENAMED
@@ -2,6 +2,6 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Exceptions;
|
4 |
|
5 |
-
class
|
6 |
|
7 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Exceptions;
|
4 |
|
5 |
+
class InvalidLoginIntentException extends \Exception {
|
6 |
|
7 |
}
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentRequestCapture.php
CHANGED
@@ -8,7 +8,7 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Exc
|
|
8 |
CouldNotValidate2FA,
|
9 |
LoginCancelException,
|
10 |
NoActiveProvidersForUserException,
|
11 |
-
|
12 |
NotValidUserException,
|
13 |
TooManyAttemptsException
|
14 |
};
|
@@ -16,6 +16,11 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
16 |
|
17 |
class LoginIntentRequestCapture extends Shield\Modules\Base\Common\ExecOnceModConsumer {
|
18 |
|
|
|
|
|
|
|
|
|
|
|
19 |
protected function canRun() :bool {
|
20 |
return Services::Request()->isPost()
|
21 |
&& $this->getCon()->getShieldAction() === 'wp_login_2fa_verify'
|
@@ -32,34 +37,39 @@ class LoginIntentRequestCapture extends Shield\Modules\Base\Common\ExecOnceModCo
|
|
32 |
$mfaCon = $mod->getMfaController();
|
33 |
$req = Services::Request();
|
34 |
|
35 |
-
$user = $req->post( 'wp_user_id' ) ? Services::WpUsers()->getUserById( $req->post( 'wp_user_id' ) ) : null;
|
36 |
-
|
37 |
try {
|
|
|
|
|
|
|
|
|
|
|
38 |
$this->capture();
|
39 |
}
|
40 |
-
catch ( LoginCancelException $e ) {
|
41 |
-
$redirect = $req->post( 'cancel_href' );
|
42 |
-
empty( $redirect ) ? Services::Response()->redirectToLogin() : Services::Response()->redirect( $redirect );
|
43 |
-
}
|
44 |
catch ( NotValidUserException $e ) {
|
45 |
-
//
|
46 |
Services::Response()->redirectToLogin( [
|
47 |
'shield_msg' => 'no_user_login_intent'
|
48 |
] );
|
49 |
}
|
50 |
-
catch (
|
51 |
-
// put error about no login intent
|
52 |
Services::Response()->redirectToLogin( [
|
53 |
'shield_msg' => 'no_user_login_intent'
|
54 |
] );
|
55 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
catch ( TooManyAttemptsException $e ) {
|
57 |
-
|
58 |
Services::Response()->redirectToLogin( [
|
59 |
'shield_msg' => 'too_many_attempts'
|
60 |
] );
|
61 |
}
|
62 |
catch ( NoActiveProvidersForUserException $e ) {
|
|
|
63 |
Services::Response()->redirectToLogin( [
|
64 |
'shield_msg' => 'no_providers'
|
65 |
] );
|
@@ -68,7 +78,7 @@ class LoginIntentRequestCapture extends Shield\Modules\Base\Common\ExecOnceModCo
|
|
68 |
// Allow a further attempt to 2FA
|
69 |
$pageRender = $mfaCon->useLoginIntentPage() ? new Render\RenderLoginIntentPage() : new Render\RenderWpLoginReplica();
|
70 |
$pageRender->setMod( $mod )
|
71 |
-
->setWpUser( $user );
|
72 |
$pageRender->login_nonce = $req->request( 'login_nonce', false, '' );
|
73 |
$pageRender->redirect_to = $req->request( 'redirect_to', false, '' );
|
74 |
$pageRender->rememberme = $req->request( 'rememberme' );
|
@@ -82,8 +92,7 @@ class LoginIntentRequestCapture extends Shield\Modules\Base\Common\ExecOnceModCo
|
|
82 |
* @throws Exceptions\TooManyAttemptsException
|
83 |
* @throws LoginCancelException
|
84 |
* @throws NoActiveProvidersForUserException
|
85 |
-
* @throws
|
86 |
-
* @throws NotValidUserException
|
87 |
*/
|
88 |
private function capture() {
|
89 |
$con = $this->getCon();
|
@@ -93,32 +102,22 @@ class LoginIntentRequestCapture extends Shield\Modules\Base\Common\ExecOnceModCo
|
|
93 |
$opts = $this->getOptions();
|
94 |
$req = Services::Request();
|
95 |
|
|
|
|
|
|
|
|
|
|
|
96 |
if ( $req->post( 'cancel' ) ) {
|
97 |
throw new LoginCancelException();
|
98 |
}
|
99 |
|
100 |
-
$user = Services::WpUsers()->getUserById( $req->post( 'wp_user_id' ) );
|
101 |
-
if ( empty( $user ) ) {
|
102 |
-
throw new NotValidUserException();
|
103 |
-
}
|
104 |
-
|
105 |
-
$nonce = (string)$req->post( 'login_nonce' );
|
106 |
-
if ( !preg_match( '#^[\da-z]{10}$#i', $nonce ) ) {
|
107 |
-
throw new NoLoginIntentForUserException();
|
108 |
-
}
|
109 |
-
|
110 |
-
$valid = ( new LoginIntentRequestValidate() )
|
111 |
-
->setMod( $mod )
|
112 |
-
->setWpUser( $user )
|
113 |
-
->run( $nonce );
|
114 |
-
|
115 |
if ( $valid ) {
|
116 |
-
wp_set_auth_cookie( $user->ID, (bool)$req->post( 'rememberme' ) );
|
117 |
|
118 |
if ( $req->post( 'skip_mfa' ) === 'Y' ) {
|
119 |
( new MfaSkip() )
|
120 |
->setMod( $this->getMod() )
|
121 |
-
->addMfaSkip( $user );
|
122 |
}
|
123 |
|
124 |
$con->fireEvent( '2fa_success' );
|
@@ -131,7 +130,7 @@ class LoginIntentRequestCapture extends Shield\Modules\Base\Common\ExecOnceModCo
|
|
131 |
}, 100, 0 );
|
132 |
$renderer = ( new Render\RenderWpLoginReplica() )
|
133 |
->setMod( $mod )
|
134 |
-
->setWpUser( $user );
|
135 |
$renderer->interim_message = __( '2FA authentication verified successfully.', 'wp-simple-firewall' );
|
136 |
$renderer->include_body = false;
|
137 |
$renderer->render();
|
@@ -141,12 +140,12 @@ class LoginIntentRequestCapture extends Shield\Modules\Base\Common\ExecOnceModCo
|
|
141 |
if ( $opts->isEnabledBackupCodes() ) {
|
142 |
$flash .= ' '.__( 'If you used your Backup Code, you will need to reset it.', 'wp-simple-firewall' );
|
143 |
}
|
144 |
-
$this->getMod()->setFlashAdminNotice( $flash, $user );
|
145 |
}
|
146 |
|
147 |
$redirect = $req->request( 'redirect_to', false, $req->getPath() );
|
148 |
Services::Response()->redirect(
|
149 |
-
apply_filters( 'login_redirect', $redirect, $redirect, $user ),
|
150 |
[], true, false
|
151 |
);
|
152 |
}
|
8 |
CouldNotValidate2FA,
|
9 |
LoginCancelException,
|
10 |
NoActiveProvidersForUserException,
|
11 |
+
InvalidLoginIntentException,
|
12 |
NotValidUserException,
|
13 |
TooManyAttemptsException
|
14 |
};
|
16 |
|
17 |
class LoginIntentRequestCapture extends Shield\Modules\Base\Common\ExecOnceModConsumer {
|
18 |
|
19 |
+
/**
|
20 |
+
* @var \WP_User
|
21 |
+
*/
|
22 |
+
private $user;
|
23 |
+
|
24 |
protected function canRun() :bool {
|
25 |
return Services::Request()->isPost()
|
26 |
&& $this->getCon()->getShieldAction() === 'wp_login_2fa_verify'
|
37 |
$mfaCon = $mod->getMfaController();
|
38 |
$req = Services::Request();
|
39 |
|
|
|
|
|
40 |
try {
|
41 |
+
$user = $req->post( 'wp_user_id' ) ? Services::WpUsers()->getUserById( $req->post( 'wp_user_id' ) ) : null;
|
42 |
+
if ( empty( $user ) ) {
|
43 |
+
throw new NotValidUserException();
|
44 |
+
}
|
45 |
+
$this->user = $user;
|
46 |
$this->capture();
|
47 |
}
|
|
|
|
|
|
|
|
|
48 |
catch ( NotValidUserException $e ) {
|
49 |
+
// output error about no login intent so there's no way to discern externally whether such a user exists
|
50 |
Services::Response()->redirectToLogin( [
|
51 |
'shield_msg' => 'no_user_login_intent'
|
52 |
] );
|
53 |
}
|
54 |
+
catch ( InvalidLoginIntentException $e ) {
|
|
|
55 |
Services::Response()->redirectToLogin( [
|
56 |
'shield_msg' => 'no_user_login_intent'
|
57 |
] );
|
58 |
}
|
59 |
+
catch ( LoginCancelException $e ) {
|
60 |
+
// This should always be a user since we can only throw this exception after loading the user
|
61 |
+
$this->getCon()->getUserMeta( $this->user )->login_intents = [];
|
62 |
+
$redirect = $req->post( 'cancel_href' );
|
63 |
+
empty( $redirect ) ? Services::Response()->redirectToLogin() : Services::Response()->redirect( $redirect );
|
64 |
+
}
|
65 |
catch ( TooManyAttemptsException $e ) {
|
66 |
+
$this->getCon()->getUserMeta( $this->user )->login_intents = [];
|
67 |
Services::Response()->redirectToLogin( [
|
68 |
'shield_msg' => 'too_many_attempts'
|
69 |
] );
|
70 |
}
|
71 |
catch ( NoActiveProvidersForUserException $e ) {
|
72 |
+
$this->getCon()->getUserMeta( $this->user )->login_intents = [];
|
73 |
Services::Response()->redirectToLogin( [
|
74 |
'shield_msg' => 'no_providers'
|
75 |
] );
|
78 |
// Allow a further attempt to 2FA
|
79 |
$pageRender = $mfaCon->useLoginIntentPage() ? new Render\RenderLoginIntentPage() : new Render\RenderWpLoginReplica();
|
80 |
$pageRender->setMod( $mod )
|
81 |
+
->setWpUser( $this->user );
|
82 |
$pageRender->login_nonce = $req->request( 'login_nonce', false, '' );
|
83 |
$pageRender->redirect_to = $req->request( 'redirect_to', false, '' );
|
84 |
$pageRender->rememberme = $req->request( 'rememberme' );
|
92 |
* @throws Exceptions\TooManyAttemptsException
|
93 |
* @throws LoginCancelException
|
94 |
* @throws NoActiveProvidersForUserException
|
95 |
+
* @throws InvalidLoginIntentException
|
|
|
96 |
*/
|
97 |
private function capture() {
|
98 |
$con = $this->getCon();
|
102 |
$opts = $this->getOptions();
|
103 |
$req = Services::Request();
|
104 |
|
105 |
+
$valid = ( new LoginIntentRequestValidate() )
|
106 |
+
->setMod( $mod )
|
107 |
+
->setWpUser( $this->user )
|
108 |
+
->run( (string)$req->post( 'login_nonce' ) );
|
109 |
+
|
110 |
if ( $req->post( 'cancel' ) ) {
|
111 |
throw new LoginCancelException();
|
112 |
}
|
113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
if ( $valid ) {
|
115 |
+
wp_set_auth_cookie( $this->user->ID, (bool)$req->post( 'rememberme' ) );
|
116 |
|
117 |
if ( $req->post( 'skip_mfa' ) === 'Y' ) {
|
118 |
( new MfaSkip() )
|
119 |
->setMod( $this->getMod() )
|
120 |
+
->addMfaSkip( $this->user );
|
121 |
}
|
122 |
|
123 |
$con->fireEvent( '2fa_success' );
|
130 |
}, 100, 0 );
|
131 |
$renderer = ( new Render\RenderWpLoginReplica() )
|
132 |
->setMod( $mod )
|
133 |
+
->setWpUser( $this->user );
|
134 |
$renderer->interim_message = __( '2FA authentication verified successfully.', 'wp-simple-firewall' );
|
135 |
$renderer->include_body = false;
|
136 |
$renderer->render();
|
140 |
if ( $opts->isEnabledBackupCodes() ) {
|
141 |
$flash .= ' '.__( 'If you used your Backup Code, you will need to reset it.', 'wp-simple-firewall' );
|
142 |
}
|
143 |
+
$this->getMod()->setFlashAdminNotice( $flash, $this->user );
|
144 |
}
|
145 |
|
146 |
$redirect = $req->request( 'redirect_to', false, $req->getPath() );
|
147 |
Services::Response()->redirect(
|
148 |
+
apply_filters( 'login_redirect', $redirect, $redirect, $this->user ),
|
149 |
[], true, false
|
150 |
);
|
151 |
}
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentRequestValidate.php
CHANGED
@@ -6,7 +6,7 @@ use FernleafSystems\Wordpress\Plugin\Shield;
|
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Exceptions\{
|
7 |
CouldNotValidate2FA,
|
8 |
NoActiveProvidersForUserException,
|
9 |
-
|
10 |
TooManyAttemptsException
|
11 |
};
|
12 |
|
@@ -18,17 +18,17 @@ class LoginIntentRequestValidate {
|
|
18 |
/**
|
19 |
* @throws CouldNotValidate2FA
|
20 |
* @throws NoActiveProvidersForUserException
|
21 |
-
* @throws
|
22 |
* @throws TooManyAttemptsException
|
23 |
*/
|
24 |
-
public function run( string $
|
25 |
/** @var Shield\Modules\LoginGuard\ModCon $mod */
|
26 |
$mod = $this->getMod();
|
27 |
$mfaCon = $mod->getMfaController();
|
28 |
$user = $this->getWpUser();
|
29 |
|
30 |
-
if (
|
31 |
-
throw new
|
32 |
}
|
33 |
|
34 |
$providers = $mfaCon->getProvidersForUser( $user, true );
|
@@ -39,30 +39,23 @@ class LoginIntentRequestValidate {
|
|
39 |
$validated = false;
|
40 |
foreach ( $providers as $provider ) {
|
41 |
$provider->setUser( $user );
|
42 |
-
if ( $provider->validateLoginIntent( $
|
43 |
$provider->postSuccessActions();
|
44 |
$validated = true;
|
45 |
break;
|
46 |
}
|
47 |
}
|
48 |
|
49 |
-
// Always remove intent after success, otherwise increment attempts.
|
50 |
-
$intents = $mfaCon->getActiveLoginIntents( $user );
|
51 |
-
if ( $validated ) {
|
52 |
-
unset( $intents[ $loginNonce ] );
|
53 |
-
}
|
54 |
-
else {
|
55 |
-
$intents[ $loginNonce ][ 'attempts' ]++;
|
56 |
-
}
|
57 |
-
$this->getCon()->getUserMeta( $user )->login_intents = $intents;
|
58 |
-
|
59 |
if ( !$validated ) {
|
60 |
-
|
|
|
61 |
throw new TooManyAttemptsException();
|
62 |
}
|
63 |
-
throw new CouldNotValidate2FA();
|
64 |
}
|
65 |
|
|
|
|
|
|
|
66 |
return true;
|
67 |
}
|
68 |
}
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Exceptions\{
|
7 |
CouldNotValidate2FA,
|
8 |
NoActiveProvidersForUserException,
|
9 |
+
InvalidLoginIntentException,
|
10 |
TooManyAttemptsException
|
11 |
};
|
12 |
|
18 |
/**
|
19 |
* @throws CouldNotValidate2FA
|
20 |
* @throws NoActiveProvidersForUserException
|
21 |
+
* @throws InvalidLoginIntentException
|
22 |
* @throws TooManyAttemptsException
|
23 |
*/
|
24 |
+
public function run( string $plainNonce ) :bool {
|
25 |
/** @var Shield\Modules\LoginGuard\ModCon $mod */
|
26 |
$mod = $this->getMod();
|
27 |
$mfaCon = $mod->getMfaController();
|
28 |
$user = $this->getWpUser();
|
29 |
|
30 |
+
if ( !$mfaCon->verifyLoginNonce( $user, $plainNonce ) ) {
|
31 |
+
throw new InvalidLoginIntentException();
|
32 |
}
|
33 |
|
34 |
$providers = $mfaCon->getProvidersForUser( $user, true );
|
39 |
$validated = false;
|
40 |
foreach ( $providers as $provider ) {
|
41 |
$provider->setUser( $user );
|
42 |
+
if ( $provider->validateLoginIntent( $mfaCon->findHashedNonce( $user, $plainNonce ) ) ) {
|
43 |
$provider->postSuccessActions();
|
44 |
$validated = true;
|
45 |
break;
|
46 |
}
|
47 |
}
|
48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
if ( !$validated ) {
|
50 |
+
throw new CouldNotValidate2FA();
|
51 |
+
if ( empty( $mfaCon->getActiveLoginIntents( $user )[ $plainNonce ] ) ) {
|
52 |
throw new TooManyAttemptsException();
|
53 |
}
|
|
|
54 |
}
|
55 |
|
56 |
+
// Always remove intents after success.
|
57 |
+
$this->getCon()->getUserMeta( $user )->login_intents = [];
|
58 |
+
|
59 |
return true;
|
60 |
}
|
61 |
}
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginRequestCapture.php
CHANGED
@@ -27,17 +27,17 @@ class LoginRequestCapture extends Shield\Modules\Base\Common\ExecOnceModConsumer
|
|
27 |
->captureLoginAttempt();
|
28 |
}
|
29 |
|
30 |
-
|
31 |
-
$
|
32 |
-
$loginNonce = substr( hash( 'sha256', uniqid( '', true ) ), $randStart, 10 );
|
33 |
|
34 |
-
$meta = $this->getCon()->getUserMeta( $user );
|
35 |
$intents = $mfaCon->getActiveLoginIntents( $user );
|
36 |
-
$intents[ $
|
|
|
37 |
'start' => Services::Request()->ts(),
|
38 |
'attempts' => 0,
|
39 |
];
|
40 |
-
|
|
|
41 |
|
42 |
$loggedInCookie = $this->getLoggedInCookie();
|
43 |
if ( !empty( $loggedInCookie ) ) {
|
27 |
->captureLoginAttempt();
|
28 |
}
|
29 |
|
30 |
+
$loginNonce = bin2hex( random_bytes( 32 ) );
|
31 |
+
$loginNonceHashed = wp_hash_password( $loginNonce.$user->ID );
|
|
|
32 |
|
|
|
33 |
$intents = $mfaCon->getActiveLoginIntents( $user );
|
34 |
+
$intents[ $loginNonceHashed ] = [
|
35 |
+
'hash' => $loginNonceHashed,
|
36 |
'start' => Services::Request()->ts(),
|
37 |
'attempts' => 0,
|
38 |
];
|
39 |
+
|
40 |
+
$this->getCon()->getUserMeta( $user )->login_intents = $intents;
|
41 |
|
42 |
$loggedInCookie = $this->getLoggedInCookie();
|
43 |
if ( !empty( $loggedInCookie ) ) {
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php
CHANGED
@@ -60,9 +60,9 @@ class MfaController extends Shield\Modules\Base\Common\ExecOnceModConsumer {
|
|
60 |
/** @var Provider\Email|null $emailProvider */
|
61 |
$emailProvider = $providers[ Provider\Email::SLUG ] ?? null;
|
62 |
if ( count( $providers ) === 1 && !empty( $emailProvider ) ) {
|
63 |
-
$
|
64 |
-
$
|
65 |
-
$auto =
|
66 |
}
|
67 |
return $auto;
|
68 |
}
|
@@ -207,4 +207,27 @@ class MfaController extends Shield\Modules\Base\Common\ExecOnceModConsumer {
|
|
207 |
}
|
208 |
);
|
209 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
210 |
}
|
60 |
/** @var Provider\Email|null $emailProvider */
|
61 |
$emailProvider = $providers[ Provider\Email::SLUG ] ?? null;
|
62 |
if ( count( $providers ) === 1 && !empty( $emailProvider ) ) {
|
63 |
+
$intents = $this->getActiveLoginIntents( $user );
|
64 |
+
$latest = array_pop( $intents );
|
65 |
+
$auto = !empty( $latest ) && empty( $latest[ 'auto_email_sent' ] );
|
66 |
}
|
67 |
return $auto;
|
68 |
}
|
207 |
}
|
208 |
);
|
209 |
}
|
210 |
+
|
211 |
+
public function findHashedNonce( \WP_User $user, string $plainNonce ) :string {
|
212 |
+
$hashedNonce = '';
|
213 |
+
foreach ( array_keys( $this->getActiveLoginIntents( $user ) ) as $maybeHash ) {
|
214 |
+
if ( wp_check_password( $plainNonce.$user->ID, $maybeHash ) ) {
|
215 |
+
$hashedNonce = $maybeHash;
|
216 |
+
break;
|
217 |
+
}
|
218 |
+
}
|
219 |
+
return $hashedNonce;
|
220 |
+
}
|
221 |
+
|
222 |
+
public function verifyLoginNonce( \WP_User $user, string $plainNonce ) :bool {
|
223 |
+
$valid = !empty( $this->findHashedNonce( $user, $plainNonce ) );
|
224 |
+
if ( !$valid ) {
|
225 |
+
$this->getCon()->fireEvent( '2fa_nonce_verify_fail', [
|
226 |
+
'audit_params' => [
|
227 |
+
'user_login' => $user->user_login,
|
228 |
+
]
|
229 |
+
] );
|
230 |
+
}
|
231 |
+
return $valid;
|
232 |
+
}
|
233 |
}
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BackupCodes.php
CHANGED
@@ -73,7 +73,7 @@ class BackupCodes extends BaseProvider {
|
|
73 |
return $this;
|
74 |
}
|
75 |
|
76 |
-
protected function processOtp( string $otp
|
77 |
return (bool)wp_check_password( str_replace( '-', '', $otp ), $this->getSecret() );
|
78 |
}
|
79 |
|
73 |
return $this;
|
74 |
}
|
75 |
|
76 |
+
protected function processOtp( string $otp ) :bool {
|
77 |
return (bool)wp_check_password( str_replace( '-', '', $otp ), $this->getSecret() );
|
78 |
}
|
79 |
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php
CHANGED
@@ -22,6 +22,11 @@ abstract class BaseProvider {
|
|
22 |
*/
|
23 |
private $user;
|
24 |
|
|
|
|
|
|
|
|
|
|
|
25 |
public function __construct() {
|
26 |
}
|
27 |
|
@@ -34,11 +39,12 @@ abstract class BaseProvider {
|
|
34 |
/**
|
35 |
* Assumes this is only called on active profiles
|
36 |
*/
|
37 |
-
public function validateLoginIntent( string $
|
38 |
$otpSuccess = false;
|
39 |
$otp = $this->fetchCodeFromRequest();
|
40 |
if ( !empty( $otp ) ) {
|
41 |
-
$
|
|
|
42 |
$this->auditLogin( $otpSuccess );
|
43 |
}
|
44 |
return $otpSuccess;
|
@@ -115,7 +121,7 @@ abstract class BaseProvider {
|
|
115 |
return '';
|
116 |
}
|
117 |
|
118 |
-
abstract protected function processOtp( string $otp
|
119 |
|
120 |
/**
|
121 |
* Only to be fired if and when Login has been completely verified.
|
22 |
*/
|
23 |
private $user;
|
24 |
|
25 |
+
/**
|
26 |
+
* @var string
|
27 |
+
*/
|
28 |
+
protected $workingHashedLoginNonce;
|
29 |
+
|
30 |
public function __construct() {
|
31 |
}
|
32 |
|
39 |
/**
|
40 |
* Assumes this is only called on active profiles
|
41 |
*/
|
42 |
+
public function validateLoginIntent( string $hashedNonce ) :bool {
|
43 |
$otpSuccess = false;
|
44 |
$otp = $this->fetchCodeFromRequest();
|
45 |
if ( !empty( $otp ) ) {
|
46 |
+
$this->workingHashedLoginNonce = $hashedNonce;
|
47 |
+
$otpSuccess = $this->processOtp( $otp );
|
48 |
$this->auditLogin( $otpSuccess );
|
49 |
}
|
50 |
return $otpSuccess;
|
121 |
return '';
|
122 |
}
|
123 |
|
124 |
+
abstract protected function processOtp( string $otp ) :bool;
|
125 |
|
126 |
/**
|
127 |
* Only to be fired if and when Login has been completely verified.
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php
CHANGED
@@ -22,10 +22,17 @@ class Email extends BaseProvider {
|
|
22 |
* If login nonce is provided, the OTP check is stricter and must be the same as that assigned to the nonce.
|
23 |
* Otherwise, we just check whether the OTP exists.
|
24 |
*/
|
25 |
-
protected function processOtp( string $otp
|
26 |
-
|
27 |
-
|
28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
}
|
30 |
|
31 |
public function getFormField() :array {
|
@@ -71,16 +78,30 @@ class Email extends BaseProvider {
|
|
71 |
return true;
|
72 |
}
|
73 |
|
74 |
-
public function sendEmailTwoFactorVerify( string $
|
|
|
|
|
|
|
|
|
75 |
$user = $this->getUser();
|
76 |
-
$
|
|
|
77 |
$useSureSend = $sureCon->isEnabled2Fa() && $sureCon->canUserSend( $user );
|
78 |
|
79 |
$success = false;
|
80 |
try {
|
81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
|
83 |
-
$
|
|
|
|
|
84 |
|| $this->getMod()
|
85 |
->getEmailProcessor()
|
86 |
->sendEmailWithTemplate(
|
@@ -92,7 +113,7 @@ class Email extends BaseProvider {
|
|
92 |
'show_login_link' => !$this->getCon()->isRelabelled()
|
93 |
],
|
94 |
'vars' => [
|
95 |
-
'code' => $
|
96 |
],
|
97 |
'hrefs' => [
|
98 |
'login_link' => 'https://shsec.io/96',
|
@@ -149,32 +170,24 @@ class Email extends BaseProvider {
|
|
149 |
&& ( $this->isEnforced() || $opts->isEnabledEmailAuthAnyUserSet() );
|
150 |
}
|
151 |
|
152 |
-
private function
|
153 |
-
$secrets = $this->getAllCodes();
|
154 |
-
if ( !isset( $secrets[ $loginNonce ] ) ) {
|
155 |
-
$secrets[ $loginNonce ] = $this->generateSimpleOTP();
|
156 |
-
$this->storeCodes( $secrets );
|
157 |
-
}
|
158 |
-
return $secrets[ $loginNonce ];
|
159 |
-
}
|
160 |
-
|
161 |
-
public function hasOtpForNonce( string $loginNonce ) :bool {
|
162 |
-
return isset( $this->getAllCodes()[ $loginNonce ] );
|
163 |
-
}
|
164 |
-
|
165 |
-
private function getAllCodes() :array {
|
166 |
/** @var LoginGuard\ModCon $mod */
|
167 |
$mod = $this->getMod();
|
168 |
-
|
169 |
$secrets = $this->getSecret();
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
|
|
175 |
|
176 |
-
|
177 |
-
$this->setSecret(
|
|
|
|
|
|
|
|
|
178 |
}
|
179 |
|
180 |
public function getProviderName() :string {
|
22 |
* If login nonce is provided, the OTP check is stricter and must be the same as that assigned to the nonce.
|
23 |
* Otherwise, we just check whether the OTP exists.
|
24 |
*/
|
25 |
+
protected function processOtp( string $otp ) :bool {
|
26 |
+
$secret = $this->getSecret()[ $this->workingHashedLoginNonce ] ?? '';
|
27 |
+
return !empty( $secret ) && wp_check_password( $otp, $secret );
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @inheritDoc
|
32 |
+
*/
|
33 |
+
public function postSuccessActions() {
|
34 |
+
parent::postSuccessActions();
|
35 |
+
return $this->setSecret( [] );
|
36 |
}
|
37 |
|
38 |
public function getFormField() :array {
|
78 |
return true;
|
79 |
}
|
80 |
|
81 |
+
public function sendEmailTwoFactorVerify( string $plainNonce ) :bool {
|
82 |
+
$con = $this->getCon();
|
83 |
+
/** @var LoginGuard\ModCon $mod */
|
84 |
+
$mod = $this->getMod();
|
85 |
+
$mfaCon = $mod->getMfaController();
|
86 |
$user = $this->getUser();
|
87 |
+
$userMeta = $con->getUserMeta( $user );
|
88 |
+
$sureCon = $con->getModule_Comms()->getSureSendController();
|
89 |
$useSureSend = $sureCon->isEnabled2Fa() && $sureCon->canUserSend( $user );
|
90 |
|
91 |
$success = false;
|
92 |
try {
|
93 |
+
if ( !$mfaCon->verifyLoginNonce( $user, $plainNonce ) ) {
|
94 |
+
throw new \Exception( 'No such login intent' );
|
95 |
+
}
|
96 |
+
|
97 |
+
$hashedNonce = $mfaCon->findHashedNonce( $user, $plainNonce );
|
98 |
+
$intents = $mfaCon->getActiveLoginIntents( $user );
|
99 |
+
$intents[ $hashedNonce ][ 'auto_email_sent' ] = true;
|
100 |
+
$userMeta->login_intents = $intents;
|
101 |
|
102 |
+
$otp = $this->generate2faCode( $hashedNonce );
|
103 |
+
|
104 |
+
$success = ( $useSureSend && $this->send2faEmailSureSend( $otp ) )
|
105 |
|| $this->getMod()
|
106 |
->getEmailProcessor()
|
107 |
->sendEmailWithTemplate(
|
113 |
'show_login_link' => !$this->getCon()->isRelabelled()
|
114 |
],
|
115 |
'vars' => [
|
116 |
+
'code' => $otp
|
117 |
],
|
118 |
'hrefs' => [
|
119 |
'login_link' => 'https://shsec.io/96',
|
170 |
&& ( $this->isEnforced() || $opts->isEnabledEmailAuthAnyUserSet() );
|
171 |
}
|
172 |
|
173 |
+
private function generate2faCode( string $hashedLoginNonce ) :string {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
/** @var LoginGuard\ModCon $mod */
|
175 |
$mod = $this->getMod();
|
176 |
+
|
177 |
$secrets = $this->getSecret();
|
178 |
+
if ( !is_array( $secrets ) ) {
|
179 |
+
$secrets = [];
|
180 |
+
}
|
181 |
+
|
182 |
+
$otp = $this->generateSimpleOTP();
|
183 |
+
$secrets[ $hashedLoginNonce ] = wp_hash_password( $otp );
|
184 |
|
185 |
+
// Clean old secrets linked to expired login intents
|
186 |
+
$this->setSecret( array_intersect_key(
|
187 |
+
$secrets,
|
188 |
+
$mod->getMfaController()->getActiveLoginIntents( $this->getUser() )
|
189 |
+
) );
|
190 |
+
return $otp;
|
191 |
}
|
192 |
|
193 |
public function getProviderName() :string {
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/GoogleAuth.php
CHANGED
@@ -115,7 +115,7 @@ class GoogleAuth extends BaseProvider {
|
|
115 |
|
116 |
public function activateGA( string $otp ) :StdResponse {
|
117 |
$r = new StdResponse();
|
118 |
-
$r->success = $this->processOtp( $otp
|
119 |
if ( $r->success ) {
|
120 |
$this->setProfileValidated( true );
|
121 |
$r->msg_text = sprintf(
|
@@ -147,7 +147,7 @@ class GoogleAuth extends BaseProvider {
|
|
147 |
];
|
148 |
}
|
149 |
|
150 |
-
protected function processOtp( string $otp
|
151 |
$valid = false;
|
152 |
try {
|
153 |
$valid = preg_match( '#^\d{6}$#', $otp )
|
115 |
|
116 |
public function activateGA( string $otp ) :StdResponse {
|
117 |
$r = new StdResponse();
|
118 |
+
$r->success = $this->processOtp( $otp );
|
119 |
if ( $r->success ) {
|
120 |
$this->setProfileValidated( true );
|
121 |
$r->msg_text = sprintf(
|
147 |
];
|
148 |
}
|
149 |
|
150 |
+
protected function processOtp( string $otp ) :bool {
|
151 |
$valid = false;
|
152 |
try {
|
153 |
$valid = preg_match( '#^\d{6}$#', $otp )
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Sms.php
CHANGED
@@ -116,7 +116,7 @@ class Sms extends BaseProvider {
|
|
116 |
return $this;
|
117 |
}
|
118 |
|
119 |
-
protected function processOtp( string $otp
|
120 |
$meta = $this->getCon()->getUserMeta( $this->getUser() );
|
121 |
return !empty( $meta->sms_registration[ 'code' ] )
|
122 |
&& $meta->sms_registration[ 'code' ] === strtoupper( $otp );
|
116 |
return $this;
|
117 |
}
|
118 |
|
119 |
+
protected function processOtp( string $otp ) :bool {
|
120 |
$meta = $this->getCon()->getUserMeta( $this->getUser() );
|
121 |
return !empty( $meta->sms_registration[ 'code' ] )
|
122 |
&& $meta->sms_registration[ 'code' ] === strtoupper( $otp );
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/U2F.php
CHANGED
@@ -221,7 +221,7 @@ class U2F extends BaseProvider {
|
|
221 |
return $response;
|
222 |
}
|
223 |
|
224 |
-
protected function processOtp( string $otp
|
225 |
try {
|
226 |
$registration = ( new \u2flib_server\U2F( $this->getU2fAppID() ) )
|
227 |
->doAuthenticate(
|
221 |
return $response;
|
222 |
}
|
223 |
|
224 |
+
protected function processOtp( string $otp ) :bool {
|
225 |
try {
|
226 |
$registration = ( new \u2flib_server\U2F( $this->getU2fAppID() ) )
|
227 |
->doAuthenticate(
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Yubikey.php
CHANGED
@@ -55,7 +55,7 @@ class Yubikey extends BaseProvider {
|
|
55 |
return count( $this->getYubiIds() ) > 0;
|
56 |
}
|
57 |
|
58 |
-
protected function processOtp( string $otp
|
59 |
$valid = false;
|
60 |
|
61 |
foreach ( $this->getYubiIds() as $key ) {
|
55 |
return count( $this->getYubiIds() ) > 0;
|
56 |
}
|
57 |
|
58 |
+
protected function processOtp( string $otp ) :bool {
|
59 |
$valid = false;
|
60 |
|
61 |
foreach ( $this->getYubiIds() as $key ) {
|
src/lib/src/Modules/LoginGuard/Strings.php
CHANGED
@@ -12,68 +12,74 @@ class Strings extends Base\Strings {
|
|
12 |
*/
|
13 |
public function getEventStrings() :array {
|
14 |
return [
|
15 |
-
'botbox_fail'
|
16 |
'name' => __( 'BotBox Fail', 'wp-simple-firewall' ),
|
17 |
'audit' => [
|
18 |
__( 'User "{{user_login}}" attempted "{{action}}" but Bot checkbox was not found.', 'wp-simple-firewall' ),
|
19 |
],
|
20 |
],
|
21 |
-
'cooldown_fail'
|
22 |
'name' => __( 'Cooldown Fail', 'wp-simple-firewall' ),
|
23 |
'audit' => [
|
24 |
__( 'Login/Register request triggered cooldown and was blocked.', 'wp-simple-firewall' )
|
25 |
],
|
26 |
],
|
27 |
-
'honeypot_fail'
|
28 |
'name' => __( 'Honeypot Fail', 'wp-simple-firewall' ),
|
29 |
'audit' => [
|
30 |
__( 'User "{{user_login}}" attempted {{action}} but they were caught by the honeypot.', 'wp-simple-firewall' )
|
31 |
],
|
32 |
],
|
33 |
-
'2fa_success'
|
34 |
'name' => __( '2FA Login Success', 'wp-simple-firewall' ),
|
35 |
'audit' => [
|
36 |
__( 'Successful 2FA Login Verification', 'wp-simple-firewall' ),
|
37 |
],
|
38 |
],
|
39 |
-
'2fa_verify_success'
|
40 |
'name' => __( '2FA Verify Success', 'wp-simple-firewall' ),
|
41 |
'audit' => [
|
42 |
__( 'User "{{user_login}}" verified their identity using "{{method}}".', 'wp-simple-firewall' )
|
43 |
],
|
44 |
],
|
45 |
-
'2fa_verify_fail'
|
46 |
'name' => __( '2FA Verify Fail', 'wp-simple-firewall' ),
|
47 |
'audit' => [
|
48 |
__( 'User "{{user_login}}" failed to verify their identity using "{{method}}".', 'wp-simple-firewall' )
|
49 |
],
|
50 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
// todo rename to block_login
|
52 |
-
'login_block'
|
53 |
'name' => __( 'Login Blocked', 'wp-simple-firewall' ),
|
54 |
'audit' => [
|
55 |
__( 'User login request blocked.', 'wp-simple-firewall' ),
|
56 |
],
|
57 |
],
|
58 |
-
'block_register'
|
59 |
'name' => __( 'Registration Blocked', 'wp-simple-firewall' ),
|
60 |
'audit' => [
|
61 |
__( 'User registration request blocked.', 'wp-simple-firewall' ),
|
62 |
],
|
63 |
],
|
64 |
-
'block_lostpassword'
|
65 |
'name' => __( 'Lost Password Blocked', 'wp-simple-firewall' ),
|
66 |
'audit' => [
|
67 |
__( 'User lost password request blocked.', 'wp-simple-firewall' ),
|
68 |
],
|
69 |
],
|
70 |
-
'block_checkout'
|
71 |
'name' => __( 'Checkout Blocked', 'wp-simple-firewall' ),
|
72 |
'audit' => [
|
73 |
__( 'User attempting checkout request blocked.', 'wp-simple-firewall' ),
|
74 |
],
|
75 |
],
|
76 |
-
'hide_login_url'
|
77 |
'name' => __( 'Hidden Login URL Fail', 'wp-simple-firewall' ),
|
78 |
'audit' => [
|
79 |
__( 'Redirecting wp-login due to hidden login URL', 'wp-simple-firewall' ),
|
12 |
*/
|
13 |
public function getEventStrings() :array {
|
14 |
return [
|
15 |
+
'botbox_fail' => [
|
16 |
'name' => __( 'BotBox Fail', 'wp-simple-firewall' ),
|
17 |
'audit' => [
|
18 |
__( 'User "{{user_login}}" attempted "{{action}}" but Bot checkbox was not found.', 'wp-simple-firewall' ),
|
19 |
],
|
20 |
],
|
21 |
+
'cooldown_fail' => [
|
22 |
'name' => __( 'Cooldown Fail', 'wp-simple-firewall' ),
|
23 |
'audit' => [
|
24 |
__( 'Login/Register request triggered cooldown and was blocked.', 'wp-simple-firewall' )
|
25 |
],
|
26 |
],
|
27 |
+
'honeypot_fail' => [
|
28 |
'name' => __( 'Honeypot Fail', 'wp-simple-firewall' ),
|
29 |
'audit' => [
|
30 |
__( 'User "{{user_login}}" attempted {{action}} but they were caught by the honeypot.', 'wp-simple-firewall' )
|
31 |
],
|
32 |
],
|
33 |
+
'2fa_success' => [
|
34 |
'name' => __( '2FA Login Success', 'wp-simple-firewall' ),
|
35 |
'audit' => [
|
36 |
__( 'Successful 2FA Login Verification', 'wp-simple-firewall' ),
|
37 |
],
|
38 |
],
|
39 |
+
'2fa_verify_success' => [
|
40 |
'name' => __( '2FA Verify Success', 'wp-simple-firewall' ),
|
41 |
'audit' => [
|
42 |
__( 'User "{{user_login}}" verified their identity using "{{method}}".', 'wp-simple-firewall' )
|
43 |
],
|
44 |
],
|
45 |
+
'2fa_verify_fail' => [
|
46 |
'name' => __( '2FA Verify Fail', 'wp-simple-firewall' ),
|
47 |
'audit' => [
|
48 |
__( 'User "{{user_login}}" failed to verify their identity using "{{method}}".', 'wp-simple-firewall' )
|
49 |
],
|
50 |
],
|
51 |
+
'2fa_nonce_verify_fail' => [
|
52 |
+
'name' => __( '2FA Nonce Verify Fail', 'wp-simple-firewall' ),
|
53 |
+
'audit' => [
|
54 |
+
__( 'An attempt was made to verify a 2FA login "{{user_login}}" using an invalid nonce.', 'wp-simple-firewall' )
|
55 |
+
],
|
56 |
+
],
|
57 |
// todo rename to block_login
|
58 |
+
'login_block' => [
|
59 |
'name' => __( 'Login Blocked', 'wp-simple-firewall' ),
|
60 |
'audit' => [
|
61 |
__( 'User login request blocked.', 'wp-simple-firewall' ),
|
62 |
],
|
63 |
],
|
64 |
+
'block_register' => [
|
65 |
'name' => __( 'Registration Blocked', 'wp-simple-firewall' ),
|
66 |
'audit' => [
|
67 |
__( 'User registration request blocked.', 'wp-simple-firewall' ),
|
68 |
],
|
69 |
],
|
70 |
+
'block_lostpassword' => [
|
71 |
'name' => __( 'Lost Password Blocked', 'wp-simple-firewall' ),
|
72 |
'audit' => [
|
73 |
__( 'User lost password request blocked.', 'wp-simple-firewall' ),
|
74 |
],
|
75 |
],
|
76 |
+
'block_checkout' => [
|
77 |
'name' => __( 'Checkout Blocked', 'wp-simple-firewall' ),
|
78 |
'audit' => [
|
79 |
__( 'User attempting checkout request blocked.', 'wp-simple-firewall' ),
|
80 |
],
|
81 |
],
|
82 |
+
'hide_login_url' => [
|
83 |
'name' => __( 'Hidden Login URL Fail', 'wp-simple-firewall' ),
|
84 |
'audit' => [
|
85 |
__( 'Redirecting wp-login due to hidden login URL', 'wp-simple-firewall' ),
|
src/lib/vendor/composer/autoload_classmap.php
CHANGED
@@ -826,9 +826,9 @@ return array(
|
|
826 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\CooldownFlagFile' => $baseDir . '/src/Modules/LoginGuard/Lib/CooldownFlagFile.php',
|
827 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\Rename\\RenameLogin' => $baseDir . '/src/Modules/LoginGuard/Lib/Rename/RenameLogin.php',
|
828 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\CouldNotValidate2FA' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/CouldNotValidate2FA.php',
|
|
|
829 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\LoginCancelException' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/LoginCancelException.php',
|
830 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\NoActiveProvidersForUserException' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/NoActiveProvidersForUserException.php',
|
831 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\NoLoginIntentForUserException' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/NoLoginIntentForUserException.php',
|
832 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\NotValidUserException' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/NotValidUserException.php',
|
833 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\TooManyAttemptsException' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/TooManyAttemptsException.php',
|
834 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\LoginIntentRequestCapture' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentRequestCapture.php',
|
826 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\CooldownFlagFile' => $baseDir . '/src/Modules/LoginGuard/Lib/CooldownFlagFile.php',
|
827 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\Rename\\RenameLogin' => $baseDir . '/src/Modules/LoginGuard/Lib/Rename/RenameLogin.php',
|
828 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\CouldNotValidate2FA' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/CouldNotValidate2FA.php',
|
829 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\InvalidLoginIntentException' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/InvalidLoginIntentException.php',
|
830 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\LoginCancelException' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/LoginCancelException.php',
|
831 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\NoActiveProvidersForUserException' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/NoActiveProvidersForUserException.php',
|
|
|
832 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\NotValidUserException' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/NotValidUserException.php',
|
833 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\TooManyAttemptsException' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/TooManyAttemptsException.php',
|
834 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\LoginIntentRequestCapture' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentRequestCapture.php',
|
src/lib/vendor/composer/autoload_static.php
CHANGED
@@ -1021,9 +1021,9 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
1021 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\CooldownFlagFile' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/CooldownFlagFile.php',
|
1022 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\Rename\\RenameLogin' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/Rename/RenameLogin.php',
|
1023 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\CouldNotValidate2FA' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/CouldNotValidate2FA.php',
|
|
|
1024 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\LoginCancelException' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/LoginCancelException.php',
|
1025 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\NoActiveProvidersForUserException' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/NoActiveProvidersForUserException.php',
|
1026 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\NoLoginIntentForUserException' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/NoLoginIntentForUserException.php',
|
1027 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\NotValidUserException' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/NotValidUserException.php',
|
1028 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\TooManyAttemptsException' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/TooManyAttemptsException.php',
|
1029 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\LoginIntentRequestCapture' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentRequestCapture.php',
|
1021 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\CooldownFlagFile' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/CooldownFlagFile.php',
|
1022 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\Rename\\RenameLogin' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/Rename/RenameLogin.php',
|
1023 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\CouldNotValidate2FA' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/CouldNotValidate2FA.php',
|
1024 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\InvalidLoginIntentException' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/InvalidLoginIntentException.php',
|
1025 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\LoginCancelException' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/LoginCancelException.php',
|
1026 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\NoActiveProvidersForUserException' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/NoActiveProvidersForUserException.php',
|
|
|
1027 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\NotValidUserException' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/NotValidUserException.php',
|
1028 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Exceptions\\TooManyAttemptsException' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Exceptions/TooManyAttemptsException.php',
|
1029 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\LoginIntentRequestCapture' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentRequestCapture.php',
|
src/lib/vendor/composer/installed.json
CHANGED
@@ -288,17 +288,17 @@
|
|
288 |
},
|
289 |
{
|
290 |
"name": "fernleafsystems/wordpress-services",
|
291 |
-
"version": "2.30.
|
292 |
-
"version_normalized": "2.30.
|
293 |
"source": {
|
294 |
"type": "git",
|
295 |
"url": "git@gitlab.com:fernleafsystems/wordpress/wordpress-services.git",
|
296 |
-
"reference": "
|
297 |
},
|
298 |
"dist": {
|
299 |
"type": "zip",
|
300 |
-
"url": "https://gitlab.com/api/v4/projects/fernleafsystems%2Fwordpress%2Fwordpress-services/repository/archive.zip?sha=
|
301 |
-
"reference": "
|
302 |
"shasum": ""
|
303 |
},
|
304 |
"require": {
|
@@ -317,7 +317,7 @@
|
|
317 |
"symfony/yaml": "~3.0",
|
318 |
"twig/twig": "^1.42"
|
319 |
},
|
320 |
-
"time": "2022-09-
|
321 |
"type": "library",
|
322 |
"installation-source": "dist",
|
323 |
"autoload": {
|
288 |
},
|
289 |
{
|
290 |
"name": "fernleafsystems/wordpress-services",
|
291 |
+
"version": "2.30.3",
|
292 |
+
"version_normalized": "2.30.3.0",
|
293 |
"source": {
|
294 |
"type": "git",
|
295 |
"url": "git@gitlab.com:fernleafsystems/wordpress/wordpress-services.git",
|
296 |
+
"reference": "34e9e70321792811571efa0dea1ccf422484f3e9"
|
297 |
},
|
298 |
"dist": {
|
299 |
"type": "zip",
|
300 |
+
"url": "https://gitlab.com/api/v4/projects/fernleafsystems%2Fwordpress%2Fwordpress-services/repository/archive.zip?sha=34e9e70321792811571efa0dea1ccf422484f3e9",
|
301 |
+
"reference": "34e9e70321792811571efa0dea1ccf422484f3e9",
|
302 |
"shasum": ""
|
303 |
},
|
304 |
"require": {
|
317 |
"symfony/yaml": "~3.0",
|
318 |
"twig/twig": "^1.42"
|
319 |
},
|
320 |
+
"time": "2022-09-13T09:24:49+00:00",
|
321 |
"type": "library",
|
322 |
"installation-source": "dist",
|
323 |
"autoload": {
|
src/lib/vendor/composer/installed.php
CHANGED
@@ -1,11 +1,11 @@
|
|
1 |
<?php return array(
|
2 |
'root' => array(
|
3 |
-
'pretty_version' => 'dev-
|
4 |
-
'version' => 'dev-
|
5 |
'type' => 'library',
|
6 |
'install_path' => __DIR__ . '/../../',
|
7 |
'aliases' => array(),
|
8 |
-
'reference' => '
|
9 |
'name' => 'apto-shield/requirements',
|
10 |
'dev' => true,
|
11 |
),
|
@@ -20,12 +20,12 @@
|
|
20 |
'dev_requirement' => false,
|
21 |
),
|
22 |
'apto-shield/requirements' => array(
|
23 |
-
'pretty_version' => 'dev-
|
24 |
-
'version' => 'dev-
|
25 |
'type' => 'library',
|
26 |
'install_path' => __DIR__ . '/../../',
|
27 |
'aliases' => array(),
|
28 |
-
'reference' => '
|
29 |
'dev_requirement' => false,
|
30 |
),
|
31 |
'christian-riesen/base32' => array(
|
@@ -74,12 +74,12 @@
|
|
74 |
'dev_requirement' => false,
|
75 |
),
|
76 |
'fernleafsystems/wordpress-services' => array(
|
77 |
-
'pretty_version' => '2.30.
|
78 |
-
'version' => '2.30.
|
79 |
'type' => 'library',
|
80 |
'install_path' => __DIR__ . '/../fernleafsystems/wordpress-services',
|
81 |
'aliases' => array(),
|
82 |
-
'reference' => '
|
83 |
'dev_requirement' => false,
|
84 |
),
|
85 |
'fernleafsystems/zxcvbn-php' => array(
|
1 |
<?php return array(
|
2 |
'root' => array(
|
3 |
+
'pretty_version' => 'dev-master',
|
4 |
+
'version' => 'dev-master',
|
5 |
'type' => 'library',
|
6 |
'install_path' => __DIR__ . '/../../',
|
7 |
'aliases' => array(),
|
8 |
+
'reference' => '2ec6ed3be8e4285ee1e10f6afafd8f4b3e4d2402',
|
9 |
'name' => 'apto-shield/requirements',
|
10 |
'dev' => true,
|
11 |
),
|
20 |
'dev_requirement' => false,
|
21 |
),
|
22 |
'apto-shield/requirements' => array(
|
23 |
+
'pretty_version' => 'dev-master',
|
24 |
+
'version' => 'dev-master',
|
25 |
'type' => 'library',
|
26 |
'install_path' => __DIR__ . '/../../',
|
27 |
'aliases' => array(),
|
28 |
+
'reference' => '2ec6ed3be8e4285ee1e10f6afafd8f4b3e4d2402',
|
29 |
'dev_requirement' => false,
|
30 |
),
|
31 |
'christian-riesen/base32' => array(
|
74 |
'dev_requirement' => false,
|
75 |
),
|
76 |
'fernleafsystems/wordpress-services' => array(
|
77 |
+
'pretty_version' => '2.30.3',
|
78 |
+
'version' => '2.30.3.0',
|
79 |
'type' => 'library',
|
80 |
'install_path' => __DIR__ . '/../fernleafsystems/wordpress-services',
|
81 |
'aliases' => array(),
|
82 |
+
'reference' => '34e9e70321792811571efa0dea1ccf422484f3e9',
|
83 |
'dev_requirement' => false,
|
84 |
),
|
85 |
'fernleafsystems/zxcvbn-php' => array(
|
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/IpUtils.php
CHANGED
@@ -37,10 +37,12 @@ class IpUtils {
|
|
37 |
else {
|
38 |
foreach ( $ipsOrRanges as $ipOrRangeHaystack ) {
|
39 |
$range = Factory::parseRangeString( $ipOrRangeHaystack );
|
40 |
-
if ( empty( $range )
|
41 |
-
|
|
|
|
|
42 |
}
|
43 |
-
|
44 |
$in = true;
|
45 |
break;
|
46 |
}
|
37 |
else {
|
38 |
foreach ( $ipsOrRanges as $ipOrRangeHaystack ) {
|
39 |
$range = Factory::parseRangeString( $ipOrRangeHaystack );
|
40 |
+
if ( empty( $range ) ) {
|
41 |
+
if ( $throwException ) {
|
42 |
+
throw new NotAnIpAddressOrRangeException( $ipOrRangeHaystack );
|
43 |
+
}
|
44 |
}
|
45 |
+
elseif ( $range->containsRange( $IP ) ) {
|
46 |
$in = true;
|
47 |
break;
|
48 |
}
|
templates/twig/wpadmin_pages/base.twig
CHANGED
@@ -18,8 +18,7 @@
|
|
18 |
<div class="row">
|
19 |
|
20 |
{% if flags.show_sidebar_nav|default(true) %}
|
21 |
-
<div id="apto-PageMainSide"
|
22 |
-
class="col-2 col-lg-1">
|
23 |
{% block page_main_side %}
|
24 |
{% include '/wpadmin_pages/components/page/nav_sidebar.twig' %}
|
25 |
{% endblock %}
|
18 |
<div class="row">
|
19 |
|
20 |
{% if flags.show_sidebar_nav|default(true) %}
|
21 |
+
<div id="apto-PageMainSide" class="col-2 col-lg-1">
|
|
|
22 |
{% block page_main_side %}
|
23 |
{% include '/wpadmin_pages/components/page/nav_sidebar.twig' %}
|
24 |
{% endblock %}
|
templates/twig/wpadmin_pages/components/page/nav_sidebar.twig
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
<div id="NavSideBar">
|
2 |
|
3 |
<ul class="nav top-level-nav flex-column accordion" id="ShieldCollapseNav">
|
|
|
4 |
{% for mitem in vars.navbar_menu %}
|
5 |
|
6 |
<li class="nav-item pb-2{% if mitem.sub_items|default([]) is not empty %} with-submenu{% endif %}"
|
@@ -42,7 +43,8 @@
|
|
42 |
</a>
|
43 |
|
44 |
{% if mitem.sub_items|default([]) is not empty %}
|
45 |
-
<div class="subnava-menu accordion-collapse {{ mitem.active|default(false) ? 'show':'collapse' }}"
|
|
|
46 |
data-bs-parent="#ShieldCollapseNav"
|
47 |
>
|
48 |
<ul class="nav flex-column pt-0 primary_side_sub_menu px-0 py-2">
|
@@ -64,4 +66,11 @@
|
|
64 |
|
65 |
{% endfor %}
|
66 |
</ul>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
</div>
|
1 |
<div id="NavSideBar">
|
2 |
|
3 |
<ul class="nav top-level-nav flex-column accordion" id="ShieldCollapseNav">
|
4 |
+
|
5 |
{% for mitem in vars.navbar_menu %}
|
6 |
|
7 |
<li class="nav-item pb-2{% if mitem.sub_items|default([]) is not empty %} with-submenu{% endif %}"
|
43 |
</a>
|
44 |
|
45 |
{% if mitem.sub_items|default([]) is not empty %}
|
46 |
+
<div class="subnava-menu accordion-collapse {{ mitem.active|default(false) ? 'show':'collapse' }}"
|
47 |
+
id="subnav-{{ mitem.slug }}"
|
48 |
data-bs-parent="#ShieldCollapseNav"
|
49 |
>
|
50 |
<ul class="nav flex-column pt-0 primary_side_sub_menu px-0 py-2">
|
66 |
|
67 |
{% endfor %}
|
68 |
</ul>
|
69 |
+
|
70 |
+
{% if not flags.is_whitelabelled %}
|
71 |
+
<div class="text-muted py-1 px-2"
|
72 |
+
style="position:fixed; bottom:10px;background: #e9e9e9;">
|
73 |
+
{{ strings.running_version|raw }}
|
74 |
+
</div>
|
75 |
+
{% endif %}
|
76 |
</div>
|