Version Description
- Custom Apps functionality implemented. More details: https://limitloginattempts.com/app/
Download this release
Release Info
Developer | wpchefgadget |
Plugin | Limit Login Attempts Reloaded |
Version | 2.16.0 |
Comparing to | |
See all releases |
Code changes from version 2.15.2 to 2.16.0
- assets/css/limit-login-attempts.css +1 -1
- assets/js/limit-login-attempts.js +51 -0
- assets/sass/limit-login-attempts.scss +261 -0
- core/App.php +259 -0
- core/LimitLoginAttempts.php +839 -286
- limit-login-attempts-reloaded.php +5 -4
- readme.txt +55 -13
- views/options-page.php +21 -6
- views/tab-logs-custom.php +414 -0
- views/{tab-dashboard.php → tab-logs-local.php} +3 -3
- views/tab-settings.php +179 -13
assets/css/limit-login-attempts.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
.limit-login-page-settings .field-col{display:inline-block;margin-right:20px}.limit-login-page-settings .limit-login-log table{background-color:#fff}.limit-login-page-settings .limit-login-log table th,.limit-login-page-settings .limit-login-log table td{padding:10px}.limit-login-page-settings .limit-login-log table tr:nth-child(even){background-color:rgba(0,0,0,0.09)}.limit-login-page-settings input[name="admin_notify_email"]{min-width:243px}.llar-notice-review{display:-webkit-box;display:-ms-flexbox;display:flex;padding:15px 20px 0 !important;border-left:4px solid #333 !important}.llar-notice-review .llar-review-image img{margin-top:10px}.llar-notice-review .llar-review-info{-webkit-box-flex:1;-ms-flex:1;flex:1;margin-left:30px}.llar-notice-review .llar-review-info .llar-buttons{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.llar-notice-review .llar-review-info .llar-buttons li{margin-right:10px}.llar-notice-review .llar-review-info .llar-buttons li .dashicons{margin-right:5px}.llar-accordion .ui-accordion-header{font-weight:bold;background-color:#778899;color:#fff}.llar-accordion .ui-accordion-header.ui-accordion-header-active{background-color:#87CEFA}
|
1 |
+
.limit-login-page-settings .field-col{display:inline-block;margin-right:20px}.limit-login-page-settings .limit-login-log table{background-color:#fff}.limit-login-page-settings .limit-login-log table th,.limit-login-page-settings .limit-login-log table td{padding:10px}.limit-login-page-settings .limit-login-log table tr:nth-child(even){background-color:rgba(0,0,0,0.09)}.limit-login-page-settings #limit-login-app-setup-link{width:85%}.limit-login-page-settings .nav-tab-wrapper{position:relative}.limit-login-page-settings .nav-tab-wrapper .llar-failover-link{font-size:14px;float:right;line-height:2}.limit-login-page-settings .limit-login-app-dashboard .llar-table-scroll-wrap{max-height:400px;overflow-y:auto}.limit-login-page-settings .limit-login-app-dashboard .form-table{background-color:#fff;border:1px solid #f4f4f4;border-top:3px solid #3c8dbc;position:relative}.limit-login-page-settings .limit-login-app-dashboard .form-table.llar-preloader:before{content:"";display:block;width:100%;height:100%;background-color:rgba(255,255,255,0.7);z-index:999;position:absolute;top:0;left:0}.limit-login-page-settings .limit-login-app-dashboard .form-table th{font-weight:bold;border-bottom:1px solid #dbdbdb !important}.limit-login-page-settings .limit-login-app-dashboard .form-table th,.limit-login-page-settings .limit-login-app-dashboard .form-table td{padding:10px;border:1px solid #b9b9b9}.limit-login-page-settings .limit-login-app-dashboard .form-table th.llar-col-nowrap,.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-col-nowrap{white-space:nowrap}.limit-login-page-settings .limit-login-app-dashboard .form-table td button{line-height:1;margin-right:5px}.limit-login-page-settings .limit-login-app-dashboard .form-table td button:last-child{margin-right:0}.limit-login-page-settings .limit-login-app-dashboard .form-table td button .dashicons{vertical-align:middle}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions{text-align:center}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn{display:inline-block;line-height:20px;cursor:pointer}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn i{vertical-align:middle}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn:hover i{color:#3c8dbc}.limit-login-page-settings .limit-login-app-dashboard .form-table tr:nth-child(even){background-color:#f9f9f9}.limit-login-page-settings .limit-login-app-dashboard .llar-app-log-pagination>a{font-size:16px;line-height:1.625}.limit-login-page-settings .limit-login-app-dashboard .llar-app-log-pagination .spinner{float:none}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col{-webkit-box-flex:0;-ms-flex:0 0 49%;flex:0 0 49%}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table select{width:100%}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-acl-action-col{text-align:center}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-pass{background-color:#cffbe8}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-allow{background-color:#abdfff}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-deny{background-color:#fd2c2c3d}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-acl-remove{color:crimson;border-color:crimson}.limit-login-page-settings .llar-app-notice{background-color:#fff;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);padding:15px;border-radius:3px;margin-top:20px;margin-bottom:20px;font-size:14px;border-left:5px solid #ffba00}.limit-login-page-settings .llar-app-notice.success{border-color:#46b450}.limit-login-page-settings .llar-app-notice p{font-size:inherit;margin:0 0 20px}.limit-login-page-settings .llar-app-notice p:last-child{margin-bottom:0}.limit-login-page-settings input[name="admin_notify_email"]{min-width:243px}.limit-login-page-settings .llar-protect-notice{font-size:15px;color:#848484;margin-left:10px}.limit-login-page-settings .llar-protect-notice a{color:#222222;text-decoration:none;border-bottom:1px dashed}.limit-login-page-settings .llar-show-app-fields{position:absolute;right:15px;top:15px;color:#bdbdbd}.limit-login-page-settings .llar-show-app-fields:hover{color:#222}.limit-login-page-settings .llar-app-field{display:none}.limit-login-page-settings .llar-app-field.active{display:table-row}.llar-notice-review{display:-webkit-box;display:-ms-flexbox;display:flex;padding:15px 20px 0 !important;border-left:4px solid #333 !important}.llar-notice-review .llar-review-image img{margin-top:10px}.llar-notice-review .llar-review-info{-webkit-box-flex:1;-ms-flex:1;flex:1;margin-left:30px}.llar-notice-review .llar-review-info .llar-buttons{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.llar-notice-review .llar-review-info .llar-buttons li{margin-right:10px}.llar-notice-review .llar-review-info .llar-buttons li .dashicons{margin-right:5px}.llar-accordion .ui-accordion-header{font-weight:bold;background-color:#778899;color:#fff}.llar-accordion .ui-accordion-header.ui-accordion-header-active{background-color:#87CEFA}.custom-app-tab{position:relative}.custom-app-tab .spinner{float:none}.custom-app-tab .llar-app-ajax-msg{font-size:13px;margin-top:5px;display:block}.custom-app-tab .llar-app-ajax-msg.error{color:red}.custom-app-tab .llar-app-ajax-msg.success{color:green}.custom-app-tab .llar-delete-app{color:#dc3232;position:absolute;bottom:15px;right:15px}.custom-app-tab .llar-delete-app:hover{opacity:0.8}.custom-app-tab .llar-why-use-premium-text{margin-top:20px}.custom-app-tab .llar-why-use-premium-text .title{font-weight:bold;font-size:16px;color:#4d4d4d}.custom-app-tab .llar-why-use-premium-text ul li .dashicons{color:#3ab54a;font-size:25px;width:25px;top:-2px;position:relative}#llar-progress-bar{position:fixed;top:0;height:6px;left:0;width:100%;z-index:999999;background-color:#eee}#llar-progress-bar span{height:100%;position:absolute;display:block;width:0;background-color:#00b357;-webkit-transition:width 0.4s;transition:width 0.4s}
|
assets/js/limit-login-attempts.js
CHANGED
@@ -1,6 +1,57 @@
|
|
1 |
;(function($){
|
2 |
"use strict";
|
3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
$(document).ready(function(){
|
5 |
|
6 |
});
|
1 |
;(function($){
|
2 |
"use strict";
|
3 |
|
4 |
+
window.llar = {
|
5 |
+
progressbar: {
|
6 |
+
timeouts: [],
|
7 |
+
$bar: null,
|
8 |
+
$fill: null,
|
9 |
+
start: function() {
|
10 |
+
|
11 |
+
if($('body').find('#llar-progress-bar').length) {
|
12 |
+
|
13 |
+
this.$bar = $('body').find('#llar-progress-bar');
|
14 |
+
|
15 |
+
} else {
|
16 |
+
|
17 |
+
this.$bar = $('<div id="llar-progress-bar"><span></span></div>');
|
18 |
+
|
19 |
+
$('body').prepend(this.$bar);
|
20 |
+
}
|
21 |
+
|
22 |
+
this.clearTimeouts();
|
23 |
+
|
24 |
+
this.$fill = this.$bar.find('span');
|
25 |
+
|
26 |
+
this.timeouts.push(setTimeout(function(){llar.progressbar.percent(35);}, 100));
|
27 |
+
this.timeouts.push(setTimeout(function(){llar.progressbar.percent(60);}, 800));
|
28 |
+
this.timeouts.push(setTimeout(function(){llar.progressbar.percent(75);}, 1400));
|
29 |
+
this.timeouts.push(setTimeout(function(){llar.progressbar.percent(80);}, 1800));
|
30 |
+
this.timeouts.push(setTimeout(function(){llar.progressbar.percent(85);}, 2200));
|
31 |
+
this.timeouts.push(setTimeout(function(){llar.progressbar.percent(95);}, 2600));
|
32 |
+
|
33 |
+
},
|
34 |
+
percent: function(val) {
|
35 |
+
this.$fill.css('width', val + '%');
|
36 |
+
},
|
37 |
+
clearTimeouts: function() {
|
38 |
+
this.timeouts.forEach(function (t) {
|
39 |
+
clearTimeout(t);
|
40 |
+
});
|
41 |
+
},
|
42 |
+
stop: function() {
|
43 |
+
|
44 |
+
this.clearTimeouts();
|
45 |
+
|
46 |
+
this.percent(100);
|
47 |
+
|
48 |
+
setTimeout(function () {
|
49 |
+
llar.progressbar.$bar.remove();
|
50 |
+
}, 500);
|
51 |
+
}
|
52 |
+
}
|
53 |
+
};
|
54 |
+
|
55 |
$(document).ready(function(){
|
56 |
|
57 |
});
|
assets/sass/limit-login-attempts.scss
CHANGED
@@ -15,9 +15,202 @@
|
|
15 |
}
|
16 |
}
|
17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
input[name="admin_notify_email"] {
|
19 |
min-width: 243px;
|
20 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
}
|
22 |
|
23 |
.llar-notice-review {
|
@@ -59,4 +252,72 @@
|
|
59 |
background-color: #87CEFA;
|
60 |
}
|
61 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
}
|
15 |
}
|
16 |
}
|
17 |
|
18 |
+
#limit-login-app-setup-link {
|
19 |
+
width: 85%;
|
20 |
+
}
|
21 |
+
|
22 |
+
.nav-tab-wrapper {
|
23 |
+
position: relative;
|
24 |
+
|
25 |
+
.llar-failover-link {
|
26 |
+
font-size: 14px;
|
27 |
+
float: right;
|
28 |
+
line-height: 2;
|
29 |
+
}
|
30 |
+
}
|
31 |
+
|
32 |
+
.limit-login-app-dashboard {
|
33 |
+
.llar-table-scroll-wrap {
|
34 |
+
max-height: 400px;
|
35 |
+
overflow-y: auto;
|
36 |
+
}
|
37 |
+
|
38 |
+
.form-table {
|
39 |
+
background-color: #fff;
|
40 |
+
border: 1px solid #f4f4f4;
|
41 |
+
border-top: 3px solid #3c8dbc;
|
42 |
+
position: relative;
|
43 |
+
|
44 |
+
&.llar-preloader {
|
45 |
+
&:before {
|
46 |
+
content: "";
|
47 |
+
display: block;
|
48 |
+
width: 100%;
|
49 |
+
height: 100%;
|
50 |
+
background-color: rgba(255,255,255,0.7);
|
51 |
+
z-index: 999;
|
52 |
+
position: absolute;
|
53 |
+
top: 0;
|
54 |
+
left: 0;
|
55 |
+
}
|
56 |
+
}
|
57 |
+
|
58 |
+
th {
|
59 |
+
//color: #3c8dbc;
|
60 |
+
font-weight: bold;
|
61 |
+
border-bottom: 1px solid #dbdbdb !important;
|
62 |
+
}
|
63 |
+
th, td {
|
64 |
+
padding: 10px;
|
65 |
+
border: 1px solid #b9b9b9;
|
66 |
+
|
67 |
+
&.llar-col-nowrap {
|
68 |
+
white-space: nowrap;
|
69 |
+
}
|
70 |
+
}
|
71 |
+
td {
|
72 |
+
button {
|
73 |
+
line-height: 1;
|
74 |
+
margin-right: 5px;
|
75 |
+
|
76 |
+
&:last-child {
|
77 |
+
margin-right: 0;
|
78 |
+
}
|
79 |
+
|
80 |
+
.dashicons {
|
81 |
+
vertical-align: middle;
|
82 |
+
}
|
83 |
+
}
|
84 |
+
&.llar-app-log-actions {
|
85 |
+
text-align: center;
|
86 |
+
|
87 |
+
.llar-app-log-action-btn {
|
88 |
+
display: inline-block;
|
89 |
+
line-height: 20px;
|
90 |
+
cursor: pointer;
|
91 |
+
|
92 |
+
i {
|
93 |
+
vertical-align: middle;
|
94 |
+
}
|
95 |
+
|
96 |
+
&:hover {
|
97 |
+
i {
|
98 |
+
color: #3c8dbc;
|
99 |
+
}
|
100 |
+
}
|
101 |
+
}
|
102 |
+
|
103 |
+
}
|
104 |
+
}
|
105 |
+
tr:nth-child(even) {
|
106 |
+
background-color: #f9f9f9;
|
107 |
+
}
|
108 |
+
}
|
109 |
+
.llar-app-log-pagination {
|
110 |
+
> a {
|
111 |
+
font-size: 16px;
|
112 |
+
line-height: 1.625;
|
113 |
+
}
|
114 |
+
.spinner {
|
115 |
+
float: none;
|
116 |
+
}
|
117 |
+
}
|
118 |
+
.llar-app-acl-rules {
|
119 |
+
display: flex;
|
120 |
+
justify-content: space-between;
|
121 |
+
|
122 |
+
.app-rules-col {
|
123 |
+
flex: 0 0 49%;
|
124 |
+
|
125 |
+
.form-table {
|
126 |
+
select {
|
127 |
+
width: 100%;
|
128 |
+
}
|
129 |
+
|
130 |
+
.llar-app-acl-action-col {
|
131 |
+
text-align: center;
|
132 |
+
}
|
133 |
+
|
134 |
+
.llar-app-rule-pass {
|
135 |
+
background-color: #cffbe8;
|
136 |
+
}
|
137 |
+
.llar-app-rule-allow {
|
138 |
+
background-color: #abdfff;
|
139 |
+
}
|
140 |
+
.llar-app-rule-deny {
|
141 |
+
background-color: #fd2c2c3d;
|
142 |
+
}
|
143 |
+
.llar-app-acl-remove {
|
144 |
+
color: crimson;
|
145 |
+
border-color: crimson;
|
146 |
+
}
|
147 |
+
}
|
148 |
+
}
|
149 |
+
}
|
150 |
+
}
|
151 |
+
|
152 |
+
.llar-app-notice {
|
153 |
+
background-color: #fff;
|
154 |
+
box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
|
155 |
+
padding: 15px;
|
156 |
+
border-radius: 3px;
|
157 |
+
margin-top: 20px;
|
158 |
+
margin-bottom: 20px;
|
159 |
+
font-size: 14px;
|
160 |
+
border-left: 5px solid #ffba00;
|
161 |
+
|
162 |
+
&.success {
|
163 |
+
border-color: #46b450;
|
164 |
+
}
|
165 |
+
|
166 |
+
p {
|
167 |
+
font-size: inherit;
|
168 |
+
margin: 0 0 20px;
|
169 |
+
|
170 |
+
&:last-child {
|
171 |
+
margin-bottom: 0;
|
172 |
+
}
|
173 |
+
}
|
174 |
+
}
|
175 |
+
|
176 |
input[name="admin_notify_email"] {
|
177 |
min-width: 243px;
|
178 |
}
|
179 |
+
|
180 |
+
.llar-protect-notice {
|
181 |
+
font-size: 15px;
|
182 |
+
color: #848484;
|
183 |
+
margin-left: 10px;
|
184 |
+
|
185 |
+
a {
|
186 |
+
color: #222222;
|
187 |
+
//text-decoration-style: dotted;
|
188 |
+
//text-underline-offset: 3px;
|
189 |
+
text-decoration: none;
|
190 |
+
border-bottom: 1px dashed;
|
191 |
+
}
|
192 |
+
}
|
193 |
+
|
194 |
+
|
195 |
+
|
196 |
+
.llar-show-app-fields {
|
197 |
+
position: absolute;
|
198 |
+
right: 15px;
|
199 |
+
top: 15px;
|
200 |
+
color: #bdbdbd;
|
201 |
+
|
202 |
+
&:hover {
|
203 |
+
color: #222;
|
204 |
+
}
|
205 |
+
}
|
206 |
+
|
207 |
+
.llar-app-field {
|
208 |
+
display: none;
|
209 |
+
|
210 |
+
&.active {
|
211 |
+
display: table-row;
|
212 |
+
}
|
213 |
+
}
|
214 |
}
|
215 |
|
216 |
.llar-notice-review {
|
252 |
background-color: #87CEFA;
|
253 |
}
|
254 |
}
|
255 |
+
}
|
256 |
+
|
257 |
+
.custom-app-tab {
|
258 |
+
position: relative;
|
259 |
+
.spinner {
|
260 |
+
float: none;
|
261 |
+
}
|
262 |
+
.llar-app-ajax-msg {
|
263 |
+
font-size: 13px;
|
264 |
+
margin-top: 5px;
|
265 |
+
display: block;
|
266 |
+
|
267 |
+
&.error {
|
268 |
+
color: red;
|
269 |
+
}
|
270 |
+
&.success {
|
271 |
+
color: green;
|
272 |
+
}
|
273 |
+
}
|
274 |
+
.llar-delete-app {
|
275 |
+
color: #dc3232;
|
276 |
+
position: absolute;
|
277 |
+
bottom: 15px;
|
278 |
+
right: 15px;
|
279 |
+
|
280 |
+
&:hover {
|
281 |
+
opacity: 0.8;
|
282 |
+
}
|
283 |
+
}
|
284 |
+
.llar-why-use-premium-text {
|
285 |
+
margin-top: 20px;
|
286 |
+
|
287 |
+
.title {
|
288 |
+
font-weight: bold;
|
289 |
+
font-size: 16px;
|
290 |
+
color: #4d4d4d;
|
291 |
+
}
|
292 |
+
ul {
|
293 |
+
li {
|
294 |
+
.dashicons {
|
295 |
+
color: #3ab54a;
|
296 |
+
font-size: 25px;
|
297 |
+
width: 25px;
|
298 |
+
top: -2px;
|
299 |
+
position: relative;
|
300 |
+
}
|
301 |
+
}
|
302 |
+
}
|
303 |
+
}
|
304 |
+
}
|
305 |
+
|
306 |
+
#llar-progress-bar {
|
307 |
+
position: fixed;
|
308 |
+
top: 0;
|
309 |
+
height: 6px;
|
310 |
+
left: 0;
|
311 |
+
width: 100%;
|
312 |
+
z-index: 999999;
|
313 |
+
background-color: #eee;
|
314 |
+
|
315 |
+
span {
|
316 |
+
height: 100%;
|
317 |
+
position: absolute;
|
318 |
+
display: block;
|
319 |
+
width: 0;
|
320 |
+
background-color: #00b357;
|
321 |
+
transition: width 0.4s;
|
322 |
+
}
|
323 |
}
|
core/App.php
ADDED
@@ -0,0 +1,259 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class LLAR_App {
|
4 |
+
|
5 |
+
/**
|
6 |
+
* @var null|string
|
7 |
+
*/
|
8 |
+
private $id = null;
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @var mixed|string
|
12 |
+
*/
|
13 |
+
private $endpoint = '';
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @var array
|
17 |
+
*/
|
18 |
+
private $config = array();
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @var array
|
22 |
+
*/
|
23 |
+
private $login_errors = array();
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @var null
|
27 |
+
*/
|
28 |
+
public $last_response_code = null;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* LLAR_App constructor.
|
32 |
+
* @param array $config
|
33 |
+
*/
|
34 |
+
public function __construct( array $config ) {
|
35 |
+
|
36 |
+
if( empty( $config ) ) {
|
37 |
+
return false;
|
38 |
+
}
|
39 |
+
|
40 |
+
$this->id = 'app_' . $config['id'];
|
41 |
+
$this->api = $config['api'];
|
42 |
+
$this->config = $config;
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @param $error
|
47 |
+
* @return bool
|
48 |
+
*/
|
49 |
+
public function add_error( $error ) {
|
50 |
+
|
51 |
+
if( !$error ) return false;
|
52 |
+
|
53 |
+
$this->login_errors[] = $error;
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* @return array
|
58 |
+
*/
|
59 |
+
public function get_errors() {
|
60 |
+
|
61 |
+
return $this->login_errors;
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* @return null|string
|
66 |
+
*/
|
67 |
+
public function get_id() {
|
68 |
+
return $this->id;
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* @return array
|
73 |
+
*/
|
74 |
+
public function get_config() {
|
75 |
+
return $this->config;
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* @param $link
|
80 |
+
* @return false[]
|
81 |
+
*/
|
82 |
+
public static function setup( $link ) {
|
83 |
+
|
84 |
+
$return = array(
|
85 |
+
'success' => false,
|
86 |
+
);
|
87 |
+
|
88 |
+
if( empty( $link ) ) {
|
89 |
+
|
90 |
+
return $return;
|
91 |
+
}
|
92 |
+
|
93 |
+
$link = add_query_arg( 'domain', $_SERVER['SERVER_NAME'], $link );
|
94 |
+
|
95 |
+
$plugin_data = get_plugin_data( LLA_PLUGIN_DIR . '/limit-login-attempts-reloaded.php' );
|
96 |
+
$link = add_query_arg( 'version', $plugin_data['Version'], $link );
|
97 |
+
|
98 |
+
$setup_response = wp_remote_get( $link );
|
99 |
+
$setup_response_body = json_decode( wp_remote_retrieve_body( $setup_response ), true );
|
100 |
+
|
101 |
+
if( is_wp_error( $setup_response ) ) {
|
102 |
+
|
103 |
+
$return['error'] = $setup_response->get_error_message();
|
104 |
+
|
105 |
+
} else if( wp_remote_retrieve_response_code( $setup_response ) === 200 ) {
|
106 |
+
|
107 |
+
$return['success'] = true;
|
108 |
+
$return['app_config'] = $setup_response_body;
|
109 |
+
|
110 |
+
} else {
|
111 |
+
|
112 |
+
$return['error'] = ( !empty( $setup_response_body['message'] ) )
|
113 |
+
? $setup_response_body['message']
|
114 |
+
: __( 'The endpoint is not responding. Please contact your app provider to settle that.', 'limit-login-attempts-reloaded' );
|
115 |
+
$return['response_code'] = wp_remote_retrieve_response_code( $setup_response );
|
116 |
+
}
|
117 |
+
|
118 |
+
return $return;
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* @param $data
|
123 |
+
* @return bool|mixed
|
124 |
+
*/
|
125 |
+
public function acl_check( $data ) {
|
126 |
+
|
127 |
+
$this->prepare_settings( 'acl', $data );
|
128 |
+
|
129 |
+
return $this->request( 'acl', 'post', $data );
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* @param $data
|
134 |
+
* @return bool|mixed
|
135 |
+
*/
|
136 |
+
public function acl( $data ) {
|
137 |
+
|
138 |
+
return $this->request( 'acl', 'get', $data );
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* @param $data
|
143 |
+
* @return bool|mixed
|
144 |
+
*/
|
145 |
+
public function acl_create( $data ) {
|
146 |
+
|
147 |
+
return $this->request( 'acl/create', 'post', $data );
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* @param $data
|
152 |
+
* @return bool|mixed
|
153 |
+
*/
|
154 |
+
public function acl_delete( $data ) {
|
155 |
+
|
156 |
+
return $this->request( 'acl/delete', 'post', $data );
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* @param $data
|
161 |
+
* @return bool|mixed
|
162 |
+
*/
|
163 |
+
public function lockout_check( $data ) {
|
164 |
+
|
165 |
+
$this->prepare_settings( 'lockout', $data );
|
166 |
+
|
167 |
+
return $this->request( 'lockout', 'post', $data );
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* @param int $limit
|
172 |
+
* @param string $offset
|
173 |
+
* @return bool|mixed
|
174 |
+
*/
|
175 |
+
public function log($limit = 25, $offset = '') {
|
176 |
+
|
177 |
+
$data = array();
|
178 |
+
|
179 |
+
$data['limit'] = $limit;
|
180 |
+
$data['offset'] = $offset;
|
181 |
+
|
182 |
+
return $this->request( 'log', 'get', $data );
|
183 |
+
}
|
184 |
+
|
185 |
+
public function get_lockouts($limit = 25, $offset = '') {
|
186 |
+
|
187 |
+
$data = array();
|
188 |
+
|
189 |
+
$data['limit'] = $limit;
|
190 |
+
$data['offset'] = $offset;
|
191 |
+
|
192 |
+
return $this->request( 'lockout', 'get', $data );
|
193 |
+
}
|
194 |
+
|
195 |
+
/**
|
196 |
+
* Prepare settings for API request
|
197 |
+
*
|
198 |
+
* @param $method
|
199 |
+
*/
|
200 |
+
public function prepare_settings( $method, &$data ) {
|
201 |
+
|
202 |
+
$settings = array();
|
203 |
+
|
204 |
+
if( !empty( $this->config['settings'] ) ) {
|
205 |
+
|
206 |
+
foreach ( $this->config['settings'] as $setting_name => $setting_data ) {
|
207 |
+
|
208 |
+
if( in_array( $method, $setting_data['methods'] ) ) {
|
209 |
+
|
210 |
+
$settings[$setting_name] = $setting_data['value'];
|
211 |
+
}
|
212 |
+
}
|
213 |
+
}
|
214 |
+
|
215 |
+
if( $settings )
|
216 |
+
$data['settings'] = $settings;
|
217 |
+
}
|
218 |
+
|
219 |
+
/**
|
220 |
+
* @param $method
|
221 |
+
* @param string $type
|
222 |
+
* @param null $data
|
223 |
+
* @return bool|mixed
|
224 |
+
* @throws Exception
|
225 |
+
*/
|
226 |
+
public function request( $method, $type = 'get', $data = null ) {
|
227 |
+
|
228 |
+
if( !$method ) {
|
229 |
+
throw new Exception( 'You must to specify API method.' );
|
230 |
+
}
|
231 |
+
|
232 |
+
$headers = array();
|
233 |
+
$headers[$this->config['header']] = $this->config['key'];
|
234 |
+
|
235 |
+
if( $type === 'post' ) {
|
236 |
+
|
237 |
+
$headers['Content-Type'] = 'application/json; charset=utf-8';
|
238 |
+
}
|
239 |
+
|
240 |
+
$func = ( $type === 'post' ) ? 'wp_remote_post' : 'wp_remote_get';
|
241 |
+
|
242 |
+
$response = $func( $this->api.'/'.$method, array(
|
243 |
+
'headers' => $headers,
|
244 |
+
'body' => ( $type === 'post' ) ? json_encode( $data, JSON_FORCE_OBJECT ) : $data
|
245 |
+
));
|
246 |
+
|
247 |
+
$this->last_response_code = wp_remote_retrieve_response_code( $response );
|
248 |
+
|
249 |
+
if( is_wp_error( $response ) || $this->last_response_code !== 200 ) {
|
250 |
+
|
251 |
+
return false;
|
252 |
+
} else {
|
253 |
+
|
254 |
+
return json_decode( sanitize_textarea_field( stripslashes( wp_remote_retrieve_body( $response ) ) ), true );
|
255 |
+
}
|
256 |
+
|
257 |
+
}
|
258 |
+
|
259 |
+
}
|
core/LimitLoginAttempts.php
CHANGED
@@ -3,8 +3,8 @@
|
|
3 |
/**
|
4 |
* Class Limit_Login_Attempts
|
5 |
*/
|
6 |
-
class Limit_Login_Attempts
|
7 |
-
|
8 |
public $default_options = array(
|
9 |
'gdpr' => 0,
|
10 |
|
@@ -41,6 +41,9 @@ class Limit_Login_Attempts
|
|
41 |
'whitelist_usernames' => array(),
|
42 |
'blacklist' => array(),
|
43 |
'blacklist_usernames' => array(),
|
|
|
|
|
|
|
44 |
);
|
45 |
/**
|
46 |
* Admin options page slug
|
@@ -67,8 +70,16 @@ class Limit_Login_Attempts
|
|
67 |
*/
|
68 |
private $use_local_options = null;
|
69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
public function __construct() {
|
71 |
$this->hooks_init();
|
|
|
72 |
}
|
73 |
|
74 |
/**
|
@@ -85,6 +96,14 @@ class Limit_Login_Attempts
|
|
85 |
add_filter( 'illegal_user_logins', array( $this, 'register_user_blacklist' ), 999 );
|
86 |
add_action( 'admin_notices', array( $this, 'show_leave_review_notice' ) );
|
87 |
add_action( 'wp_ajax_dismiss_review_notice', array( $this, 'dismiss_review_notice_callback' ));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
|
89 |
add_action( 'admin_print_scripts-settings_page_limit-login-attempts', array( $this, 'load_admin_scripts' ) );
|
90 |
}
|
@@ -125,7 +144,6 @@ class Limit_Login_Attempts
|
|
125 |
add_filter( 'wp_authenticate_user', array( $this, 'wp_authenticate_user' ), 99999, 2 );
|
126 |
|
127 |
add_filter( 'shake_error_codes', array( $this, 'failure_shake' ) );
|
128 |
-
add_action( 'login_head', array( $this, 'add_error_message' ) );
|
129 |
add_action( 'login_errors', array( $this, 'fixup_error_messages' ) );
|
130 |
|
131 |
if ( $this->network_mode )
|
@@ -146,14 +164,28 @@ class Limit_Login_Attempts
|
|
146 |
* later versions of WP.
|
147 |
*/
|
148 |
add_action( 'wp_authenticate', array( $this, 'track_credentials' ), 10, 2 );
|
149 |
-
add_action( 'authenticate', array( $this, 'authenticate_filter' ),
|
|
|
|
|
|
|
|
|
|
|
150 |
|
151 |
if ( defined('XMLRPC_REQUEST') && XMLRPC_REQUEST )
|
152 |
add_action( 'init', array( $this, 'check_xmlrpc_lock' ) );
|
153 |
|
154 |
add_action('wp_ajax_limit-login-unlock', array( $this, 'ajax_unlock' ) );
|
|
|
155 |
}
|
156 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
157 |
public function load_admin_scripts() {
|
158 |
|
159 |
wp_enqueue_script('jquery-ui-accordion');
|
@@ -314,45 +346,125 @@ class Limit_Login_Attempts
|
|
314 |
|
315 |
if ( ! empty( $username ) && ! empty( $password ) ) {
|
316 |
|
317 |
-
|
|
|
|
|
|
|
|
|
318 |
|
319 |
-
|
320 |
-
}
|
321 |
|
322 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
323 |
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
|
|
|
|
|
|
328 |
|
329 |
-
|
330 |
-
remove_filter( 'login_head', array( $this, 'add_error_message' ) );
|
331 |
-
remove_filter( 'wp_login_failed', array( $this, 'limit_login_failed' ) );
|
332 |
-
remove_filter( 'wp_authenticate_user', array( $this, 'wp_authenticate_user' ), 99999 );
|
333 |
-
remove_filter( 'login_head', array( $this, 'add_error_message' ) );
|
334 |
-
remove_filter( 'login_errors', array( $this, 'fixup_error_messages' ) );
|
335 |
|
336 |
-
|
337 |
-
|
|
|
|
|
338 |
|
339 |
-
|
340 |
-
|
|
|
|
|
341 |
|
342 |
-
|
343 |
|
344 |
-
|
345 |
-
remove_filter( 'wp_authenticate_user', array( $this, 'wp_authenticate_user' ), 99999 );
|
346 |
-
remove_filter( 'login_head', array( $this, 'add_error_message' ) );
|
347 |
-
remove_filter( 'login_errors', array( $this, 'fixup_error_messages' ) );
|
348 |
|
349 |
-
|
|
|
|
|
|
|
350 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
351 |
}
|
352 |
|
353 |
return $user;
|
354 |
}
|
355 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
356 |
/**
|
357 |
* Check if the original plugin is installed
|
358 |
*/
|
@@ -372,6 +484,7 @@ class Limit_Login_Attempts
|
|
372 |
*/
|
373 |
public function enqueue() {
|
374 |
wp_enqueue_style( 'lla-main', LLA_PLUGIN_URL . 'assets/css/limit-login-attempts.css' );
|
|
|
375 |
}
|
376 |
|
377 |
/**
|
@@ -388,11 +501,12 @@ class Limit_Login_Attempts
|
|
388 |
}
|
389 |
|
390 |
/**
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
|
|
396 |
{
|
397 |
|
398 |
if ( is_network_admin() )
|
@@ -400,9 +514,9 @@ class Limit_Login_Attempts
|
|
400 |
else
|
401 |
$uri = menu_page_url( $this->_options_page_slug, false );
|
402 |
|
403 |
-
if(!empty($
|
404 |
|
405 |
-
$uri
|
406 |
}
|
407 |
|
408 |
return $uri;
|
@@ -455,6 +569,18 @@ class Limit_Login_Attempts
|
|
455 |
return $func( $option, $value, '', 'no' );
|
456 |
}
|
457 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
458 |
/**
|
459 |
* Setup main options
|
460 |
*/
|
@@ -519,98 +645,130 @@ class Limit_Login_Attempts
|
|
519 |
*/
|
520 |
public function limit_login_failed( $username ) {
|
521 |
|
522 |
-
$
|
523 |
-
|
|
|
|
|
|
|
524 |
|
525 |
-
|
526 |
-
$lockouts = $this->get_option( 'lockouts' );
|
527 |
|
528 |
-
|
529 |
-
|
530 |
-
|
|
|
531 |
|
532 |
-
|
533 |
-
|
534 |
-
}
|
535 |
|
536 |
-
|
537 |
-
$retries = $this->get_option( 'retries' );
|
538 |
-
$valid = $this->get_option( 'retries_valid' );
|
539 |
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
|
|
|
|
|
|
544 |
|
545 |
-
|
546 |
-
|
547 |
-
$this->add_option( 'retries_valid', $valid );
|
548 |
-
}
|
549 |
|
550 |
-
$gdpr = $this->get_option('gdpr');
|
551 |
-
$ip = ($gdpr ? $ipHash : $ip);
|
552 |
-
/* Check validity and add one to retries */
|
553 |
-
if ( isset( $retries[ $ip ] ) && isset( $valid[ $ip ] ) && time() < $valid[ $ip ]) {
|
554 |
-
$retries[ $ip ] ++;
|
555 |
} else {
|
556 |
-
$retries[ $ip ] = 1;
|
557 |
-
}
|
558 |
-
$valid[ $ip ] = time() + $this->get_option( 'valid_duration' );
|
559 |
|
560 |
-
|
561 |
-
|
562 |
-
/*
|
563 |
-
* Not lockout (yet!)
|
564 |
-
* Do housecleaning (which also saves retry/valid values).
|
565 |
-
*/
|
566 |
-
$this->cleanup( $retries, null, $valid );
|
567 |
|
568 |
-
|
569 |
-
|
570 |
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
|
575 |
-
|
576 |
-
|
577 |
-
* done as usual for whitelisted ips , but no lockout is done.
|
578 |
-
*/
|
579 |
-
if ( $whitelisted ) {
|
580 |
-
if ( $retries[ $ip ] >= $retries_long ) {
|
581 |
-
unset( $retries[ $ip ] );
|
582 |
-
unset( $valid[ $ip ] );
|
583 |
}
|
584 |
-
|
585 |
-
|
586 |
-
$
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
596 |
} else {
|
597 |
-
|
598 |
-
$lockouts[ $index ] = time() + $this->get_option( 'lockout_duration' );
|
599 |
}
|
600 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
601 |
|
602 |
-
|
603 |
-
|
604 |
|
605 |
-
|
606 |
-
|
|
|
607 |
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
614 |
}
|
615 |
}
|
616 |
|
@@ -760,15 +918,7 @@ class Limit_Login_Attempts
|
|
760 |
$log[ $index ][ $user_login ]['counter']++;
|
761 |
$log[ $index ][ $user_login ]['date'] = time();
|
762 |
|
763 |
-
|
764 |
-
$gateway = 'WooCommerce';
|
765 |
-
} elseif ( isset( $GLOBALS['wp_xmlrpc_server'] ) && is_object( $GLOBALS['wp_xmlrpc_server'] ) ) {
|
766 |
-
$gateway = 'XMLRPC';
|
767 |
-
} else {
|
768 |
-
$gateway = 'WP Login';
|
769 |
-
}
|
770 |
-
|
771 |
-
$log[ $index ][ $user_login ]['gateway'] = $gateway;
|
772 |
|
773 |
if ( $option === false ) {
|
774 |
$this->add_option( 'logged', $log );
|
@@ -777,6 +927,22 @@ class Limit_Login_Attempts
|
|
777 |
}
|
778 |
}
|
779 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
780 |
/**
|
781 |
* Check if IP is whitelisted.
|
782 |
*
|
@@ -850,6 +1016,10 @@ class Limit_Login_Attempts
|
|
850 |
*/
|
851 |
public function wp_authenticate_user( $user, $password ) {
|
852 |
|
|
|
|
|
|
|
|
|
853 |
$user_login = '';
|
854 |
|
855 |
if( is_a( $user, 'WP_User' ) ) {
|
@@ -858,8 +1028,7 @@ class Limit_Login_Attempts
|
|
858 |
$user_login = $user;
|
859 |
}
|
860 |
|
861 |
-
if (
|
862 |
-
$this->check_whitelist_ips( false, $this->get_address() ) ||
|
863 |
$this->check_whitelist_usernames( false, $user_login ) ||
|
864 |
$this->is_limit_login_ok()
|
865 |
) {
|
@@ -908,24 +1077,6 @@ class Limit_Login_Attempts
|
|
908 |
$limit_login_nonempty_credentials = ( ! empty( $user ) && ! empty( $password ) );
|
909 |
}
|
910 |
|
911 |
-
/**
|
912 |
-
* Should we show errors and messages on this page?
|
913 |
-
*
|
914 |
-
* @return bool
|
915 |
-
*/
|
916 |
-
public function login_show_msg() {
|
917 |
-
if ( isset( $_GET['key'] ) ) {
|
918 |
-
/* reset password */
|
919 |
-
return false;
|
920 |
-
}
|
921 |
-
|
922 |
-
$action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : '';
|
923 |
-
|
924 |
-
return ( $action != 'lostpassword' && $action != 'retrievepassword'
|
925 |
-
&& $action != 'resetpass' && $action != 'rp'
|
926 |
-
&& $action != 'register' );
|
927 |
-
}
|
928 |
-
|
929 |
/**
|
930 |
* Construct informative error message
|
931 |
*
|
@@ -991,45 +1142,19 @@ class Limit_Login_Attempts
|
|
991 |
public function fixup_error_messages( $content ) {
|
992 |
global $limit_login_just_lockedout, $limit_login_nonempty_credentials, $limit_login_my_error_shown;
|
993 |
|
994 |
-
|
995 |
-
return $content;
|
996 |
-
}
|
997 |
|
998 |
-
|
999 |
-
* During lockout we do not want to show any other error messages (like
|
1000 |
-
* unknown user or empty password).
|
1001 |
-
*/
|
1002 |
-
if ( ! $this->is_limit_login_ok() && ! $limit_login_just_lockedout ) {
|
1003 |
-
return $this->error_msg();
|
1004 |
-
}
|
1005 |
-
|
1006 |
-
/*
|
1007 |
-
* We want to filter the messages 'Invalid username' and
|
1008 |
-
* 'Invalid password' as that is an information leak regarding user
|
1009 |
-
* account names (prior to WP 2.9?).
|
1010 |
-
*
|
1011 |
-
* Also, if more than one error message, put an extra <br /> tag between
|
1012 |
-
* them.
|
1013 |
-
*/
|
1014 |
-
$msgs = explode( "<br />\n", $content );
|
1015 |
-
|
1016 |
-
if ( strlen( end( $msgs ) ) == 0 ) {
|
1017 |
-
/* remove last entry empty string */
|
1018 |
-
array_pop( $msgs );
|
1019 |
-
}
|
1020 |
|
1021 |
-
|
1022 |
-
$my_warn_count = $limit_login_my_error_shown ? 1 : 0;
|
1023 |
-
|
1024 |
-
if ( $limit_login_nonempty_credentials && $count > $my_warn_count ) {
|
1025 |
|
1026 |
if($this->other_login_errors) {
|
1027 |
|
1028 |
-
$content = '';
|
1029 |
foreach ($this->other_login_errors as $msg) {
|
1030 |
$content .= $msg . "<br />\n";
|
1031 |
}
|
1032 |
-
|
|
|
1033 |
|
1034 |
/* Replace error message, including ours if necessary */
|
1035 |
if( !empty( $_REQUEST['log'] ) && is_email( $_REQUEST['log'] ) ) {
|
@@ -1039,24 +1164,14 @@ class Limit_Login_Attempts
|
|
1039 |
}
|
1040 |
}
|
1041 |
|
1042 |
-
if ( $
|
1043 |
-
$content .= "<br />\n" . $this->get_message() . "<br />\n";
|
1044 |
-
}
|
1045 |
-
|
1046 |
-
return $content;
|
1047 |
-
} elseif ( $count <= 1 ) {
|
1048 |
-
return $content;
|
1049 |
-
}
|
1050 |
|
1051 |
-
|
1052 |
-
|
1053 |
-
$new .= array_shift( $msgs ) . "<br />\n";
|
1054 |
-
if ( $count > 0 ) {
|
1055 |
-
$new .= "<br />\n";
|
1056 |
}
|
1057 |
}
|
1058 |
|
1059 |
-
return $
|
1060 |
}
|
1061 |
|
1062 |
public function fixup_error_messages_wc( \WP_Error $error ) {
|
@@ -1069,17 +1184,24 @@ class Limit_Login_Attempts
|
|
1069 |
* @return string
|
1070 |
*/
|
1071 |
public function get_message() {
|
1072 |
-
/* Check external whitelist */
|
1073 |
-
if ( $this->is_ip_whitelisted() ) {
|
1074 |
-
return '';
|
1075 |
-
}
|
1076 |
|
1077 |
-
|
1078 |
-
|
1079 |
-
|
1080 |
-
|
1081 |
|
1082 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1083 |
}
|
1084 |
|
1085 |
/**
|
@@ -1250,138 +1372,165 @@ class Limit_Login_Attempts
|
|
1250 |
* Render admin options page
|
1251 |
*/
|
1252 |
public function options_page() {
|
|
|
1253 |
$this->use_local_options = !is_network_admin();
|
1254 |
$this->cleanup();
|
1255 |
|
1256 |
-
if( !empty( $_POST ) )
|
1257 |
-
|
1258 |
check_admin_referer( 'limit-login-attempts-options' );
|
1259 |
|
1260 |
-
|
1261 |
-
|
1262 |
|
1263 |
-
|
1264 |
-
|
1265 |
|
1266 |
/* Should we clear log? */
|
1267 |
-
|
1268 |
-
|
1269 |
-
|
1270 |
-
|
1271 |
-
|
1272 |
|
1273 |
-
|
1274 |
-
|
1275 |
-
|
1276 |
-
|
1277 |
-
|
1278 |
-
|
1279 |
|
1280 |
-
|
1281 |
-
|
1282 |
-
|
1283 |
-
|
1284 |
-
|
1285 |
-
|
1286 |
|
1287 |
-
|
1288 |
-
|
1289 |
|
1290 |
-
|
1291 |
|
1292 |
-
|
1293 |
-
|
1294 |
-
|
1295 |
-
|
1296 |
-
|
1297 |
-
|
1298 |
-
|
1299 |
-
|
1300 |
|
1301 |
-
|
1302 |
|
1303 |
-
|
1304 |
-
|
1305 |
-
|
1306 |
-
|
1307 |
-
|
1308 |
-
|
1309 |
-
|
1310 |
-
|
1311 |
|
1312 |
-
|
1313 |
|
1314 |
-
|
1315 |
-
|
1316 |
$range = array_map('trim', explode('-', $ip) );
|
1317 |
if ( count( $range ) > 1 && (float)sprintf("%u",ip2long($range[0])) > (float)sprintf("%u",ip2long($range[1]))) {
|
1318 |
$this->show_error( __( 'The "'. $ip .'" IP range is invalid', 'limit-login-attempts-reloaded' ) );
|
1319 |
}
|
1320 |
-
|
1321 |
-
|
1322 |
-
|
1323 |
-
|
1324 |
-
|
1325 |
$this->update_option('blacklist', $black_list_ips );
|
1326 |
|
1327 |
-
|
1328 |
|
1329 |
-
|
1330 |
-
|
1331 |
-
|
1332 |
-
|
1333 |
-
|
1334 |
-
|
1335 |
-
|
1336 |
-
|
1337 |
|
1338 |
-
|
1339 |
|
1340 |
-
|
1341 |
-
|
1342 |
-
|
1343 |
|
1344 |
-
|
1345 |
-
|
1346 |
|
1347 |
-
|
1348 |
-
|
1349 |
|
1350 |
-
|
1351 |
-
|
1352 |
|
1353 |
-
|
1354 |
-
|
1355 |
-
|
1356 |
-
|
1357 |
-
|
1358 |
-
|
|
|
1359 |
|
1360 |
-
|
1361 |
|
1362 |
-
|
1363 |
-
|
1364 |
-
|
1365 |
|
1366 |
-
|
1367 |
|
1368 |
-
|
1369 |
-
|
1370 |
|
1371 |
-
|
1372 |
|
1373 |
-
|
1374 |
-
|
1375 |
-
|
1376 |
-
|
1377 |
-
|
1378 |
-
|
1379 |
-
|
1380 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1381 |
|
1382 |
-
|
1383 |
|
1384 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1385 |
}
|
1386 |
}
|
1387 |
|
@@ -1575,4 +1724,408 @@ class Limit_Login_Attempts
|
|
1575 |
|
1576 |
wp_send_json_success(array());
|
1577 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1578 |
}
|
3 |
/**
|
4 |
* Class Limit_Login_Attempts
|
5 |
*/
|
6 |
+
class Limit_Login_Attempts {
|
7 |
+
|
8 |
public $default_options = array(
|
9 |
'gdpr' => 0,
|
10 |
|
41 |
'whitelist_usernames' => array(),
|
42 |
'blacklist' => array(),
|
43 |
'blacklist_usernames' => array(),
|
44 |
+
|
45 |
+
'active_app' => 'local',
|
46 |
+
'app_config' => '',
|
47 |
);
|
48 |
/**
|
49 |
* Admin options page slug
|
70 |
*/
|
71 |
private $use_local_options = null;
|
72 |
|
73 |
+
/**
|
74 |
+
* Current app object
|
75 |
+
*
|
76 |
+
* @var LLAR_App
|
77 |
+
*/
|
78 |
+
public $app = null;
|
79 |
+
|
80 |
public function __construct() {
|
81 |
$this->hooks_init();
|
82 |
+
$this->app_init();
|
83 |
}
|
84 |
|
85 |
/**
|
96 |
add_filter( 'illegal_user_logins', array( $this, 'register_user_blacklist' ), 999 );
|
97 |
add_action( 'admin_notices', array( $this, 'show_leave_review_notice' ) );
|
98 |
add_action( 'wp_ajax_dismiss_review_notice', array( $this, 'dismiss_review_notice_callback' ));
|
99 |
+
add_action( 'wp_ajax_app_config_save', array( $this, 'app_config_save_callback' ));
|
100 |
+
add_action( 'wp_ajax_app_setup', array( $this, 'app_setup_callback' ));
|
101 |
+
add_action( 'wp_ajax_app_log_action', array( $this, 'app_log_action_callback' ));
|
102 |
+
add_action( 'wp_ajax_app_load_log', array( $this, 'app_load_log_callback' ));
|
103 |
+
add_action( 'wp_ajax_app_load_lockouts', array( $this, 'app_load_lockouts_callback' ));
|
104 |
+
add_action( 'wp_ajax_app_load_acl_rules', array( $this, 'app_load_acl_rules_callback' ));
|
105 |
+
add_action( 'wp_ajax_app_acl_add_rule', array( $this, 'app_acl_add_rule_callback' ));
|
106 |
+
add_action( 'wp_ajax_app_acl_remove_rule', array( $this, 'app_acl_remove_rule_callback' ));
|
107 |
|
108 |
add_action( 'admin_print_scripts-settings_page_limit-login-attempts', array( $this, 'load_admin_scripts' ) );
|
109 |
}
|
144 |
add_filter( 'wp_authenticate_user', array( $this, 'wp_authenticate_user' ), 99999, 2 );
|
145 |
|
146 |
add_filter( 'shake_error_codes', array( $this, 'failure_shake' ) );
|
|
|
147 |
add_action( 'login_errors', array( $this, 'fixup_error_messages' ) );
|
148 |
|
149 |
if ( $this->network_mode )
|
164 |
* later versions of WP.
|
165 |
*/
|
166 |
add_action( 'wp_authenticate', array( $this, 'track_credentials' ), 10, 2 );
|
167 |
+
add_action( 'authenticate', array( $this, 'authenticate_filter' ), 5, 3 );
|
168 |
+
|
169 |
+
/**
|
170 |
+
* BuddyPress unactivated user account message
|
171 |
+
*/
|
172 |
+
add_action( 'authenticate', array( $this, 'bp_authenticate_filter' ), 35, 3 );
|
173 |
|
174 |
if ( defined('XMLRPC_REQUEST') && XMLRPC_REQUEST )
|
175 |
add_action( 'init', array( $this, 'check_xmlrpc_lock' ) );
|
176 |
|
177 |
add_action('wp_ajax_limit-login-unlock', array( $this, 'ajax_unlock' ) );
|
178 |
+
|
179 |
}
|
180 |
|
181 |
+
public function app_init() {
|
182 |
+
|
183 |
+
if( $this->get_option( 'active_app' ) === 'custom' && $config = $this->get_custom_app_config() ) {
|
184 |
+
|
185 |
+
$this->app = new LLAR_App( $config );
|
186 |
+
}
|
187 |
+
}
|
188 |
+
|
189 |
public function load_admin_scripts() {
|
190 |
|
191 |
wp_enqueue_script('jquery-ui-accordion');
|
346 |
|
347 |
if ( ! empty( $username ) && ! empty( $password ) ) {
|
348 |
|
349 |
+
if( $this->app && $response = $this->app->acl_check( array(
|
350 |
+
'ip' => $this->get_all_ips(),
|
351 |
+
'login' => $username,
|
352 |
+
'gateway' => $this->detect_gateway()
|
353 |
+
) ) ) {
|
354 |
|
355 |
+
if( $response['result'] === 'deny' ) {
|
|
|
356 |
|
357 |
+
remove_filter( 'login_errors', array( $this, 'fixup_error_messages' ) );
|
358 |
+
remove_filter( 'wp_login_failed', array( $this, 'limit_login_failed' ) );
|
359 |
+
remove_filter( 'wp_authenticate_user', array( $this, 'wp_authenticate_user' ), 99999 );
|
360 |
+
|
361 |
+
// Remove default WP authentication filters
|
362 |
+
remove_filter( 'authenticate', 'wp_authenticate_username_password', 20 );
|
363 |
+
remove_filter( 'authenticate', 'wp_authenticate_email_password', 20 );
|
364 |
+
|
365 |
+
$err = __( '<strong>ERROR</strong>: Too many failed login attempts.', 'limit-login-attempts-reloaded' );
|
366 |
+
|
367 |
+
$time_left = ( !empty( $response['time_left'] ) ) ? $response['time_left'] : 0;
|
368 |
+
if( $time_left ) {
|
369 |
|
370 |
+
if ( $time_left > 60 ) {
|
371 |
+
$time_left = ceil( $time_left / 60 );
|
372 |
+
$err .= ' ' . sprintf( _n( 'Please try again in %d hour.', 'Please try again in %d hours.', $time_left, 'limit-login-attempts-reloaded' ), $time_left );
|
373 |
+
} else {
|
374 |
+
$err .= ' ' . sprintf( _n( 'Please try again in %d minute.', 'Please try again in %d minutes.', $time_left, 'limit-login-attempts-reloaded' ), $time_left );
|
375 |
+
}
|
376 |
+
}
|
377 |
|
378 |
+
$this->app->add_error( $err );
|
|
|
|
|
|
|
|
|
|
|
379 |
|
380 |
+
$user = new WP_Error();
|
381 |
+
$user->add( 'username_blacklisted', $err );
|
382 |
+
}
|
383 |
+
else if( $response['result'] === 'pass' ) {
|
384 |
|
385 |
+
remove_filter( 'login_errors', array( $this, 'fixup_error_messages' ) );
|
386 |
+
remove_filter( 'wp_login_failed', array( $this, 'limit_login_failed' ) );
|
387 |
+
remove_filter( 'wp_authenticate_user', array( $this, 'wp_authenticate_user' ), 99999 );
|
388 |
+
}
|
389 |
|
390 |
+
} else {
|
391 |
|
392 |
+
$ip = $this->get_address();
|
|
|
|
|
|
|
393 |
|
394 |
+
// Check if username is blacklisted
|
395 |
+
if ( ! $this->is_username_whitelisted( $username ) && ! $this->is_ip_whitelisted( $ip ) &&
|
396 |
+
( $this->is_username_blacklisted( $username ) || $this->is_ip_blacklisted( $ip ) )
|
397 |
+
) {
|
398 |
|
399 |
+
remove_filter( 'login_errors', array( $this, 'fixup_error_messages' ) );
|
400 |
+
remove_filter( 'wp_login_failed', array( $this, 'limit_login_failed' ) );
|
401 |
+
remove_filter( 'wp_authenticate_user', array( $this, 'wp_authenticate_user' ), 99999 );
|
402 |
+
|
403 |
+
// Remove default WP authentication filters
|
404 |
+
remove_filter( 'authenticate', 'wp_authenticate_username_password', 20 );
|
405 |
+
remove_filter( 'authenticate', 'wp_authenticate_email_password', 20 );
|
406 |
+
|
407 |
+
$user = new WP_Error();
|
408 |
+
$user->add( 'username_blacklisted', "<strong>ERROR:</strong> Too many failed login attempts." );
|
409 |
+
|
410 |
+
} elseif ( $this->is_username_whitelisted( $username ) || $this->is_ip_whitelisted( $ip ) ) {
|
411 |
+
|
412 |
+
remove_filter( 'wp_login_failed', array( $this, 'limit_login_failed' ) );
|
413 |
+
remove_filter( 'wp_authenticate_user', array( $this, 'wp_authenticate_user' ), 99999 );
|
414 |
+
remove_filter( 'login_errors', array( $this, 'fixup_error_messages' ) );
|
415 |
+
|
416 |
+
}
|
417 |
+
}
|
418 |
}
|
419 |
|
420 |
return $user;
|
421 |
}
|
422 |
|
423 |
+
/**
|
424 |
+
* BuddyPress unactivated user account message fix
|
425 |
+
*
|
426 |
+
* @param $user
|
427 |
+
* @param $username
|
428 |
+
* @param $password
|
429 |
+
* @return mixed
|
430 |
+
*/
|
431 |
+
public function bp_authenticate_filter( $user, $username, $password ) {
|
432 |
+
|
433 |
+
if ( ! empty( $username ) && ! empty( $password ) ) {
|
434 |
+
|
435 |
+
if(is_wp_error($user) && in_array('bp_account_not_activated', $user->get_error_codes()) ) {
|
436 |
+
|
437 |
+
$this->other_login_errors[] = $user->get_error_message('bp_account_not_activated');
|
438 |
+
}
|
439 |
+
}
|
440 |
+
return $user;
|
441 |
+
}
|
442 |
+
|
443 |
+
/**
|
444 |
+
* @return array
|
445 |
+
*/
|
446 |
+
public function get_all_ips() {
|
447 |
+
|
448 |
+
$ips = array();
|
449 |
+
|
450 |
+
foreach ( $_SERVER as $key => $value ) {
|
451 |
+
|
452 |
+
if( in_array( $key, ['SERVER_ADDR'] ) ) continue;
|
453 |
+
|
454 |
+
if( filter_var( $value, FILTER_VALIDATE_IP ) ) {
|
455 |
+
|
456 |
+
$ips[$key] = $value;
|
457 |
+
}
|
458 |
+
}
|
459 |
+
|
460 |
+
if( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) && !array_key_exists( 'HTTP_X_FORWARDED_FOR', $ips ) ) {
|
461 |
+
|
462 |
+
$ips['HTTP_X_FORWARDED_FOR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
463 |
+
}
|
464 |
+
|
465 |
+
return $ips;
|
466 |
+
}
|
467 |
+
|
468 |
/**
|
469 |
* Check if the original plugin is installed
|
470 |
*/
|
484 |
*/
|
485 |
public function enqueue() {
|
486 |
wp_enqueue_style( 'lla-main', LLA_PLUGIN_URL . 'assets/css/limit-login-attempts.css' );
|
487 |
+
wp_enqueue_script( 'lla-main', LLA_PLUGIN_URL . 'assets/js/limit-login-attempts.js' );
|
488 |
}
|
489 |
|
490 |
/**
|
501 |
}
|
502 |
|
503 |
/**
|
504 |
+
* Get the correct options page URI
|
505 |
+
*
|
506 |
+
* @param bool $tab
|
507 |
+
* @return mixed
|
508 |
+
*/
|
509 |
+
public function get_options_page_uri($tab = false)
|
510 |
{
|
511 |
|
512 |
if ( is_network_admin() )
|
514 |
else
|
515 |
$uri = menu_page_url( $this->_options_page_slug, false );
|
516 |
|
517 |
+
if( !empty( $tab ) ) {
|
518 |
|
519 |
+
$uri = add_query_arg( 'tab', $tab, $uri );
|
520 |
}
|
521 |
|
522 |
return $uri;
|
569 |
return $func( $option, $value, '', 'no' );
|
570 |
}
|
571 |
|
572 |
+
public function delete_option( $option_name, $local=null )
|
573 |
+
{
|
574 |
+
if ( is_null( $local ) )
|
575 |
+
$local = $this->use_local_options;
|
576 |
+
|
577 |
+
$option = 'limit_login_'.$option_name;
|
578 |
+
|
579 |
+
$func = $local ? 'delete_option' : 'delete_site_option';
|
580 |
+
|
581 |
+
return $func( $option );
|
582 |
+
}
|
583 |
+
|
584 |
/**
|
585 |
* Setup main options
|
586 |
*/
|
645 |
*/
|
646 |
public function limit_login_failed( $username ) {
|
647 |
|
648 |
+
if( $this->app && $response = $this->app->lockout_check( array(
|
649 |
+
'ip' => $this->get_all_ips(),
|
650 |
+
'login' => $username,
|
651 |
+
'gateway' => $this->detect_gateway()
|
652 |
+
) ) ) {
|
653 |
|
654 |
+
if( $response['result'] === 'allow' ) {
|
|
|
655 |
|
656 |
+
$this->app->add_error(
|
657 |
+
sprintf( _n( "<strong>%d</strong> attempt remaining.", "<strong>%d</strong> attempts remaining.", $response['attempts_left'], 'limit-login-attempts-reloaded' ), $response['attempts_left'] )
|
658 |
+
);
|
659 |
+
} elseif( $response['result'] === 'deny' ) {
|
660 |
|
661 |
+
global $limit_login_just_lockedout;
|
662 |
+
$limit_login_just_lockedout = true;
|
|
|
663 |
|
664 |
+
$err = __( '<strong>ERROR</strong>: Too many failed login attempts.', 'limit-login-attempts-reloaded' );
|
|
|
|
|
665 |
|
666 |
+
$time_left = ( !empty( $response['time_left'] ) ) ? $response['time_left'] : 0;
|
667 |
+
if ( $time_left > 60 ) {
|
668 |
+
$time_left = ceil( $time_left / 60 );
|
669 |
+
$err .= ' ' . sprintf( _n( 'Please try again in %d hour.', 'Please try again in %d hours.', $time_left, 'limit-login-attempts-reloaded' ), $time_left );
|
670 |
+
} else {
|
671 |
+
$err .= ' ' . sprintf( _n( 'Please try again in %d minute.', 'Please try again in %d minutes.', $time_left, 'limit-login-attempts-reloaded' ), $time_left );
|
672 |
+
}
|
673 |
|
674 |
+
$this->app->add_error( $err );
|
675 |
+
}
|
|
|
|
|
676 |
|
|
|
|
|
|
|
|
|
|
|
677 |
} else {
|
|
|
|
|
|
|
678 |
|
679 |
+
$ip = $this->get_address();
|
680 |
+
$ipHash = $this->getHash($this->get_address());
|
|
|
|
|
|
|
|
|
|
|
681 |
|
682 |
+
/* if currently locked-out, do not add to retries */
|
683 |
+
$lockouts = $this->get_option( 'lockouts' );
|
684 |
|
685 |
+
if ( ! is_array( $lockouts ) ) {
|
686 |
+
$lockouts = array();
|
687 |
+
}
|
688 |
|
689 |
+
if ( (isset( $lockouts[ $ip ] ) && time() < $lockouts[ $ip ]) || (isset( $lockouts[ $ipHash ] ) && time() < $lockouts[ $ipHash ] )) {
|
690 |
+
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
691 |
}
|
692 |
+
|
693 |
+
/* Get the arrays with retries and retries-valid information */
|
694 |
+
$retries = $this->get_option( 'retries' );
|
695 |
+
$valid = $this->get_option( 'retries_valid' );
|
696 |
+
|
697 |
+
if ( ! is_array( $retries ) ) {
|
698 |
+
$retries = array();
|
699 |
+
$this->add_option( 'retries', $retries );
|
700 |
+
}
|
701 |
+
|
702 |
+
if ( ! is_array( $valid ) ) {
|
703 |
+
$valid = array();
|
704 |
+
$this->add_option( 'retries_valid', $valid );
|
705 |
+
}
|
706 |
+
|
707 |
+
$gdpr = $this->get_option('gdpr');
|
708 |
+
$ip = ($gdpr ? $ipHash : $ip);
|
709 |
+
/* Check validity and add one to retries */
|
710 |
+
if ( isset( $retries[ $ip ] ) && isset( $valid[ $ip ] ) && time() < $valid[ $ip ]) {
|
711 |
+
$retries[ $ip ] ++;
|
712 |
} else {
|
713 |
+
$retries[ $ip ] = 1;
|
|
|
714 |
}
|
715 |
+
$valid[ $ip ] = time() + $this->get_option( 'valid_duration' );
|
716 |
+
|
717 |
+
/* lockout? */
|
718 |
+
if ( $retries[ $ip ] % $this->get_option( 'allowed_retries' ) != 0 ) {
|
719 |
+
/*
|
720 |
+
* Not lockout (yet!)
|
721 |
+
* Do housecleaning (which also saves retry/valid values).
|
722 |
+
*/
|
723 |
+
$this->cleanup( $retries, null, $valid );
|
724 |
|
725 |
+
return;
|
726 |
+
}
|
727 |
|
728 |
+
/* lockout! */
|
729 |
+
$whitelisted = $this->is_ip_whitelisted( $ip );
|
730 |
+
$retries_long = $this->get_option( 'allowed_retries' ) * $this->get_option( 'allowed_lockouts' );
|
731 |
|
732 |
+
/*
|
733 |
+
* Note that retries and statistics are still counted and notifications
|
734 |
+
* done as usual for whitelisted ips , but no lockout is done.
|
735 |
+
*/
|
736 |
+
if ( $whitelisted ) {
|
737 |
+
if ( $retries[ $ip ] >= $retries_long ) {
|
738 |
+
unset( $retries[ $ip ] );
|
739 |
+
unset( $valid[ $ip ] );
|
740 |
+
}
|
741 |
+
} else {
|
742 |
+
global $limit_login_just_lockedout;
|
743 |
+
$limit_login_just_lockedout = true;
|
744 |
+
$gdpr = $this->get_option('gdpr');
|
745 |
+
$index = ($gdpr ? $ipHash : $ip);
|
746 |
+
|
747 |
+
/* setup lockout, reset retries as needed */
|
748 |
+
if ( (isset($retries[ $ip ]) ? $retries[ $ip ] : 0) >= $retries_long || (isset($retries[ $ipHash ]) ? $retries[ $ipHash ] : 0) >= $retries_long ) {
|
749 |
+
/* long lockout */
|
750 |
+
$lockouts[ $index ] = time() + $this->get_option( 'long_duration' );
|
751 |
+
unset( $retries[ $index ] );
|
752 |
+
unset( $valid[ $index ] );
|
753 |
+
} else {
|
754 |
+
/* normal lockout */
|
755 |
+
$lockouts[ $index ] = time() + $this->get_option( 'lockout_duration' );
|
756 |
+
}
|
757 |
+
}
|
758 |
+
|
759 |
+
/* do housecleaning and save values */
|
760 |
+
$this->cleanup( $retries, $lockouts, $valid );
|
761 |
+
|
762 |
+
/* do any notification */
|
763 |
+
$this->notify( $username );
|
764 |
+
|
765 |
+
/* increase statistics */
|
766 |
+
$total = $this->get_option( 'lockouts_total' );
|
767 |
+
if ( $total === false || ! is_numeric( $total ) ) {
|
768 |
+
$this->add_option( 'lockouts_total', 1 );
|
769 |
+
} else {
|
770 |
+
$this->update_option( 'lockouts_total', $total + 1 );
|
771 |
+
}
|
772 |
}
|
773 |
}
|
774 |
|
918 |
$log[ $index ][ $user_login ]['counter']++;
|
919 |
$log[ $index ][ $user_login ]['date'] = time();
|
920 |
|
921 |
+
$log[ $index ][ $user_login ]['gateway'] = $this->detect_gateway();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
922 |
|
923 |
if ( $option === false ) {
|
924 |
$this->add_option( 'logged', $log );
|
927 |
}
|
928 |
}
|
929 |
|
930 |
+
/**
|
931 |
+
* @return string
|
932 |
+
*/
|
933 |
+
public function detect_gateway() {
|
934 |
+
|
935 |
+
$gateway = 'wp_login';
|
936 |
+
|
937 |
+
if ( isset( $_POST['woocommerce-login-nonce'] ) ) {
|
938 |
+
$gateway = 'wp_woo_login';
|
939 |
+
} elseif ( isset( $GLOBALS['wp_xmlrpc_server'] ) && is_object( $GLOBALS['wp_xmlrpc_server'] ) ) {
|
940 |
+
$gateway = 'wp_xmlrpc';
|
941 |
+
}
|
942 |
+
|
943 |
+
return $gateway;
|
944 |
+
}
|
945 |
+
|
946 |
/**
|
947 |
* Check if IP is whitelisted.
|
948 |
*
|
1016 |
*/
|
1017 |
public function wp_authenticate_user( $user, $password ) {
|
1018 |
|
1019 |
+
if( is_wp_error( $user ) ) {
|
1020 |
+
return $user;
|
1021 |
+
}
|
1022 |
+
|
1023 |
$user_login = '';
|
1024 |
|
1025 |
if( is_a( $user, 'WP_User' ) ) {
|
1028 |
$user_login = $user;
|
1029 |
}
|
1030 |
|
1031 |
+
if ( $this->check_whitelist_ips( false, $this->get_address() ) ||
|
|
|
1032 |
$this->check_whitelist_usernames( false, $user_login ) ||
|
1033 |
$this->is_limit_login_ok()
|
1034 |
) {
|
1077 |
$limit_login_nonempty_credentials = ( ! empty( $user ) && ! empty( $password ) );
|
1078 |
}
|
1079 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1080 |
/**
|
1081 |
* Construct informative error message
|
1082 |
*
|
1142 |
public function fixup_error_messages( $content ) {
|
1143 |
global $limit_login_just_lockedout, $limit_login_nonempty_credentials, $limit_login_my_error_shown;
|
1144 |
|
1145 |
+
$error_msg = $this->get_message();
|
|
|
|
|
1146 |
|
1147 |
+
if ( $limit_login_nonempty_credentials ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1148 |
|
1149 |
+
$content = '';
|
|
|
|
|
|
|
1150 |
|
1151 |
if($this->other_login_errors) {
|
1152 |
|
|
|
1153 |
foreach ($this->other_login_errors as $msg) {
|
1154 |
$content .= $msg . "<br />\n";
|
1155 |
}
|
1156 |
+
|
1157 |
+
} else if( !$limit_login_just_lockedout ) {
|
1158 |
|
1159 |
/* Replace error message, including ours if necessary */
|
1160 |
if( !empty( $_REQUEST['log'] ) && is_email( $_REQUEST['log'] ) ) {
|
1164 |
}
|
1165 |
}
|
1166 |
|
1167 |
+
if ( $error_msg ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1168 |
|
1169 |
+
$content .= ( !empty( $content ) ) ? "<br />\n" : '';
|
1170 |
+
$content .= $error_msg . "<br />\n";
|
|
|
|
|
|
|
1171 |
}
|
1172 |
}
|
1173 |
|
1174 |
+
return $content;
|
1175 |
}
|
1176 |
|
1177 |
public function fixup_error_messages_wc( \WP_Error $error ) {
|
1184 |
* @return string
|
1185 |
*/
|
1186 |
public function get_message() {
|
|
|
|
|
|
|
|
|
1187 |
|
1188 |
+
if( $this->app && $app_errors = $this->app->get_errors() ) {
|
1189 |
+
|
1190 |
+
return implode( '<br>', $app_errors);
|
1191 |
+
} else {
|
1192 |
|
1193 |
+
/* Check external whitelist */
|
1194 |
+
if ( $this->is_ip_whitelisted() ) {
|
1195 |
+
return '';
|
1196 |
+
}
|
1197 |
+
|
1198 |
+
/* Is lockout in effect? */
|
1199 |
+
if ( ! $this->is_limit_login_ok() ) {
|
1200 |
+
return $this->error_msg();
|
1201 |
+
}
|
1202 |
+
|
1203 |
+
return $this->retries_remaining_msg();
|
1204 |
+
}
|
1205 |
}
|
1206 |
|
1207 |
/**
|
1372 |
* Render admin options page
|
1373 |
*/
|
1374 |
public function options_page() {
|
1375 |
+
|
1376 |
$this->use_local_options = !is_network_admin();
|
1377 |
$this->cleanup();
|
1378 |
|
1379 |
+
if( !empty( $_POST ) ) {
|
1380 |
+
|
1381 |
check_admin_referer( 'limit-login-attempts-options' );
|
1382 |
|
1383 |
+
if ( is_network_admin() )
|
1384 |
+
$this->update_option( 'allow_local_options', !empty($_POST['allow_local_options']) );
|
1385 |
|
1386 |
+
elseif ( $this->network_mode )
|
1387 |
+
$this->update_option( 'use_local_options', empty($_POST['use_global_options']) );
|
1388 |
|
1389 |
/* Should we clear log? */
|
1390 |
+
if( isset( $_POST[ 'clear_log' ] ) )
|
1391 |
+
{
|
1392 |
+
$this->update_option( 'logged', '' );
|
1393 |
+
$this->show_error( __( 'Cleared IP log', 'limit-login-attempts-reloaded' ) );
|
1394 |
+
}
|
1395 |
|
1396 |
+
/* Should we reset counter? */
|
1397 |
+
if( isset( $_POST[ 'reset_total' ] ) )
|
1398 |
+
{
|
1399 |
+
$this->update_option( 'lockouts_total', 0 );
|
1400 |
+
$this->show_error( __( 'Reset lockout count', 'limit-login-attempts-reloaded' ) );
|
1401 |
+
}
|
1402 |
|
1403 |
+
/* Should we restore current lockouts? */
|
1404 |
+
if( isset( $_POST[ 'reset_current' ] ) )
|
1405 |
+
{
|
1406 |
+
$this->update_option( 'lockouts', array() );
|
1407 |
+
$this->show_error( __( 'Cleared current lockouts', 'limit-login-attempts-reloaded' ) );
|
1408 |
+
}
|
1409 |
|
1410 |
+
/* Should we update options? */
|
1411 |
+
if( isset( $_POST[ 'llar_update_dashboard' ] ) ) {
|
1412 |
|
1413 |
+
$white_list_ips = ( !empty( $_POST['lla_whitelist_ips'] ) ) ? explode("\n", str_replace("\r", "", stripslashes($_POST['lla_whitelist_ips']) ) ) : array();
|
1414 |
|
1415 |
+
if( !empty( $white_list_ips ) ) {
|
1416 |
+
foreach( $white_list_ips as $key => $ip ) {
|
1417 |
+
if( '' == $ip ) {
|
1418 |
+
unset( $white_list_ips[ $key ] );
|
1419 |
+
}
|
1420 |
+
}
|
1421 |
+
}
|
1422 |
+
$this->update_option('whitelist', $white_list_ips );
|
1423 |
|
1424 |
+
$white_list_usernames = ( !empty( $_POST['lla_whitelist_usernames'] ) ) ? explode("\n", str_replace("\r", "", stripslashes($_POST['lla_whitelist_usernames']) ) ) : array();
|
1425 |
|
1426 |
+
if( !empty( $white_list_usernames ) ) {
|
1427 |
+
foreach( $white_list_usernames as $key => $ip ) {
|
1428 |
+
if( '' == $ip ) {
|
1429 |
+
unset( $white_list_usernames[ $key ] );
|
1430 |
+
}
|
1431 |
+
}
|
1432 |
+
}
|
1433 |
+
$this->update_option('whitelist_usernames', $white_list_usernames );
|
1434 |
|
1435 |
+
$black_list_ips = ( !empty( $_POST['lla_blacklist_ips'] ) ) ? explode("\n", str_replace("\r", "", stripslashes($_POST['lla_blacklist_ips']) ) ) : array();
|
1436 |
|
1437 |
+
if( !empty( $black_list_ips ) ) {
|
1438 |
+
foreach( $black_list_ips as $key => $ip ) {
|
1439 |
$range = array_map('trim', explode('-', $ip) );
|
1440 |
if ( count( $range ) > 1 && (float)sprintf("%u",ip2long($range[0])) > (float)sprintf("%u",ip2long($range[1]))) {
|
1441 |
$this->show_error( __( 'The "'. $ip .'" IP range is invalid', 'limit-login-attempts-reloaded' ) );
|
1442 |
}
|
1443 |
+
if( '' == $ip ) {
|
1444 |
+
unset( $black_list_ips[ $key ] );
|
1445 |
+
}
|
1446 |
+
}
|
1447 |
+
}
|
1448 |
$this->update_option('blacklist', $black_list_ips );
|
1449 |
|
1450 |
+
$black_list_usernames = ( !empty( $_POST['lla_blacklist_usernames'] ) ) ? explode("\n", str_replace("\r", "", stripslashes($_POST['lla_blacklist_usernames']) ) ) : array();
|
1451 |
|
1452 |
+
if( !empty( $black_list_usernames ) ) {
|
1453 |
+
foreach( $black_list_usernames as $key => $ip ) {
|
1454 |
+
if( '' == $ip ) {
|
1455 |
+
unset( $black_list_usernames[ $key ] );
|
1456 |
+
}
|
1457 |
+
}
|
1458 |
+
}
|
1459 |
+
$this->update_option('blacklist_usernames', $black_list_usernames );
|
1460 |
|
1461 |
+
$this->sanitize_options();
|
1462 |
|
1463 |
+
$this->show_error( __( 'Settings saved.', 'limit-login-attempts-reloaded' ) );
|
1464 |
+
}
|
1465 |
+
elseif( isset( $_POST[ 'llar_update_settings' ] ) ) {
|
1466 |
|
1467 |
+
/* Should we support GDPR */
|
1468 |
+
if( isset( $_POST[ 'gdpr' ] ) ) {
|
1469 |
|
1470 |
+
$this->update_option( 'gdpr', 1 );
|
1471 |
+
} else {
|
1472 |
|
1473 |
+
$this->update_option( 'gdpr', 0 );
|
1474 |
+
}
|
1475 |
|
1476 |
+
$this->update_option('allowed_retries', (int)$_POST['allowed_retries'] );
|
1477 |
+
$this->update_option('lockout_duration', (int)$_POST['lockout_duration'] * 60 );
|
1478 |
+
$this->update_option('valid_duration', (int)$_POST['valid_duration'] * 3600 );
|
1479 |
+
$this->update_option('allowed_lockouts', (int)$_POST['allowed_lockouts'] );
|
1480 |
+
$this->update_option('long_duration', (int)$_POST['long_duration'] * 3600 );
|
1481 |
+
$this->update_option('notify_email_after', (int)$_POST['email_after'] );
|
1482 |
+
$this->update_option('active_app', sanitize_text_field( $_POST['active_app'] ) );
|
1483 |
|
1484 |
+
$this->update_option('admin_notify_email', sanitize_email( $_POST['admin_notify_email'] ) );
|
1485 |
|
1486 |
+
$trusted_ip_origins = ( !empty( $_POST['lla_trusted_ip_origins'] ) )
|
1487 |
+
? array_map( 'trim', explode( ',', sanitize_text_field( $_POST['lla_trusted_ip_origins'] ) ) )
|
1488 |
+
: array();
|
1489 |
|
1490 |
+
if( !in_array( 'REMOTE_ADDR', $trusted_ip_origins ) ) {
|
1491 |
|
1492 |
+
$trusted_ip_origins[] = 'REMOTE_ADDR';
|
1493 |
+
}
|
1494 |
|
1495 |
+
$this->update_option('trusted_ip_origins', $trusted_ip_origins );
|
1496 |
|
1497 |
+
$notify_methods = array();
|
1498 |
+
if( isset( $_POST[ 'lockout_notify_log' ] ) ) {
|
1499 |
+
$notify_methods[] = 'log';
|
1500 |
+
}
|
1501 |
+
if( isset( $_POST[ 'lockout_notify_email' ] ) ) {
|
1502 |
+
$notify_methods[] = 'email';
|
1503 |
+
}
|
1504 |
+
$this->update_option('lockout_notify', implode( ',', $notify_methods ) );
|
1505 |
+
|
1506 |
+
$this->sanitize_options();
|
1507 |
+
|
1508 |
+
if( !empty( $_POST['llar_app_settings'] ) && $this->app ) {
|
1509 |
+
|
1510 |
+
if( ( $app_setup_link = $this->get_option( 'app_setup_link' ) ) && $setup_result = LLAR_App::setup( $app_setup_link ) ) {
|
1511 |
+
|
1512 |
+
if( $setup_result['success'] && $active_app_config = $setup_result['app_config'] ) {
|
1513 |
+
|
1514 |
+
foreach ( $_POST['llar_app_settings'] as $key => $value ) {
|
1515 |
|
1516 |
+
if( array_key_exists( $key, $active_app_config['settings'] ) ) {
|
1517 |
|
1518 |
+
if( !empty( $active_app_config['settings'][$key]['options'] ) &&
|
1519 |
+
!in_array( $value, $active_app_config['settings'][$key]['options'] ) ) {
|
1520 |
+
|
1521 |
+
continue;
|
1522 |
+
}
|
1523 |
+
|
1524 |
+
$active_app_config['settings'][$key]['value'] = $value;
|
1525 |
+
}
|
1526 |
+
}
|
1527 |
+
|
1528 |
+
$this->update_option( 'app_config', $active_app_config );
|
1529 |
+
}
|
1530 |
+
}
|
1531 |
+
}
|
1532 |
+
|
1533 |
+
$this->show_error( __( 'Settings saved.', 'limit-login-attempts-reloaded' ) );
|
1534 |
}
|
1535 |
}
|
1536 |
|
1724 |
|
1725 |
wp_send_json_success(array());
|
1726 |
}
|
1727 |
+
|
1728 |
+
public function app_setup_callback() {
|
1729 |
+
|
1730 |
+
if ( !current_user_can('activate_plugins') ) {
|
1731 |
+
|
1732 |
+
wp_send_json_error(array());
|
1733 |
+
}
|
1734 |
+
|
1735 |
+
check_ajax_referer('llar-action', 'sec');
|
1736 |
+
|
1737 |
+
if( !empty( $_POST['link'] ) ) {
|
1738 |
+
|
1739 |
+
$link = sanitize_text_field( $_POST['link'] );
|
1740 |
+
|
1741 |
+
if( $setup_result = LLAR_App::setup( $link ) ) {
|
1742 |
+
|
1743 |
+
if( $setup_result['success'] ) {
|
1744 |
+
|
1745 |
+
if( $setup_result['app_config'] ) {
|
1746 |
+
|
1747 |
+
$this->app_update_config( $setup_result['app_config'], true );
|
1748 |
+
$this->update_option( 'active_app', 'custom' );
|
1749 |
+
|
1750 |
+
$this->update_option( 'app_setup_link', $link );
|
1751 |
+
|
1752 |
+
wp_send_json_success(array(
|
1753 |
+
'msg' => ( !empty( $setup_result['app_config']['messages']['setup_success'] ) )
|
1754 |
+
? $setup_result['app_config']['messages']['setup_success']
|
1755 |
+
: __( 'The app has been successfully imported.', 'limit-login-attempts-reloaded' )
|
1756 |
+
));
|
1757 |
+
}
|
1758 |
+
|
1759 |
+
} else {
|
1760 |
+
|
1761 |
+
wp_send_json_error(array(
|
1762 |
+
'msg' => $setup_result['error']
|
1763 |
+
));
|
1764 |
+
}
|
1765 |
+
}
|
1766 |
+
}
|
1767 |
+
|
1768 |
+
wp_send_json_error(array(
|
1769 |
+
'msg' => __( 'Please specify the Setup Link', 'limit-login-attempts-reloaded' )
|
1770 |
+
));
|
1771 |
+
}
|
1772 |
+
|
1773 |
+
public function app_update_config( $new_app_config, $update_created_at = false ) {
|
1774 |
+
|
1775 |
+
if( !$new_app_config ) return false;
|
1776 |
+
|
1777 |
+
if( $active_app_config = $this->get_custom_app_config() ) {
|
1778 |
+
|
1779 |
+
foreach ( $active_app_config['settings'] as $key => $info ) {
|
1780 |
+
|
1781 |
+
if( array_key_exists( $key, $new_app_config['settings'] ) ) {
|
1782 |
+
|
1783 |
+
if( !empty( $new_app_config['settings'][$key]['options'] ) &&
|
1784 |
+
!in_array( $info['value'], $new_app_config['settings'][$key]['options'] ) ) {
|
1785 |
+
|
1786 |
+
continue;
|
1787 |
+
}
|
1788 |
+
|
1789 |
+
$new_app_config['settings'][$key]['value'] = $info['value'];
|
1790 |
+
}
|
1791 |
+
}
|
1792 |
+
|
1793 |
+
}
|
1794 |
+
|
1795 |
+
if( $update_created_at )
|
1796 |
+
$new_app_config['created_at'] = time();
|
1797 |
+
|
1798 |
+
$this->update_option( 'app_config', $new_app_config );
|
1799 |
+
}
|
1800 |
+
|
1801 |
+
public function app_log_action_callback() {
|
1802 |
+
|
1803 |
+
if ( !current_user_can('activate_plugins') ) {
|
1804 |
+
|
1805 |
+
wp_send_json_error(array());
|
1806 |
+
}
|
1807 |
+
|
1808 |
+
check_ajax_referer('llar-action', 'sec');
|
1809 |
+
|
1810 |
+
if( !empty( $_POST['method'] ) && !empty( $_POST['params'] ) ) {
|
1811 |
+
|
1812 |
+
$method = sanitize_text_field( $_POST['method'] );
|
1813 |
+
$params = (array) $_POST['params'];
|
1814 |
+
|
1815 |
+
if( !in_array( $method, array( 'lockout/delete', 'acl/create', 'acl/delete' ) ) ) {
|
1816 |
+
|
1817 |
+
wp_send_json_error(array(
|
1818 |
+
'msg' => 'Wrong method.'
|
1819 |
+
));
|
1820 |
+
}
|
1821 |
+
|
1822 |
+
if( $response = $this->app->request( $method, 'post', $params ) ) {
|
1823 |
+
|
1824 |
+
wp_send_json_success(array(
|
1825 |
+
'msg' => $response['message']
|
1826 |
+
));
|
1827 |
+
|
1828 |
+
} else {
|
1829 |
+
|
1830 |
+
wp_send_json_error(array(
|
1831 |
+
'msg' => 'The endpoint is not responding. Please contact your app provider to settle that.'
|
1832 |
+
));
|
1833 |
+
}
|
1834 |
+
}
|
1835 |
+
|
1836 |
+
wp_send_json_error(array(
|
1837 |
+
'msg' => 'Wrong App id.'
|
1838 |
+
));
|
1839 |
+
}
|
1840 |
+
|
1841 |
+
public function app_acl_add_rule_callback() {
|
1842 |
+
|
1843 |
+
if ( !current_user_can('activate_plugins') ) {
|
1844 |
+
|
1845 |
+
wp_send_json_error(array());
|
1846 |
+
}
|
1847 |
+
|
1848 |
+
check_ajax_referer('llar-action', 'sec');
|
1849 |
+
|
1850 |
+
if( !empty( $_POST['pattern'] ) && !empty( $_POST['rule'] ) && !empty( $_POST['type'] ) ) {
|
1851 |
+
|
1852 |
+
$pattern = sanitize_text_field( $_POST['pattern'] );
|
1853 |
+
$rule = sanitize_text_field( $_POST['rule'] );
|
1854 |
+
$type = sanitize_text_field( $_POST['type'] );
|
1855 |
+
|
1856 |
+
if( !in_array( $rule, array( 'pass', 'allow', 'deny' ) ) ) {
|
1857 |
+
|
1858 |
+
wp_send_json_error(array(
|
1859 |
+
'msg' => 'Wrong rule.'
|
1860 |
+
));
|
1861 |
+
}
|
1862 |
+
|
1863 |
+
if( $response = $this->app->acl_create( array(
|
1864 |
+
'pattern' => $pattern,
|
1865 |
+
'rule' => $rule,
|
1866 |
+
'type' => ( $type === 'ip' ) ? 'ip' : 'login',
|
1867 |
+
) ) ) {
|
1868 |
+
|
1869 |
+
wp_send_json_success(array(
|
1870 |
+
'msg' => $response['message']
|
1871 |
+
));
|
1872 |
+
|
1873 |
+
} else {
|
1874 |
+
|
1875 |
+
wp_send_json_error(array(
|
1876 |
+
'msg' => 'The endpoint is not responding. Please contact your app provider to settle that.'
|
1877 |
+
));
|
1878 |
+
}
|
1879 |
+
}
|
1880 |
+
|
1881 |
+
wp_send_json_error(array(
|
1882 |
+
'msg' => 'Wrong input data.'
|
1883 |
+
));
|
1884 |
+
}
|
1885 |
+
|
1886 |
+
public function app_acl_remove_rule_callback() {
|
1887 |
+
|
1888 |
+
if ( !current_user_can('activate_plugins') ) {
|
1889 |
+
|
1890 |
+
wp_send_json_error(array());
|
1891 |
+
}
|
1892 |
+
|
1893 |
+
check_ajax_referer('llar-action', 'sec');
|
1894 |
+
|
1895 |
+
if( !empty( $_POST['pattern'] ) && !empty( $_POST['type'] ) ) {
|
1896 |
+
|
1897 |
+
$pattern = sanitize_text_field( $_POST['pattern'] );
|
1898 |
+
$type = sanitize_text_field( $_POST['type'] );
|
1899 |
+
|
1900 |
+
if( $response = $this->app->acl_delete( array(
|
1901 |
+
'pattern' => $pattern,
|
1902 |
+
'type' => ( $type === 'ip' ) ? 'ip' : 'login',
|
1903 |
+
) ) ) {
|
1904 |
+
|
1905 |
+
wp_send_json_success(array(
|
1906 |
+
'msg' => $response['message']
|
1907 |
+
));
|
1908 |
+
|
1909 |
+
} else {
|
1910 |
+
|
1911 |
+
wp_send_json_error(array(
|
1912 |
+
'msg' => 'The endpoint is not responding. Please contact your app provider to settle that.'
|
1913 |
+
));
|
1914 |
+
}
|
1915 |
+
}
|
1916 |
+
|
1917 |
+
wp_send_json_error(array(
|
1918 |
+
'msg' => 'Wrong input data.'
|
1919 |
+
));
|
1920 |
+
}
|
1921 |
+
|
1922 |
+
public function app_load_log_callback() {
|
1923 |
+
|
1924 |
+
if ( !current_user_can('activate_plugins') ) {
|
1925 |
+
|
1926 |
+
wp_send_json_error(array());
|
1927 |
+
}
|
1928 |
+
|
1929 |
+
check_ajax_referer('llar-action', 'sec');
|
1930 |
+
|
1931 |
+
$offset = sanitize_text_field( $_POST['offset'] );
|
1932 |
+
|
1933 |
+
$log = $this->app->log( 25, $offset );
|
1934 |
+
|
1935 |
+
if( $log ) {
|
1936 |
+
|
1937 |
+
ob_start(); ?>
|
1938 |
+
|
1939 |
+
<tr>
|
1940 |
+
<th scope="col"><?php _e( "Time", 'limit-login-attempts-reloaded' ); ?></th>
|
1941 |
+
<th scope="col"><?php _e( "IP", 'limit-login-attempts-reloaded' ); ?></th>
|
1942 |
+
<th scope="col"><?php _e( "Gateway", 'limit-login-attempts-reloaded' ); ?></th>
|
1943 |
+
<th scope="col"><?php _e( "Login", 'limit-login-attempts-reloaded' ); ?></th>
|
1944 |
+
<th scope="col"><?php _e( "Rule", 'limit-login-attempts-reloaded' ); ?></th>
|
1945 |
+
<th scope="col"><?php _e( "Reason", 'limit-login-attempts-reloaded' ); ?></th>
|
1946 |
+
<th scope="col"><?php _e( "Pattern", 'limit-login-attempts-reloaded' ); ?></th>
|
1947 |
+
<th scope="col"><?php _e( "Attempts Left", 'limit-login-attempts-reloaded' ); ?></th>
|
1948 |
+
<th scope="col"><?php _e( "Lockout Duration", 'limit-login-attempts-reloaded' ); ?></th>
|
1949 |
+
<th scope="col"><?php _e( "Actions", 'limit-login-attempts-reloaded' ); ?></th>
|
1950 |
+
</tr>
|
1951 |
+
|
1952 |
+
<?php
|
1953 |
+
$date_format = get_option('date_format') . ' ' . get_option('time_format');
|
1954 |
+
?>
|
1955 |
+
|
1956 |
+
<?php if( $log['items'] ) : ?>
|
1957 |
+
|
1958 |
+
<?php foreach ( $log['items'] as $item ) : ?>
|
1959 |
+
<tr>
|
1960 |
+
<td class="llar-col-nowrap"><?php echo get_date_from_gmt( date( 'Y-m-d H:i:s', $item['created_at'] ), $date_format ); ?></td>
|
1961 |
+
<td><?php echo esc_html( $item['ip'] ); ?></td>
|
1962 |
+
<td><?php echo esc_html( $item['gateway'] ); ?></td>
|
1963 |
+
<td><?php echo (is_null($item['login'])) ? '-' : esc_html( $item['login'] ); ?></td>
|
1964 |
+
<td><?php echo (is_null($item['result'])) ? '-' : esc_html( $item['result'] ); ?></td>
|
1965 |
+
<td><?php echo (is_null($item['reason'])) ? '-' : esc_html( $item['reason'] ); ?></td>
|
1966 |
+
<td><?php echo (is_null($item['pattern'])) ? '-' : esc_html( $item['pattern'] ); ?></td>
|
1967 |
+
<td><?php echo (is_null($item['attempts_left'])) ? '-' : esc_html( $item['attempts_left'] ); ?></td>
|
1968 |
+
<td><?php echo (is_null($item['time_left'])) ? '-' : esc_html( $item['time_left'] ) ?></td>
|
1969 |
+
<td class="llar-app-log-actions">
|
1970 |
+
<?php
|
1971 |
+
if( $item['actions'] ) {
|
1972 |
+
|
1973 |
+
foreach ( $item['actions'] as $action ) {
|
1974 |
+
|
1975 |
+
echo '<button class="button llar-app-log-action-btn js-app-log-action" style="color:' . esc_attr( $action['color'] ) . ';border-color:' . esc_attr( $action['color'] ) . '"
|
1976 |
+
data-method="' . esc_attr( $action['method'] ) . '"
|
1977 |
+
data-params="' . esc_attr( json_encode( $action['data'], JSON_FORCE_OBJECT ) ) . '"
|
1978 |
+
href="#" title="' . $action['label'] . '"><i class="dashicons dashicons-' . esc_attr( $action['icon'] ) . '"></i></button>';
|
1979 |
+
}
|
1980 |
+
} else {
|
1981 |
+
echo '-';
|
1982 |
+
}
|
1983 |
+
?>
|
1984 |
+
</td>
|
1985 |
+
</tr>
|
1986 |
+
<?php endforeach; ?>
|
1987 |
+
<?php else : ?>
|
1988 |
+
<tr class="empty-row"><td colspan="9" style="text-align: center"><?php _e('No events yet.', 'limit-login-attempts-reloaded' ); ?></td></tr>
|
1989 |
+
<?php endif; ?>
|
1990 |
+
<?php
|
1991 |
+
|
1992 |
+
wp_send_json_success(array(
|
1993 |
+
'html' => ob_get_clean(),
|
1994 |
+
'offset' => $log['offset']
|
1995 |
+
));
|
1996 |
+
|
1997 |
+
} else {
|
1998 |
+
|
1999 |
+
wp_send_json_error(array(
|
2000 |
+
'msg' => 'The endpoint is not responding. Please contact your app provider to settle that.'
|
2001 |
+
));
|
2002 |
+
}
|
2003 |
+
}
|
2004 |
+
|
2005 |
+
public function app_load_lockouts_callback() {
|
2006 |
+
|
2007 |
+
if ( !current_user_can('activate_plugins') ) {
|
2008 |
+
|
2009 |
+
wp_send_json_error(array());
|
2010 |
+
}
|
2011 |
+
|
2012 |
+
check_ajax_referer('llar-action', 'sec');
|
2013 |
+
|
2014 |
+
$offset = sanitize_text_field( $_POST['offset'] );
|
2015 |
+
|
2016 |
+
$lockouts = $this->app->get_lockouts( 25, $offset );
|
2017 |
+
|
2018 |
+
if( $lockouts ) {
|
2019 |
+
|
2020 |
+
ob_start(); ?>
|
2021 |
+
|
2022 |
+
<tr>
|
2023 |
+
<th scope="col"><?php _e( "IP", 'limit-login-attempts-reloaded' ); ?></th>
|
2024 |
+
<th scope="col"><?php _e( "Login", 'limit-login-attempts-reloaded' ); ?></th>
|
2025 |
+
<th scope="col"><?php _e( "Count", 'limit-login-attempts-reloaded' ); ?></th>
|
2026 |
+
<th scope="col"><?php _e( "Expires in (minutes)", 'limit-login-attempts-reloaded' ); ?></th>
|
2027 |
+
</tr>
|
2028 |
+
|
2029 |
+
<?php if( $lockouts['items'] ) : ?>
|
2030 |
+
<?php foreach ( $lockouts['items'] as $item ) : ?>
|
2031 |
+
<tr>
|
2032 |
+
<td><?php echo esc_html( $item['ip'] ); ?></td>
|
2033 |
+
<td><?php echo (is_null($item['login'])) ? '-' : esc_html( implode( ',', $item['login'] ) ); ?></td>
|
2034 |
+
<td><?php echo (is_null($item['count'])) ? '-' : esc_html( $item['count'] ); ?></td>
|
2035 |
+
<td><?php echo (is_null($item['ttl'])) ? '-' : esc_html( round( ( $item['ttl'] - time() ) / 60 ) ); ?></td>
|
2036 |
+
</tr>
|
2037 |
+
<?php endforeach; ?>
|
2038 |
+
|
2039 |
+
<?php else: ?>
|
2040 |
+
<tr class="empty-row"><td colspan="4" style="text-align: center"><?php _e('No lockouts yet.', 'limit-login-attempts-reloaded' ); ?></td></tr>
|
2041 |
+
<?php endif; ?>
|
2042 |
+
<?php
|
2043 |
+
|
2044 |
+
wp_send_json_success(array(
|
2045 |
+
'html' => ob_get_clean(),
|
2046 |
+
'offset' => $lockouts['offset']
|
2047 |
+
));
|
2048 |
+
|
2049 |
+
} elseif( intval( $this->app->last_response_code ) >= 400 && intval( $this->app->last_response_code ) < 500) {
|
2050 |
+
|
2051 |
+
$app_config = $this->get_custom_app_config();
|
2052 |
+
|
2053 |
+
wp_send_json_error(array(
|
2054 |
+
'error_notice' => '<div class="llar-app-notice">
|
2055 |
+
<p>'. $app_config['messages']['sync_error'] .'<br><br>'. sprintf( __( 'Meanwhile, the app falls over to the <a href="%s">default functionality</a>.', 'limit-login-attempts-reloaded' ), admin_url('options-general.php?page=limit-login-attempts&tab=logs-local') ) . '</p>
|
2056 |
+
</div>'
|
2057 |
+
));
|
2058 |
+
} else {
|
2059 |
+
|
2060 |
+
wp_send_json_error(array(
|
2061 |
+
'msg' => 'The endpoint is not responding. Please contact your app provider to settle that.'
|
2062 |
+
));
|
2063 |
+
}
|
2064 |
+
}
|
2065 |
+
|
2066 |
+
public function app_load_acl_rules_callback() {
|
2067 |
+
|
2068 |
+
if ( !current_user_can('activate_plugins') ) {
|
2069 |
+
|
2070 |
+
wp_send_json_error(array());
|
2071 |
+
}
|
2072 |
+
|
2073 |
+
check_ajax_referer('llar-action', 'sec');
|
2074 |
+
|
2075 |
+
$type = sanitize_text_field( $_POST['type'] );
|
2076 |
+
|
2077 |
+
$acl_list = $this->app->acl( array(
|
2078 |
+
'type' => $type
|
2079 |
+
) );
|
2080 |
+
|
2081 |
+
if( $acl_list ) {
|
2082 |
+
|
2083 |
+
ob_start(); ?>
|
2084 |
+
|
2085 |
+
<tr>
|
2086 |
+
<th scope="col"><?php _e( 'Pattern', 'limit-login-attempts-reloaded' ); ?></th>
|
2087 |
+
<th scope="col"><?php _e( 'Rule', 'limit-login-attempts-reloaded' ); ?></th>
|
2088 |
+
<th class="llar-app-acl-action-col" scope="col"><?php _e( 'Action', 'limit-login-attempts-reloaded' ); ?></th>
|
2089 |
+
</tr>
|
2090 |
+
<tr>
|
2091 |
+
<td><input class="regular-text llar-app-acl-pattern" type="text" placeholder="<?php esc_attr_e( 'Pattern', 'limit-login-attempts-reloaded' ); ?>"></td>
|
2092 |
+
<td>
|
2093 |
+
<select class="llar-app-acl-rule">
|
2094 |
+
<option value="deny" selected><?php esc_html_e( 'Deny', 'limit-login-attempts-reloaded' ); ?></option>
|
2095 |
+
<option value="allow"><?php esc_html_e( 'Allow', 'limit-login-attempts-reloaded' ); ?></option>
|
2096 |
+
<option value="pass"><?php esc_html_e( 'Pass', 'limit-login-attempts-reloaded' ); ?></option>
|
2097 |
+
</select>
|
2098 |
+
</td>
|
2099 |
+
<td class="llar-app-acl-action-col"><button class="button llar-app-acl-add-rule" data-type="<?php echo esc_attr( $type ); ?>"><?php _e( 'Add', 'limit-login-attempts-reloaded' ); ?></button></td>
|
2100 |
+
</tr>
|
2101 |
+
|
2102 |
+
<?php if( $acl_list['items'] ) : ?>
|
2103 |
+
<?php foreach ( $acl_list['items'] as $item ) : ?>
|
2104 |
+
<tr class="llar-app-rule-<?php echo esc_attr( $item['rule'] ); ?>">
|
2105 |
+
<td class="rule-pattern" scope="col"><?php echo esc_html( $item['pattern'] ); ?></td>
|
2106 |
+
<td scope="col"><?php echo esc_html( $item['rule'] ); ?></td>
|
2107 |
+
<td class="llar-app-acl-action-col" scope="col"><button class="button llar-app-acl-remove" data-type="login" data-pattern="<?php echo esc_attr( $item['pattern'] ); ?>"><span class="dashicons dashicons-no"></span></button></td>
|
2108 |
+
</tr>
|
2109 |
+
<?php endforeach; ?>
|
2110 |
+
<?php else : ?>
|
2111 |
+
<tr class="empty-row"><td colspan="3" style="text-align: center"><?php _e('No rules yet.', 'limit-login-attempts-reloaded' ); ?></td></tr>
|
2112 |
+
<?php endif; ?>
|
2113 |
+
<?php
|
2114 |
+
|
2115 |
+
wp_send_json_success(array(
|
2116 |
+
'html' => ob_get_clean(),
|
2117 |
+
));
|
2118 |
+
|
2119 |
+
} else {
|
2120 |
+
|
2121 |
+
wp_send_json_error(array(
|
2122 |
+
'msg' => 'The endpoint is not responding. Please contact your app provider to settle that.'
|
2123 |
+
));
|
2124 |
+
}
|
2125 |
+
}
|
2126 |
+
|
2127 |
+
public function get_custom_app_config() {
|
2128 |
+
|
2129 |
+
return $this->get_option( 'app_config' );
|
2130 |
+
}
|
2131 |
}
|
limit-login-attempts-reloaded.php
CHANGED
@@ -2,12 +2,12 @@
|
|
2 |
/*
|
3 |
Plugin Name: Limit Login Attempts Reloaded
|
4 |
Description: Limit the rate of login attempts for each IP address.
|
5 |
-
Author:
|
6 |
-
Author URI: https://
|
7 |
Text Domain: limit-login-attempts-reloaded
|
8 |
-
Version: 2.
|
9 |
|
10 |
-
Copyright 2008 - 2012 Johan Eenfeldt, 2016 - 2020
|
11 |
*/
|
12 |
|
13 |
/***************************************************************************************
|
@@ -33,6 +33,7 @@ $limit_login_nonempty_credentials = false; /* user and pwd nonempty */
|
|
33 |
* Include files
|
34 |
**************************************************************************************/
|
35 |
require_once( LLA_PLUGIN_DIR . '/core/Helpers.php' );
|
|
|
36 |
require_once( LLA_PLUGIN_DIR . '/core/LimitLoginAttempts.php' );
|
37 |
|
38 |
$limit_login_attempts_obj = new Limit_Login_Attempts();
|
2 |
/*
|
3 |
Plugin Name: Limit Login Attempts Reloaded
|
4 |
Description: Limit the rate of login attempts for each IP address.
|
5 |
+
Author: Limit Login Attempts Reloaded
|
6 |
+
Author URI: https://limitloginattempts.com/
|
7 |
Text Domain: limit-login-attempts-reloaded
|
8 |
+
Version: 2.16.0
|
9 |
|
10 |
+
Copyright 2008 - 2012 Johan Eenfeldt, 2016 - 2020 Limit Login Attempts Reloaded
|
11 |
*/
|
12 |
|
13 |
/***************************************************************************************
|
33 |
* Include files
|
34 |
**************************************************************************************/
|
35 |
require_once( LLA_PLUGIN_DIR . '/core/Helpers.php' );
|
36 |
+
require_once( LLA_PLUGIN_DIR . '/core/App.php' );
|
37 |
require_once( LLA_PLUGIN_DIR . '/core/LimitLoginAttempts.php' );
|
38 |
|
39 |
$limit_login_attempts_obj = new Limit_Login_Attempts();
|
readme.txt
CHANGED
@@ -1,47 +1,68 @@
|
|
1 |
=== Limit Login Attempts Reloaded ===
|
2 |
Contributors: wpchefgadget
|
|
|
3 |
Tags: brute force, login, security, GDPR, protection
|
4 |
Requires at least: 3.0
|
5 |
Tested up to: 5.5
|
6 |
-
Stable tag: 2.
|
7 |
|
8 |
Reloaded version of the original Limit Login Attempts plugin for Login Protection by a team of WordPress developers. GDPR compliant.
|
9 |
|
10 |
== Description ==
|
11 |
|
12 |
-
Limit the number of login attempts that possible through the normal login as well as XMLRPC, Woocommerce and custom login pages.
|
13 |
-
WordPress by default allows unlimited login attempts. This allows passwords to be cracked via brute-force relatively easily.
|
14 |
-
Limit Login Attempts Reloaded blocks an Internet address from making further attempts after a specified limit on retries has been reached, making a brute-force attack difficult or impossible.
|
15 |
|
16 |
-
|
17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
* Limit the number of retry attempts when logging in (per each IP). This is fully customizable.
|
19 |
* Informs the user about the remaining retries or lockout time on the login page.
|
20 |
-
*
|
21 |
-
* It is possible to
|
22 |
* Sucuri Website Firewall compatibility.
|
23 |
* **XMLRPC** gateway protection.
|
24 |
* **Woocommerce** login page protection.
|
25 |
* **Multi-site** compatibility with extra MU settings.
|
26 |
-
* **GDPR** compliant.
|
27 |
* **Custom IP origins** support (Cloudflare, Sucuri, etc.)
|
28 |
|
29 |
-
=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
1. Go to the Plugins section in your site's backend.
|
31 |
1. Remove the Limit Login Attempts plugin.
|
32 |
1. Install the Limit Login Attempts Reloaded plugin.
|
33 |
|
34 |
All your settings will be kept in tact!
|
35 |
|
36 |
-
Many languages are currently supported in Limit Login Attempts Reloaded plugin but we welcome any additional ones.
|
37 |
-
Help us bring Limit Login Attempts Reloaded to even more
|
38 |
|
39 |
Translations: Bulgarian, Brazilian Portuguese, Catalan, Chinese (Traditional), Czech, Dutch, Finnish, French, German, Hungarian, Norwegian, Persian, Romanian, Russian, Spanish, Swedish, Turkish
|
40 |
|
41 |
Plugin uses standard actions and filters only.
|
42 |
|
43 |
-
Based on the original code from Limit Login
|
44 |
-
|
|
|
|
|
|
|
|
|
45 |
|
46 |
== Screenshots ==
|
47 |
|
@@ -49,8 +70,29 @@ Based on the original code from Limit Login Attemps plugin by Johan Eenfeldt.
|
|
49 |
2. Lockout loginscreen
|
50 |
3. Administration interface in WordPress 5.2.1
|
51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
== Changelog ==
|
53 |
|
|
|
|
|
|
|
54 |
= 2.15.2 =
|
55 |
* Alternative method of closing the feedback message.
|
56 |
|
1 |
=== Limit Login Attempts Reloaded ===
|
2 |
Contributors: wpchefgadget
|
3 |
+
Donate link: https://www.paypal.com/donate?hosted_button_id=FKD4MYFCMNVQQ
|
4 |
Tags: brute force, login, security, GDPR, protection
|
5 |
Requires at least: 3.0
|
6 |
Tested up to: 5.5
|
7 |
+
Stable tag: 2.16.0
|
8 |
|
9 |
Reloaded version of the original Limit Login Attempts plugin for Login Protection by a team of WordPress developers. GDPR compliant.
|
10 |
|
11 |
== Description ==
|
12 |
|
13 |
+
Limit the number of login attempts that are possible through the normal login as well as XMLRPC, Woocommerce and custom login pages.
|
|
|
|
|
14 |
|
15 |
+
WordPress by default allows unlimited login attempts. This can lead to passwords being easily cracked via brute-force.
|
16 |
|
17 |
+
Limit Login Attempts Reloaded blocks an Internet address (IP) from making further attempts after a specified limit on retries has been reached, making a brute-force attack difficult or impossible.
|
18 |
+
|
19 |
+
> <strong>Limit Login Attempts Reloaded Cloud App</strong><br>
|
20 |
+
> Enables cloud protection app for Limit Login Attempts Reloaded plugin. It comes with all the great features you'll need to stop hackers and bots from brute-force attacks. The cloud app <a href="https://www.limitloginattempts.com/features/">offers several features</a> including advanced protection out of the box, and the ability for site admins and agencies to sync allow/deny/pass lists across multiple domains. <a href="https://app.limitloginattempts.com/network/create">Click here to activate the cloud app for the best WordPress security plugin now!</a>
|
21 |
+
|
22 |
+
https://www.youtube.com/watch?v=IsotthPWCPA
|
23 |
+
|
24 |
+
= Features: =
|
25 |
* Limit the number of retry attempts when logging in (per each IP). This is fully customizable.
|
26 |
* Informs the user about the remaining retries or lockout time on the login page.
|
27 |
+
* Logging and optional email notification.
|
28 |
+
* It is possible to allow/deny IPs and Usernames.
|
29 |
* Sucuri Website Firewall compatibility.
|
30 |
* **XMLRPC** gateway protection.
|
31 |
* **Woocommerce** login page protection.
|
32 |
* **Multi-site** compatibility with extra MU settings.
|
33 |
+
* **GDPR** compliant.
|
34 |
* **Custom IP origins** support (Cloudflare, Sucuri, etc.)
|
35 |
|
36 |
+
= Features (Cloud app): =
|
37 |
+
* **Outsource the site load** - All calculations and database queries are done in the cloud
|
38 |
+
* **Throttling** - Longer lockout intervals each time a hacker/bot tries to login unsuccessfully
|
39 |
+
* **Auto backups of all data**
|
40 |
+
* **Autofix diverse origin IPs (e.g. Cloudflare)** - Securely trust certain popular IP origins out of the box
|
41 |
+
* **Synced lockout & deny/pass lists check** - Lockouts can be shared between sites of the same admin
|
42 |
+
* **Synchronized allow/deny/pass lists** - Allow/Deny/Pass lists can be shared between sites of the same admin
|
43 |
+
* **Premium forum support** - Get answers within 1-2 business days.
|
44 |
+
* **Enhanced lockout logs** - A log of lockouts with extra features
|
45 |
+
|
46 |
+
= Upgrading from the old Limit Login Attempts plugin? =
|
47 |
1. Go to the Plugins section in your site's backend.
|
48 |
1. Remove the Limit Login Attempts plugin.
|
49 |
1. Install the Limit Login Attempts Reloaded plugin.
|
50 |
|
51 |
All your settings will be kept in tact!
|
52 |
|
53 |
+
Many languages are currently supported in the Limit Login Attempts Reloaded plugin but we welcome any additional ones.
|
54 |
+
Help us bring Limit Login Attempts Reloaded to even more countries.
|
55 |
|
56 |
Translations: Bulgarian, Brazilian Portuguese, Catalan, Chinese (Traditional), Czech, Dutch, Finnish, French, German, Hungarian, Norwegian, Persian, Romanian, Russian, Spanish, Swedish, Turkish
|
57 |
|
58 |
Plugin uses standard actions and filters only.
|
59 |
|
60 |
+
Based on the original code from Limit Login Attempts plugin by Johan Eenfeldt.
|
61 |
+
|
62 |
+
= Branding Guidelines =
|
63 |
+
Limit Login Attempts Reloaded™ is a trademark of Atlantic Silicon Inc. When writing about the plugin, please make sure to use Reloaded after Limit Login Attempts. Limit Login Attempts is the old plugin.
|
64 |
+
* Limit Login Attempts Reloaded (correct)
|
65 |
+
* Limit Login Attempts (incorrect)
|
66 |
|
67 |
== Screenshots ==
|
68 |
|
70 |
2. Lockout loginscreen
|
71 |
3. Administration interface in WordPress 5.2.1
|
72 |
|
73 |
+
== Frequently Asked Questions ==
|
74 |
+
|
75 |
+
= What do I do if all users get blocked? =
|
76 |
+
|
77 |
+
If you are using contemporary hosting, it's likely your site uses a proxy domain service like CloudFlare, Sucuri, Nginx, etc. They replace your user's IP address with their own. If the server where your site runs is not configured properly (this happens a lot) all users will get the same IP address. This also applies to bots and hackers. Therefore, locking one user will lead to locking everybody else out. If the plugin is not using our <a href="https://www.limitloginattempts.com/">Cloud App</a>, this can be adjusted using the Trusted IP Origin setting. The cloud service intelligently recognizes the non-standard IP origins and handles them correctly, even if your hosting provider does not.
|
78 |
+
|
79 |
+
= What settings should I use In The Plugin? =
|
80 |
+
|
81 |
+
The settings are explained within the plugin in great detail. If you are unsure, use the default settings as they are the recommended ones.
|
82 |
+
|
83 |
+
= Can I share the allow/deny/pass lists throughout all of my sites?=
|
84 |
+
|
85 |
+
By default, you will need to copy and paste the lists to each site manually. For the <a href="https://www.limitloginattempts.com/features/">premium service</a>, sites are grouped within the same private cloud account. Each site within that group can be configured if it shares its lockouts and access lists with other group members. The setting is located in the plugin's interface. The default options are recommended.
|
86 |
+
|
87 |
+
= Where can I find answers to my Cloud App related questions? =
|
88 |
+
|
89 |
+
Please follow this link: <a href="https://www.limitloginattempts.com/resources/">https://www.limitloginattempts.com/resources/</a>
|
90 |
+
|
91 |
== Changelog ==
|
92 |
|
93 |
+
= 2.16.0 =
|
94 |
+
* Custom Apps functionality implemented. More details: https://limitloginattempts.com/app/
|
95 |
+
|
96 |
= 2.15.2 =
|
97 |
* Alternative method of closing the feedback message.
|
98 |
|
views/options-page.php
CHANGED
@@ -2,10 +2,17 @@
|
|
2 |
|
3 |
if( !defined( 'ABSPATH' ) ) exit();
|
4 |
|
5 |
-
$active_tab = "
|
6 |
-
|
|
|
7 |
|
8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
}
|
10 |
?>
|
11 |
|
@@ -13,9 +20,17 @@ if(!empty($_GET["tab"]) && in_array($_GET["tab"], ['dashboard', 'settings', 'deb
|
|
13 |
<h2><?php echo __( 'Limit Login Attempts Reloaded', 'limit-login-attempts-reloaded' ); ?></h2>
|
14 |
|
15 |
<h2 class="nav-tab-wrapper">
|
16 |
-
<a href="<?php echo $this->get_options_page_uri();
|
17 |
-
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
</h2>
|
20 |
|
21 |
<?php include_once(LLA_PLUGIN_DIR.'views/tab-'.$active_tab.'.php'); ?>
|
2 |
|
3 |
if( !defined( 'ABSPATH' ) ) exit();
|
4 |
|
5 |
+
$active_tab = "settings";
|
6 |
+
$active_app = $this->get_option( 'active_app' );
|
7 |
+
if(!empty($_GET["tab"]) && in_array($_GET["tab"], ['logs-local', 'logs-custom', 'settings', 'debug'])) {
|
8 |
|
9 |
+
if(!$this->app && $_GET['tab'] === 'logs-custom') {
|
10 |
+
|
11 |
+
$active_tab = 'logs-local';
|
12 |
+
} else {
|
13 |
+
|
14 |
+
$active_tab = sanitize_text_field( $_GET["tab"] );
|
15 |
+
}
|
16 |
}
|
17 |
?>
|
18 |
|
20 |
<h2><?php echo __( 'Limit Login Attempts Reloaded', 'limit-login-attempts-reloaded' ); ?></h2>
|
21 |
|
22 |
<h2 class="nav-tab-wrapper">
|
23 |
+
<a href="<?php echo $this->get_options_page_uri('settings'); ?>" class="nav-tab <?php if($active_tab == 'settings'){echo 'nav-tab-active';} ?> "><?php _e('Settings', 'limit-login-attempts-reloaded'); ?></a>
|
24 |
+
<?php if( $active_app === 'custom' ) : ?>
|
25 |
+
<a href="<?php echo $this->get_options_page_uri('logs-custom'); ?>" class="nav-tab <?php if($active_tab == 'logs-custom'){echo 'nav-tab-active';} ?> "><?php _e('Logs', 'limit-login-attempts-reloaded'); ?></a>
|
26 |
+
<?php else : ?>
|
27 |
+
<a href="<?php echo $this->get_options_page_uri('logs-local'); ?>" class="nav-tab <?php if($active_tab == 'logs-local'){echo 'nav-tab-active';} ?> "><?php _e('Logs', 'limit-login-attempts-reloaded'); ?></a>
|
28 |
+
<?php endif; ?>
|
29 |
+
<a href="<?php echo $this->get_options_page_uri('debug'); ?>" class="nav-tab <?php if($active_tab == 'debug'){echo 'nav-tab-active';} ?>"><?php _e('Debug', 'limit-login-attempts-reloaded'); ?></a>
|
30 |
+
|
31 |
+
<?php if($active_tab == 'logs-custom') : ?>
|
32 |
+
<a class="llar-failover-link" href="<?php echo $this->get_options_page_uri('logs-local'); ?>"><?php _e( 'Failover', 'limit-login-attempts-reloaded' ); ?></a>
|
33 |
+
<?php endif; ?>
|
34 |
</h2>
|
35 |
|
36 |
<?php include_once(LLA_PLUGIN_DIR.'views/tab-'.$active_tab.'.php'); ?>
|
views/tab-logs-custom.php
ADDED
@@ -0,0 +1,414 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
if( !defined( 'ABSPATH' ) ) exit();
|
4 |
+
|
5 |
+
/**
|
6 |
+
* @var $this Limit_Login_Attempts
|
7 |
+
*/
|
8 |
+
?>
|
9 |
+
|
10 |
+
<div class="limit-login-app-dashboard">
|
11 |
+
|
12 |
+
<h3><?php _e( 'Lockouts', 'limit-login-attempts-reloaded' ); ?></h3>
|
13 |
+
|
14 |
+
<div class="llar-app-lockouts-pagination">
|
15 |
+
<a class="llar-prev-page button disabled" href="#">
|
16 |
+
<span aria-hidden="true">‹</span>
|
17 |
+
</a>
|
18 |
+
<a class="llar-next-page button disabled" href="#">
|
19 |
+
<span aria-hidden="true">›</span>
|
20 |
+
</a>
|
21 |
+
</div>
|
22 |
+
|
23 |
+
<table class="form-table llar-table-app-lockouts">
|
24 |
+
<tr>
|
25 |
+
<th scope="col"><?php _e( "IP", 'limit-login-attempts-reloaded' ); ?></th>
|
26 |
+
<th scope="col"><?php _e( "Login", 'limit-login-attempts-reloaded' ); ?></th>
|
27 |
+
<th scope="col"><?php _e( "Count", 'limit-login-attempts-reloaded' ); ?></th>
|
28 |
+
<th scope="col"><?php _e( "Expires in (minutes)", 'limit-login-attempts-reloaded' ); ?></th>
|
29 |
+
</tr>
|
30 |
+
</table>
|
31 |
+
|
32 |
+
<script type="text/javascript">
|
33 |
+
;(function($){
|
34 |
+
|
35 |
+
$(document).ready(function () {
|
36 |
+
|
37 |
+
var $log_table = $('.llar-table-app-lockouts'),
|
38 |
+
current_page = 0,
|
39 |
+
page_offsets = [''];
|
40 |
+
|
41 |
+
load_lockouts_data();
|
42 |
+
|
43 |
+
$('.llar-app-lockouts-pagination').on('click', '.llar-prev-page:not(.disabled)', function(e){
|
44 |
+
e.preventDefault();
|
45 |
+
|
46 |
+
load_lockouts_data(page_offsets[--current_page]);
|
47 |
+
|
48 |
+
toggle_next_btn(true);
|
49 |
+
});
|
50 |
+
|
51 |
+
$('.llar-app-lockouts-pagination').on('click', '.llar-next-page:not(.disabled)', function(e){
|
52 |
+
e.preventDefault();
|
53 |
+
|
54 |
+
load_lockouts_data(page_offsets[++current_page]);
|
55 |
+
});
|
56 |
+
|
57 |
+
function toggle_prev_btn(enable) {
|
58 |
+
if(enable) {
|
59 |
+
|
60 |
+
$('.llar-app-lockouts-pagination .llar-prev-page').removeClass('disabled');
|
61 |
+
} else {
|
62 |
+
|
63 |
+
$('.llar-app-lockouts-pagination .llar-prev-page').addClass('disabled');
|
64 |
+
}
|
65 |
+
}
|
66 |
+
function toggle_next_btn(enable) {
|
67 |
+
if(enable) {
|
68 |
+
|
69 |
+
$('.llar-app-lockouts-pagination .llar-next-page').removeClass('disabled');
|
70 |
+
} else {
|
71 |
+
|
72 |
+
$('.llar-app-lockouts-pagination .llar-next-page').addClass('disabled');
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
function load_lockouts_data(offset) {
|
77 |
+
|
78 |
+
llar.progressbar.start();
|
79 |
+
|
80 |
+
$.post(ajaxurl, {
|
81 |
+
action: 'app_load_lockouts',
|
82 |
+
offset: offset,
|
83 |
+
sec: '<?php echo wp_create_nonce( "llar-action" ); ?>'
|
84 |
+
}, function(response){
|
85 |
+
|
86 |
+
llar.progressbar.stop();
|
87 |
+
|
88 |
+
if(response.success) {
|
89 |
+
|
90 |
+
$log_table.html(response.data.html);
|
91 |
+
|
92 |
+
if(current_page > 0) {
|
93 |
+
toggle_prev_btn(true);
|
94 |
+
} else {
|
95 |
+
toggle_prev_btn(false);
|
96 |
+
|
97 |
+
}
|
98 |
+
|
99 |
+
if(response.data.offset) {
|
100 |
+
page_offsets.push(response.data.offset);
|
101 |
+
toggle_next_btn(true);
|
102 |
+
} else {
|
103 |
+
toggle_next_btn(false);
|
104 |
+
}
|
105 |
+
|
106 |
+
} else {
|
107 |
+
|
108 |
+
if(response.data.error_notice) {
|
109 |
+
$('.limit-login-app-dashboard').find('.llar-app-notice').remove();
|
110 |
+
$('.limit-login-app-dashboard').prepend(response.data.error_notice);
|
111 |
+
}
|
112 |
+
|
113 |
+
}
|
114 |
+
|
115 |
+
});
|
116 |
+
|
117 |
+
}
|
118 |
+
});
|
119 |
+
|
120 |
+
})(jQuery);
|
121 |
+
</script>
|
122 |
+
|
123 |
+
<h3><?php _e( 'Event Log', 'limit-login-attempts-reloaded' ); ?></h3>
|
124 |
+
|
125 |
+
<div class="llar-app-log-pagination">
|
126 |
+
<a class="llar-prev-page button disabled" href="#">
|
127 |
+
<span aria-hidden="true">‹</span>
|
128 |
+
</a>
|
129 |
+
<a class="llar-next-page button disabled" href="#">
|
130 |
+
<span aria-hidden="true">›</span>
|
131 |
+
</a>
|
132 |
+
</div>
|
133 |
+
|
134 |
+
<div class="llar-table-scroll-wrap">
|
135 |
+
<table class="form-table llar-table-app-log">
|
136 |
+
<tr>
|
137 |
+
<th scope="col"><?php _e( "Time", 'limit-login-attempts-reloaded' ); ?></th>
|
138 |
+
<th scope="col"><?php _e( "IP", 'limit-login-attempts-reloaded' ); ?></th>
|
139 |
+
<th scope="col"><?php _e( "Gateway", 'limit-login-attempts-reloaded' ); ?></th>
|
140 |
+
<th scope="col"><?php _e( "Login", 'limit-login-attempts-reloaded' ); ?></th>
|
141 |
+
<th scope="col"><?php _e( "Rule", 'limit-login-attempts-reloaded' ); ?></th>
|
142 |
+
<th scope="col"><?php _e( "Reason", 'limit-login-attempts-reloaded' ); ?></th>
|
143 |
+
<th scope="col"><?php _e( "Pattern", 'limit-login-attempts-reloaded' ); ?></th>
|
144 |
+
<th scope="col"><?php _e( "Attempts Left", 'limit-login-attempts-reloaded' ); ?></th>
|
145 |
+
<th scope="col"><?php _e( "Lockout Duration", 'limit-login-attempts-reloaded' ); ?></th>
|
146 |
+
<th scope="col"><?php _e( "Actions", 'limit-login-attempts-reloaded' ); ?></th>
|
147 |
+
</tr>
|
148 |
+
</table>
|
149 |
+
</div>
|
150 |
+
<script type="text/javascript">
|
151 |
+
;(function($){
|
152 |
+
|
153 |
+
$(document).ready(function () {
|
154 |
+
|
155 |
+
var $log_table = $('.llar-table-app-log'),
|
156 |
+
current_page = 0,
|
157 |
+
page_offsets = [''];
|
158 |
+
|
159 |
+
load_log_data();
|
160 |
+
|
161 |
+
$('.llar-app-log-pagination').on('click', '.llar-prev-page:not(.disabled)', function(e){
|
162 |
+
e.preventDefault();
|
163 |
+
|
164 |
+
load_log_data(page_offsets[--current_page]);
|
165 |
+
|
166 |
+
toggle_next_btn(true);
|
167 |
+
});
|
168 |
+
|
169 |
+
$('.llar-app-log-pagination').on('click', '.llar-next-page:not(.disabled)', function(e){
|
170 |
+
e.preventDefault();
|
171 |
+
|
172 |
+
load_log_data(page_offsets[++current_page]);
|
173 |
+
});
|
174 |
+
|
175 |
+
$log_table.on('click', '.js-app-log-action', function (e) {
|
176 |
+
e.preventDefault();
|
177 |
+
|
178 |
+
var $this = $(this),
|
179 |
+
method = $this.data('method'),
|
180 |
+
params = $this.data('params');
|
181 |
+
|
182 |
+
if(!confirm('Are you sure?')) return;
|
183 |
+
|
184 |
+
llar.progressbar.start();
|
185 |
+
|
186 |
+
$.post(ajaxurl, {
|
187 |
+
action: 'app_log_action',
|
188 |
+
method: method,
|
189 |
+
params: params,
|
190 |
+
sec: '<?php echo esc_js( wp_create_nonce( "llar-action" ) ); ?>'
|
191 |
+
}, function(response){
|
192 |
+
|
193 |
+
llar.progressbar.stop();
|
194 |
+
|
195 |
+
console.log(response);
|
196 |
+
if(response.success) {
|
197 |
+
|
198 |
+
|
199 |
+
}
|
200 |
+
|
201 |
+
});
|
202 |
+
});
|
203 |
+
|
204 |
+
function toggle_prev_btn(enable) {
|
205 |
+
if(enable) {
|
206 |
+
|
207 |
+
$('.llar-app-log-pagination .llar-prev-page').removeClass('disabled');
|
208 |
+
} else {
|
209 |
+
|
210 |
+
$('.llar-app-log-pagination .llar-prev-page').addClass('disabled');
|
211 |
+
}
|
212 |
+
}
|
213 |
+
function toggle_next_btn(enable) {
|
214 |
+
if(enable) {
|
215 |
+
|
216 |
+
$('.llar-app-log-pagination .llar-next-page').removeClass('disabled');
|
217 |
+
} else {
|
218 |
+
|
219 |
+
$('.llar-app-log-pagination .llar-next-page').addClass('disabled');
|
220 |
+
}
|
221 |
+
}
|
222 |
+
|
223 |
+
function load_log_data(offset) {
|
224 |
+
|
225 |
+
llar.progressbar.start();
|
226 |
+
|
227 |
+
$.post(ajaxurl, {
|
228 |
+
action: 'app_load_log',
|
229 |
+
offset: offset,
|
230 |
+
sec: '<?php echo wp_create_nonce( "llar-action" ); ?>'
|
231 |
+
}, function(response){
|
232 |
+
|
233 |
+
llar.progressbar.stop();
|
234 |
+
|
235 |
+
if(response.success) {
|
236 |
+
|
237 |
+
$log_table.html(response.data.html);
|
238 |
+
|
239 |
+
if(current_page > 0) {
|
240 |
+
toggle_prev_btn(true);
|
241 |
+
} else {
|
242 |
+
toggle_prev_btn(false);
|
243 |
+
|
244 |
+
}
|
245 |
+
|
246 |
+
if(response.data.offset) {
|
247 |
+
page_offsets.push(response.data.offset);
|
248 |
+
toggle_next_btn(true);
|
249 |
+
} else {
|
250 |
+
toggle_next_btn(false);
|
251 |
+
}
|
252 |
+
|
253 |
+
}
|
254 |
+
|
255 |
+
});
|
256 |
+
|
257 |
+
}
|
258 |
+
});
|
259 |
+
|
260 |
+
})(jQuery);
|
261 |
+
</script>
|
262 |
+
|
263 |
+
<div class="llar-app-acl-rules">
|
264 |
+
<div class="app-rules-col">
|
265 |
+
<h3><?php _e( 'Login Access Rules', 'limit-login-attempts-reloaded' ); ?></h3>
|
266 |
+
<table class="form-table llar-app-login-access-rules-table">
|
267 |
+
<tr>
|
268 |
+
<th scope="col"><?php _e( 'Pattern', 'limit-login-attempts-reloaded' ); ?></th>
|
269 |
+
<th scope="col"><?php _e( 'Rule', 'limit-login-attempts-reloaded' ); ?></th>
|
270 |
+
<th class="llar-app-acl-action-col" scope="col"><?php _e( 'Action', 'limit-login-attempts-reloaded' ); ?></th>
|
271 |
+
</tr>
|
272 |
+
</table>
|
273 |
+
</div>
|
274 |
+
<div class="app-rules-col">
|
275 |
+
<h3><?php _e( 'IP Access Rules', 'limit-login-attempts-reloaded' ); ?></h3>
|
276 |
+
<table class="form-table llar-app-ip-access-rules-table">
|
277 |
+
<tr>
|
278 |
+
<th scope="col"><?php _e( 'Pattern', 'limit-login-attempts-reloaded' ); ?></th>
|
279 |
+
<th scope="col"><?php _e( 'Rule', 'limit-login-attempts-reloaded' ); ?></th>
|
280 |
+
<th class="llar-app-acl-action-col" scope="col"><?php _e( 'Action', 'limit-login-attempts-reloaded' ); ?></th>
|
281 |
+
</tr>
|
282 |
+
</table>
|
283 |
+
</div>
|
284 |
+
|
285 |
+
<script type="text/javascript">
|
286 |
+
;(function($){
|
287 |
+
|
288 |
+
$(document).ready(function () {
|
289 |
+
|
290 |
+
var $app_acl_rules = $('.llar-app-acl-rules');
|
291 |
+
|
292 |
+
load_rules_data('login');
|
293 |
+
load_rules_data('ip');
|
294 |
+
|
295 |
+
$app_acl_rules
|
296 |
+
.on('click', '.llar-app-acl-remove', function(e){
|
297 |
+
e.preventDefault();
|
298 |
+
|
299 |
+
if(!confirm('Are you sure?')) {
|
300 |
+
return false;
|
301 |
+
}
|
302 |
+
|
303 |
+
var $this = $(this),
|
304 |
+
pattern = $this.data('pattern');
|
305 |
+
|
306 |
+
if(!pattern) {
|
307 |
+
|
308 |
+
console.log('Wrong pattern');
|
309 |
+
return false;
|
310 |
+
}
|
311 |
+
|
312 |
+
llar.progressbar.start();
|
313 |
+
|
314 |
+
$.post(ajaxurl, {
|
315 |
+
action: 'app_acl_remove_rule',
|
316 |
+
pattern: pattern,
|
317 |
+
type: $this.data('type'),
|
318 |
+
sec: '<?php echo esc_js( wp_create_nonce( "llar-action" ) ); ?>'
|
319 |
+
}, function(response){
|
320 |
+
|
321 |
+
llar.progressbar.stop();
|
322 |
+
|
323 |
+
if(response.success) {
|
324 |
+
|
325 |
+
$this.closest('tr').fadeOut(300, function(){
|
326 |
+
$this.closest('tr').remove();
|
327 |
+
})
|
328 |
+
|
329 |
+
}
|
330 |
+
|
331 |
+
});
|
332 |
+
|
333 |
+
})
|
334 |
+
.on('click', '.llar-app-acl-add-rule', function(e){
|
335 |
+
e.preventDefault();
|
336 |
+
|
337 |
+
var $this = $(this),
|
338 |
+
pattern = $this.closest('tr').find('.llar-app-acl-pattern').val().trim(),
|
339 |
+
rule = $this.closest('tr').find('.llar-app-acl-rule').val(),
|
340 |
+
type = $this.data('type');
|
341 |
+
|
342 |
+
if(!pattern) {
|
343 |
+
|
344 |
+
alert('Pattern can\'t be empty!');
|
345 |
+
return false;
|
346 |
+
}
|
347 |
+
|
348 |
+
var row_exist = {};
|
349 |
+
$this.closest('table').find('.rule-pattern').each(function(i, el){
|
350 |
+
var res = el.innerText.localeCompare(pattern);
|
351 |
+
if(res === 0) {
|
352 |
+
row_exist = $(el).closest('tr');
|
353 |
+
}
|
354 |
+
});
|
355 |
+
|
356 |
+
if(row_exist.length) {
|
357 |
+
|
358 |
+
$this.closest('tr').find('.llar-app-acl-pattern').val('');
|
359 |
+
row_exist.remove();
|
360 |
+
}
|
361 |
+
|
362 |
+
llar.progressbar.start();
|
363 |
+
|
364 |
+
$.post(ajaxurl, {
|
365 |
+
action: 'app_acl_add_rule',
|
366 |
+
pattern: pattern,
|
367 |
+
rule: rule,
|
368 |
+
type: type,
|
369 |
+
sec: '<?php echo esc_js( wp_create_nonce( "llar-action" ) ); ?>'
|
370 |
+
}, function(response){
|
371 |
+
|
372 |
+
llar.progressbar.stop();
|
373 |
+
|
374 |
+
if(response.success) {
|
375 |
+
|
376 |
+
$this.closest('table').find('.empty-row').remove();
|
377 |
+
|
378 |
+
$this.closest('tr').after('<tr class="llar-app-rule-'+rule+'">' +
|
379 |
+
'<td class="rule-pattern">'+pattern+'</td>' +
|
380 |
+
'<td>'+rule+'</td>' +
|
381 |
+
'<td class="llar-app-acl-action-col" scope="col"><button class="button llar-app-acl-remove" data-type="'+type+'" data-pattern="'+pattern+'"><span class="dashicons dashicons-no"></span></button></td>' +
|
382 |
+
'</tr>');
|
383 |
+
|
384 |
+
}
|
385 |
+
|
386 |
+
});
|
387 |
+
|
388 |
+
});
|
389 |
+
|
390 |
+
});
|
391 |
+
|
392 |
+
function load_rules_data(type) {
|
393 |
+
|
394 |
+
llar.progressbar.start();
|
395 |
+
|
396 |
+
$.post(ajaxurl, {
|
397 |
+
action: 'app_load_acl_rules',
|
398 |
+
type: type,
|
399 |
+
sec: '<?php echo wp_create_nonce( "llar-action" ); ?>'
|
400 |
+
}, function(response){
|
401 |
+
|
402 |
+
llar.progressbar.stop();
|
403 |
+
|
404 |
+
if(response.success) {
|
405 |
+
|
406 |
+
$('.llar-app-'+type+'-access-rules-table').html(response.data.html);
|
407 |
+
}
|
408 |
+
});
|
409 |
+
}
|
410 |
+
|
411 |
+
})(jQuery);
|
412 |
+
</script>
|
413 |
+
</div>
|
414 |
+
</div>
|
views/{tab-dashboard.php → tab-logs-local.php}
RENAMED
@@ -24,7 +24,7 @@ $black_list_usernames = ( is_array( $black_list_usernames ) && !empty( $black_li
|
|
24 |
?>
|
25 |
|
26 |
<h3><?php echo __( 'Statistics', 'limit-login-attempts-reloaded' ); ?></h3>
|
27 |
-
<form action="<?php echo $this->get_options_page_uri(); ?>" method="post">
|
28 |
<?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
|
29 |
<table class="form-table">
|
30 |
<tr>
|
@@ -54,7 +54,7 @@ $black_list_usernames = ( is_array( $black_list_usernames ) && !empty( $black_li
|
|
54 |
<?php } ?>
|
55 |
</table>
|
56 |
</form>
|
57 |
-
<form action="<?php echo $this->get_options_page_uri(); ?>" method="post">
|
58 |
<?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
|
59 |
|
60 |
<table class="form-table">
|
@@ -100,7 +100,7 @@ $lockouts = (array)$this->get_option('lockouts');
|
|
100 |
|
101 |
if( is_array( $log ) && ! empty( $log ) ) { ?>
|
102 |
<h3><?php echo __( 'Lockout log', 'limit-login-attempts-reloaded' ); ?></h3>
|
103 |
-
<form action="<?php echo $this->get_options_page_uri(); ?>" method="post">
|
104 |
<?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
|
105 |
<input type="hidden" value="true" name="clear_log"/>
|
106 |
<p class="submit">
|
24 |
?>
|
25 |
|
26 |
<h3><?php echo __( 'Statistics', 'limit-login-attempts-reloaded' ); ?></h3>
|
27 |
+
<form action="<?php echo $this->get_options_page_uri('logs-local'); ?>" method="post">
|
28 |
<?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
|
29 |
<table class="form-table">
|
30 |
<tr>
|
54 |
<?php } ?>
|
55 |
</table>
|
56 |
</form>
|
57 |
+
<form action="<?php echo $this->get_options_page_uri('logs-local'); ?>" method="post">
|
58 |
<?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
|
59 |
|
60 |
<table class="form-table">
|
100 |
|
101 |
if( is_array( $log ) && ! empty( $log ) ) { ?>
|
102 |
<h3><?php echo __( 'Lockout log', 'limit-login-attempts-reloaded' ); ?></h3>
|
103 |
+
<form action="<?php echo $this->get_options_page_uri('logs-local'); ?>" method="post">
|
104 |
<?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
|
105 |
<input type="hidden" value="true" name="clear_log"/>
|
106 |
<p class="submit">
|
views/tab-settings.php
CHANGED
@@ -17,11 +17,21 @@ $admin_email_placeholder = (!is_multisite()) ? get_option( 'admin_email' ) : get
|
|
17 |
|
18 |
$trusted_ip_origins = $this->get_option( 'trusted_ip_origins' );
|
19 |
$trusted_ip_origins = ( is_array( $trusted_ip_origins ) && !empty( $trusted_ip_origins ) ) ? implode( ", ", $trusted_ip_origins ) : 'REMOTE_ADDR';
|
|
|
|
|
|
|
|
|
|
|
20 |
?>
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
<h3><?php echo __( 'General Settings', 'limit-login-attempts-reloaded' ); ?></h3>
|
23 |
-
<p><?php echo __( 'These settings are independent of the
|
24 |
-
<form action="<?php echo $this->get_options_page_uri(); ?>" method="post">
|
25 |
|
26 |
<?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
|
27 |
|
@@ -49,6 +59,7 @@ $trusted_ip_origins = ( is_array( $trusted_ip_origins ) && !empty( $trusted_ip_o
|
|
49 |
<?php endif ?>
|
50 |
|
51 |
<table class="form-table">
|
|
|
52 |
<tr>
|
53 |
<th scope="row"
|
54 |
valign="top"><?php echo __( 'GDPR compliance', 'limit-login-attempts-reloaded' ); ?></th>
|
@@ -57,6 +68,8 @@ $trusted_ip_origins = ( is_array( $trusted_ip_origins ) && !empty( $trusted_ip_o
|
|
57 |
<?php echo __( 'this makes the plugin <a href="https://gdpr-info.eu/" target="_blank" >GDPR</a> compliant', 'limit-login-attempts-reloaded' ); ?> <br/>
|
58 |
</td>
|
59 |
</tr>
|
|
|
|
|
60 |
<tr>
|
61 |
<th scope="row"
|
62 |
valign="top"><?php echo __( 'Notify on lockout', 'limit-login-attempts-reloaded' ); ?></th>
|
@@ -76,13 +89,28 @@ $trusted_ip_origins = ( is_array( $trusted_ip_origins ) && !empty( $trusted_ip_o
|
|
76 |
name="email_after"/> <?php echo __( 'lockouts', 'limit-login-attempts-reloaded' ); ?>
|
77 |
</td>
|
78 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
</table>
|
80 |
|
81 |
-
<h3><?php echo __( '
|
82 |
-
<p><?php echo __( 'The
|
83 |
|
84 |
-
<div id="llar-
|
85 |
-
<h3
|
86 |
<div>
|
87 |
<table class="form-table">
|
88 |
<tr>
|
@@ -121,20 +149,158 @@ $trusted_ip_origins = ( is_array( $trusted_ip_origins ) && !empty( $trusted_ip_o
|
|
121 |
</table>
|
122 |
</div>
|
123 |
|
124 |
-
<h3
|
125 |
-
<div>
|
126 |
-
|
127 |
-
|
128 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
</div>
|
130 |
</div>
|
131 |
|
132 |
-
<script>
|
133 |
(function($){
|
134 |
|
135 |
$(document).ready(function(){
|
136 |
|
137 |
-
$( "#llar-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
});
|
139 |
|
140 |
})(jQuery);
|
17 |
|
18 |
$trusted_ip_origins = $this->get_option( 'trusted_ip_origins' );
|
19 |
$trusted_ip_origins = ( is_array( $trusted_ip_origins ) && !empty( $trusted_ip_origins ) ) ? implode( ", ", $trusted_ip_origins ) : 'REMOTE_ADDR';
|
20 |
+
|
21 |
+
$active_app = $this->get_option( 'active_app' );
|
22 |
+
$app_setup_link = $this->get_option( 'app_setup_link' );
|
23 |
+
$active_app_config = $this->get_custom_app_config();
|
24 |
+
|
25 |
?>
|
26 |
+
<?php if( isset( $_GET['activated'] ) ) : ?>
|
27 |
+
<div class="llar-app-notice success">
|
28 |
+
<p><?php echo $active_app_config['messages']['setup_success']; ?></p>
|
29 |
+
</div>
|
30 |
+
<?php endif; ?>
|
31 |
|
32 |
<h3><?php echo __( 'General Settings', 'limit-login-attempts-reloaded' ); ?></h3>
|
33 |
+
<p><?php echo __( 'These settings are independent of the apps (see below).', 'limit-login-attempts-reloaded' ); ?></p>
|
34 |
+
<form action="<?php echo $this->get_options_page_uri('settings'); ?>" method="post">
|
35 |
|
36 |
<?php wp_nonce_field( 'limit-login-attempts-options' ); ?>
|
37 |
|
59 |
<?php endif ?>
|
60 |
|
61 |
<table class="form-table">
|
62 |
+
<?php if( $active_app === 'local' ) : ?>
|
63 |
<tr>
|
64 |
<th scope="row"
|
65 |
valign="top"><?php echo __( 'GDPR compliance', 'limit-login-attempts-reloaded' ); ?></th>
|
68 |
<?php echo __( 'this makes the plugin <a href="https://gdpr-info.eu/" target="_blank" >GDPR</a> compliant', 'limit-login-attempts-reloaded' ); ?> <br/>
|
69 |
</td>
|
70 |
</tr>
|
71 |
+
<?php endif; ?>
|
72 |
+
|
73 |
<tr>
|
74 |
<th scope="row"
|
75 |
valign="top"><?php echo __( 'Notify on lockout', 'limit-login-attempts-reloaded' ); ?></th>
|
89 |
name="email_after"/> <?php echo __( 'lockouts', 'limit-login-attempts-reloaded' ); ?>
|
90 |
</td>
|
91 |
</tr>
|
92 |
+
<tr>
|
93 |
+
<th scope="row"
|
94 |
+
valign="top"><?php echo __( 'Active App', 'limit-login-attempts-reloaded' ); ?></th>
|
95 |
+
<td>
|
96 |
+
<select name="active_app" id="">
|
97 |
+
<option value="local" <?php selected( $active_app, 'local' ); ?>><?php echo __( 'Local', 'limit-login-attempts-reloaded' ); ?></option>
|
98 |
+
<?php if( $active_app_config ) : ?>
|
99 |
+
<option value="custom" <?php selected( $active_app, 'custom' ); ?>><?php echo esc_html( $active_app_config['name'] ); ?></option>
|
100 |
+
<?php endif; ?>
|
101 |
+
</select>
|
102 |
+
<?php if( $active_app === 'local' ) : ?>
|
103 |
+
<span class="llar-protect-notice"><?php _e( 'Get advanced protection by <a href="#" class="llar-upgrade-to-cloud">upgrading to our Cloud App.</a>', 'limit-login-attempts-reloaded' ); ?></span>
|
104 |
+
<?php endif; ?>
|
105 |
+
</td>
|
106 |
+
</tr>
|
107 |
</table>
|
108 |
|
109 |
+
<h3><?php echo __( 'App Settings', 'limit-login-attempts-reloaded' ); ?></h3>
|
110 |
+
<p><?php echo __( 'The apps absorb the main load caused by brute-force attacks, analyse login attempts and block unwanted visitors. They might provide other service functions as well.', 'limit-login-attempts-reloaded' ); ?></p>
|
111 |
|
112 |
+
<div id="llar-apps-accordion" class="llar-accordion">
|
113 |
+
<h3><?php echo __( 'Local App', 'limit-login-attempts-reloaded' ); ?></h3>
|
114 |
<div>
|
115 |
<table class="form-table">
|
116 |
<tr>
|
149 |
</table>
|
150 |
</div>
|
151 |
|
152 |
+
<h3><?php echo ($active_app_config) ? $active_app_config['name'] : __('Custom App', 'limit-login-attempts-reloaded' ); ?></h3>
|
153 |
+
<div class="custom-app-tab">
|
154 |
+
|
155 |
+
<?php if( $active_app === 'custom' ) : ?>
|
156 |
+
<a class="dashicons dashicons-admin-generic llar-show-app-fields" href="#"></a>
|
157 |
+
<?php endif; ?>
|
158 |
+
|
159 |
+
<table class="form-table">
|
160 |
+
|
161 |
+
<tr class="llar-app-field <?php echo ( $active_app === 'local' || !$active_app_config ) ? 'active' : ''; ?>">
|
162 |
+
<th scope="row"
|
163 |
+
valign="top"><?php echo __( 'Setup Link', 'limit-login-attempts-reloaded' ); ?></th>
|
164 |
+
<td>
|
165 |
+
<input type="text" class="regular-text" id="limit-login-app-setup-link" value="<?php echo ( !empty( $app_setup_link ) ) ? esc_attr( $app_setup_link ) : ''; ?>">
|
166 |
+
<button class="button" id="limit-login-app-setup"><?php echo __( 'Submit', 'limit-login-attempts-reloaded' ); ?></button>
|
167 |
+
<span class="spinner llar-app-ajax-spinner"></span><br>
|
168 |
+
<span class="llar-app-ajax-msg"></span>
|
169 |
+
|
170 |
+
<?php if( $active_app === 'local' ) : ?>
|
171 |
+
<p class="description"><?php echo sprintf( __( 'Use the <a href="%s" target="_blank">premium app</a> that we offer or follow the instructions on <a href="%s" target="_blank">how to</a> create your own one.', 'limit-login-attempts-reloaded' ), 'https://app.limitloginattempts.com/network/create', 'https://www.limitloginattempts.com/app/' ); ?></p>
|
172 |
+
<div class="llar-why-use-premium-text">
|
173 |
+
<div class="title"><?php _e( 'Why Use Our Premium Cloud App?', 'limit-login-attempts-reloaded' ); ?></div>
|
174 |
+
<ul>
|
175 |
+
<li><span class="dashicons dashicons-yes"></span><?php _e( 'Absorb site load caused by attacks', 'limit-login-attempts-reloaded' ); ?></li>
|
176 |
+
<li><span class="dashicons dashicons-yes"></span><?php _e( 'Use intelligent IP blocking/unblocking technology', 'limit-login-attempts-reloaded' ); ?></li>
|
177 |
+
<li><span class="dashicons dashicons-yes"></span><?php _e( 'Sync the allow/deny/pass lists between multiple domains', 'limit-login-attempts-reloaded' ); ?></li>
|
178 |
+
<li><span class="dashicons dashicons-yes"></span><?php _e( 'Get premium support', 'limit-login-attempts-reloaded' ); ?></li>
|
179 |
+
<li><span class="dashicons dashicons-yes"></span><?php _e( 'Run auto backups of access control lists, lockouts and logs', 'limit-login-attempts-reloaded' ); ?></li>
|
180 |
+
<li><span class="dashicons dashicons-yes"></span><?php _e( 'Only pay $4.99/m per domain - cancel any time', 'limit-login-attempts-reloaded' ); ?></li>
|
181 |
+
</ul>
|
182 |
+
</div>
|
183 |
+
<?php endif; ?>
|
184 |
+
</td>
|
185 |
+
</tr>
|
186 |
+
<?php if( $active_app === 'custom' && $active_app_config ) : ?>
|
187 |
+
<tr class="llar-app-field">
|
188 |
+
<th scope="row"
|
189 |
+
valign="top"><?php echo __( 'Configuration', 'limit-login-attempts-reloaded' ); ?></th>
|
190 |
+
<td>
|
191 |
+
<div class="field-col">
|
192 |
+
<textarea id="limit-login-app-config" readonly="readonly" name="limit-login-app-config" cols="60" rows="5"><?php echo esc_textarea( json_encode( $active_app_config ) ); ?></textarea><br>
|
193 |
+
</div>
|
194 |
+
</td>
|
195 |
+
</tr>
|
196 |
+
<?php endif; ?>
|
197 |
+
|
198 |
+
<?php if( $active_app === 'custom' && !empty( $active_app_config['settings'] ) ) : ?>
|
199 |
+
<?php foreach( $active_app_config['settings'] as $setting_name => $setting_params ) : ?>
|
200 |
+
<tr>
|
201 |
+
<th scope="row" valign="top"><?php echo $setting_params['label']; ?></th>
|
202 |
+
<td>
|
203 |
+
<div class="field-col">
|
204 |
+
<?php if( !empty( $setting_params['options'] ) ) : ?>
|
205 |
+
<select name="llar_app_settings[<?php echo $setting_name; ?>]">
|
206 |
+
<?php foreach ( $setting_params['options'] as $option ) : ?>
|
207 |
+
<option value="<?php echo esc_attr( $option ); ?>" <?php selected( $option, $setting_params['value'] ); ?>><?php echo esc_html( $option ); ?></option>
|
208 |
+
<?php endforeach; ?>
|
209 |
+
</select>
|
210 |
+
<?php else : ?>
|
211 |
+
<input type="text" class="regular-text" name="llar_app_settings[<?php echo esc_attr( $setting_name ); ?>]" value="<?php echo esc_attr( $setting_params['value'] ); ?>">
|
212 |
+
<?php endif; ?>
|
213 |
+
|
214 |
+
<p class="description"><?php echo esc_html( $setting_params['description'] ); ?></p>
|
215 |
+
</div>
|
216 |
+
</td>
|
217 |
+
</tr>
|
218 |
+
<?php endforeach; ?>
|
219 |
+
<?php endif; ?>
|
220 |
+
</table>
|
221 |
</div>
|
222 |
</div>
|
223 |
|
224 |
+
<script type="text/javascript">
|
225 |
(function($){
|
226 |
|
227 |
$(document).ready(function(){
|
228 |
|
229 |
+
$( "#llar-apps-accordion" ).accordion({
|
230 |
+
heightStyle: "content",
|
231 |
+
active: <?php echo ( $active_app === 'local' ) ? 0 : 1; ?>
|
232 |
+
});
|
233 |
+
|
234 |
+
var $app_ajax_spinner = $('.llar-app-ajax-spinner'),
|
235 |
+
$app_ajax_msg = $('.llar-app-ajax-msg'),
|
236 |
+
$app_config_field = $('#limit-login-app-config');
|
237 |
+
|
238 |
+
if($app_config_field.val()) {
|
239 |
+
var pretty = JSON.stringify(JSON.parse($app_config_field.val()), undefined, 2);
|
240 |
+
$app_config_field.val(pretty);
|
241 |
+
}
|
242 |
+
|
243 |
+
$('#limit-login-app-setup').on('click', function(e) {
|
244 |
+
e.preventDefault();
|
245 |
+
|
246 |
+
$app_ajax_msg.text('').removeClass('success error');
|
247 |
+
$app_ajax_spinner.css('visibility', 'visible');
|
248 |
+
|
249 |
+
var setup_link = $('#limit-login-app-setup-link').val();
|
250 |
+
|
251 |
+
$.post(ajaxurl, {
|
252 |
+
action: 'app_setup',
|
253 |
+
link: setup_link,
|
254 |
+
sec: '<?php echo esc_js( wp_create_nonce( "llar-action" ) ); ?>'
|
255 |
+
}, function(response){
|
256 |
+
|
257 |
+
if(!response.success) {
|
258 |
+
|
259 |
+
$app_ajax_msg.addClass('error');
|
260 |
+
} else {
|
261 |
+
|
262 |
+
$app_ajax_msg.addClass('success');
|
263 |
+
|
264 |
+
setTimeout(function(){
|
265 |
+
|
266 |
+
window.location = window.location + '&activated';
|
267 |
+
|
268 |
+
}, 1000);
|
269 |
+
}
|
270 |
+
|
271 |
+
if(!response.success && response.data.msg) {
|
272 |
+
|
273 |
+
$app_ajax_msg.text(response.data.msg);
|
274 |
+
}
|
275 |
+
|
276 |
+
$app_ajax_spinner.css('visibility', 'hidden');
|
277 |
+
|
278 |
+
setTimeout(function(){
|
279 |
+
|
280 |
+
$app_ajax_msg.text('').removeClass('success error');
|
281 |
+
|
282 |
+
}, 5000);
|
283 |
+
});
|
284 |
+
|
285 |
+
});
|
286 |
+
|
287 |
+
$('.llar-show-app-fields').on('click', function(e){
|
288 |
+
e.preventDefault();
|
289 |
+
|
290 |
+
$('.llar-app-field').toggleClass('active');
|
291 |
+
|
292 |
+
});
|
293 |
+
|
294 |
+
$('.llar-upgrade-to-cloud').on('click', function(e){
|
295 |
+
e.preventDefault();
|
296 |
+
|
297 |
+
$("#ui-id-3").click();
|
298 |
+
|
299 |
+
$([document.documentElement, document.body]).animate({
|
300 |
+
scrollTop: $("#llar-apps-accordion").offset().top
|
301 |
+
}, 500);
|
302 |
+
});
|
303 |
+
|
304 |
});
|
305 |
|
306 |
})(jQuery);
|