Cerber Security & Antispam - Version 7.9.7

Version Description

  • New: Authorized users only mode.
  • New: An ability to block a user account.
  • New: Role-based access to WordPress REST API.
  • Update: Added ability to search and filter a user on the Activity page.
  • Update: A new, separate setting for preventing user enumeration via WordPress REST API.
  • Update: A new Changelog section on the Tools page.
  • Update: Improved handling scheduled maintenance tasks on a multi-site WordPress installation.
  • Fixed: Several HTML markup errors on plugin admin pages.
  • Read more
Download this release

Release Info

Developer Gioni
Plugin Icon 128x128 Cerber Security & Antispam
Version 7.9.7
Comparing to
See all releases

Code changes from version 7.9.3 to 7.9.7

assets/admin.css CHANGED
@@ -6,15 +6,15 @@
6
  margin-left:20px;
7
  }
8
 
9
- .crb-admin {
10
  font-family: 'Roboto', sans-serif;
11
  }
12
 
13
- .crb-admin b, .crb-admin strong {
14
  font-weight: 500;
15
  }
16
 
17
- .crb-admin h2, .crb-admin h3 {
18
  font-weight: 500;
19
  }
20
 
@@ -44,9 +44,38 @@
44
  font-weight: bold;
45
  }
46
 
47
- .form-table {
 
 
48
  margin-bottom: 30px;
49
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
  /* Dashboard */
52
 
@@ -421,19 +450,19 @@ td.crb-traffic-details div{
421
  width: auto;
422
  line-height: 26px;
423
  }
424
- #activity-filter select{
425
- max-width: 250px;
426
- margin-top: -4px;
427
  }
428
  #activity-filter input[type="submit"]{
429
  margin-right: 3em;
430
  }
431
- #activity-filter input[type="text"]{
432
- min-width: 250px;
433
- }
434
  #activity-filter input,
435
- #activity-filter select{
436
- margin-right: 0.2em;
 
 
 
437
  }
438
  #activity-filter a{
439
  text-decoration: none;
@@ -706,6 +735,15 @@ a.nav-tab:last-of-type{
706
  text-align: center;
707
  }
708
 
 
 
 
 
 
 
 
 
 
709
  /* Scanner page */
710
 
711
  body.wp-cerber_page_cerber-integrity {
@@ -779,6 +817,11 @@ body.wp-cerber_page_cerber-integrity {
779
  color: #000;
780
  }
781
 
 
 
 
 
 
782
  @media screen and (max-width: 1300px) {
783
  #crb-aside {
784
  display: none;
@@ -786,8 +829,10 @@ body.wp-cerber_page_cerber-integrity {
786
  #activity-filter div:first-child{
787
  max-width: 70%;
788
  }
 
 
 
789
  }
790
-
791
  @media screen and (max-width: 768px) {
792
  #activity-filter div:first-child,
793
  #activity-filter div:nth-child(2){
@@ -1181,6 +1226,10 @@ div#whois:hover {
1181
  margin-right: 3em;
1182
  }
1183
 
 
 
 
 
1184
  /* Diagnostic */
1185
 
1186
  #diagnostic h3 {
@@ -1321,6 +1370,7 @@ table.crb-avatar a{
1321
  }
1322
 
1323
  /* Help tab */
 
1324
  #crb-help {
1325
  padding: 0 10px;
1326
  }
@@ -1479,6 +1529,20 @@ table.vtable td:nth-child(2) {
1479
  margin: 0;
1480
  }
1481
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1482
  /* Switches & Toggle */
1483
 
1484
  .crb-switch {
6
  margin-left:20px;
7
  }
8
 
9
+ #crb-admin {
10
  font-family: 'Roboto', sans-serif;
11
  }
12
 
13
+ #crb-admin b, #crb-admin strong {
14
  font-weight: 500;
15
  }
16
 
17
+ #crb-admin h2, #crb-admin h3 {
18
  font-weight: 500;
19
  }
20
 
44
  font-weight: bold;
45
  }
46
 
47
+ /* Settings' forms */
48
+
49
+ #crb-settings .form-table {
50
  margin-bottom: 30px;
51
  }
52
+ #crb-settings .form-table:last-of-type {
53
+ margin-bottom: 0;
54
+ }
55
+ #crb-settings .form-table td {
56
+ padding-right: 15% !important;
57
+ }
58
+ #crb-settings .form-table th {
59
+ min-width: 200px;
60
+ }
61
+ #crb-settings input[type="text"] {
62
+ padding: 0.4em;
63
+ }
64
+ #crb-settings label.crb-below {
65
+ padding-top: 0.5em;
66
+ /*padding-left: 0.5em;*/
67
+ color: #555;
68
+ }
69
+ #crb-settings .form-table input.crb-wide,
70
+ #crb-settings .form-table textarea {
71
+ width: 95% !important;
72
+ }
73
+ #crb-settings input[type="submit"] {
74
+ margin-top: 20px;
75
+ }
76
+ #crb-settings .crb-disable-this {
77
+ display: none;
78
+ }
79
 
80
  /* Dashboard */
81
 
450
  width: auto;
451
  line-height: 26px;
452
  }
453
+ #activity-filter select,
454
+ #activity-filter input[type="text"]{
455
+ width: 250px;
456
  }
457
  #activity-filter input[type="submit"]{
458
  margin-right: 3em;
459
  }
 
 
 
460
  #activity-filter input,
461
+ #activity-filter select,
462
+ #activity-filter .select2-container {
463
+ margin: 0 0.3em 0.3em 0;
464
+ height: 28px;
465
+ vertical-align: middle;
466
  }
467
  #activity-filter a{
468
  text-decoration: none;
735
  text-align: center;
736
  }
737
 
738
+ .crb-user-blocked td.column-username {
739
+ color: red;
740
+ }
741
+
742
+ .crb-user-blocked td.column-username strong::after,
743
+ .crb-user-blocked .crb-user-name::after {
744
+ content: ' BLOCKED';
745
+ }
746
+
747
  /* Scanner page */
748
 
749
  body.wp-cerber_page_cerber-integrity {
817
  color: #000;
818
  }
819
 
820
+ @media screen and (max-width: 1600px) {
821
+ #crb-settings .form-table td {
822
+ padding-right: 10% !important;
823
+ }
824
+ }
825
  @media screen and (max-width: 1300px) {
826
  #crb-aside {
827
  display: none;
829
  #activity-filter div:first-child{
830
  max-width: 70%;
831
  }
832
+ #crb-settings .form-table td {
833
+ padding-right: 5% !important;
834
+ }
835
  }
 
836
  @media screen and (max-width: 768px) {
837
  #activity-filter div:first-child,
838
  #activity-filter div:nth-child(2){
1226
  margin-right: 3em;
1227
  }
1228
 
1229
+ #user-extra-info .crb-user-name {
1230
+ color: red;
1231
+ }
1232
+
1233
  /* Diagnostic */
1234
 
1235
  #diagnostic h3 {
1370
  }
1371
 
1372
  /* Help tab */
1373
+
1374
  #crb-help {
1375
  padding: 0 10px;
1376
  }
1529
  margin: 0;
1530
  }
1531
 
1532
+ #crb-change-log-view {
1533
+ background-color: #fff;
1534
+ color: #111;
1535
+ padding: 1em;
1536
+ margin: 0;
1537
+ line-height: 1.6em;
1538
+ }
1539
+ #crb-change-log-view .crb-version{
1540
+ font-size: 120%;
1541
+ line-height: 2em;
1542
+ font-weight: bold;
1543
+ }
1544
+
1545
+
1546
  /* Switches & Toggle */
1547
 
1548
  .crb-switch {
assets/admin.js CHANGED
@@ -1,8 +1,43 @@
1
  /**
2
- * Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
3
  */
4
  jQuery(document).ready(function ($) {
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  /* WP Comments page */
7
  var comtable = 'table.wp-list-table.comments';
8
 
@@ -124,5 +159,46 @@ jQuery(document).ready(function ($) {
124
  $(this).find('a.crb-traffic-more').hide();
125
  });
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
  });
1
  /**
2
+ * Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
3
  */
4
  jQuery(document).ready(function ($) {
5
 
6
+ /* Select2 */
7
+ var crb_admin = $('#crb-admin');
8
+
9
+ var crb_se2 = crb_admin.find('.crb-select2-ajax');
10
+ if (crb_se2.length) {
11
+ crb_se2.select2({
12
+ allowClear: true,
13
+ placeholder: crb_se2.data( 'placeholder' ),
14
+ minimumInputLength: crb_se2.data('min_symbols') ? crb_se2.data('min_symbols') : '1',
15
+ ajax: {
16
+ url: ajaxurl,
17
+ dataType: 'json',
18
+ delay: 1000,
19
+ data: function (params) {
20
+ return {
21
+ user_search: params.term,
22
+ action: 'cerber_ajax',
23
+ ajax_nonce: crb_ajax_nonce,
24
+ };
25
+ },
26
+ processResults: function( data ) {
27
+ return {
28
+ results: data
29
+ };
30
+ },
31
+ // cache: true // doesn't work due to "no-cache" header, see also: https://github.com/select2/select2/issues/3862
32
+ }
33
+ });
34
+ }
35
+
36
+ crb_se2 = crb_admin.find('.crb-select2');
37
+ if (crb_se2.length) {
38
+ crb_se2.select2();
39
+ }
40
+
41
  /* WP Comments page */
42
  var comtable = 'table.wp-list-table.comments';
43
 
159
  $(this).find('a.crb-traffic-more').hide();
160
  });
161
 
162
+ /* Enabling conditional input setting fields */
163
+
164
+ var setting_form = $('#crb-settings');
165
+ setting_form.find('input').change(function () {
166
+ var enabler_id = $(this).attr('id');
167
+ var enabler_val;
168
+ if ('checkbox' === $(this).attr('type')) {
169
+ if ($(this).is(':checked')) {
170
+ enabler_val = true;
171
+ }
172
+ else {
173
+ enabler_val = false;
174
+ }
175
+ }
176
+ else {
177
+ enabler_val = $(this).val();
178
+ }
179
+ setting_form.find('[data-enabler="' + enabler_id + '"]').each(function () {
180
+ var input_data = $(this).data();
181
+ var method;
182
+ if (typeof input_data['enabler_value'] !== "undefined") {
183
+ if (enabler_val === input_data['enabler_value']) {
184
+ method = 'show';
185
+ }
186
+ else {
187
+ method = 'hide';
188
+ }
189
+ }
190
+ else {
191
+ if (enabler_val) {
192
+ method = 'show';
193
+ }
194
+ else {
195
+ method = 'hide';
196
+ }
197
+ }
198
+
199
+ var element = $(this).closest('tr');
200
+ element[method]();
201
+ });
202
+ });
203
 
204
  });
assets/icons/fonts/crb.svg CHANGED
@@ -40,6 +40,7 @@
40
  <glyph unicode="&#xe93d;" glyph-name="bx-bolt" d="M207.147-100.416c1.855-0.584 3.987-0.921 6.198-0.921 7.368 0 13.862 3.738 17.689 9.421l0.048 0.076 170.667 256c2.247 3.327 3.587 7.427 3.587 11.84 0 11.782-9.551 21.333-21.334 21.333-0.001 0-0.002 0-0.003 0h-102.805l17.195 103.147c0.187 1.059 0.294 2.279 0.294 3.523 0 5.271-1.919 10.093-5.097 13.807l0.024-0.029c-3.93 4.632-9.757 7.552-16.264 7.552-0.005 0-0.009 0-0.014 0h-128c0 0 0 0-0 0-11.030 0-20.106-8.372-21.219-19.108l-0.007-0.091-21.334-213.334c-0.068-0.639-0.107-1.382-0.107-2.134 0-11.782 9.552-21.334 21.334-21.334 0 0 0 0 0.001 0h64v-149.333c0-9.575 6.309-17.676 14.995-20.375l0.151-0.041zM151.573 112l17.066 170.667h83.499l-17.195-103.147c-0.187-1.059-0.294-2.279-0.294-3.523 0-5.271 1.919-10.094 5.097-13.807l-0.024 0.029c4.054-4.8 10.006-7.552 16.278-7.552h88.149l-109.483-164.202v100.202c0 11.782-9.552 21.334-21.334 21.334v0h-61.76z" />
41
  <glyph unicode="&#xe949;" glyph-name="bx-bug" d="M422.4 101.334c0 10.923-0.918 21.547-2.262 32h47.914v42.666h-57.493c-8.389 25.751-20.612 48.074-36.209 67.58l0.327-0.422 45.76 45.76-30.166 30.165-46.166-46.144c-25.579 19.563-55.723 31.062-88.106 31.062s-62.528-11.499-88.106-31.062l-46.144 46.144-30.166-30.165 45.76-45.76c-15.27-19.083-27.493-41.405-35.457-65.659l-0.426-1.498h-58.794v-42.666h49.216c-1.365-10.453-2.282-21.077-2.282-32 0-10.986 0.918-21.718 2.304-32.234h-49.237v-42.666h58.859c4.864-14.784 11.094-28.714 18.517-41.558l-49.792-49.792 30.165-30.166 45.184 45.184c29.418-31.872 68.032-51.435 110.4-51.435s80.981 19.563 110.4 51.435l45.184-45.184 30.166 30.166-49.792 49.792c7.445 12.842 13.675 26.774 18.517 41.558h58.858v42.666h-49.259c1.408 10.517 2.325 21.248 2.325 32.234zM256 261.334c47.382 0 88.555-34.646 109.355-85.334h-218.709c20.8 50.688 61.974 85.334 109.355 85.334zM277.334-56.106v146.774h-42.666v-146.774c-58.090 13.12-102.4 78.656-102.4 157.44 0 10.965 0.853 21.654 2.496 32h242.453c1.642-10.346 2.496-21.035 2.496-32 0.022-78.805-44.288-144.32-102.379-157.44z" />
42
  <glyph unicode="&#xe970;" glyph-name="bx-chip" d="M426.666 261.334c0 11.782-9.551 21.334-21.334 21.334v0h-42.666v42.666h-42.666v-42.666h-42.666v42.666h-42.666v-42.666h-42.666v42.666h-42.666v-42.666h-42.666c-11.782 0-21.334-9.552-21.334-21.334v0-42.667h-42.666v-42.667h42.666v-42.666h-42.666v-42.666h42.666v-42.666h-42.666v-42.666h42.666v-42.666c0-11.782 9.552-21.334 21.334-21.334v0h42.666v-42.666h42.666v42.666h42.666v-42.666h42.666v42.666h42.666v-42.666h42.666v42.666h42.666c11.782 0 21.334 9.551 21.334 21.334v0 42.666h42.666v42.666h-42.666v42.666h42.666v42.666h-42.666v42.666h42.666v42.666h-42.666v42.666zM384-16h-256v256h256v-256zM213.333 154.667h85.333v-85.333h-85.334z" />
 
43
  <glyph unicode="&#xe9c2;" glyph-name="bx-flask" d="M341.334 158.422v124.246h21.334v42.666h-213.333v-42.666h21.333v-124.246l-84.032-231.125c-0.815-2.17-1.287-4.678-1.287-7.296 0-11.777 9.543-21.325 21.317-21.334h298.668c0.005 0 0.010 0 0.015 0 11.771 0 21.312 9.541 21.312 21.312 0 2.626-0.475 5.142-1.344 7.464l0.048-0.147-84.032 231.125zM298.666 282.666v-128c0-2.475 0.448-4.95 1.301-7.296l12.842-35.37h-113.621l12.864 35.37c0.832 2.346 1.28 4.822 1.28 7.296v128h85.333zM137.131-58.666l46.549 128h144.661l46.55-128h-237.76z" />
44
  <glyph unicode="&#xe9db;" glyph-name="bx-hide" d="M256-37.334c20.182 0 38.613 2.197 55.424 5.995l-37.483 37.483c-5.824-0.448-11.733-0.81-17.941-0.81-114.155 0-158.379 82.048-169.088 106.666 4.352 10.026 14.379 29.462 32.171 49.002l-29.824 29.824c-32.81-35.563-45.248-71.382-45.483-72.085-1.472-4.374-1.472-9.131 0-13.504 0.448-1.408 49.386-142.57 212.224-142.57zM468.224 105.259c1.472 4.373 1.472 9.131 0 13.504-0.448 1.408-49.387 142.571-212.224 142.571-39.19 0-71.382-8.448-98.219-20.928l-78.698 78.678-30.166-30.166 384-384 30.166 30.166-70.805 70.805c55.765 41.642 75.669 98.475 75.947 99.37zM313.408 84.757c4.075 8.298 6.592 17.45 6.592 27.243 0 35.008-28.992 64-64 64-9.792 0-18.944-2.518-27.243-6.592l-38.571 38.571c18.794 6.571 40.512 10.688 65.814 10.688 114.154 0 158.379-82.048 169.088-106.666-6.442-14.762-24.875-49.962-63.019-75.904l-48.661 48.661z" />
45
  <glyph unicode="&#xe9dc;" glyph-name="bx-history" d="M234.667 197.333v-106.667h106.667v42.666h-64v64zM426.666 112c0 92.501-78.144 170.667-170.667 170.667-92.501 0-170.667-78.166-170.667-170.667h-42.666l64-84.8 64 84.8h-42.666c0 69.376 58.624 128 128 128s128-58.624 128-128-58.624-128-128-128v-42.666c92.522 0 170.667 78.166 170.667 170.666z" />
40
  <glyph unicode="&#xe93d;" glyph-name="bx-bolt" d="M207.147-100.416c1.855-0.584 3.987-0.921 6.198-0.921 7.368 0 13.862 3.738 17.689 9.421l0.048 0.076 170.667 256c2.247 3.327 3.587 7.427 3.587 11.84 0 11.782-9.551 21.333-21.334 21.333-0.001 0-0.002 0-0.003 0h-102.805l17.195 103.147c0.187 1.059 0.294 2.279 0.294 3.523 0 5.271-1.919 10.093-5.097 13.807l0.024-0.029c-3.93 4.632-9.757 7.552-16.264 7.552-0.005 0-0.009 0-0.014 0h-128c0 0 0 0-0 0-11.030 0-20.106-8.372-21.219-19.108l-0.007-0.091-21.334-213.334c-0.068-0.639-0.107-1.382-0.107-2.134 0-11.782 9.552-21.334 21.334-21.334 0 0 0 0 0.001 0h64v-149.333c0-9.575 6.309-17.676 14.995-20.375l0.151-0.041zM151.573 112l17.066 170.667h83.499l-17.195-103.147c-0.187-1.059-0.294-2.279-0.294-3.523 0-5.271 1.919-10.094 5.097-13.807l-0.024 0.029c4.054-4.8 10.006-7.552 16.278-7.552h88.149l-109.483-164.202v100.202c0 11.782-9.552 21.334-21.334 21.334v0h-61.76z" />
41
  <glyph unicode="&#xe949;" glyph-name="bx-bug" d="M422.4 101.334c0 10.923-0.918 21.547-2.262 32h47.914v42.666h-57.493c-8.389 25.751-20.612 48.074-36.209 67.58l0.327-0.422 45.76 45.76-30.166 30.165-46.166-46.144c-25.579 19.563-55.723 31.062-88.106 31.062s-62.528-11.499-88.106-31.062l-46.144 46.144-30.166-30.165 45.76-45.76c-15.27-19.083-27.493-41.405-35.457-65.659l-0.426-1.498h-58.794v-42.666h49.216c-1.365-10.453-2.282-21.077-2.282-32 0-10.986 0.918-21.718 2.304-32.234h-49.237v-42.666h58.859c4.864-14.784 11.094-28.714 18.517-41.558l-49.792-49.792 30.165-30.166 45.184 45.184c29.418-31.872 68.032-51.435 110.4-51.435s80.981 19.563 110.4 51.435l45.184-45.184 30.166 30.166-49.792 49.792c7.445 12.842 13.675 26.774 18.517 41.558h58.858v42.666h-49.259c1.408 10.517 2.325 21.248 2.325 32.234zM256 261.334c47.382 0 88.555-34.646 109.355-85.334h-218.709c20.8 50.688 61.974 85.334 109.355 85.334zM277.334-56.106v146.774h-42.666v-146.774c-58.090 13.12-102.4 78.656-102.4 157.44 0 10.965 0.853 21.654 2.496 32h242.453c1.642-10.346 2.496-21.035 2.496-32 0.022-78.805-44.288-144.32-102.379-157.44z" />
42
  <glyph unicode="&#xe970;" glyph-name="bx-chip" d="M426.666 261.334c0 11.782-9.551 21.334-21.334 21.334v0h-42.666v42.666h-42.666v-42.666h-42.666v42.666h-42.666v-42.666h-42.666v42.666h-42.666v-42.666h-42.666c-11.782 0-21.334-9.552-21.334-21.334v0-42.667h-42.666v-42.667h42.666v-42.666h-42.666v-42.666h42.666v-42.666h-42.666v-42.666h42.666v-42.666c0-11.782 9.552-21.334 21.334-21.334v0h42.666v-42.666h42.666v42.666h42.666v-42.666h42.666v42.666h42.666v-42.666h42.666v42.666h42.666c11.782 0 21.334 9.551 21.334 21.334v0 42.666h42.666v42.666h-42.666v42.666h42.666v42.666h-42.666v42.666h42.666v42.666h-42.666v42.666zM384-16h-256v256h256v-256zM213.333 154.667h85.333v-85.333h-85.334z" />
43
+ <glyph unicode="&#xe980;" glyph-name="bx-collection" d="M426.666 154.667h-341.334c-11.782 0-21.334-9.552-21.334-21.333v0-213.334c0-11.782 9.552-21.334 21.334-21.334v0h341.334c11.782 0 21.334 9.551 21.334 21.334v0 213.333c0 11.782-9.551 21.333-21.334 21.333v0zM405.334-58.666h-298.666v170.666h298.666v-170.666zM106.666 240h298.666v-42.666h-298.666zM149.333 325.334h213.333v-42.666h-213.333z" />
44
  <glyph unicode="&#xe9c2;" glyph-name="bx-flask" d="M341.334 158.422v124.246h21.334v42.666h-213.333v-42.666h21.333v-124.246l-84.032-231.125c-0.815-2.17-1.287-4.678-1.287-7.296 0-11.777 9.543-21.325 21.317-21.334h298.668c0.005 0 0.010 0 0.015 0 11.771 0 21.312 9.541 21.312 21.312 0 2.626-0.475 5.142-1.344 7.464l0.048-0.147-84.032 231.125zM298.666 282.666v-128c0-2.475 0.448-4.95 1.301-7.296l12.842-35.37h-113.621l12.864 35.37c0.832 2.346 1.28 4.822 1.28 7.296v128h85.333zM137.131-58.666l46.549 128h144.661l46.55-128h-237.76z" />
45
  <glyph unicode="&#xe9db;" glyph-name="bx-hide" d="M256-37.334c20.182 0 38.613 2.197 55.424 5.995l-37.483 37.483c-5.824-0.448-11.733-0.81-17.941-0.81-114.155 0-158.379 82.048-169.088 106.666 4.352 10.026 14.379 29.462 32.171 49.002l-29.824 29.824c-32.81-35.563-45.248-71.382-45.483-72.085-1.472-4.374-1.472-9.131 0-13.504 0.448-1.408 49.386-142.57 212.224-142.57zM468.224 105.259c1.472 4.373 1.472 9.131 0 13.504-0.448 1.408-49.387 142.571-212.224 142.571-39.19 0-71.382-8.448-98.219-20.928l-78.698 78.678-30.166-30.166 384-384 30.166 30.166-70.805 70.805c55.765 41.642 75.669 98.475 75.947 99.37zM313.408 84.757c4.075 8.298 6.592 17.45 6.592 27.243 0 35.008-28.992 64-64 64-9.792 0-18.944-2.518-27.243-6.592l-38.571 38.571c18.794 6.571 40.512 10.688 65.814 10.688 114.154 0 158.379-82.048 169.088-106.666-6.442-14.762-24.875-49.962-63.019-75.904l-48.661 48.661z" />
46
  <glyph unicode="&#xe9dc;" glyph-name="bx-history" d="M234.667 197.333v-106.667h106.667v42.666h-64v64zM426.666 112c0 92.501-78.144 170.667-170.667 170.667-92.501 0-170.667-78.166-170.667-170.667h-42.666l64-84.8 64 84.8h-42.666c0 69.376 58.624 128 128 128s128-58.624 128-128-58.624-128-128-128v-42.666c92.522 0 170.667 78.166 170.667 170.666z" />
assets/icons/fonts/crb.ttf CHANGED
Binary file
assets/icons/fonts/crb.woff CHANGED
Binary file
assets/icons/style.css CHANGED
@@ -1,9 +1,9 @@
1
  @font-face {
2
  font-family: 'crb';
3
  src:
4
- url('fonts/crb.ttf?po5qqo') format('truetype'),
5
- url('fonts/crb.woff?po5qqo') format('woff'),
6
- url('fonts/crb.svg?po5qqo#crb') format('svg');
7
  font-weight: normal;
8
  font-style: normal;
9
  }
@@ -47,6 +47,9 @@
47
  .crb-icon-bx-cog:before {
48
  content: "\e203";
49
  }
 
 
 
50
  .crb-icon-bx-dashboard:before {
51
  content: "\e204";
52
  }
1
  @font-face {
2
  font-family: 'crb';
3
  src:
4
+ url('fonts/crb.ttf?o0t6it') format('truetype'),
5
+ url('fonts/crb.woff?o0t6it') format('woff'),
6
+ url('fonts/crb.svg?o0t6it#crb') format('svg');
7
  font-weight: normal;
8
  font-style: normal;
9
  }
47
  .crb-icon-bx-cog:before {
48
  content: "\e203";
49
  }
50
+ .crb-icon-bx-collection:before {
51
+ content: "\e980";
52
+ }
53
  .crb-icon-bx-dashboard:before {
54
  content: "\e204";
55
  }
assets/scanner.js CHANGED
@@ -1,5 +1,5 @@
1
  /**
2
- * Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
3
  */
4
  jQuery(document).ready(function ($) {
5
 
@@ -689,7 +689,7 @@ jQuery(document).ready(function ($) {
689
  $.each(e[2], function (index, s) {
690
  ls.push('<code>Line ' + s[2] + ': <b>' + s[0] + '</b></code>');
691
  });
692
- regs.push(ls.join('</br>') + '<p>' + crb_txt_strings[e[0]][e[1]] + ' (' + e[1] + ')' + '</p>');
693
  }
694
  });
695
 
1
  /**
2
+ * Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
3
  */
4
  jQuery(document).ready(function ($) {
5
 
689
  $.each(e[2], function (index, s) {
690
  ls.push('<code>Line ' + s[2] + ': <b>' + s[0] + '</b></code>');
691
  });
692
+ regs.push(ls.join('<br />') + '<p>' + crb_txt_strings[e[0]][e[1]] + ' (' + e[1] + ')' + '</p>');
693
  }
694
  });
695
 
assets/select2/LICENSE.md ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
assets/select2/dist/css/select2.min.css ADDED
@@ -0,0 +1 @@
 
1
+ .select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;height:1px !important;margin:-1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__placeholder{color:#999;margin-top:5px;float:left}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb}
assets/select2/dist/js/select2.min.js ADDED
@@ -0,0 +1 @@
 
1
+ /*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&module.exports?module.exports=function(b,c){return void 0===c&&(c="undefined"!=typeof window?require("jquery"):require("jquery")(b)),a(c),c}:a(jQuery)}(function(a){var b=function(){if(a&&a.fn&&a.fn.select2&&a.fn.select2.amd)var b=a.fn.select2.amd;var b;return function(){if(!b||!b.requirejs){b?c=b:b={};var a,c,d;!function(b){function e(a,b){return v.call(a,b)}function f(a,b){var c,d,e,f,g,h,i,j,k,l,m,n,o=b&&b.split("/"),p=t.map,q=p&&p["*"]||{};if(a){for(a=a.split("/"),g=a.length-1,t.nodeIdCompat&&x.test(a[g])&&(a[g]=a[g].replace(x,"")),"."===a[0].charAt(0)&&o&&(n=o.slice(0,o.length-1),a=n.concat(a)),k=0;k<a.length;k++)if("."===(m=a[k]))a.splice(k,1),k-=1;else if(".."===m){if(0===k||1===k&&".."===a[2]||".."===a[k-1])continue;k>0&&(a.splice(k-1,2),k-=2)}a=a.join("/")}if((o||q)&&p){for(c=a.split("/"),k=c.length;k>0;k-=1){if(d=c.slice(0,k).join("/"),o)for(l=o.length;l>0;l-=1)if((e=p[o.slice(0,l).join("/")])&&(e=e[d])){f=e,h=k;break}if(f)break;!i&&q&&q[d]&&(i=q[d],j=k)}!f&&i&&(f=i,h=j),f&&(c.splice(0,h,f),a=c.join("/"))}return a}function g(a,c){return function(){var d=w.call(arguments,0);return"string"!=typeof d[0]&&1===d.length&&d.push(null),o.apply(b,d.concat([a,c]))}}function h(a){return function(b){return f(b,a)}}function i(a){return function(b){r[a]=b}}function j(a){if(e(s,a)){var c=s[a];delete s[a],u[a]=!0,n.apply(b,c)}if(!e(r,a)&&!e(u,a))throw new Error("No "+a);return r[a]}function k(a){var b,c=a?a.indexOf("!"):-1;return c>-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function l(a){return a?k(a):[]}function m(a){return function(){return t&&t.config&&t.config[a]||{}}}var n,o,p,q,r={},s={},t={},u={},v=Object.prototype.hasOwnProperty,w=[].slice,x=/\.js$/;p=function(a,b){var c,d=k(a),e=d[0],g=b[1];return a=d[1],e&&(e=f(e,g),c=j(e)),e?a=c&&c.normalize?c.normalize(a,h(g)):f(a,g):(a=f(a,g),d=k(a),e=d[0],a=d[1],e&&(c=j(e))),{f:e?e+"!"+a:a,n:a,pr:e,p:c}},q={require:function(a){return g(a)},exports:function(a){var b=r[a];return void 0!==b?b:r[a]={}},module:function(a){return{id:a,uri:"",exports:r[a],config:m(a)}}},n=function(a,c,d,f){var h,k,m,n,o,t,v,w=[],x=typeof d;if(f=f||a,t=l(f),"undefined"===x||"function"===x){for(c=!c.length&&d.length?["require","exports","module"]:c,o=0;o<c.length;o+=1)if(n=p(c[o],t),"require"===(k=n.f))w[o]=q.require(a);else if("exports"===k)w[o]=q.exports(a),v=!0;else if("module"===k)h=w[o]=q.module(a);else if(e(r,k)||e(s,k)||e(u,k))w[o]=j(k);else{if(!n.p)throw new Error(a+" missing "+k);n.p.load(n.n,g(f,!0),i(k),{}),w[o]=r[k]}m=d?d.apply(r[a],w):void 0,a&&(h&&h.exports!==b&&h.exports!==r[a]?r[a]=h.exports:m===b&&v||(r[a]=m))}else a&&(r[a]=d)},a=c=o=function(a,c,d,e,f){if("string"==typeof a)return q[a]?q[a](c):j(p(a,l(c)).f);if(!a.splice){if(t=a,t.deps&&o(t.deps,t.callback),!c)return;c.splice?(a=c,c=d,d=null):a=b}return c=c||function(){},"function"==typeof d&&(d=e,e=f),e?n(b,a,c,d):setTimeout(function(){n(b,a,c,d)},4),o},o.config=function(a){return o(a)},a._defined=r,d=function(a,b,c){if("string"!=typeof a)throw new Error("See almond README: incorrect module build, no module name");b.splice||(c=b,b=[]),e(r,a)||e(s,a)||(s[a]=[a,b,c])},d.amd={jQuery:!0}}(),b.requirejs=a,b.require=c,b.define=d}}(),b.define("almond",function(){}),b.define("jquery",[],function(){var b=a||$;return null==b&&console&&console.error&&console.error("Select2: An instance of jQuery or a jQuery-compatible library was not found. Make sure that you are including jQuery before Select2 on your web page."),b}),b.define("select2/utils",["jquery"],function(a){function b(a){var b=a.prototype,c=[];for(var d in b){"function"==typeof b[d]&&("constructor"!==d&&c.push(d))}return c}var c={};c.Extend=function(a,b){function c(){this.constructor=a}var d={}.hasOwnProperty;for(var e in b)d.call(b,e)&&(a[e]=b[e]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},c.Decorate=function(a,c){function d(){var b=Array.prototype.unshift,d=c.prototype.constructor.length,e=a.prototype.constructor;d>0&&(b.call(arguments,a.prototype.constructor),e=c.prototype.constructor),e.apply(this,arguments)}function e(){this.constructor=d}var f=b(c),g=b(a);c.displayName=a.displayName,d.prototype=new e;for(var h=0;h<g.length;h++){var i=g[h];d.prototype[i]=a.prototype[i]}for(var j=(function(a){var b=function(){};a in d.prototype&&(b=d.prototype[a]);var e=c.prototype[a];return function(){return Array.prototype.unshift.call(arguments,b),e.apply(this,arguments)}}),k=0;k<f.length;k++){var l=f[k];d.prototype[l]=j(l)}return d};var d=function(){this.listeners={}};return d.prototype.on=function(a,b){this.listeners=this.listeners||{},a in this.listeners?this.listeners[a].push(b):this.listeners[a]=[b]},d.prototype.trigger=function(a){var b=Array.prototype.slice,c=b.call(arguments,1);this.listeners=this.listeners||{},null==c&&(c=[]),0===c.length&&c.push({}),c[0]._type=a,a in this.listeners&&this.invoke(this.listeners[a],b.call(arguments,1)),"*"in this.listeners&&this.invoke(this.listeners["*"],arguments)},d.prototype.invoke=function(a,b){for(var c=0,d=a.length;c<d;c++)a[c].apply(this,b)},c.Observable=d,c.generateChars=function(a){for(var b="",c=0;c<a;c++){b+=Math.floor(36*Math.random()).toString(36)}return b},c.bind=function(a,b){return function(){a.apply(b,arguments)}},c._convertData=function(a){for(var b in a){var c=b.split("-"),d=a;if(1!==c.length){for(var e=0;e<c.length;e++){var f=c[e];f=f.substring(0,1).toLowerCase()+f.substring(1),f in d||(d[f]={}),e==c.length-1&&(d[f]=a[b]),d=d[f]}delete a[b]}}return a},c.hasScroll=function(b,c){var d=a(c),e=c.style.overflowX,f=c.style.overflowY;return(e!==f||"hidden"!==f&&"visible"!==f)&&("scroll"===e||"scroll"===f||(d.innerHeight()<c.scrollHeight||d.innerWidth()<c.scrollWidth))},c.escapeMarkup=function(a){var b={"\\":"&#92;","&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#47;"};return"string"!=typeof a?a:String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})},c.appendMany=function(b,c){if("1.7"===a.fn.jquery.substr(0,3)){var d=a();a.map(c,function(a){d=d.add(a)}),c=d}b.append(c)},c}),b.define("select2/results",["jquery","./utils"],function(a,b){function c(a,b,d){this.$element=a,this.data=d,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<ul class="select2-results__options" role="tree"></ul>');return this.options.get("multiple")&&b.attr("aria-multiselectable","true"),this.$results=b,b},c.prototype.clear=function(){this.$results.empty()},c.prototype.displayMessage=function(b){var c=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var d=a('<li role="treeitem" aria-live="assertive" class="select2-results__option"></li>'),e=this.options.get("translations").get(b.message);d.append(c(e(b.args))),d[0].className+=" select2-results__message",this.$results.append(d)},c.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},c.prototype.append=function(a){this.hideLoading();var b=[];if(null==a.results||0===a.results.length)return void(0===this.$results.children().length&&this.trigger("results:message",{message:"noResults"}));a.results=this.sort(a.results);for(var c=0;c<a.results.length;c++){var d=a.results[c],e=this.option(d);b.push(e)}this.$results.append(b)},c.prototype.position=function(a,b){b.find(".select2-results").append(a)},c.prototype.sort=function(a){return this.options.get("sorter")(a)},c.prototype.highlightFirstItem=function(){var a=this.$results.find(".select2-results__option[aria-selected]"),b=a.filter("[aria-selected=true]");b.length>0?b.first().trigger("mouseenter"):a.first().trigger("mouseenter"),this.ensureHighlightVisible()},c.prototype.setClasses=function(){var b=this;this.data.current(function(c){var d=a.map(c,function(a){return a.id.toString()});b.$results.find(".select2-results__option[aria-selected]").each(function(){var b=a(this),c=a.data(this,"data"),e=""+c.id;null!=c.element&&c.element.selected||null==c.element&&a.inArray(e,d)>-1?b.attr("aria-selected","true"):b.attr("aria-selected","false")})})},c.prototype.showLoading=function(a){this.hideLoading();var b=this.options.get("translations").get("searching"),c={disabled:!0,loading:!0,text:b(a)},d=this.option(c);d.className+=" loading-results",this.$results.prepend(d)},c.prototype.hideLoading=function(){this.$results.find(".loading-results").remove()},c.prototype.option=function(b){var c=document.createElement("li");c.className="select2-results__option";var d={role:"treeitem","aria-selected":"false"};b.disabled&&(delete d["aria-selected"],d["aria-disabled"]="true"),null==b.id&&delete d["aria-selected"],null!=b._resultId&&(c.id=b._resultId),b.title&&(c.title=b.title),b.children&&(d.role="group",d["aria-label"]=b.text,delete d["aria-selected"]);for(var e in d){var f=d[e];c.setAttribute(e,f)}if(b.children){var g=a(c),h=document.createElement("strong");h.className="select2-results__group";a(h);this.template(b,h);for(var i=[],j=0;j<b.children.length;j++){var k=b.children[j],l=this.option(k);i.push(l)}var m=a("<ul></ul>",{class:"select2-results__options select2-results__options--nested"});m.append(i),g.append(h),g.append(m)}else this.template(b,c);return a.data(c,"data",b),c},c.prototype.bind=function(b,c){var d=this,e=b.id+"-results";this.$results.attr("id",e),b.on("results:all",function(a){d.clear(),d.append(a.data),b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("results:append",function(a){d.append(a.data),b.isOpen()&&d.setClasses()}),b.on("query",function(a){d.hideMessages(),d.showLoading(a)}),b.on("select",function(){b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("unselect",function(){b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("open",function(){d.$results.attr("aria-expanded","true"),d.$results.attr("aria-hidden","false"),d.setClasses(),d.ensureHighlightVisible()}),b.on("close",function(){d.$results.attr("aria-expanded","false"),d.$results.attr("aria-hidden","true"),d.$results.removeAttr("aria-activedescendant")}),b.on("results:toggle",function(){var a=d.getHighlightedResults();0!==a.length&&a.trigger("mouseup")}),b.on("results:select",function(){var a=d.getHighlightedResults();if(0!==a.length){var b=a.data("data");"true"==a.attr("aria-selected")?d.trigger("close",{}):d.trigger("select",{data:b})}}),b.on("results:previous",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a);if(0!==c){var e=c-1;0===a.length&&(e=0);var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top,h=f.offset().top,i=d.$results.scrollTop()+(h-g);0===e?d.$results.scrollTop(0):h-g<0&&d.$results.scrollTop(i)}}),b.on("results:next",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a),e=c+1;if(!(e>=b.length)){var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top+d.$results.outerHeight(!1),h=f.offset().top+f.outerHeight(!1),i=d.$results.scrollTop()+h-g;0===e?d.$results.scrollTop(0):h>g&&d.$results.scrollTop(i)}}),b.on("results:focus",function(a){a.element.addClass("select2-results__option--highlighted")}),b.on("results:message",function(a){d.displayMessage(a)}),a.fn.mousewheel&&this.$results.on("mousewheel",function(a){var b=d.$results.scrollTop(),c=d.$results.get(0).scrollHeight-b+a.deltaY,e=a.deltaY>0&&b-a.deltaY<=0,f=a.deltaY<0&&c<=d.$results.height();e?(d.$results.scrollTop(0),a.preventDefault(),a.stopPropagation()):f&&(d.$results.scrollTop(d.$results.get(0).scrollHeight-d.$results.height()),a.preventDefault(),a.stopPropagation())}),this.$results.on("mouseup",".select2-results__option[aria-selected]",function(b){var c=a(this),e=c.data("data");if("true"===c.attr("aria-selected"))return void(d.options.get("multiple")?d.trigger("unselect",{originalEvent:b,data:e}):d.trigger("close",{}));d.trigger("select",{originalEvent:b,data:e})}),this.$results.on("mouseenter",".select2-results__option[aria-selected]",function(b){var c=a(this).data("data");d.getHighlightedResults().removeClass("select2-results__option--highlighted"),d.trigger("results:focus",{data:c,element:a(this)})})},c.prototype.getHighlightedResults=function(){return this.$results.find(".select2-results__option--highlighted")},c.prototype.destroy=function(){this.$results.remove()},c.prototype.ensureHighlightVisible=function(){var a=this.getHighlightedResults();if(0!==a.length){var b=this.$results.find("[aria-selected]"),c=b.index(a),d=this.$results.offset().top,e=a.offset().top,f=this.$results.scrollTop()+(e-d),g=e-d;f-=2*a.outerHeight(!1),c<=2?this.$results.scrollTop(0):(g>this.$results.outerHeight()||g<0)&&this.$results.scrollTop(f)}},c.prototype.template=function(b,c){var d=this.options.get("templateResult"),e=this.options.get("escapeMarkup"),f=d(b,c);null==f?c.style.display="none":"string"==typeof f?c.innerHTML=e(f):a(c).append(f)},c}),b.define("select2/keys",[],function(){return{BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46}}),b.define("select2/selection/base",["jquery","../utils","../keys"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,b.Observable),d.prototype.render=function(){var b=a('<span class="select2-selection" role="combobox" aria-haspopup="true" aria-expanded="false"></span>');return this._tabindex=0,null!=this.$element.data("old-tabindex")?this._tabindex=this.$element.data("old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),b.attr("title",this.$element.attr("title")),b.attr("tabindex",this._tabindex),this.$selection=b,b},d.prototype.bind=function(a,b){var d=this,e=(a.id,a.id+"-results");this.container=a,this.$selection.on("focus",function(a){d.trigger("focus",a)}),this.$selection.on("blur",function(a){d._handleBlur(a)}),this.$selection.on("keydown",function(a){d.trigger("keypress",a),a.which===c.SPACE&&a.preventDefault()}),a.on("results:focus",function(a){d.$selection.attr("aria-activedescendant",a.data._resultId)}),a.on("selection:update",function(a){d.update(a.data)}),a.on("open",function(){d.$selection.attr("aria-expanded","true"),d.$selection.attr("aria-owns",e),d._attachCloseHandler(a)}),a.on("close",function(){d.$selection.attr("aria-expanded","false"),d.$selection.removeAttr("aria-activedescendant"),d.$selection.removeAttr("aria-owns"),d.$selection.focus(),d._detachCloseHandler(a)}),a.on("enable",function(){d.$selection.attr("tabindex",d._tabindex)}),a.on("disable",function(){d.$selection.attr("tabindex","-1")})},d.prototype._handleBlur=function(b){var c=this;window.setTimeout(function(){document.activeElement==c.$selection[0]||a.contains(c.$selection[0],document.activeElement)||c.trigger("blur",b)},1)},d.prototype._attachCloseHandler=function(b){a(document.body).on("mousedown.select2."+b.id,function(b){var c=a(b.target),d=c.closest(".select2");a(".select2.select2-container--open").each(function(){var b=a(this);this!=d[0]&&b.data("element").select2("close")})})},d.prototype._detachCloseHandler=function(b){a(document.body).off("mousedown.select2."+b.id)},d.prototype.position=function(a,b){b.find(".selection").append(a)},d.prototype.destroy=function(){this._detachCloseHandler(this.container)},d.prototype.update=function(a){throw new Error("The `update` method must be defined in child classes.")},d}),b.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(a,b,c,d){function e(){e.__super__.constructor.apply(this,arguments)}return c.Extend(e,b),e.prototype.render=function(){var a=e.__super__.render.call(this);return a.addClass("select2-selection--single"),a.html('<span class="select2-selection__rendered"></span><span class="select2-selection__arrow" role="presentation"><b role="presentation"></b></span>'),a},e.prototype.bind=function(a,b){var c=this;e.__super__.bind.apply(this,arguments);var d=a.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",d),this.$selection.attr("aria-labelledby",d),this.$selection.on("mousedown",function(a){1===a.which&&c.trigger("toggle",{originalEvent:a})}),this.$selection.on("focus",function(a){}),this.$selection.on("blur",function(a){}),a.on("focus",function(b){a.isOpen()||c.$selection.focus()}),a.on("selection:update",function(a){c.update(a.data)})},e.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},e.prototype.display=function(a,b){var c=this.options.get("templateSelection");return this.options.get("escapeMarkup")(c(a,b))},e.prototype.selectionContainer=function(){return a("<span></span>")},e.prototype.update=function(a){if(0===a.length)return void this.clear();var b=a[0],c=this.$selection.find(".select2-selection__rendered"),d=this.display(b,c);c.empty().append(d),c.prop("title",b.title||b.text)},e}),b.define("select2/selection/multiple",["jquery","./base","../utils"],function(a,b,c){function d(a,b){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--multiple"),a.html('<ul class="select2-selection__rendered"></ul>'),a},d.prototype.bind=function(b,c){var e=this;d.__super__.bind.apply(this,arguments),this.$selection.on("click",function(a){e.trigger("toggle",{originalEvent:a})}),this.$selection.on("click",".select2-selection__choice__remove",function(b){if(!e.options.get("disabled")){var c=a(this),d=c.parent(),f=d.data("data");e.trigger("unselect",{originalEvent:b,data:f})}})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a,b){var c=this.options.get("templateSelection");return this.options.get("escapeMarkup")(c(a,b))},d.prototype.selectionContainer=function(){return a('<li class="select2-selection__choice"><span class="select2-selection__choice__remove" role="presentation">&times;</span></li>')},d.prototype.update=function(a){if(this.clear(),0!==a.length){for(var b=[],d=0;d<a.length;d++){var e=a[d],f=this.selectionContainer(),g=this.display(e,f);f.append(g),f.prop("title",e.title||e.text),f.data("data",e),b.push(f)}var h=this.$selection.find(".select2-selection__rendered");c.appendMany(h,b)}},d}),b.define("select2/selection/placeholder",["../utils"],function(a){function b(a,b,c){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c)}return b.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},b.prototype.createPlaceholder=function(a,b){var c=this.selectionContainer();return c.html(this.display(b)),c.addClass("select2-selection__placeholder").removeClass("select2-selection__choice"),c},b.prototype.update=function(a,b){var c=1==b.length&&b[0].id!=this.placeholder.id;if(b.length>1||c)return a.call(this,b);this.clear();var d=this.createPlaceholder(this.placeholder);this.$selection.find(".select2-selection__rendered").append(d)},b}),b.define("select2/selection/allowClear",["jquery","../keys"],function(a,b){function c(){}return c.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),null==this.placeholder&&this.options.get("debug")&&window.console&&console.error&&console.error("Select2: The `allowClear` option should be used in combination with the `placeholder` option."),this.$selection.on("mousedown",".select2-selection__clear",function(a){d._handleClear(a)}),b.on("keypress",function(a){d._handleKeyboardClear(a,b)})},c.prototype._handleClear=function(a,b){if(!this.options.get("disabled")){var c=this.$selection.find(".select2-selection__clear");if(0!==c.length){b.stopPropagation();for(var d=c.data("data"),e=0;e<d.length;e++){var f={data:d[e]};if(this.trigger("unselect",f),f.prevented)return}this.$element.val(this.placeholder.id).trigger("change"),this.trigger("toggle",{})}}},c.prototype._handleKeyboardClear=function(a,c,d){d.isOpen()||c.which!=b.DELETE&&c.which!=b.BACKSPACE||this._handleClear(c)},c.prototype.update=function(b,c){if(b.call(this,c),!(this.$selection.find(".select2-selection__placeholder").length>0||0===c.length)){var d=a('<span class="select2-selection__clear">&times;</span>');d.data("data",c),this.$selection.find(".select2-selection__rendered").prepend(d)}},c}),b.define("select2/selection/search",["jquery","../utils","../keys"],function(a,b,c){function d(a,b,c){a.call(this,b,c)}return d.prototype.render=function(b){var c=a('<li class="select2-search select2-search--inline"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="none" spellcheck="false" role="textbox" aria-autocomplete="list" /></li>');this.$searchContainer=c,this.$search=c.find("input");var d=b.call(this);return this._transferTabIndex(),d},d.prototype.bind=function(a,b,d){var e=this;a.call(this,b,d),b.on("open",function(){e.$search.trigger("focus")}),b.on("close",function(){e.$search.val(""),e.$search.removeAttr("aria-activedescendant"),e.$search.trigger("focus")}),b.on("enable",function(){e.$search.prop("disabled",!1),e._transferTabIndex()}),b.on("disable",function(){e.$search.prop("disabled",!0)}),b.on("focus",function(a){e.$search.trigger("focus")}),b.on("results:focus",function(a){e.$search.attr("aria-activedescendant",a.id)}),this.$selection.on("focusin",".select2-search--inline",function(a){e.trigger("focus",a)}),this.$selection.on("focusout",".select2-search--inline",function(a){e._handleBlur(a)}),this.$selection.on("keydown",".select2-search--inline",function(a){if(a.stopPropagation(),e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented(),a.which===c.BACKSPACE&&""===e.$search.val()){var b=e.$searchContainer.prev(".select2-selection__choice");if(b.length>0){var d=b.data("data");e.searchRemoveChoice(d),a.preventDefault()}}});var f=document.documentMode,g=f&&f<=11;this.$selection.on("input.searchcheck",".select2-search--inline",function(a){if(g)return void e.$selection.off("input.search input.searchcheck");e.$selection.off("keyup.search")}),this.$selection.on("keyup.search input.search",".select2-search--inline",function(a){if(g&&"input"===a.type)return void e.$selection.off("input.search input.searchcheck");var b=a.which;b!=c.SHIFT&&b!=c.CTRL&&b!=c.ALT&&b!=c.TAB&&e.handleSearch(a)})},d.prototype._transferTabIndex=function(a){this.$search.attr("tabindex",this.$selection.attr("tabindex")),this.$selection.attr("tabindex","-1")},d.prototype.createPlaceholder=function(a,b){this.$search.attr("placeholder",b.text)},d.prototype.update=function(a,b){var c=this.$search[0]==document.activeElement;this.$search.attr("placeholder",""),a.call(this,b),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch(),c&&this.$search.focus()},d.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},d.prototype.searchRemoveChoice=function(a,b){this.trigger("unselect",{data:b}),this.$search.val(b.text),this.handleSearch()},d.prototype.resizeSearch=function(){this.$search.css("width","25px");var a="";if(""!==this.$search.attr("placeholder"))a=this.$selection.find(".select2-selection__rendered").innerWidth();else{a=.75*(this.$search.val().length+1)+"em"}this.$search.css("width",a)},d}),b.define("select2/selection/eventRelay",["jquery"],function(a){function b(){}return b.prototype.bind=function(b,c,d){var e=this,f=["open","opening","close","closing","select","selecting","unselect","unselecting"],g=["opening","closing","selecting","unselecting"];b.call(this,c,d),c.on("*",function(b,c){if(-1!==a.inArray(b,f)){c=c||{};var d=a.Event("select2:"+b,{params:c});e.$element.trigger(d),-1!==a.inArray(b,g)&&(c.prevented=d.isDefaultPrevented())}})},b}),b.define("select2/translation",["jquery","require"],function(a,b){function c(a){this.dict=a||{}}return c.prototype.all=function(){return this.dict},c.prototype.get=function(a){return this.dict[a]},c.prototype.extend=function(b){this.dict=a.extend({},b.all(),this.dict)},c._cache={},c.loadPath=function(a){if(!(a in c._cache)){var d=b(a);c._cache[a]=d}return new c(c._cache[a])},c}),b.define("select2/diacritics",[],function(){return{"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ω":"ω","ς":"σ"}}),b.define("select2/data/base",["../utils"],function(a){function b(a,c){b.__super__.constructor.call(this)}return a.Extend(b,a.Observable),b.prototype.current=function(a){throw new Error("The `current` method must be defined in child classes.")},b.prototype.query=function(a,b){throw new Error("The `query` method must be defined in child classes.")},b.prototype.bind=function(a,b){},b.prototype.destroy=function(){},b.prototype.generateResultId=function(b,c){var d=b.id+"-result-";return d+=a.generateChars(4),null!=c.id?d+="-"+c.id.toString():d+="-"+a.generateChars(4),d},b}),b.define("select2/data/select",["./base","../utils","jquery"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,a),d.prototype.current=function(a){var b=[],d=this;this.$element.find(":selected").each(function(){var a=c(this),e=d.item(a);b.push(e)}),a(b)},d.prototype.select=function(a){var b=this;if(a.selected=!0,c(a.element).is("option"))return a.element.selected=!0,void this.$element.trigger("change");if(this.$element.prop("multiple"))this.current(function(d){var e=[];a=[a],a.push.apply(a,d);for(var f=0;f<a.length;f++){var g=a[f].id;-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")});else{var d=a.id;this.$element.val(d),this.$element.trigger("change")}},d.prototype.unselect=function(a){var b=this;if(this.$element.prop("multiple")){if(a.selected=!1,c(a.element).is("option"))return a.element.selected=!1,void this.$element.trigger("change");this.current(function(d){for(var e=[],f=0;f<d.length;f++){var g=d[f].id;g!==a.id&&-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")})}},d.prototype.bind=function(a,b){var c=this;this.container=a,a.on("select",function(a){c.select(a.data)}),a.on("unselect",function(a){c.unselect(a.data)})},d.prototype.destroy=function(){this.$element.find("*").each(function(){c.removeData(this,"data")})},d.prototype.query=function(a,b){var d=[],e=this;this.$element.children().each(function(){var b=c(this);if(b.is("option")||b.is("optgroup")){var f=e.item(b),g=e.matches(a,f);null!==g&&d.push(g)}}),b({results:d})},d.prototype.addOptions=function(a){b.appendMany(this.$element,a)},d.prototype.option=function(a){var b;a.children?(b=document.createElement("optgroup"),b.label=a.text):(b=document.createElement("option"),void 0!==b.textContent?b.textContent=a.text:b.innerText=a.text),void 0!==a.id&&(b.value=a.id),a.disabled&&(b.disabled=!0),a.selected&&(b.selected=!0),a.title&&(b.title=a.title);var d=c(b),e=this._normalizeItem(a);return e.element=b,c.data(b,"data",e),d},d.prototype.item=function(a){var b={};if(null!=(b=c.data(a[0],"data")))return b;if(a.is("option"))b={id:a.val(),text:a.text(),disabled:a.prop("disabled"),selected:a.prop("selected"),title:a.prop("title")};else if(a.is("optgroup")){b={text:a.prop("label"),children:[],title:a.prop("title")};for(var d=a.children("option"),e=[],f=0;f<d.length;f++){var g=c(d[f]),h=this.item(g);e.push(h)}b.children=e}return b=this._normalizeItem(b),b.element=a[0],c.data(a[0],"data",b),b},d.prototype._normalizeItem=function(a){c.isPlainObject(a)||(a={id:a,text:a}),a=c.extend({},{text:""},a);var b={selected:!1,disabled:!1};return null!=a.id&&(a.id=a.id.toString()),null!=a.text&&(a.text=a.text.toString()),null==a._resultId&&a.id&&null!=this.container&&(a._resultId=this.generateResultId(this.container,a)),c.extend({},b,a)},d.prototype.matches=function(a,b){return this.options.get("matcher")(a,b)},d}),b.define("select2/data/array",["./select","../utils","jquery"],function(a,b,c){function d(a,b){var c=b.get("data")||[];d.__super__.constructor.call(this,a,b),this.addOptions(this.convertToOptions(c))}return b.Extend(d,a),d.prototype.select=function(a){var b=this.$element.find("option").filter(function(b,c){return c.value==a.id.toString()});0===b.length&&(b=this.option(a),this.addOptions(b)),d.__super__.select.call(this,a)},d.prototype.convertToOptions=function(a){function d(a){return function(){return c(this).val()==a.id}}for(var e=this,f=this.$element.find("option"),g=f.map(function(){return e.item(c(this)).id}).get(),h=[],i=0;i<a.length;i++){var j=this._normalizeItem(a[i]);if(c.inArray(j.id,g)>=0){var k=f.filter(d(j)),l=this.item(k),m=c.extend(!0,{},j,l),n=this.option(m);k.replaceWith(n)}else{var o=this.option(j);if(j.children){var p=this.convertToOptions(j.children);b.appendMany(o,p)}h.push(o)}}return h},d}),b.define("select2/data/ajax",["./array","../utils","jquery"],function(a,b,c){function d(a,b){this.ajaxOptions=this._applyDefaults(b.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),d.__super__.constructor.call(this,a,b)}return b.Extend(d,a),d.prototype._applyDefaults=function(a){var b={data:function(a){return c.extend({},a,{q:a.term})},transport:function(a,b,d){var e=c.ajax(a);return e.then(b),e.fail(d),e}};return c.extend({},b,a,!0)},d.prototype.processResults=function(a){return a},d.prototype.query=function(a,b){function d(){var d=f.transport(f,function(d){var f=e.processResults(d,a);e.options.get("debug")&&window.console&&console.error&&(f&&f.results&&c.isArray(f.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),b(f)},function(){d.status&&"0"===d.status||e.trigger("results:message",{message:"errorLoading"})});e._request=d}var e=this;null!=this._request&&(c.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var f=c.extend({type:"GET"},this.ajaxOptions);"function"==typeof f.url&&(f.url=f.url.call(this.$element,a)),"function"==typeof f.data&&(f.data=f.data.call(this.$element,a)),this.ajaxOptions.delay&&null!=a.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(d,this.ajaxOptions.delay)):d()},d}),b.define("select2/data/tags",["jquery"],function(a){function b(b,c,d){var e=d.get("tags"),f=d.get("createTag");void 0!==f&&(this.createTag=f);var g=d.get("insertTag");if(void 0!==g&&(this.insertTag=g),b.call(this,c,d),a.isArray(e))for(var h=0;h<e.length;h++){var i=e[h],j=this._normalizeItem(i),k=this.option(j);this.$element.append(k)}}return b.prototype.query=function(a,b,c){function d(a,f){for(var g=a.results,h=0;h<g.length;h++){var i=g[h],j=null!=i.children&&!d({results:i.children},!0);if((i.text||"").toUpperCase()===(b.term||"").toUpperCase()||j)return!f&&(a.data=g,void c(a))}if(f)return!0;var k=e.createTag(b);if(null!=k){var l=e.option(k);l.attr("data-select2-tag",!0),e.addOptions([l]),e.insertTag(g,k)}a.results=g,c(a)}var e=this;if(this._removeOldTags(),null==b.term||null!=b.page)return void a.call(this,b,c);a.call(this,b,d)},b.prototype.createTag=function(b,c){var d=a.trim(c.term);return""===d?null:{id:d,text:d}},b.prototype.insertTag=function(a,b,c){b.unshift(c)},b.prototype._removeOldTags=function(b){this._lastTag;this.$element.find("option[data-select2-tag]").each(function(){this.selected||a(this).remove()})},b}),b.define("select2/data/tokenizer",["jquery"],function(a){function b(a,b,c){var d=c.get("tokenizer");void 0!==d&&(this.tokenizer=d),a.call(this,b,c)}return b.prototype.bind=function(a,b,c){a.call(this,b,c),this.$search=b.dropdown.$search||b.selection.$search||c.find(".select2-search__field")},b.prototype.query=function(b,c,d){function e(b){var c=g._normalizeItem(b);if(!g.$element.find("option").filter(function(){return a(this).val()===c.id}).length){var d=g.option(c);d.attr("data-select2-tag",!0),g._removeOldTags(),g.addOptions([d])}f(c)}function f(a){g.trigger("select",{data:a})}var g=this;c.term=c.term||"";var h=this.tokenizer(c,this.options,e);h.term!==c.term&&(this.$search.length&&(this.$search.val(h.term),this.$search.focus()),c.term=h.term),b.call(this,c,d)},b.prototype.tokenizer=function(b,c,d,e){for(var f=d.get("tokenSeparators")||[],g=c.term,h=0,i=this.createTag||function(a){return{id:a.term,text:a.term}};h<g.length;){var j=g[h];if(-1!==a.inArray(j,f)){var k=g.substr(0,h),l=a.extend({},c,{term:k}),m=i(l);null!=m?(e(m),g=g.substr(h+1)||"",h=0):h++}else h++}return{term:g}},b}),b.define("select2/data/minimumInputLength",[],function(){function a(a,b,c){this.minimumInputLength=c.get("minimumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){if(b.term=b.term||"",b.term.length<this.minimumInputLength)return void this.trigger("results:message",{message:"inputTooShort",args:{minimum:this.minimumInputLength,input:b.term,params:b}});a.call(this,b,c)},a}),b.define("select2/data/maximumInputLength",[],function(){function a(a,b,c){this.maximumInputLength=c.get("maximumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){if(b.term=b.term||"",this.maximumInputLength>0&&b.term.length>this.maximumInputLength)return void this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:b.term,params:b}});a.call(this,b,c)},a}),b.define("select2/data/maximumSelectionLength",[],function(){function a(a,b,c){this.maximumSelectionLength=c.get("maximumSelectionLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){var d=this;this.current(function(e){var f=null!=e?e.length:0;if(d.maximumSelectionLength>0&&f>=d.maximumSelectionLength)return void d.trigger("results:message",{message:"maximumSelected",args:{maximum:d.maximumSelectionLength}});a.call(d,b,c)})},a}),b.define("select2/dropdown",["jquery","./utils"],function(a,b){function c(a,b){this.$element=a,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<span class="select2-dropdown"><span class="select2-results"></span></span>');return b.attr("dir",this.options.get("dir")),this.$dropdown=b,b},c.prototype.bind=function(){},c.prototype.position=function(a,b){},c.prototype.destroy=function(){this.$dropdown.remove()},c}),b.define("select2/dropdown/search",["jquery","../utils"],function(a,b){function c(){}return c.prototype.render=function(b){var c=b.call(this),d=a('<span class="select2-search select2-search--dropdown"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="none" spellcheck="false" role="textbox" /></span>');return this.$searchContainer=d,this.$search=d.find("input"),c.prepend(d),c},c.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),this.$search.on("keydown",function(a){e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented()}),this.$search.on("input",function(b){a(this).off("keyup")}),this.$search.on("keyup input",function(a){e.handleSearch(a)}),c.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus(),window.setTimeout(function(){e.$search.focus()},0)}),c.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val("")}),c.on("focus",function(){c.isOpen()||e.$search.focus()}),c.on("results:all",function(a){if(null==a.query.term||""===a.query.term){e.showSearch(a)?e.$searchContainer.removeClass("select2-search--hide"):e.$searchContainer.addClass("select2-search--hide")}})},c.prototype.handleSearch=function(a){if(!this._keyUpPrevented){var b=this.$search.val();this.trigger("query",{term:b})}this._keyUpPrevented=!1},c.prototype.showSearch=function(a,b){return!0},c}),b.define("select2/dropdown/hidePlaceholder",[],function(){function a(a,b,c,d){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c,d)}return a.prototype.append=function(a,b){b.results=this.removePlaceholder(b.results),a.call(this,b)},a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.removePlaceholder=function(a,b){for(var c=b.slice(0),d=b.length-1;d>=0;d--){var e=b[d];this.placeholder.id===e.id&&c.splice(d,1)}return c},a}),b.define("select2/dropdown/infiniteScroll",["jquery"],function(a){function b(a,b,c,d){this.lastParams={},a.call(this,b,c,d),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return b.prototype.append=function(a,b){this.$loadingMore.remove(),this.loading=!1,a.call(this,b),this.showLoadingMore(b)&&this.$results.append(this.$loadingMore)},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),c.on("query",function(a){e.lastParams=a,e.loading=!0}),c.on("query:append",function(a){e.lastParams=a,e.loading=!0}),this.$results.on("scroll",function(){var b=a.contains(document.documentElement,e.$loadingMore[0]);if(!e.loading&&b){e.$results.offset().top+e.$results.outerHeight(!1)+50>=e.$loadingMore.offset().top+e.$loadingMore.outerHeight(!1)&&e.loadMore()}})},b.prototype.loadMore=function(){this.loading=!0;var b=a.extend({},{page:1},this.lastParams);b.page++,this.trigger("query:append",b)},b.prototype.showLoadingMore=function(a,b){return b.pagination&&b.pagination.more},b.prototype.createLoadingMore=function(){var b=a('<li class="select2-results__option select2-results__option--load-more"role="treeitem" aria-disabled="true"></li>'),c=this.options.get("translations").get("loadingMore");return b.html(c(this.lastParams)),b},b}),b.define("select2/dropdown/attachBody",["jquery","../utils"],function(a,b){function c(b,c,d){this.$dropdownParent=d.get("dropdownParent")||a(document.body),b.call(this,c,d)}return c.prototype.bind=function(a,b,c){var d=this,e=!1;a.call(this,b,c),b.on("open",function(){d._showDropdown(),d._attachPositioningHandler(b),e||(e=!0,b.on("results:all",function(){d._positionDropdown(),d._resizeDropdown()}),b.on("results:append",function(){d._positionDropdown(),d._resizeDropdown()}))}),b.on("close",function(){d._hideDropdown(),d._detachPositioningHandler(b)}),this.$dropdownContainer.on("mousedown",function(a){a.stopPropagation()})},c.prototype.destroy=function(a){a.call(this),this.$dropdownContainer.remove()},c.prototype.position=function(a,b,c){b.attr("class",c.attr("class")),b.removeClass("select2"),b.addClass("select2-container--open"),b.css({position:"absolute",top:-999999}),this.$container=c},c.prototype.render=function(b){var c=a("<span></span>"),d=b.call(this);return c.append(d),this.$dropdownContainer=c,c},c.prototype._hideDropdown=function(a){this.$dropdownContainer.detach()},c.prototype._attachPositioningHandler=function(c,d){var e=this,f="scroll.select2."+d.id,g="resize.select2."+d.id,h="orientationchange.select2."+d.id,i=this.$container.parents().filter(b.hasScroll);i.each(function(){a(this).data("select2-scroll-position",{x:a(this).scrollLeft(),y:a(this).scrollTop()})}),i.on(f,function(b){var c=a(this).data("select2-scroll-position");a(this).scrollTop(c.y)}),a(window).on(f+" "+g+" "+h,function(a){e._positionDropdown(),e._resizeDropdown()})},c.prototype._detachPositioningHandler=function(c,d){var e="scroll.select2."+d.id,f="resize.select2."+d.id,g="orientationchange.select2."+d.id;this.$container.parents().filter(b.hasScroll).off(e),a(window).off(e+" "+f+" "+g)},c.prototype._positionDropdown=function(){var b=a(window),c=this.$dropdown.hasClass("select2-dropdown--above"),d=this.$dropdown.hasClass("select2-dropdown--below"),e=null,f=this.$container.offset();f.bottom=f.top+this.$container.outerHeight(!1);var g={height:this.$container.outerHeight(!1)};g.top=f.top,g.bottom=f.top+g.height;var h={height:this.$dropdown.outerHeight(!1)},i={top:b.scrollTop(),bottom:b.scrollTop()+b.height()},j=i.top<f.top-h.height,k=i.bottom>f.bottom+h.height,l={left:f.left,top:g.bottom},m=this.$dropdownParent;"static"===m.css("position")&&(m=m.offsetParent());var n=m.offset();l.top-=n.top,l.left-=n.left,c||d||(e="below"),k||!j||c?!j&&k&&c&&(e="below"):e="above",("above"==e||c&&"below"!==e)&&(l.top=g.top-n.top-h.height),null!=e&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+e),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+e)),this.$dropdownContainer.css(l)},c.prototype._resizeDropdown=function(){var a={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(a.minWidth=a.width,a.position="relative",a.width="auto"),this.$dropdown.css(a)},c.prototype._showDropdown=function(a){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},c}),b.define("select2/dropdown/minimumResultsForSearch",[],function(){function a(b){for(var c=0,d=0;d<b.length;d++){var e=b[d];e.children?c+=a(e.children):c++}return c}function b(a,b,c,d){this.minimumResultsForSearch=c.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),a.call(this,b,c,d)}return b.prototype.showSearch=function(b,c){return!(a(c.data.results)<this.minimumResultsForSearch)&&b.call(this,c)},b}),b.define("select2/dropdown/selectOnClose",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("close",function(a){d._handleSelectOnClose(a)})},a.prototype._handleSelectOnClose=function(a,b){if(b&&null!=b.originalSelect2Event){var c=b.originalSelect2Event;if("select"===c._type||"unselect"===c._type)return}var d=this.getHighlightedResults();if(!(d.length<1)){var e=d.data("data");null!=e.element&&e.element.selected||null==e.element&&e.selected||this.trigger("select",{data:e})}},a}),b.define("select2/dropdown/closeOnSelect",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("select",function(a){d._selectTriggered(a)}),b.on("unselect",function(a){d._selectTriggered(a)})},a.prototype._selectTriggered=function(a,b){var c=b.originalEvent;c&&c.ctrlKey||this.trigger("close",{originalEvent:c,originalSelect2Event:b})},a}),b.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(a){var b=a.input.length-a.maximum,c="Please delete "+b+" character";return 1!=b&&(c+="s"),c},inputTooShort:function(a){return"Please enter "+(a.minimum-a.input.length)+" or more characters"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(a){var b="You can only select "+a.maximum+" item";return 1!=a.maximum&&(b+="s"),b},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),b.define("select2/defaults",["jquery","require","./results","./selection/single","./selection/multiple","./selection/placeholder","./selection/allowClear","./selection/search","./selection/eventRelay","./utils","./translation","./diacritics","./data/select","./data/array","./data/ajax","./data/tags","./data/tokenizer","./data/minimumInputLength","./data/maximumInputLength","./data/maximumSelectionLength","./dropdown","./dropdown/search","./dropdown/hidePlaceholder","./dropdown/infiniteScroll","./dropdown/attachBody","./dropdown/minimumResultsForSearch","./dropdown/selectOnClose","./dropdown/closeOnSelect","./i18n/en"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C){function D(){this.reset()}return D.prototype.apply=function(l){if(l=a.extend(!0,{},this.defaults,l),null==l.dataAdapter){if(null!=l.ajax?l.dataAdapter=o:null!=l.data?l.dataAdapter=n:l.dataAdapter=m,l.minimumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,r)),l.maximumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,s)),l.maximumSelectionLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,t)),l.tags&&(l.dataAdapter=j.Decorate(l.dataAdapter,p)),null==l.tokenSeparators&&null==l.tokenizer||(l.dataAdapter=j.Decorate(l.dataAdapter,q)),null!=l.query){var C=b(l.amdBase+"compat/query");l.dataAdapter=j.Decorate(l.dataAdapter,C)}if(null!=l.initSelection){var D=b(l.amdBase+"compat/initSelection");l.dataAdapter=j.Decorate(l.dataAdapter,D)}}if(null==l.resultsAdapter&&(l.resultsAdapter=c,null!=l.ajax&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,x)),null!=l.placeholder&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,w)),l.selectOnClose&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,A))),null==l.dropdownAdapter){if(l.multiple)l.dropdownAdapter=u;else{var E=j.Decorate(u,v);l.dropdownAdapter=E}if(0!==l.minimumResultsForSearch&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,z)),l.closeOnSelect&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,B)),null!=l.dropdownCssClass||null!=l.dropdownCss||null!=l.adaptDropdownCssClass){var F=b(l.amdBase+"compat/dropdownCss");l.dropdownAdapter=j.Decorate(l.dropdownAdapter,F)}l.dropdownAdapter=j.Decorate(l.dropdownAdapter,y)}if(null==l.selectionAdapter){if(l.multiple?l.selectionAdapter=e:l.selectionAdapter=d,null!=l.placeholder&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,f)),l.allowClear&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,g)),l.multiple&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,h)),null!=l.containerCssClass||null!=l.containerCss||null!=l.adaptContainerCssClass){var G=b(l.amdBase+"compat/containerCss");l.selectionAdapter=j.Decorate(l.selectionAdapter,G)}l.selectionAdapter=j.Decorate(l.selectionAdapter,i)}if("string"==typeof l.language)if(l.language.indexOf("-")>0){var H=l.language.split("-"),I=H[0];l.language=[l.language,I]}else l.language=[l.language];if(a.isArray(l.language)){var J=new k;l.language.push("en");for(var K=l.language,L=0;L<K.length;L++){var M=K[L],N={};try{N=k.loadPath(M)}catch(a){try{M=this.defaults.amdLanguageBase+M,N=k.loadPath(M)}catch(a){l.debug&&window.console&&console.warn&&console.warn('Select2: The language file for "'+M+'" could not be automatically loaded. A fallback will be used instead.');continue}}J.extend(N)}l.translations=J}else{var O=k.loadPath(this.defaults.amdLanguageBase+"en"),P=new k(l.language);P.extend(O),l.translations=P}return l},D.prototype.reset=function(){function b(a){function b(a){return l[a]||a}return a.replace(/[^\u0000-\u007E]/g,b)}function c(d,e){if(""===a.trim(d.term))return e;if(e.children&&e.children.length>0){for(var f=a.extend(!0,{},e),g=e.children.length-1;g>=0;g--){null==c(d,e.children[g])&&f.children.splice(g,1)}return f.children.length>0?f:c(d,f)}var h=b(e.text).toUpperCase(),i=b(d.term).toUpperCase();return h.indexOf(i)>-1?e:null}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:j.escapeMarkup,language:C,matcher:c,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,sorter:function(a){return a},templateResult:function(a){return a.text},templateSelection:function(a){return a.text},theme:"default",width:"resolve"}},D.prototype.set=function(b,c){var d=a.camelCase(b),e={};e[d]=c;var f=j._convertData(e);a.extend(this.defaults,f)},new D}),b.define("select2/options",["require","jquery","./defaults","./utils"],function(a,b,c,d){function e(b,e){if(this.options=b,null!=e&&this.fromElement(e),this.options=c.apply(this.options),e&&e.is("input")){var f=a(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=d.Decorate(this.options.dataAdapter,f)}}return e.prototype.fromElement=function(a){var c=["select2"];null==this.options.multiple&&(this.options.multiple=a.prop("multiple")),null==this.options.disabled&&(this.options.disabled=a.prop("disabled")),null==this.options.language&&(a.prop("lang")?this.options.language=a.prop("lang").toLowerCase():a.closest("[lang]").prop("lang")&&(this.options.language=a.closest("[lang]").prop("lang"))),null==this.options.dir&&(a.prop("dir")?this.options.dir=a.prop("dir"):a.closest("[dir]").prop("dir")?this.options.dir=a.closest("[dir]").prop("dir"):this.options.dir="ltr"),a.prop("disabled",this.options.disabled),a.prop("multiple",this.options.multiple),a.data("select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),a.data("data",a.data("select2Tags")),a.data("tags",!0)),a.data("ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),a.attr("ajax--url",a.data("ajaxUrl")),a.data("ajax--url",a.data("ajaxUrl")));var e={};e=b.fn.jquery&&"1."==b.fn.jquery.substr(0,2)&&a[0].dataset?b.extend(!0,{},a[0].dataset,a.data()):a.data();var f=b.extend(!0,{},e);f=d._convertData(f);for(var g in f)b.inArray(g,c)>-1||(b.isPlainObject(this.options[g])?b.extend(this.options[g],f[g]):this.options[g]=f[g]);return this},e.prototype.get=function(a){return this.options[a]},e.prototype.set=function(a,b){this.options[a]=b},e}),b.define("select2/core",["jquery","./options","./utils","./keys"],function(a,b,c,d){var e=function(a,c){null!=a.data("select2")&&a.data("select2").destroy(),this.$element=a,this.id=this._generateId(a),c=c||{},this.options=new b(c,a),e.__super__.constructor.call(this);var d=a.attr("tabindex")||0;a.data("old-tabindex",d),a.attr("tabindex","-1");var f=this.options.get("dataAdapter");this.dataAdapter=new f(a,this.options);var g=this.render();this._placeContainer(g);var h=this.options.get("selectionAdapter");this.selection=new h(a,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,g);var i=this.options.get("dropdownAdapter");this.dropdown=new i(a,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,g);var j=this.options.get("resultsAdapter");this.results=new j(a,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var k=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(a){k.trigger("selection:update",{data:a})}),a.addClass("select2-hidden-accessible"),a.attr("aria-hidden","true"),this._syncAttributes(),a.data("select2",this)};return c.Extend(e,c.Observable),e.prototype._generateId=function(a){var b="";return b=null!=a.attr("id")?a.attr("id"):null!=a.attr("name")?a.attr("name")+"-"+c.generateChars(2):c.generateChars(4),b=b.replace(/(:|\.|\[|\]|,)/g,""),b="select2-"+b},e.prototype._placeContainer=function(a){a.insertAfter(this.$element);var b=this._resolveWidth(this.$element,this.options.get("width"));null!=b&&a.css("width",b)},e.prototype._resolveWidth=function(a,b){var c=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==b){var d=this._resolveWidth(a,"style");return null!=d?d:this._resolveWidth(a,"element")}if("element"==b){var e=a.outerWidth(!1);return e<=0?"auto":e+"px"}if("style"==b){var f=a.attr("style");if("string"!=typeof f)return null;for(var g=f.split(";"),h=0,i=g.length;h<i;h+=1){var j=g[h].replace(/\s/g,""),k=j.match(c);if(null!==k&&k.length>=1)return k[1]}return null}return b},e.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},e.prototype._registerDomEvents=function(){var b=this;this.$element.on("change.select2",function(){b.dataAdapter.current(function(a){b.trigger("selection:update",{data:a})})}),this.$element.on("focus.select2",function(a){b.trigger("focus",a)}),this._syncA=c.bind(this._syncAttributes,this),this._syncS=c.bind(this._syncSubtree,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._syncA);var d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=d?(this._observer=new d(function(c){a.each(c,b._syncA),a.each(c,b._syncS)}),this._observer.observe(this.$element[0],{attributes:!0,childList:!0,subtree:!1})):this.$element[0].addEventListener&&(this.$element[0].addEventListener("DOMAttrModified",b._syncA,!1),this.$element[0].addEventListener("DOMNodeInserted",b._syncS,!1),this.$element[0].addEventListener("DOMNodeRemoved",b._syncS,!1))},e.prototype._registerDataEvents=function(){var a=this;this.dataAdapter.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerSelectionEvents=function(){var b=this,c=["toggle","focus"];this.selection.on("toggle",function(){b.toggleDropdown()}),this.selection.on("focus",function(a){b.focus(a)}),this.selection.on("*",function(d,e){-1===a.inArray(d,c)&&b.trigger(d,e)})},e.prototype._registerDropdownEvents=function(){var a=this;this.dropdown.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerResultsEvents=function(){var a=this;this.results.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerEvents=function(){var a=this;this.on("open",function(){a.$container.addClass("select2-container--open")}),this.on("close",function(){a.$container.removeClass("select2-container--open")}),this.on("enable",function(){a.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){a.$container.addClass("select2-container--disabled")}),this.on("blur",function(){a.$container.removeClass("select2-container--focus")}),this.on("query",function(b){a.isOpen()||a.trigger("open",{}),this.dataAdapter.query(b,function(c){a.trigger("results:all",{data:c,query:b})})}),this.on("query:append",function(b){this.dataAdapter.query(b,function(c){a.trigger("results:append",{data:c,query:b})})}),this.on("keypress",function(b){var c=b.which;a.isOpen()?c===d.ESC||c===d.TAB||c===d.UP&&b.altKey?(a.close(),b.preventDefault()):c===d.ENTER?(a.trigger("results:select",{}),b.preventDefault()):c===d.SPACE&&b.ctrlKey?(a.trigger("results:toggle",{}),b.preventDefault()):c===d.UP?(a.trigger("results:previous",{}),b.preventDefault()):c===d.DOWN&&(a.trigger("results:next",{}),b.preventDefault()):(c===d.ENTER||c===d.SPACE||c===d.DOWN&&b.altKey)&&(a.open(),b.preventDefault())})},e.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable",{})):this.trigger("enable",{})},e.prototype._syncSubtree=function(a,b){var c=!1,d=this;if(!a||!a.target||"OPTION"===a.target.nodeName||"OPTGROUP"===a.target.nodeName){if(b)if(b.addedNodes&&b.addedNodes.length>0)for(var e=0;e<b.addedNodes.length;e++){var f=b.addedNodes[e];f.selected&&(c=!0)}else b.removedNodes&&b.removedNodes.length>0&&(c=!0);else c=!0;c&&this.dataAdapter.current(function(a){d.trigger("selection:update",{data:a})})}},e.prototype.trigger=function(a,b){var c=e.__super__.trigger,d={open:"opening",close:"closing",select:"selecting",unselect:"unselecting"};if(void 0===b&&(b={}),a in d){var f=d[a],g={prevented:!1,name:a,args:b};if(c.call(this,f,g),g.prevented)return void(b.prevented=!0)}c.call(this,a,b)},e.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},e.prototype.open=function(){this.isOpen()||this.trigger("query",{})},e.prototype.close=function(){this.isOpen()&&this.trigger("close",{})},e.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},e.prototype.hasFocus=function(){return this.$container.hasClass("select2-container--focus")},e.prototype.focus=function(a){this.hasFocus()||(this.$container.addClass("select2-container--focus"),this.trigger("focus",{}))},e.prototype.enable=function(a){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),null!=a&&0!==a.length||(a=[!0]);var b=!a[0];this.$element.prop("disabled",b)},e.prototype.data=function(){this.options.get("debug")&&arguments.length>0&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var a=[];return this.dataAdapter.current(function(b){a=b}),a},e.prototype.val=function(b){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==b||0===b.length)return this.$element.val();var c=b[0];a.isArray(c)&&(c=a.map(c,function(a){return a.toString()})),this.$element.val(c).trigger("change")},e.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._syncA),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&(this.$element[0].removeEventListener("DOMAttrModified",this._syncA,!1),this.$element[0].removeEventListener("DOMNodeInserted",this._syncS,!1),this.$element[0].removeEventListener("DOMNodeRemoved",this._syncS,!1)),this._syncA=null,this._syncS=null,this.$element.off(".select2"),this.$element.attr("tabindex",this.$element.data("old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null},e.prototype.render=function(){var b=a('<span class="select2 select2-container"><span class="selection"></span><span class="dropdown-wrapper" aria-hidden="true"></span></span>');return b.attr("dir",this.options.get("dir")),this.$container=b,this.$container.addClass("select2-container--"+this.options.get("theme")),b.data("element",this.$element),b},e}),b.define("jquery-mousewheel",["jquery"],function(a){return a}),b.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults"],function(a,b,c,d){if(null==a.fn.select2){var e=["open","close","destroy"];a.fn.select2=function(b){if("object"==typeof(b=b||{}))return this.each(function(){var d=a.extend(!0,{},b);new c(a(this),d)}),this;if("string"==typeof b){var d,f=Array.prototype.slice.call(arguments,1);return this.each(function(){var c=a(this).data("select2");null==c&&window.console&&console.error&&console.error("The select2('"+b+"') method was called on an element that is not using Select2."),d=c[b].apply(c,f)}),a.inArray(b,e)>-1?this:d}throw new Error("Invalid arguments for Select2: "+b)}}return null==a.fn.select2.defaults&&(a.fn.select2.defaults=d),c}),{define:b.define,require:b.require}}(),c=b.require("jquery.select2");return a.fn.select2.amd=b,c});
assets/wp-admin.js CHANGED
@@ -1,5 +1,5 @@
1
  /**
2
- * Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
3
  *
4
  * WordPress related JavaScript
5
  *
1
  /**
2
+ * Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
3
  *
4
  * WordPress related JavaScript
5
  *
cerber-lab.php CHANGED
@@ -2,8 +2,8 @@
2
  /*
3
  Cerber Laboratory (cerberlab.net) specific routines.
4
 
5
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
6
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
7
 
8
  Licenced under the GNU GPL.
9
 
@@ -285,13 +285,21 @@ function lab_send_request($request, $node_id = null, $scheme = null) {
285
  $data = @curl_exec( $curl );
286
  $stop = microtime( true );
287
 
288
- //if (!$data) // curl_error($curl) . curl_errno($curl) );
289
 
290
- curl_close( $curl );
 
 
 
 
 
 
 
 
291
 
292
- $node_delay = $stop - $start;
293
 
294
- $response = lab_parse_response( $data );
295
 
296
  lab_update_node_last( $node[0], array(
297
  $node_delay,
@@ -316,26 +324,28 @@ function lab_send_request($request, $node_id = null, $scheme = null) {
316
  *
317
  * @return array|mixed|object
318
  */
319
- function lab_parse_response($response){
320
  $ret = array( 'status' => 1, 'error' => false );
321
 
322
- if (!empty($response)) {
323
  $ret = json_decode( $response, true );
324
  if ( JSON_ERROR_NONE != json_last_error() ) {
325
  $ret['status'] = 0;
326
- $ret['error'] = 'JSON ERROR: '.json_last_error_msg();
327
  }
328
  // Is everything is OK?
329
- if (empty($ret['key']) || !empty($ret['error'])){
330
  $ret['status'] = 0; // Not OK
331
  }
332
  }
333
  else {
334
  $ret['status'] = 0;
335
- $ret['error'] = 'No node answer';
336
  }
337
 
338
- if (!isset($ret['error'])) $ret['error'] = false;
 
 
339
 
340
  return $ret;
341
  }
@@ -457,12 +467,10 @@ function lab_update_node_last($node_id, $last = array()) {
457
  $nodes = array();
458
  }
459
  $nodes['nodes'][$node_id]['last'] = $last;
460
- //return update_site_option('_cerberlab_', $nodes);
461
  return cerber_update_set('_cerberlab_', $nodes);
462
  }
463
 
464
  function lab_get_nodes() {
465
- //return get_site_option( '_cerberlab_' );
466
  return cerber_get_set( '_cerberlab_' );
467
  }
468
 
@@ -618,8 +626,8 @@ function lab_get_key( $refresh = false, $nocache = false) {
618
  $key[0] = lab_gen_site_id();
619
  }
620
  else {
621
- // Fix: WP is installed in a subdirectory, rewrite old domain based site ID
622
- if ( 2 < substr_count( home_url(), '/' ) ) {
623
  $key[0] = lab_gen_site_id();
624
  }
625
  }
@@ -649,7 +657,7 @@ function lab_gen_site_id() {
649
  $home = network_home_url();
650
  }
651
  else {
652
- $home = home_url();
653
  }
654
 
655
  $home = rtrim( trim( $home ), '/' );
2
  /*
3
  Cerber Laboratory (cerberlab.net) specific routines.
4
 
5
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
6
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
7
 
8
  Licenced under the GNU GPL.
9
 
285
  $data = @curl_exec( $curl );
286
  $stop = microtime( true );
287
 
288
+ $node_delay = $stop - $start;
289
 
290
+ if ( $data ) {
291
+ $response = lab_parse_response( $data );
292
+ }
293
+ else {
294
+ $response['status'] = 0;
295
+ $code = intval( curl_getinfo( $curl, CURLINFO_HTTP_CODE ) );
296
+ $response['error'] = 'No connection (' . $code . ')';
297
+ //if (!$data) // curl_error($curl) . curl_errno($curl) );
298
+ }
299
 
300
+ curl_close( $curl );
301
 
302
+ //$response = lab_parse_response( $data );
303
 
304
  lab_update_node_last( $node[0], array(
305
  $node_delay,
324
  *
325
  * @return array|mixed|object
326
  */
327
+ function lab_parse_response( $response ) {
328
  $ret = array( 'status' => 1, 'error' => false );
329
 
330
+ if ( ! empty( $response ) ) {
331
  $ret = json_decode( $response, true );
332
  if ( JSON_ERROR_NONE != json_last_error() ) {
333
  $ret['status'] = 0;
334
+ $ret['error'] = 'JSON ERROR: ' . json_last_error_msg();
335
  }
336
  // Is everything is OK?
337
+ if ( empty( $ret['key'] ) || ! empty( $ret['error'] ) ) {
338
  $ret['status'] = 0; // Not OK
339
  }
340
  }
341
  else {
342
  $ret['status'] = 0;
343
+ $ret['error'] = 'No node answer';
344
  }
345
 
346
+ if ( ! isset( $ret['error'] ) ) {
347
+ $ret['error'] = false;
348
+ }
349
 
350
  return $ret;
351
  }
467
  $nodes = array();
468
  }
469
  $nodes['nodes'][$node_id]['last'] = $last;
 
470
  return cerber_update_set('_cerberlab_', $nodes);
471
  }
472
 
473
  function lab_get_nodes() {
 
474
  return cerber_get_set( '_cerberlab_' );
475
  }
476
 
626
  $key[0] = lab_gen_site_id();
627
  }
628
  else {
629
+ // Fix: WP is installed in a subdirectory, rewrite old, domain based site ID
630
+ if ( 2 < substr_count( cerber_get_site_url(), '/' ) ) {
631
  $key[0] = lab_gen_site_id();
632
  }
633
  }
657
  $home = network_home_url();
658
  }
659
  else {
660
+ $home = cerber_get_site_url();
661
  }
662
 
663
  $home = rtrim( trim( $home ), '/' );
cerber-load.php CHANGED
@@ -1,5977 +1,6084 @@
1
- <?php
2
- /*
3
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
4
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
5
-
6
- Licenced under the GNU GPL.
7
-
8
- This program is free software; you can redistribute it and/or modify
9
- it under the terms of the GNU General Public License as published by
10
- the Free Software Foundation; either version 3 of the License, or
11
- (at your option) any later version.
12
-
13
- This program is distributed in the hope that it will be useful,
14
- but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- GNU General Public License for more details.
17
-
18
- You should have received a copy of the GNU General Public License
19
- along with this program; if not, write to the Free Software
20
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
-
22
- */
23
-
24
- /*
25
-
26
-
27
-
28
- ▄████▄ ▓█████ ██▀███ ▄▄▄▄ ▓█████ ██▀███
29
- ▒██▀ ▀█ ▓█ ▀ ▓██ ▒ ██▒ ▓█████▄ ▓█ ▀ ▓██ ▒ ██▒
30
- ▒▓█ ▄ ▒███ ▓██ ░▄█ ▒ ▒██▒ ▄██ ▒███ ▓██ ░▄█ ▒
31
- ▒▓▓▄ ▄██▒ ▒▓█ ▄ ▒██▀▀█▄ ▒██░█▀ ▒▓█ ▄ ▒██▀▀█▄
32
- ▒ ▓███▀ ░ ░▒████▒ ░██▓ ▒██▒ ░▓█ ▀█▓ ░▒████▒ ░██▓ ▒██▒
33
- ░ ░▒ ▒ ░ ░░ ▒░ ░ ░ ▒▓ ░▒▓░ ░▒▓███▀▒ ░░ ▒░ ░ ░ ▒▓ ░▒▓░
34
- ░ ▒ ░ ░ ░ ░▒ ░ ▒░ ▒░▒ ░ ░ ░ ░ ░▒ ░ ▒░
35
- ░ ░ ░░ ░ ░ ░ ░ ░░ ░
36
- ░ ░ ░ ░ ░ ░ ░ ░ ░
37
- ░ ░
38
-
39
-
40
-
41
-
42
- *========================================================================*
43
- | |
44
- | ATTENTION! Do not change or edit this file! |
45
- | |
46
- *========================================================================*
47
-
48
- */
49
-
50
- // If this file is called directly, abort executing.
51
- if ( ! defined( 'WPINC' ) ) {
52
- exit;
53
- }
54
-
55
- define( 'CERBER_LOG_TABLE', 'cerber_log' );
56
- define( 'CERBER_QMEM_TABLE', 'cerber_qmem' );
57
- define( 'CERBER_TRAF_TABLE', 'cerber_traffic' );
58
- define( 'CERBER_ACL_TABLE', 'cerber_acl' );
59
- define( 'CERBER_BLOCKS_TABLE', 'cerber_blocks' );
60
- define( 'CERBER_LAB_TABLE', 'cerber_lab' );
61
- define( 'CERBER_LAB_IP_TABLE', 'cerber_lab_ip' );
62
- define( 'CERBER_LAB_NET_TABLE', 'cerber_lab_net' );
63
- define( 'CERBER_GEO_TABLE', 'cerber_countries' );
64
- define( 'CERBER_SCAN_TABLE', 'cerber_files' );
65
- define( 'CERBER_SETS_TABLE', 'cerber_sets' );
66
-
67
- define( 'CERBER_PREFIX', '_cerber_' );
68
- define( 'CERBER_MARKER1', 'WP CERBER GROOVE' );
69
- define( 'CERBER_MARKER2', 'WP CERBER CLAMPS' );
70
- define( 'CERBER_NO_REMOTE_IP', '0.0.0.0' );
71
-
72
- define( 'WP_LOGIN_SCRIPT', 'wp-login.php' );
73
- define( 'WP_REG_URI', 'wp-register.php' );
74
- define( 'WP_XMLRPC_SCRIPT', 'xmlrpc.php' );
75
- define( 'WP_TRACKBACK_SCRIPT', 'wp-trackback.php' );
76
- define( 'WP_PING_SCRIPT', 'wp-trackback.php' );
77
- define( 'WP_SIGNUP_SCRIPT', 'wp-signup.php' );
78
- define( 'WP_COMMENT_SCRIPT', 'wp-comments-post.php' );
79
-
80
- define( 'GOO_RECAPTCHA_URL', 'https://www.google.com/recaptcha/api/siteverify' );
81
- define( 'CERBER_VULNDB_API', 'https://wpvulndb.com/api/v2/plugins/' );
82
-
83
- define( 'CERBER_REQ_PHP', '5.4.0' );
84
- define( 'CERBER_REQ_WP', '4.5' );
85
- define( 'CERBER_TECH', 'https://cerber.tech/' );
86
-
87
- define( 'CERBER_CIREC_LIMIT', 30 ); // Upper limit for allowed nested values during inspection for malware
88
-
89
- define( 'CERBER_AGGRESSIVE', 1 );
90
-
91
- require_once( dirname( __FILE__ ) . '/cerber-pluggable.php' );
92
- require_once( dirname( __FILE__ ) . '/common.php' );
93
- require_once( dirname( __FILE__ ) . '/settings.php' );
94
- include_once( dirname( __FILE__ ) . '/cerber-request.php' );
95
- require_once( dirname( __FILE__ ) . '/cerber-lab.php' );
96
- require_once( dirname( __FILE__ ) . '/whois.php' );
97
- require_once( dirname( __FILE__ ) . '/jetflow.php' );
98
- require_once( dirname( __FILE__ ) . '/cerber-news.php' );
99
- require_once( dirname( __FILE__ ) . '/cerber-scanner.php' );
100
-
101
- if ( defined( 'WP_ADMIN' ) || defined( 'WP_NETWORK_ADMIN' ) ) {
102
- // Load dashboard stuff
103
- require_once( dirname( __FILE__ ) . '/dashboard.php' );
104
- }
105
-
106
- // =============================================================================================
107
-
108
- class WP_Cerber {
109
- private $remote_ip;
110
- private $session_id;
111
- private $status = null;
112
- private $options;
113
- private $locked = null; // IP has been locked out
114
-
115
- private $recaptcha = null; // Can recaptcha be verified with current request
116
- private $recaptcha_verified = null; // Is recaptcha successfully verified with current request
117
- public $recaptcha_here = null; // Is recaptcha widget enabled on the currently displayed page
118
-
119
- private $uri_prohibited = null;
120
- private $deny = null;
121
- private $acl = null;
122
-
123
- //private $boot_source_file = '';
124
- //private $boot_target_file = '';
125
-
126
- public $garbage = false; // Garbage has been deleted
127
-
128
- final function __construct() {
129
-
130
- $this->session_id = substr(str_shuffle('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'), 0, 24);
131
-
132
- // Load settings with filling missing (not-set) array keys
133
- $this->options = crb_get_settings(); // @since 6.3.3
134
- $keys = array();
135
- //$defaults = array();
136
- foreach ( cerber_get_defaults() as $item ) {
137
- $keys = array_merge( $keys, array_keys( $item ) );
138
- //$defaults = array_merge( $defaults, $item );
139
- }
140
- foreach ( $keys as $key ) {
141
- if ( ! isset( $this->options[ $key ] ) ) {
142
- $this->options[ $key ] = null;
143
- }
144
- }
145
-
146
- if ( defined( 'CERBER_IP_KEY' ) ) {
147
- $this->remote_ip = filter_var( $_SERVER[ CERBER_IP_KEY ], FILTER_VALIDATE_IP );
148
- }
149
- elseif ( $this->options['proxy'] && isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
150
- $list = explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] );
151
- foreach ( $list as $maybe_ip ) {
152
- $this->remote_ip = filter_var( trim( $maybe_ip ), FILTER_VALIDATE_IP );
153
- if ( $this->remote_ip ) {
154
- break;
155
- }
156
- }
157
- if ( ! $this->remote_ip && isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
158
- $this->remote_ip = filter_var( $_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP );
159
- }
160
- } else {
161
- if ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
162
- $this->remote_ip = $_SERVER['REMOTE_ADDR'];
163
- } elseif ( isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
164
- $this->remote_ip = $_SERVER['HTTP_X_REAL_IP'];
165
- } elseif ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) {
166
- $this->remote_ip = $_SERVER['HTTP_CLIENT_IP'];
167
- } elseif ( isset( $_SERVER['SERVER_ADDR'] ) ) {
168
- $this->remote_ip = $_SERVER['SERVER_ADDR'];
169
- }
170
- $this->remote_ip = filter_var( $this->remote_ip, FILTER_VALIDATE_IP );
171
- }
172
- // No IP address was found? Roll back to localhost.
173
- if ( ! $this->remote_ip ) { // including WP-CLI, other way is: if defined('WP_CLI')
174
- $this->remote_ip = CERBER_NO_REMOTE_IP;
175
- }
176
-
177
- $this->remote_ip = cerber_short_ipv6( $this->remote_ip );
178
-
179
- $this->reCaptchaInit();
180
-
181
- $this->deleteGarbage();
182
-
183
- // Condition to check reCAPTCHA
184
-
185
- add_action( 'login_init', array( $this, 'reCaptchaNow' ) );
186
-
187
- }
188
-
189
- /**
190
- * @since 6.3.3
191
- */
192
- final public function isURIProhibited() {
193
- global $cerber_status;
194
-
195
- if ( isset( $this->uri_prohibited ) ) {
196
- return $this->uri_prohibited;
197
- }
198
-
199
- if ( crb_acl_is_white() ) {
200
- $this->uri_prohibited = false;
201
-
202
- return false;
203
- }
204
-
205
- $script = cerber_last_uri();
206
- if ( substr( $script, - 4 ) != '.php' ) {
207
- $script .= '.php'; // Apache MultiViews enabled?
208
- }
209
-
210
- if ( $script ) {
211
- if ( $script == WP_LOGIN_SCRIPT
212
- || $script == WP_SIGNUP_SCRIPT
213
- || ( $script == WP_REG_URI && ! get_option( 'users_can_register' ) ) ) {
214
- if ( !empty( $this->options['wplogin'] ) ) {
215
- $cerber_status = 19;
216
- cerber_log( 50 );
217
- cerber_soft_block_add( $this->remote_ip, 702, $script );
218
- $this->uri_prohibited = true;
219
- return true;
220
- }
221
- if ( ! empty( $this->options['loginnowp'] )
222
- || $this->isDeny() ) {
223
- cerber_log( 50 );
224
- $this->uri_prohibited = true;
225
- return true;
226
- }
227
- }
228
- elseif ( $script == WP_XMLRPC_SCRIPT || $script == WP_TRACKBACK_SCRIPT ) {
229
- if ( ! empty( $this->options['xmlrpc'] )
230
- || $this->isDeny() ) {
231
- cerber_log( 71 );
232
- $this->uri_prohibited = true;
233
- return true;
234
- }
235
- if ( !cerber_geo_allowed( 'geo_xmlrpc' ) ) {
236
- $cerber_status = 16;
237
- cerber_log( 71 );
238
- $this->uri_prohibited = true;
239
- return true;
240
- }
241
- }
242
- }
243
-
244
- $this->uri_prohibited = false;
245
-
246
- return $this->uri_prohibited;
247
- }
248
-
249
- /**
250
- * @since 6.3.3
251
- */
252
- final public function CheckProhibitedURI(){
253
- if ($this->isURIProhibited()){
254
- if ( $this->options['page404'] ) {
255
- cerber_404_page();
256
- }
257
-
258
- return true;
259
- }
260
-
261
- return false;
262
- }
263
-
264
- /**
265
- * @since 6.3.3
266
- */
267
- final public function InspectRequest() {
268
- $deny = false;
269
- $act = 18;
270
- if ( cerber_is_http_post() ) {
271
- if ( ! cerber_is_allowed( null, array( 701, 703, 704 ) ) ) {
272
- $deny = true;
273
- $act = 18;
274
- }
275
- }
276
- elseif ( cerber_get_non_wp_fields() ) { // @since 7.9
277
- if ( ! cerber_is_allowed() ) {
278
- $deny = true;
279
- $act = 100;
280
- }
281
- }
282
- if ( ! $deny && $_FILES ) {
283
- $file_names = array();
284
- foreach ( $_FILES as $file ) {
285
- if ( is_array( $file['name'] ) ) {
286
- $file_names = array_merge( $file_names, $file['name'] );
287
- }
288
- else {
289
- $file_names[] = $file['name'];
290
- }
291
- }
292
- foreach ( $file_names as $item ) {
293
- if ( $reason = $this->isProhibitedFilename( $item ) ) {
294
- $deny = true;
295
- $act = $reason;
296
- break;
297
- }
298
- }
299
- }
300
- if ( $deny ) {
301
- cerber_log( $act );
302
- cerber_forbidden_page();
303
- }
304
- }
305
-
306
- /**
307
- * @since 6.3.3
308
- */
309
- final public function isProhibitedFilename( $file_name ) {
310
- $prohibited = array( '.htaccess' );
311
- if ( in_array( $file_name, $prohibited ) ) {
312
- return 57;
313
- }
314
- if ( cerber_detect_exec_extension( $file_name, array('js') ) ) {
315
- return 56;
316
- }
317
-
318
- return false;
319
- }
320
-
321
- /**
322
- * @since 6.3.3
323
- */
324
- final public function isDeny() {
325
- if ( isset( $this->deny ) ) {
326
- return $this->deny;
327
- }
328
-
329
- $this->acl = cerber_acl_check();
330
-
331
- if ( $this->acl == 'B' || ! cerber_is_allowed() ) {
332
- $this->deny = true;
333
- }
334
- else {
335
- $this->deny = false;
336
- }
337
-
338
- return $this->deny;
339
- }
340
-
341
- // TODO: replace it with cerber_get_remote_ip()
342
- final public function getRemoteIp() {
343
- return $this->remote_ip;
344
- }
345
-
346
- final public function getSessionID() {
347
- return $this->session_id;
348
- }
349
-
350
- final public function getStatus() {
351
- if (isset($this->status)) return $this->status;
352
-
353
- $this->status = 0; // Default
354
-
355
- if ( cerber_is_citadel() ) {
356
- $this->status = 3;
357
- }
358
- else {
359
- //if ( ! cerber_is_allowed( $this->remote_ip ) ) {
360
- if ( cerber_block_check( $this->remote_ip ) ) {
361
- $this->status = 2;
362
- }
363
- else {
364
- $tag = cerber_acl_check( $this->remote_ip );
365
- if ( $tag == 'W' ) {
366
- //$this->status = 4;
367
- }
368
- elseif ( $tag == 'B' || lab_is_blocked($this->remote_ip, false)) {
369
- $this->status = 1;
370
- }
371
- }
372
- }
373
-
374
- return $this->status;
375
- }
376
-
377
- /*
378
- Return Error message in context
379
- */
380
- final public function getErrorMsg() {
381
- $status = $this->getStatus();
382
- switch ( $status ) {
383
- case 1:
384
- case 3:
385
- return apply_filters( 'cerber_msg_blocked', __( 'You are not allowed to log in. Ask your administrator for assistance.', 'wp-cerber' ) , $status);
386
- case 2:
387
- $block = cerber_get_block();
388
- $min = 1 + ( $block->block_until - time() ) / 60;
389
-
390
- return apply_filters( 'cerber_msg_reached',
391
- //sprintf( __( 'You have reached the login attempts limit. Please try again in %d minutes.', 'wp-cerber' ), $min ),
392
- sprintf( __( 'You have exceeded the number of allowed login attempts. Please try again in %d minutes.', 'wp-cerber' ), $min ),
393
- $min );
394
- break;
395
- default:
396
- return '';
397
- }
398
- }
399
-
400
- /*
401
- Return Remain message in context
402
- */
403
- final public function getRemainMsg() {
404
- $acl = !$this->options['limitwhite'];
405
- $remain = cerber_get_remain_count($this->remote_ip, $acl);
406
- if ( $remain < $this->options['attempts'] ) {
407
- if ( $remain == 0 ) {
408
- $remain = 1; // with some settings or when lockout was manually removed, we need to have 1 attempt.
409
- }
410
- return apply_filters( 'cerber_msg_remain',
411
- sprintf( _n( 'You have only one attempt remaining.', 'You have %d attempts remaining.', $remain, 'wp-cerber' ), $remain ),
412
- $remain );
413
- }
414
-
415
- return false;
416
- }
417
-
418
- final public function getSettings( $name = null ) {
419
- if ( ! empty( $name ) ) {
420
- if ( isset( $this->options[ $name ] ) ) {
421
- return $this->options[ $name ];
422
- } else {
423
- return false;
424
- }
425
- }
426
-
427
- return $this->options;
428
- }
429
-
430
- /*
431
- final public function isProhibited( $username ) {
432
- if ( empty( $this->options['prohibited'] ) ) {
433
- return false;
434
- }
435
-
436
- return in_array( $username, (array) $this->options['prohibited'] );
437
- }*/
438
-
439
- /**
440
- * Adding reCAPTCHA widgets
441
- *
442
- */
443
- final public function reCaptchaInit(){
444
-
445
- if ( $this->status == 4 || empty( $this->options['sitekey'] ) || empty( $this->options['secretkey'] )) return;
446
-
447
- // Native WP forms
448
- add_action( 'login_form', function () {
449
- global $wp_cerber;
450
- $wp_cerber->reCaptcha( 'widget', 'recaplogin' );
451
- } );
452
- add_filter( 'login_form_middle', function ( $value ) {
453
- global $wp_cerber;
454
- $value .= $wp_cerber->reCaptcha( 'widget', 'recaplogin', false );
455
- return $value;
456
- });
457
- add_action( 'lostpassword_form', function () {
458
- global $wp_cerber;
459
- $wp_cerber->reCaptcha( 'widget', 'recaplost' );
460
- } );
461
- add_action( 'register_form', function () {
462
- global $wp_cerber;
463
- if ( !did_action( 'woocommerce_register_form_start' ) ) {
464
- $wp_cerber->reCaptcha( 'widget', 'recapreg' );
465
- }
466
- } );
467
-
468
- // Support for WooCommerce forms: @since 3.8
469
- add_action( 'woocommerce_login_form', function () {
470
- global $wp_cerber;
471
- $wp_cerber->reCaptcha( 'widget', 'recapwoologin' );
472
- } );
473
- add_action( 'woocommerce_lostpassword_form', function () {
474
- global $wp_cerber;
475
- $wp_cerber->reCaptcha( 'widget', 'recapwoolost' );
476
- } );
477
- add_action( 'woocommerce_register_form', function () {
478
- global $wp_cerber;
479
- if ( ! did_action( 'woocommerce_register_form_start' ) ) {
480
- return;
481
- }
482
- $wp_cerber->reCaptcha( 'widget', 'recapwooreg' );
483
- } );
484
- add_filter( 'woocommerce_process_login_errors', function ( $validation_error ) {
485
- global $wp_cerber;
486
- //$wp_cerber->reCaptchaNow();
487
- if ( ! $wp_cerber->reCaptchaValidate('woologin', true) ) {
488
-
489
- return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-login'));
490
- }
491
- return $validation_error;
492
- });
493
- add_filter( 'allow_password_reset', function ( $var ) { // Note: 'allow_password_reset' also is fired in WP itself
494
- global $wp_cerber;
495
- if ( isset( $_POST['wc_reset_password'] ) && did_action( 'woocommerce_init' )) {
496
- //$wp_cerber->reCaptchaNow();
497
- if ( ! $wp_cerber->reCaptchaValidate( 'woolost' , true) ) {
498
-
499
- return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-lost'));
500
- }
501
- }
502
- return $var;
503
- });
504
- add_filter( 'woocommerce_process_registration_errors', function ( $validation_error ) {
505
- global $wp_cerber;
506
- //$wp_cerber->reCaptchaNow();
507
- if ( ! $wp_cerber->reCaptchaValidate('wooreg' , true) ) {
508
-
509
- return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-register'));
510
- }
511
- return $validation_error;
512
- });
513
-
514
- }
515
-
516
- /**
517
- * Generates reCAPTCHA HTML
518
- *
519
- * @param string $part 'style' or 'widget'
520
- * @param null $option what plugin setting must be set to show the reCAPTCHA
521
- * @param bool $echo if false, return the code, otherwise show it
522
- *
523
- * @return null|string
524
- */
525
- final public function reCaptcha( $part = '', $option = null, $echo = true ) {
526
- if ( $this->status == 4 || empty( $this->options['sitekey'] ) || empty( $this->options['secretkey'] )
527
- || ( $option && empty( $this->options[ $option ] ) )
528
- ) {
529
- return null;
530
- }
531
-
532
- $sitekey = $this->options['sitekey'];
533
- $ret = '';
534
-
535
- switch ( $part ) {
536
- case 'style': // for default login WP form only - fit it in width nicely.
537
- ?>
538
- <style type="text/css" media="all">
539
- #rc-imageselect, .g-recaptcha {
540
- transform: scale(0.9);
541
- -webkit-transform: scale(0.9);
542
- transform-origin: 0 0;
543
- -webkit-transform-origin: 0 0;
544
- }
545
-
546
- .g-recaptcha {
547
- margin: 16px 0 20px 0;
548
- }
549
- </style>
550
- <?php
551
- break;
552
- case 'widget':
553
- if ( ! empty( $this->options[ $option ] ) ) {
554
- $this->recaptcha_here = true;
555
-
556
- //if ($this->options['invirecap']) $ret = '<div data-size="invisible" class="g-recaptcha" data-sitekey="' . $sitekey . '" data-callback="now_submit_the_form" id="cerber-recaptcha" data-badge="bottomright"></div>';
557
- if ($this->options['invirecap']) {
558
- $ret = '<span class="cerber-form-marker"></span><div data-size="invisible" class="g-recaptcha" data-sitekey="' . $sitekey . '" data-callback="now_submit_the_form" id="cerber-recaptcha" data-badge="bottomright"></div>';
559
- }
560
- else $ret = '<span class="cerber-form-marker"></span><div class="g-recaptcha" data-sitekey="' . $sitekey . '" data-callback="form_button_enabler" id="cerber-recaptcha"></div>';
561
-
562
- //$ret = '<span class="cerber-form-marker g-recaptcha"></span>';
563
-
564
- }
565
- break;
566
- }
567
- if ( $echo ) {
568
- echo $ret;
569
- $ret = null;
570
- }
571
-
572
- return $ret;
573
- /*
574
- <script type="text/javascript">
575
- var onloadCallback = function() {
576
- //document.getElementById("wp-submit").disabled = true;
577
- grecaptcha.render("c-recaptcha", {"sitekey" : "<?php echo $sitekey; ?>" });
578
- //document.getElementById("wp-submit").disabled = false;
579
- };
580
- </script>
581
- <script src = "https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit&hl=<?php echo $lang; ?>" async defer></script>
582
- */
583
- }
584
-
585
- /**
586
- * Validate reCAPTCHA by calling Google service
587
- *
588
- * @param string $form Form ID (slug)
589
- * @param boolean $force Force validate without pre-checks
590
- *
591
- * @return bool true on success false on failure
592
- */
593
- final public function reCaptchaValidate($form = null, $force = false) {
594
- if (!$force) {
595
- if ( ! $this->recaptcha || $this->status == 4 ) {
596
- return true;
597
- }
598
- }
599
-
600
- if ($this->recaptcha_verified != null) return $this->recaptcha_verified;
601
-
602
- if ( $form == 'comment' && $this->options['recapcomauth'] && is_user_logged_in()) return true;
603
-
604
- if ( ! $form ) {
605
- $form = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login';
606
- }
607
-
608
- $forms = array( // known pairs: form => specific plugin setting
609
- 'lostpassword' => 'recaplost',
610
- 'register' => 'recapreg',
611
- 'login' => 'recaplogin',
612
- 'comment' => 'recapcom',
613
- 'woologin' => 'recapwoologin',
614
- 'woolost' => 'recapwoolost',
615
- 'wooreg' => 'recapwooreg',
616
- );
617
-
618
- if ( isset( $forms[ $form ] ) ) {
619
- if ( empty( $this->options[ $forms[ $form ] ] ) ) {
620
- return true; // no validation is required
621
- }
622
- }
623
- else {
624
- return true; // we don't know this form
625
- }
626
-
627
- if ( empty( $_POST['g-recaptcha-response'] ) ) {
628
- $this->reCaptchaFailed($form);
629
- return false;
630
- }
631
-
632
- $result = $this->reCaptchaRequest($_POST['g-recaptcha-response']);
633
- if ( ! $result ) {
634
- cerber_log( 42 );
635
- return false;
636
- }
637
-
638
- $result = json_decode( $result );
639
- $result = obj_to_arr_deep( $result );
640
-
641
- if ( ! empty( $result['success'] ) ) {
642
- $this->recaptcha_verified = true;
643
- return true;
644
- }
645
- $this->recaptcha_verified = false;
646
-
647
- if ( ! empty( $result['error-codes'] ) ) {
648
- if ( in_array( 'invalid-input-secret', (array) $result['error-codes'] ) ) {
649
- cerber_log( 41 );
650
- }
651
- }
652
-
653
- $this->reCaptchaFailed($form);
654
-
655
- return false;
656
- }
657
-
658
- final function reCaptchaFailed($context = '') {
659
- cerber_log( 40 );
660
- if ($this->options['recaptcha-period'] && $this->options['recaptcha-number'] && $this->options['recaptcha-within']) {
661
- $remain = cerber_get_remain_count($this->remote_ip , true, array( 40 ), $this->options['recaptcha-number'], $this->options['recaptcha-within']);
662
- if ($remain < 1) cerber_block_add( $this->remote_ip, 705 );
663
- }
664
- }
665
-
666
- /**
667
- * A form with possible reCAPTCHA has been submitted.
668
- * Allow to process reCAPTCHA by setting a global flag.
669
- * Must be called before reCaptchaValidate();
670
- *
671
- */
672
- final public function reCaptchaNow() {
673
- if ( cerber_is_http_post() && $this->options['sitekey'] && $this->options['secretkey'] ) {
674
- $this->recaptcha = true;
675
- }
676
- }
677
-
678
- /**
679
- * Make a request to the Google reCaptcha web service
680
- *
681
- * @param string $response Google specific field from the submitted form (widget)
682
- *
683
- * @return bool|string Response of the Google service or false on failure
684
- */
685
- final public function reCaptchaRequest($response = ''){
686
-
687
- if (!$response) {
688
- if (!empty($_POST['g-recaptcha-response'])) $response = $_POST['g-recaptcha-response'];
689
- else return false;
690
- }
691
-
692
- $curl = @curl_init(); // @since 4.32
693
- if (!$curl) {
694
- cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' Unable to initialize cURL');
695
- return false;
696
- }
697
-
698
- $opt = curl_setopt_array($curl, array(
699
- CURLOPT_URL => GOO_RECAPTCHA_URL,
700
- CURLOPT_POST => true,
701
- CURLOPT_POSTFIELDS => array( 'secret' => $this->options['secretkey'], 'response' => $response ),
702
- CURLOPT_RETURNTRANSFER => true,
703
- ));
704
-
705
- if (!$opt) {
706
- cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' '. curl_error($curl));
707
- curl_close($curl);
708
- return false;
709
- }
710
-
711
- $result = @curl_exec($curl);
712
- if (!$result) {
713
- cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' '. curl_error($curl));
714
- $result = false;
715
- }
716
- curl_close($curl);
717
-
718
- return $result;
719
-
720
- }
721
-
722
- final public function reCaptchaMsg($context = null){
723
- return apply_filters( 'cerber_msg_recaptcha', __( 'Human verification failed. Please click the square box in the reCAPTCHA block below.', 'wp-cerber' ), $context);
724
- }
725
-
726
- final public function setLocked() {
727
- if ( ! isset( $this->locked ) ) {
728
- $this->locked = 1;
729
- }
730
- }
731
-
732
- final public function wasLocked() {
733
- if ( ! empty( $this->locked ) ) {
734
- return 1;
735
- }
736
- return 0;
737
- }
738
-
739
- final public function deleteGarbage() {
740
- if ( $this->garbage ) {
741
- return;
742
- }
743
- cerber_db_query( 'DELETE FROM ' . CERBER_BLOCKS_TABLE . ' WHERE block_until < ' . time() );
744
- $this->garbage = true;
745
- }
746
- }
747
-
748
- function cerber_init() {
749
- static $done = false;
750
-
751
- if ( $done ) {
752
- return;
753
- }
754
-
755
- cerber_pre_checks();
756
-
757
- cerber_error_control();
758
- cerber_request_time();
759
-
760
- if ( crb_get_settings( 'tiphperr' ) ) {
761
- set_error_handler( 'cerber_catch_error' );
762
- }
763
-
764
- cerber_upgrade_all();
765
-
766
- global $wp_cerber;
767
- $wp_cerber = get_wp_cerber();
768
-
769
- cerber_beast();
770
-
771
- $antibot = cerber_antibot_gene();
772
- if ( $antibot && ! empty( $antibot[1] ) ) {
773
- foreach ( $antibot[1] as $item ) {
774
- setcookie( $item[0], $item[1], time() + 3600 * 24, cerber_get_cookie_path() );
775
- }
776
- }
777
-
778
- // Redirection control: no default aliases for redirections
779
- //if ( crb_get_settings( 'noredirect' ) ) {
780
- if ( cerber_no_redirect() ) {
781
- remove_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );
782
- }
783
-
784
- $hooks = apply_filters( 'cerber_antibot_hooks', array() );
785
- if ( ! empty( $hooks['login_register'] ) ) {
786
- foreach ( $hooks['login_register'] as $hook ) {
787
- add_action( $hook, 'cerber_login_register_stuff', 1000 );
788
- }
789
- }
790
-
791
- $done = true;
792
- }
793
-
794
- /**
795
- * Returns correct WP_Cerber object
796
- * Protects and sets global $wp_cerber to the proper object
797
- *
798
- * @return WP_Cerber
799
- * @since 6.0
800
- */
801
- function get_wp_cerber(){
802
- global $wp_cerber;
803
- static $the_wp_cerber = null;
804
-
805
- if ( ! isset( $the_wp_cerber ) ) {
806
- $the_wp_cerber = new WP_Cerber();
807
- }
808
-
809
- $wp_cerber = $the_wp_cerber;
810
-
811
- return $the_wp_cerber;
812
- }
813
-
814
- /**
815
- *
816
- * Initialize Cerber Security
817
- *
818
- */
819
- add_action( 'plugins_loaded', function () {
820
-
821
- cerber_error_control();
822
-
823
- get_wp_cerber();
824
-
825
- cerber_inspect_uploads(); // Uploads in the dashboard
826
-
827
- $use_eng = false;
828
- //if ( is_admin() && crb_get_settings( 'admin_lang' ) && cerber_is_admin_page() ) {
829
- if ( is_admin() && crb_get_settings( 'admin_lang' ) ) {
830
- $use_eng = true;
831
- //add_filter( 'locale', function () {
832
- /*add_filter( 'plugin_locale', function () {
833
- return 'en_US';
834
- } );*/
835
- add_filter( 'override_load_textdomain', function ( $val, $domain, $mofile ) {
836
- if ($domain == 'wp-cerber'){
837
- $val = true;
838
- }
839
- return $val;
840
- }, 100, 3 );
841
- }
842
- if ( ! $use_eng ) {
843
- load_plugin_textdomain( 'wp-cerber', false, basename( dirname( __FILE__ ) ) . '/languages' );
844
- }
845
-
846
- /* @since 5.8.8
847
- if ( ! cerber_check_groove() && ! cerber_is_allowed() ) {
848
- wp_clear_auth_cookie();
849
- }*/
850
-
851
- cerber_init_cron();
852
-
853
- __('> > > Translator of WP Cerber? To get the PRO license for free, drop your contacts here: https://wpcerber.com/contact/','wp-cerber');
854
-
855
- }, 1000 );
856
-
857
- /**
858
- * Some additional tasks...
859
- *
860
- */
861
- function cerber_extra_vision() {
862
- global $cerber_logged, $cerber_status;
863
-
864
- // Multiple different malicious activities
865
- if ( ! empty( $cerber_logged ) ) {
866
- $ip = cerber_get_remote_ip();
867
- $black = crb_get_activity_set( 'black' );
868
- $black_logged = array_intersect( $black, $cerber_logged );
869
- if ( ! empty( $black_logged ) && cerber_is_allowed() ) {
870
- $remain = cerber_get_remain_count( $ip, true, $black ); // @since 6.7.5
871
- if ( $remain < 1 ) {
872
- cerber_soft_block_add( $ip, 707 );
873
- $cerber_status = 18;
874
-
875
- return true;
876
- }
877
- }
878
- }
879
-
880
- return false;
881
- }
882
-
883
- /*
884
- Display login form if Custom login URL has been requested
885
-
886
- */
887
- add_action( 'init', 'cerber_wp_login_page', 20 );
888
- //add_action( 'setup_theme', 'cerber_wp_login_page' ); // @since 5.05
889
- function cerber_wp_login_page() {
890
- if ( $path = crb_get_settings( 'loginpath' ) ) {
891
- if ( cerber_is_login_request() ) {
892
- if ( ! defined( 'DONOTCACHEPAGE' ) ) {
893
- define( 'DONOTCACHEPAGE', true ); // @since 5.7.6
894
- }
895
- @ini_set( 'display_startup_errors', 0 );
896
- @ini_set( 'display_errors', 0 );
897
- add_action( 'login_init', function () {
898
- @ini_set( 'display_startup_errors', 0 );
899
- @ini_set( 'display_errors', 0 );
900
- } );
901
- require( ABSPATH . WP_LOGIN_SCRIPT ); // load default wp-login.php form
902
- exit;
903
- }
904
- }
905
- }
906
-
907
- /**
908
- * Check if the current HTTP request is a login/register/lost password page request
909
- *
910
- * @return bool
911
- */
912
- function cerber_is_login_request() {
913
- static $ret;
914
-
915
- if ( isset( $ret ) ) {
916
- return $ret;
917
- }
918
-
919
- $ret = false;
920
-
921
- if ( $path = crb_get_settings( 'loginpath' ) ) {
922
- $request = $_SERVER['REQUEST_URI'];
923
- if ( $pos = strpos( $request, '?' ) ) {
924
- $request = substr( $request, 0, $pos - 1 ); // @since 4.8
925
- }
926
- $request = explode( '/', rtrim( $request, '/' ) );
927
- $request = end( $request ); // @since 4.8
928
- if ( $path == $request && ! cerber_is_rest_url() ) {
929
- $ret = true;
930
- }
931
- }
932
- //elseif ( cerber_get_uri_script() == WP_LOGIN_SCRIPT ) {
933
- elseif ( CRB_Request::is_script( '/' . WP_LOGIN_SCRIPT ) ) {
934
- $ret = true;
935
- }
936
-
937
- return $ret;
938
- }
939
-
940
- /*
941
- Create message to show it above login form for any simply GET
942
- */
943
- add_action( 'login_head', 'cerber_login_head' );
944
- function cerber_login_head() {
945
- global $error, $wp_cerber;
946
-
947
- if ( !$allowed = cerber_is_allowed() ) :
948
- ?>
949
- <style type="text/css" media="all">
950
- #logidnform {
951
- display: none;
952
- }
953
- </style>
954
- <?php
955
- endif;
956
-
957
- $wp_cerber->reCaptcha( 'style' );
958
-
959
- if ( !cerber_is_http_get() ) {
960
- return;
961
- }
962
- if ( ! cerber_can_msg() ) {
963
- return;
964
- }
965
- if ( ! $allowed ) {
966
- $error = $wp_cerber->getErrorMsg();
967
- }
968
- elseif ( $msg = $wp_cerber->getRemainMsg() ) {
969
- $error = $msg;
970
- }
971
- }
972
-
973
- /**
974
- * Control the process of authentication
975
- *
976
- * @since 2.9
977
- *
978
- */
979
- remove_filter( 'authenticate', 'wp_authenticate_username_password', 20 );
980
- remove_filter( 'authenticate', 'wp_authenticate_email_password', 20 );
981
- add_filter( 'authenticate', 'cerber_auth_control', 20, 3 );
982
- function cerber_auth_control( $user, $username, $password ) {
983
- global $wp_cerber;
984
-
985
- if ( ! $wp_cerber->reCaptchaValidate() ) {
986
-
987
- return new WP_Error( 'incorrect_recaptcha',
988
- '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
989
- $wp_cerber->reCaptchaMsg('login'));
990
- }
991
-
992
- // Check for prohibited username
993
- //if ( $wp_cerber->isProhibited( $username ) ) {
994
- if ( $username && cerber_is_prohibited( $username ) ) {
995
- cerber_log( 52, $username );
996
- cerber_block_add( null, 704, $username );
997
-
998
- // Create with message that is identical default WP
999
- return new WP_Error( 'incorrect_password', sprintf(
1000
- __( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
1001
- '<strong>' . $username . '</strong>'
1002
- ) );
1003
- }
1004
- /*
1005
- if ( lab_is_blocked($wp_cerber->getRemoteIp()) ) {
1006
-
1007
- // Create with message which is identical default WP
1008
- return new WP_Error( 'incorrect_password', sprintf(
1009
- __( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
1010
- '<strong>' . $username . '</strong>'
1011
- ) );
1012
- }*/
1013
-
1014
- $user = wp_authenticate_username_password( $user, $username, $password );
1015
- $user = wp_authenticate_email_password( $user, $username, $password );
1016
-
1017
- // @since 4.18 it is replacement for 'wp_login_failed' action hook
1018
- // see WP function wp_authenticate()
1019
- $ignore_codes = array( 'empty_username', 'empty_password', 'cerber_denied' );
1020
- if ( is_wp_error( $user ) && ! in_array( $user->get_error_code(), $ignore_codes ) ) {
1021
- cerber_login_failed( $username );
1022
- }
1023
-
1024
- return $user;
1025
- }
1026
-
1027
- /*
1028
- Block authentication for an existing user if the remote IP is not allowed.
1029
- Invoking in the 'wp_authenticate_username_password()'
1030
- */
1031
- add_filter( 'wp_authenticate_user', 'cerber_stop_authentication', 9999, 2 ); // fires after user found, with 'authenticate' filter
1032
- function cerber_stop_authentication( $user, $password ) {
1033
- global $wp_cerber, $cerber_status;
1034
-
1035
- $deny = false;
1036
-
1037
- if ( ! cerber_is_allowed() ) {
1038
- $deny = true;
1039
- }
1040
- elseif ( ! cerber_geo_allowed( 'geo_login' ) ) {
1041
- $cerber_status = 16;
1042
- $deny = true;
1043
- }
1044
- elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
1045
- $cerber_status = 15;
1046
- $deny = true;
1047
- }
1048
-
1049
- if ( $deny ) {
1050
- status_header( 403 );
1051
- $error = new WP_Error();
1052
- $error->add( 'cerber_wp_error', $wp_cerber->getErrorMsg() );
1053
-
1054
- return $error;
1055
- }
1056
-
1057
- return $user;
1058
- }
1059
-
1060
- /**
1061
- *
1062
- * Handler for failed login attempts
1063
- *
1064
- * @param $user_login
1065
- *
1066
- */
1067
- //add_action( 'wp_login_failed', 'cerber_login_failed' ); // @since 4.18
1068
- function cerber_login_failed( $user_login ) {
1069
- global $wpdb, $wp_cerber, $cerber_status;
1070
- static $is_processed = false;
1071
-
1072
- if ( $is_processed ) return;
1073
- $is_processed = true;
1074
-
1075
- $ip = $wp_cerber->getRemoteIp();
1076
- $acl = cerber_acl_check( $ip );
1077
- if ( ! cerber_get_user( $user_login ) ) {
1078
- $no_user = true;
1079
- }
1080
- else {
1081
- $no_user = false;
1082
- }
1083
-
1084
- //cerber_failed_work($ip, $acl, $no_user, $user_login);
1085
-
1086
- //if ( ! $wp_cerber->isProcessed() ) {
1087
- //if ( ! cerber_get_user( $user_login ) ) {
1088
- // $no_user = true;
1089
- //}
1090
-
1091
- $ac = 7;
1092
-
1093
- if ( $no_user ) {
1094
- $ac = 51;
1095
- }
1096
- elseif ( ! cerber_is_allowed( $ip ) || $cerber_status == 15 || $cerber_status == 16 ) { // TODO should be refactored together with cerber_stop_authentication
1097
- $ac = 53;
1098
- }
1099
- /*
1100
- elseif ( $acl == 'B' ) {
1101
- $ac = 14;
1102
- }
1103
- elseif ( lab_is_blocked($ip, false) ) {
1104
- $ac = 53;
1105
- }
1106
- else {
1107
- $ac = 53;
1108
- }*/
1109
-
1110
- cerber_log( $ac, $user_login );
1111
-
1112
- //}
1113
-
1114
-
1115
- // White? Stop further actions.
1116
- if ( $acl == 'W' && !crb_get_settings( 'limitwhite' )) {
1117
- return;
1118
- }
1119
-
1120
- if ( crb_get_settings( 'usefile' ) ) {
1121
- cerber_file_log( $user_login, $ip );
1122
- }
1123
-
1124
- if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) { // Needs additional researching and, maybe, refactoring
1125
- status_header( 403 );
1126
- }
1127
-
1128
- // Blacklisted? No more actions are needed.
1129
- if ( $acl == 'B' ) {
1130
- return;
1131
- }
1132
-
1133
- // Must the Citadel mode be activated?
1134
- if ( $wp_cerber->getSettings( 'ciperiod' ) && ! cerber_is_citadel() ) {
1135
- $range = time() - $wp_cerber->getSettings( 'ciperiod' ) * 60;
1136
- //$lockouts = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
1137
- $lockouts = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
1138
- if ( $lockouts >= $wp_cerber->getSettings( 'cilimit' ) ) {
1139
- cerber_enable_citadel();
1140
- }
1141
- }
1142
-
1143
- if ( $no_user && $wp_cerber->getSettings( 'nonusers' ) ) {
1144
- cerber_block_add( $ip, 703, $user_login); // @since 5.7
1145
- }
1146
- elseif ( cerber_get_remain_count($ip, false) < 1 ) { //Limit on the number of login attempts is reached
1147
- cerber_block_add( $ip, 701, '', null, false);
1148
- }
1149
-
1150
- }
1151
-
1152
- /**
1153
- * Do the work with failed/blocked attempt
1154
- *
1155
- * @param $ip
1156
- * @param $acl
1157
- * @param $user_login
1158
- */
1159
- function cerber_failed_work($ip, $acl, $no_user, $user_login){
1160
- global $wpdb, $wp_cerber;
1161
-
1162
- // White? Stop further actions.
1163
- if ( $acl == 'W' && !$wp_cerber->getSettings( 'limitwhite' )) {
1164
- return;
1165
- }
1166
-
1167
- if ( $wp_cerber->getSettings( 'usefile' ) ) {
1168
- cerber_file_log( $user_login, $ip );
1169
- }
1170
-
1171
- if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) { // Needs additional researching and, maybe, refactoring
1172
- status_header( 403 );
1173
- }
1174
-
1175
- // Blacklisted? No more actions are needed.
1176
- if ( $acl == 'B' ) {
1177
- return;
1178
- }
1179
-
1180
- // Must the Citadel mode be activated?
1181
- if ( $wp_cerber->getSettings( 'ciperiod' ) && ! cerber_is_citadel() ) {
1182
- $range = time() - $wp_cerber->getSettings( 'ciperiod' ) * 60;
1183
- //$lockouts = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
1184
- $lockouts = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
1185
- if ( $lockouts >= $wp_cerber->getSettings( 'cilimit' ) ) {
1186
- cerber_enable_citadel();
1187
- }
1188
- }
1189
-
1190
- if ( $no_user && $wp_cerber->getSettings( 'nonusers' ) ) {
1191
- cerber_block_add( $ip, 703, $user_login );
1192
- }
1193
- elseif ( cerber_get_remain_count($ip, false) <= 1 ) { //Limit on the number of login attempts is reached
1194
- cerber_block_add( $ip, 701, '', null, false);
1195
- }
1196
- }
1197
-
1198
- // Registration -----------------------------------------------------------------------
1199
-
1200
- function cerber_is_registration_prohibited( $sanitized_user_login ) {
1201
- global $wp_cerber, $cerber_status;
1202
-
1203
- /*
1204
- if ( crb_acl_is_white() ) {
1205
- return false;
1206
- }*/
1207
-
1208
- $code = null;
1209
- $msg = null;
1210
-
1211
- if ( crb_is_reg_limit_reached() ) {
1212
- $cerber_status = 17;
1213
- cerber_log( 54 );
1214
- $code = 'ip_denied';
1215
- $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1216
- apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1217
- }
1218
- elseif ( cerber_is_bot( 'botsreg' ) ) {
1219
- cerber_log( 54 ); // TODO should be separate code to detect bot activity?
1220
- $code = 'bot_detected';
1221
- $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1222
- apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1223
- }
1224
- elseif ( ! $wp_cerber->reCaptchaValidate() ) {
1225
- $code = 'incorrect_recaptcha';
1226
- $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1227
- $wp_cerber->reCaptchaMsg( 'register' );
1228
- }
1229
- elseif ( cerber_is_prohibited( $sanitized_user_login ) ) {
1230
- $code = 'prohibited_login';
1231
- $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1232
- apply_filters( 'cerber_msg_prohibited', __( 'Username is not allowed. Please choose another one.', 'wp-cerber' ), 'register' );
1233
- }
1234
- elseif ( ! cerber_is_allowed() || lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
1235
- cerber_log( 54 );
1236
- $code = 'ip_denied';
1237
- $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1238
- apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1239
- }
1240
- elseif ( ! cerber_geo_allowed( 'geo_register' ) ) {
1241
- $cerber_status = 16; // TODO: refactor cerber_log, include this status as a second parameter
1242
- cerber_log( 54 ); // TODO should be separate code?
1243
- $code = 'country_denied';
1244
- $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1245
- apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1246
- }
1247
-
1248
- if ( $code ) {
1249
- return array( $code, $msg );
1250
- }
1251
-
1252
- return false;
1253
- }
1254
-
1255
- /**
1256
- * Limit on user registrations per IP
1257
- *
1258
- * @return bool
1259
- */
1260
- function crb_is_reg_limit_reached() {
1261
-
1262
- if ( ! lab_lab() ) {
1263
- return false;
1264
- }
1265
-
1266
- if ( ! crb_get_settings( 'reglimit_min' ) || ! crb_get_settings( 'reglimit_num' ) ) {
1267
- return false;
1268
- }
1269
-
1270
- if ( crb_acl_is_white() ) {
1271
- return false;
1272
- }
1273
-
1274
- $ip = cerber_get_remote_ip();
1275
- $stamp = absint( time() - 60 * crb_get_settings( 'reglimit_min' ) );
1276
- $count = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity = 2 AND stamp > ' . $stamp );
1277
- if ( $count >= crb_get_settings( 'reglimit_num' ) ) {
1278
- lab_save_push( $ip, 344, '' );
1279
-
1280
- return true;
1281
- }
1282
-
1283
- return false;
1284
- }
1285
-
1286
- // Fires in register_new_user()
1287
- add_filter( 'registration_errors', 'cerber_pre_new_user', 10, 3 );
1288
- function cerber_pre_new_user( $errors, $sanitized_user_login, $user_email ) {
1289
-
1290
- $prohibited = cerber_is_registration_prohibited( $sanitized_user_login );
1291
-
1292
- if ( $prohibited ) {
1293
- return new WP_Error( $prohibited[0], $prohibited[1] );
1294
- }
1295
-
1296
- return $errors;
1297
- }
1298
-
1299
- // @since 5.3
1300
- // Fires in wp_insert_user()
1301
- add_filter( 'pre_user_login', function ( $sanitized_user_login ) {
1302
-
1303
- if ( cerber_is_registration_prohibited( $sanitized_user_login ) ) {
1304
- return null;
1305
- }
1306
-
1307
- return $sanitized_user_login;
1308
- }, 9999 );
1309
-
1310
- // @since 7.2.7 for MU and BuddyPress
1311
- add_filter( 'wpmu_validate_user_signup', function ( $result ) {
1312
-
1313
- $sanitized_user_login = sanitize_user( $result['user_name'], true );
1314
-
1315
- if ( $check = cerber_is_registration_prohibited( $sanitized_user_login ) ) {
1316
- $result['errors'] = new WP_Error( 'user_name', $check[1] );
1317
- }
1318
-
1319
- return $result;
1320
- }, 9999 );
1321
-
1322
- // Filter out prohibited usernames
1323
- add_filter( 'illegal_user_logins', function () {
1324
- return (array) crb_get_settings( 'prohibited' );
1325
- }, 9999 );
1326
-
1327
- add_filter( 'option_users_can_register', function ( $value ) {
1328
- //if ( ! cerber_is_allowed() || !cerber_geo_allowed( 'geo_register' )) {
1329
- if ( ! cerber_is_allowed() || crb_is_reg_limit_reached() ) {
1330
- return false;
1331
- }
1332
-
1333
- return $value;
1334
- }, 9999 );
1335
-
1336
- // Lost password form --------------------------------------------------------------------
1337
-
1338
- /**
1339
- * Validate reCAPTCHA for the WordPress lost password form
1340
- */
1341
- add_action( 'login_form_' . 'lostpassword', 'cerber_lost_captcha' );
1342
- function cerber_lost_captcha() {
1343
- global $wp_cerber, $cerber_lost;
1344
- if ( ! $wp_cerber->reCaptchaValidate() ) {
1345
- $_POST['user_login'] = null; // workaround due to lack of any way to control lost password form
1346
- $cerber_lost = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' . $wp_cerber->reCaptchaMsg('lostpassword');
1347
- }
1348
- }
1349
- /**
1350
- * Display message on the WordPress lost password form screen
1351
- */
1352
- add_action( 'lostpassword_form', 'cerber_lost_show_msg' );
1353
- function cerber_lost_show_msg() {
1354
- global $cerber_lost;
1355
- if ( ! $cerber_lost ) {
1356
- return;
1357
- }
1358
- ?>
1359
- <script type="text/javascript">
1360
- //document.getElementById('login_error').style.visibility = "hidden";
1361
- document.getElementById('login_error').innerHTML = "<?php echo $cerber_lost; ?>";
1362
- </script>
1363
- <?php
1364
- }
1365
-
1366
-
1367
- // Comments (commenting) section ----------------------------------------------------------
1368
-
1369
- /**
1370
- * If a comment must be marked as spam
1371
- *
1372
- */
1373
- add_filter( 'pre_comment_approved', function ( $approved, $commentdata ) {
1374
- if ( 1 == crb_get_settings( 'spamcomm' ) && ! cerber_is_comment_allowed() ) {
1375
- $approved = 'spam';
1376
- }
1377
-
1378
- return $approved;
1379
- }, 10, 2 );
1380
-
1381
- /**
1382
- * If a comment must be denied
1383
- *
1384
- */
1385
- add_action( 'pre_comment_on_post', function ( $comment_post_ID ) {
1386
- global $cerber_status;
1387
-
1388
- $deny = false;
1389
-
1390
- if ( 1 != crb_get_settings( 'spamcomm' ) && ! cerber_is_comment_allowed() ) {
1391
- $deny = true;
1392
- }
1393
- elseif ( ! cerber_geo_allowed( 'geo_comment' ) ) {
1394
- $cerber_status = 16;
1395
- cerber_log(19);
1396
- $deny = true;
1397
- }
1398
-
1399
- if ( $deny ) {
1400
- setcookie( 'cerber-post-id', $comment_post_ID, time() + 60, '/' );
1401
- $comments = get_comments( array( 'number' => '1', 'post_id' => $comment_post_ID ) );
1402
- if ( $comments ) {
1403
- $loc = get_comment_link( $comments[0]->comment_ID );
1404
- } else {
1405
- $loc = get_permalink( $comment_post_ID ) . '#cerber-recaptcha-msg';
1406
- }
1407
- wp_safe_redirect( $loc );
1408
- exit;
1409
- }
1410
-
1411
- } );
1412
-
1413
- /**
1414
- * If submit comments via REST API is not allowed
1415
- *
1416
- */
1417
- add_filter( 'rest_allow_anonymous_comments', function ( $allowed, $request ) {
1418
- global $wp_cerber, $cerber_status;
1419
-
1420
- if ( ! cerber_is_allowed() ) {
1421
- $allowed = false;
1422
- }
1423
- if ( ! cerber_geo_allowed( 'geo_comment' ) ) {
1424
- ceber_log(19);
1425
- $cerber_status = 16;
1426
- $allowed = false;
1427
- }
1428
- elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
1429
- $allowed = false;
1430
- }
1431
-
1432
- return $allowed;
1433
- }, 10, 2 );
1434
-
1435
- /**
1436
- * Check if a submitted comment is allowed
1437
- *
1438
- * @return bool
1439
- */
1440
- function cerber_is_comment_allowed(){
1441
- global $wp_cerber;
1442
-
1443
- if (is_admin()) return true;
1444
-
1445
- $deny = null;
1446
-
1447
- if ( ! cerber_is_allowed() ) {
1448
- $deny = 19;
1449
- }
1450
- elseif ( cerber_is_bot('botscomm') ) {
1451
- $remain = cerber_get_remain_count( null, true, array( 16 ), 3, 60 );
1452
- if ($remain < 1) cerber_block_add( null, 706, '', 60 );
1453
- $deny = 16;
1454
- }
1455
- elseif ( ! $wp_cerber->reCaptchaValidate( 'comment' , true ) ) {
1456
- $deny = 16;
1457
- }
1458
- elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
1459
- $deny = 19;
1460
- }
1461
-
1462
- if ( $deny ) {
1463
- cerber_log( $deny );
1464
- $ret = false;
1465
- }
1466
- else {
1467
- $ret = true;
1468
- }
1469
-
1470
- return $ret;
1471
- }
1472
-
1473
- /**
1474
- * Showing reCAPTCHA widget.
1475
- * Displaying error message on the comment form for a human.
1476
- *
1477
- */
1478
- add_filter( 'comment_form_submit_field', function ( $value ) {
1479
- global $wp_cerber, $post;
1480
-
1481
- if ( ! empty( $_COOKIE["cerber-post-id"] ) && absint( $_COOKIE["cerber-post-id"] ) == $post->ID ) {
1482
- //echo '<div id="cerber-recaptcha-msg">' . __( 'ERROR:', 'wp-cerber' ) . ' ' . $wp_cerber->reCaptchaMsg( 'comment' ) . '</div>';
1483
- echo '<div id="cerber-recaptcha-msg">' . __( 'ERROR:', 'wp-cerber' ) . ' ' . __('Sorry, human verification failed.') . '</div>';
1484
- echo '<script type="text/javascript">document.cookie = "cerber-post-id=0;path=/";</script>';
1485
- }
1486
-
1487
- $au = $wp_cerber->getSettings( 'recapcomauth' );
1488
- if ( ! $au || ( $au && ! is_user_logged_in() ) ) {
1489
- $wp_cerber->reCaptcha( 'widget', 'recapcom' );
1490
- }
1491
-
1492
- return $value;
1493
- } );
1494
-
1495
-
1496
- // Messages ----------------------------------------------------------------------
1497
-
1498
- /**
1499
- * Replace ANY system messages or add notify message above login form if IP is not allowed (blocked or locked out)
1500
- */
1501
- add_filter( 'login_errors', 'cerber_login_form_msg' ); // hook on POST if credentials was wrong
1502
- function cerber_login_form_msg( $errors ) {
1503
- global $error, $wp_cerber;
1504
- if ( cerber_can_msg() ) {
1505
- if ( ! cerber_is_allowed() ) {
1506
- $errors = $wp_cerber->getErrorMsg();
1507
- }
1508
- elseif ( ! $error && ( $msg = $wp_cerber->getRemainMsg() ) ) {
1509
- $errors .= '<p>' . $msg;
1510
- }
1511
- }
1512
-
1513
- return $errors;
1514
- }
1515
-
1516
- add_filter( 'shake_error_codes', 'cerber_login_failure_shake' ); // Shake it, baby!
1517
- function cerber_login_failure_shake( $shake_error_codes ) {
1518
- $shake_error_codes[] = 'cerber_wp_error';
1519
-
1520
- return $shake_error_codes;
1521
- }
1522
-
1523
- /*
1524
- Replace default login/logout URL with Custom login page URL
1525
- */
1526
- add_filter( 'site_url', 'cerber_login_logout', 9999, 4 );
1527
- add_filter( 'network_site_url', 'cerber_login_logout', 9999, 3 );
1528
- function cerber_login_logout( $url, $path, $scheme, $blog_id = 0 ) { // $blog_id only for 'site_url'
1529
- global $wp_cerber;
1530
- if ( $login_path = $wp_cerber->getSettings( 'loginpath' ) ) {
1531
- $url = str_replace( WP_LOGIN_SCRIPT, $login_path . '/', $url );
1532
- }
1533
-
1534
- return $url;
1535
- }
1536
-
1537
- /*
1538
- Replace default logout redirect URL with Custom login page URL
1539
- */
1540
- add_filter( 'wp_redirect', 'cerber_login_redirect', 9999, 2 );
1541
- function cerber_login_redirect( $location, $status ) {
1542
- global $wp_cerber;
1543
- if ( ($path = $wp_cerber->getSettings( 'loginpath' )) && ( 0 === strpos( $location, WP_LOGIN_SCRIPT . '?' ) ) ) {
1544
- $loc = explode( '?', $location );
1545
- $location = get_home_url() . '/' . $path . '/?' . $loc[1];
1546
- }
1547
-
1548
- return $location;
1549
- }
1550
-
1551
- // Access control ========================================================================================
1552
-
1553
- add_action( 'init', function () {
1554
- if ( crb_get_settings( 'adminphp' ) && ! is_user_logged_in() ) {
1555
- define( 'CONCATENATE_SCRIPTS', false );
1556
- }
1557
- cerber_access_control();
1558
- cerber_post_control();
1559
- }, 0 );
1560
-
1561
- /**
1562
- * Restrict access to some vital parts of WP
1563
- *
1564
- */
1565
- function cerber_access_control() {
1566
- global $wp_cerber, $cerber_status;
1567
-
1568
- if ( is_admin() ) {
1569
- return;
1570
- }
1571
-
1572
- if ( crb_acl_is_white() ) {
1573
- return;
1574
- }
1575
-
1576
- $wp_cerber = get_wp_cerber();
1577
- if ( $wp_cerber->isURIProhibited() ) {
1578
- cerber_404_page();
1579
- }
1580
-
1581
- $opt = crb_get_settings();
1582
-
1583
- // REST API
1584
- if ( $wp_cerber->isDeny() ) {
1585
- cerber_block_rest();
1586
- }
1587
- elseif ( cerber_is_rest_url() ) {
1588
- $rest_allowed = true;
1589
- if ( ! empty( $opt['norest'] ) ) {
1590
- $rest_allowed = false;
1591
- if ( $opt['restauth'] && is_user_logged_in() ) {
1592
- $rest_allowed = true;
1593
- }
1594
- elseif ( cerber_is_route_allowed() ) {
1595
- $rest_allowed = true;
1596
- }
1597
- }
1598
- if ( $rest_allowed && cerber_is_route_blocked() ) {
1599
- $rest_allowed = false;
1600
- }
1601
- if ( $rest_allowed && ! cerber_geo_allowed( 'geo_restapi' ) ) {
1602
- $rest_allowed = false;
1603
- $cerber_status = 16;
1604
- }
1605
- if ( ! $rest_allowed ) {
1606
- cerber_block_rest();
1607
- }
1608
- }
1609
-
1610
- // Some XML-RPC stuff
1611
- if ( $wp_cerber->isDeny() || ! empty( $opt['xmlrpc'] ) ) {
1612
- add_filter( 'xmlrpc_enabled', '__return_false' );
1613
- add_filter( 'pings_open', '__return_false' );
1614
- add_filter( 'bloginfo_url', 'cerber_pingback_url', 10, 2 );
1615
- remove_action( 'wp_head', 'rsd_link', 10 );
1616
- remove_action( 'wp_head', 'wlwmanifest_link', 10 );
1617
- }
1618
-
1619
- // Feeds
1620
- if ( $wp_cerber->isDeny() || ! empty( $opt['nofeeds'] ) ) {
1621
- remove_action( 'wp_head', 'feed_links', 2 );
1622
- remove_action( 'wp_head', 'feed_links_extra', 3 );
1623
-
1624
- remove_action( 'do_feed_rdf', 'do_feed_rdf', 10 );
1625
- remove_action( 'do_feed_rss', 'do_feed_rss', 10 );
1626
- remove_action( 'do_feed_rss2', 'do_feed_rss2', 10 );
1627
- remove_action( 'do_feed_atom', 'do_feed_atom', 10 );
1628
- remove_action( 'do_pings', 'do_all_pings', 10 );
1629
-
1630
- add_action( 'do_feed_rdf', 'cerber_404_page', 1 );
1631
- add_action( 'do_feed_rss', 'cerber_404_page', 1 );
1632
- add_action( 'do_feed_rss2', 'cerber_404_page', 1 );
1633
- add_action( 'do_feed_atom', 'cerber_404_page', 1 );
1634
- add_action( 'do_feed_rss2_comments', 'cerber_404_page', 1 );
1635
- add_action( 'do_feed_atom_comments', 'cerber_404_page', 1 );
1636
- }
1637
- }
1638
-
1639
- /**
1640
- * Antispam & Antibot for forms
1641
- *
1642
- */
1643
- function cerber_post_control() {
1644
- global $cerber_status;
1645
-
1646
- if ( ! cerber_is_http_post() || crb_acl_is_white() ) {
1647
- return;
1648
- }
1649
-
1650
- if ( ! cerber_antibot_enabled( 'botsany' ) && ! cerber_geo_rules( 'geo_submit' ) ) {
1651
- return;
1652
- }
1653
-
1654
- // Exceptions -----------------------------------------------------------------------
1655
-
1656
- if ( cerber_is_antibot_exception() ) {
1657
- return;
1658
- }
1659
-
1660
- // Let's make the checks
1661
-
1662
- $deny = false;
1663
-
1664
- if ( ! cerber_is_allowed() ) {
1665
- $deny = true;
1666
- cerber_log( 18 );
1667
- }
1668
- elseif ( cerber_is_bot( 'botsany' ) ) {
1669
- $deny = true;
1670
- cerber_log( 17 );
1671
- }
1672
- elseif ( ! cerber_geo_allowed( 'geo_submit' ) ) {
1673
- $deny = true;
1674
- $cerber_status = 16; // TODO: refactor cerber_log, include this status as a second parameter
1675
- cerber_log( 18 );
1676
- }
1677
- elseif ( lab_is_blocked( null, true ) ) {
1678
- $deny = true;
1679
- $cerber_status = 18;
1680
- cerber_log( 18 );
1681
- }
1682
-
1683
- if ( $deny ) {
1684
- cerber_forbidden_page();
1685
- }
1686
-
1687
- }
1688
-
1689
- /**
1690
- * Exception for POST request control
1691
- *
1692
- * @return bool
1693
- */
1694
- function cerber_is_antibot_exception(){
1695
-
1696
- if ( cerber_is_wp_cron() ) {
1697
- return true;
1698
- }
1699
-
1700
- // Admin || AJAX requests by unauthorized users
1701
- if ( is_admin() ) {
1702
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1703
- if (is_user_logged_in()) {
1704
- return true;
1705
- }
1706
- }
1707
- else {
1708
- return true;
1709
- }
1710
- }
1711
-
1712
- // Standard WordPress Comments
1713
- if ( 0 === strpos( trim( $_SERVER['REQUEST_URI'], '/' ), 'wp-comments-post.php' ) ) {
1714
- return true;
1715
- }
1716
-
1717
- // XML-RPC
1718
- if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
1719
- return true;
1720
- }
1721
-
1722
- // Trackback
1723
- if ( is_trackback() ) {
1724
- return true;
1725
- }
1726
-
1727
- // Login page
1728
- if ( cerber_is_login_request() ) {
1729
- return true;
1730
- }
1731
-
1732
- // Cloud Scanner
1733
- if ( cerber_is_cloud_request() ) {
1734
- return true;
1735
- }
1736
-
1737
- // REST API (except Contact Form 7 submission)
1738
- if ( cerber_is_rest_url() ) {
1739
- if ( false === strpos( $_SERVER['REQUEST_URI'], 'contact-form-7' ) ) {
1740
- return true;
1741
- }
1742
- }
1743
-
1744
- if ( class_exists( 'WooCommerce' ) ) {
1745
- if ( cerber_is_permalink_enabled() ) {
1746
- //if ( 0 === strpos( cerber_get_site_root() . cerber_purify_uri(), get_home_url() . '/wc-api/' ) ) {
1747
- if ( 0 === strpos( CRB_Request::full_url(), get_home_url() . '/wc-api/' ) ) {
1748
- return true;
1749
- }
1750
- }
1751
- elseif ( ! empty( $_GET['wc-api'] ) ) {
1752
- if ( cerber_check_remote_domain( array( '*.paypal.com', '*.stripe.com' ) ) ) {
1753
- return true;
1754
- }
1755
- }
1756
- }
1757
-
1758
- return false;
1759
- }
1760
-
1761
- /**
1762
- * What antibot mode must be used.
1763
- *
1764
- * @return int 1 = Cookies + Fields, 2 = Cookies only
1765
- */
1766
- function cerber_antibot_mode() {
1767
- global $wp;
1768
- //static $list;
1769
-
1770
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1771
- if ( crb_get_settings( 'botssafe' ) ) {
1772
- return 2;
1773
- }
1774
- if ( ! empty( $_POST['action'] ) ) {
1775
- if ( $_POST['action'] == 'heartbeat' ) { // WP heartbeat
1776
- //$nonce_state = wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' );
1777
- return 2;
1778
- }
1779
- }
1780
-
1781
- }
1782
-
1783
- if ( cerber_get_uri_script() ) {
1784
- return 1;
1785
- }
1786
-
1787
- // Check for third party exceptions
1788
-
1789
- if ( class_exists( 'WooCommerce' ) ) {
1790
-
1791
- if ( ! empty( $_GET['wc-ajax'] ) &&
1792
- //$_GET['wc-ajax'] == 'get_refreshed_fragments' &&
1793
- count( $_GET ) == 1 &&
1794
- empty( $_POST )
1795
- ) {
1796
-
1797
- return 2;
1798
- }
1799
-
1800
- if ( cerber_is_permalink_enabled() ) {
1801
- //if ( function_exists( 'wc_get_page_id' ) && 0 === strpos( cerber_get_site_root() . cerber_purify_uri(), get_permalink( wc_get_page_id( 'checkout' ) ) ) ) {
1802
- if ( function_exists( 'wc_get_page_id' ) && 0 === strpos( CRB_Request::full_url(), get_permalink( wc_get_page_id( 'checkout' ) ) ) ) {
1803
- return 2;
1804
- }
1805
- }
1806
- else {
1807
- if ( ! empty( $_GET['order-received'] ) && ! empty( $_GET['key'] ) ) {
1808
- return 2;
1809
- }
1810
- }
1811
- }
1812
-
1813
- if ( class_exists( 'GFForms' ) ) {
1814
- if ( count( $_GET ) == 2 &&
1815
- ! empty( $_GET['gf_page'] ) &&
1816
- ! empty( $_GET['id'] ) &&
1817
- is_user_logged_in()
1818
- ) {
1819
-
1820
- return 2;
1821
- }
1822
- }
1823
-
1824
- return 1;
1825
- }
1826
-
1827
- /*
1828
- * Disable pingback URL (hide from HEAD)
1829
- */
1830
- function cerber_pingback_url( $output, $show ) {
1831
- if ( $show == 'pingback_url' ) {
1832
- $output = '';
1833
- }
1834
-
1835
- return $output;
1836
- }
1837
-
1838
- /**
1839
- * Disable REST API
1840
- *
1841
- */
1842
- function cerber_block_rest() {
1843
- // OLD WP
1844
- add_filter( 'json_enabled', '__return_false' );
1845
- add_filter( 'json_jsonp_enabled', '__return_false' );
1846
- // WP 4.4, deprecated since 4.7
1847
- if ( version_compare( cerber_get_wp_version(), '4.7', '<' ) ) {
1848
- add_filter( 'rest_enabled', '__return_false', 9999 );
1849
- }
1850
- // WP 4.7
1851
- add_filter( 'rest_jsonp_enabled', '__return_false' );
1852
- // Links
1853
- remove_action( 'wp_head', 'rest_output_link_wp_head', 10 );
1854
- remove_action( 'template_redirect', 'rest_output_link_header', 11 );
1855
- // Default REST API hooks from default-filters.php
1856
- remove_action( 'init', 'rest_api_init' );
1857
- remove_action( 'rest_api_init', 'rest_api_default_filters', 10 );
1858
- remove_action( 'rest_api_init', 'register_initial_settings', 10 );
1859
- remove_action( 'rest_api_init', 'create_initial_rest_routes', 99 );
1860
- remove_action( 'parse_request', 'rest_api_loaded' );
1861
-
1862
- if ( cerber_is_rest_url() ) {
1863
- cerber_log( 70 );
1864
- //cerber_404_page();
1865
- cerber_forbidden_page(); // @since 6.0
1866
- }
1867
- }
1868
-
1869
- /*
1870
- * Redirection control: standard admin/login redirections
1871
- *
1872
- */
1873
- add_filter( 'wp_redirect', 'cerber_no_red', 10, 2 );
1874
- function cerber_no_red( $location, $status ) {
1875
- global $current_user;
1876
- if ( ( ! $current_user || $current_user->ID == 0 ) && cerber_no_redirect() ) {
1877
- $str = urlencode( '/wp-admin/' );
1878
- $rdr = explode( 'redirect_to=', $location );
1879
- if ( isset( $rdr[1] ) && strpos( $rdr[1], $str ) ) {
1880
- cerber_404_page();
1881
- }
1882
- }
1883
-
1884
- return $location;
1885
- }
1886
-
1887
- /**
1888
- * @since 7.0
1889
- */
1890
- function cerber_no_redirect() {
1891
- if ( crb_get_settings( 'noredirect' ) && !cerber_check_groove_x()) {
1892
- return true;
1893
- }
1894
-
1895
- return false;
1896
- }
1897
-
1898
- /*
1899
- * Stop user enumeration
1900
- *
1901
- */
1902
- add_action( 'template_redirect', 'cerber_canonical', 1 );
1903
- function cerber_canonical() {
1904
- if ( crb_get_settings( 'stopenum' ) ) {
1905
- if ( ! is_admin() && ! empty( $_GET['author'] ) ) {
1906
- cerber_404_page();
1907
- }
1908
- }
1909
- }
1910
- /*
1911
- if ( $wp_cerber->getSettings( 'hashauthor' ) ) {
1912
- add_filter( 'request',
1913
- function ( $vars ) {
1914
- if (isset($vars['author_name']) && !is_admin()) {
1915
- $vars['author_name'] = '><';
1916
- }
1917
-
1918
- return $vars;
1919
- } );
1920
- }
1921
- */
1922
-
1923
- /*
1924
- Can login form message be shown?
1925
- */
1926
- function cerber_can_msg() {
1927
- if ( ! isset( $_REQUEST['action'] ) ) {
1928
- return true;
1929
- }
1930
- if ( $_REQUEST['action'] == 'login' ) {
1931
- return true;
1932
- }
1933
-
1934
- return false;
1935
- //if ( !in_array( $action, array( 'postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login' );
1936
- }
1937
-
1938
-
1939
- // Cookies ---------------------------------------------------------------------------------
1940
- /*
1941
- Mark user with Cerber Groove
1942
- @since 1.3
1943
- */
1944
- add_action( 'auth_cookie_valid', 'cerber_cookie_one', 10, 2 );
1945
- function cerber_cookie_one( $cookie_elements = null, $user = null ) {
1946
- if ( ! $user ) {
1947
- $user = wp_get_current_user();
1948
- }
1949
- $expire = time() + apply_filters( 'auth_cookie_expiration', 14 * 24 * 3600, $user->ID, true ) + ( 24 * 3600 );
1950
- cerber_set_groove( $expire );
1951
- }
1952
-
1953
- /*
1954
- Mark switched user with Cerber Groove
1955
- @since 1.6
1956
- */
1957
- add_action( 'set_logged_in_cookie', 'cerber_cookie2', 10, 5 );
1958
- function cerber_cookie2( $logged_in_cookie, $expire, $expiration, $user_id, $logged_in ) {
1959
- cerber_set_groove( $expire );
1960
- }
1961
-
1962
- /*
1963
- Track BAD cookies with non-existence user or bad password (hash)
1964
- */
1965
- add_action( 'auth_cookie_bad_username', 'cerber_cookie_bad' );
1966
- add_action( 'auth_cookie_bad_hash', 'cerber_cookie_bad' );
1967
- function cerber_cookie_bad( $cookie_elements ) {
1968
- cerber_login_failed( $cookie_elements['username'] );
1969
- }
1970
-
1971
- /**
1972
- * Is bot detection engine enabled in a given rule_id
1973
- *
1974
- * @param $location string|array ID of the location
1975
- *
1976
- * @return bool true if enabled
1977
- */
1978
- function cerber_antibot_enabled( $location ) {
1979
-
1980
- if ( crb_get_settings( 'botsnoauth' ) && is_user_logged_in() ) {
1981
- return false;
1982
- }
1983
-
1984
- if ( is_array( $location ) ) {
1985
- foreach ( $location as $loc ) {
1986
- if ( crb_get_settings( $loc ) ) {
1987
- return true;
1988
- }
1989
- }
1990
- }
1991
- else {
1992
- if ( crb_get_settings( $location ) ) {
1993
- return true;
1994
- }
1995
- }
1996
-
1997
- return false;
1998
- }
1999
-
2000
- /**
2001
- * Print out the antibot/antispam jQuery code
2002
- *
2003
- * @param $location string|array Location (setting)
2004
- */
2005
- function cerber_antibot_code($location) {
2006
- if ( ! cerber_antibot_enabled( $location ) ) {
2007
- return;
2008
- }
2009
-
2010
- $values = cerber_antibot_gene();
2011
-
2012
- if ( empty( $values ) || !is_array( $values ) ) {
2013
- return;
2014
- }
2015
-
2016
- ?>
2017
- <script type="text/javascript">
2018
- jQuery(document).ready(function ($) {
2019
- //$( document ).ajaxStart(function() {
2020
- //});
2021
-
2022
- <?php // Append form fields directly to the all forms ?>
2023
-
2024
- for (var i = 0; i < document.forms.length; ++i) {
2025
- var form = document.forms[i];
2026
- <?php
2027
- foreach ( $values[0] as $value ) {
2028
- echo 'if ($(form).attr("method") != "get") { $(form).append(\'<input type="hidden" name="' . $value[0] . '" value="' . $value[1] . '" />\'); }'."\n";
2029
- }
2030
- ?>
2031
- }
2032
-
2033
- <?php // Ordinary submit ?>
2034
-
2035
- $(document).on('submit', 'form', function () {
2036
- <?php
2037
- foreach ( $values[0] as $value ) {
2038
- echo 'if ($(this).attr("method") != "get") { $(this).append(\'<input type="hidden" name="' . $value[0] . '" value="' . $value[1] . '" />\'); }'."\n";
2039
- }
2040
- ?>
2041
- return true;
2042
- });
2043
-
2044
- <?php // Pure AJAX submit with two different types of form data (object and string) ?>
2045
-
2046
- jQuery.ajaxSetup({
2047
- beforeSend: function (e, data) {
2048
-
2049
- //console.log(Object.getOwnPropertyNames(data).sort());
2050
- //console.log(data.type);
2051
-
2052
- if (data.type !== 'POST') return;
2053
-
2054
- if (typeof data.data === 'object' && data.data !== null) {
2055
- <?php
2056
- foreach ( $values[0] as $value ) {
2057
- echo 'data.data.append("' . $value[0] . '", "' . $value[1] . '");'."\n";
2058
- }
2059
- ?>
2060
- }
2061
- else {
2062
- data.data = data.data + '<?php
2063
- foreach ( $values[0] as $value ) {
2064
- echo '&' . $value[0] . '=' . $value[1];
2065
- }
2066
- ?>';
2067
- }
2068
- }
2069
- });
2070
-
2071
- });
2072
- </script>
2073
- <?php
2074
-
2075
- }
2076
-
2077
- /**
2078
- * Generates and saves antibot markers
2079
- *
2080
- * @return array|bool
2081
- */
2082
- function cerber_antibot_gene($recreate = false) {
2083
-
2084
- if ( !crb_get_settings('botsany') && !crb_get_settings('botscomm') && !crb_get_settings('botsreg') ) {
2085
- return false;
2086
- }
2087
-
2088
- $ret = array();
2089
-
2090
- if (!$recreate) {
2091
- $ret = cerber_get_site_option( 'cerber-antibot' );
2092
- }
2093
-
2094
- if ( $recreate || !$ret ) {
2095
-
2096
- $ret = array();
2097
-
2098
- $max = rand( 2, 4 );
2099
- for ( $i = 1; $i <= $max; $i ++ ) {
2100
- $length = rand( 6, 16 );
2101
- $string1 = str_shuffle( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-' );
2102
- $string2 = str_shuffle( '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.@*_[]' );
2103
- $ret[0][] = array( substr( $string1, 0, $length ), substr( $string2, 0, $length ) );
2104
- }
2105
-
2106
- $max = rand( 2, 4 );
2107
- for ( $i = 1; $i <= $max; $i ++ ) {
2108
- $length = rand( 6, 16 );
2109
- $string1 = str_shuffle( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-' );
2110
- $string2 = str_shuffle( '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.@*_[]' );
2111
- $ret[1][] = array( substr( $string1, 0, $length ), substr( $string2, 0, $length ) );
2112
- }
2113
-
2114
- update_site_option( 'cerber-antibot', $ret );
2115
- }
2116
-
2117
- return $ret;
2118
- }
2119
-
2120
- /**
2121
- * Is a POST request (a form) submitted by a bot?
2122
- *
2123
- * @param $location string identificator of a place where we are check for a bot
2124
- *
2125
- * @return bool
2126
- */
2127
- function cerber_is_bot( $location = '' ) {
2128
- global $cerber_status;
2129
- static $ret = null;
2130
-
2131
- $remote_ip = cerber_get_remote_ip();
2132
-
2133
- if ( $remote_ip == '127.0.0.1' || $remote_ip == '::1' ) {
2134
- return false; // v. 7.8.5
2135
- }
2136
-
2137
- if ( isset( $ret ) ) {
2138
- return $ret;
2139
- }
2140
-
2141
- if ( ! $location || ! cerber_is_http_post() || cerber_is_wp_cron() ) {
2142
- $ret = false;
2143
-
2144
- return $ret;
2145
- }
2146
-
2147
- // Admin || AJAX requests by unauthorized users
2148
- if ( is_admin() ) {
2149
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
2150
- if ( is_user_logged_in() ) {
2151
- $ret = false;
2152
- }
2153
- elseif ( ! empty( $_POST['action'] ) ) {
2154
- if ( $_POST['action'] == 'heartbeat' ) { // WP heartbeat
2155
- //$nonce_state = wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' );
2156
- $ret = false;
2157
- }
2158
- }
2159
- }
2160
- else {
2161
- $ret = false;
2162
- }
2163
- }
2164
-
2165
- if ($ret !== null) {
2166
- return $ret;
2167
- }
2168
-
2169
- if ( ! cerber_antibot_enabled( $location ) ) {
2170
- $ret = false;
2171
-
2172
- return $ret;
2173
- }
2174
-
2175
- // Antibot whitelist
2176
- if ( ( $list = crb_get_settings( 'botswhite' ) ) && is_array( $list ) ) {
2177
- foreach ( $list as $item ) {
2178
- if ( substr( $item, 0, 1 ) == '{' && substr( $item, - 1 ) == '}' ) {
2179
- $pattern = '/' . substr( $item, 1, - 1 ) . '/i';
2180
- if ( @preg_match( $pattern, '/' . trim( $_SERVER['REQUEST_URI'], '/' ) ) ) {
2181
- $ret = false;
2182
- return $ret;
2183
- }
2184
- }
2185
- elseif ( false !== strpos( '/' . trim( $_SERVER['REQUEST_URI'], '/' ), $item ) ) {
2186
- $ret = false;
2187
- return $ret;
2188
- }
2189
- }
2190
- }
2191
-
2192
- $antibot = cerber_antibot_gene();
2193
-
2194
- $ret = false;
2195
-
2196
- if ( ! empty( $antibot ) ) {
2197
-
2198
- $mode = cerber_antibot_mode();
2199
-
2200
- if ( $mode == 1 ) {
2201
- foreach ( $antibot[0] as $fields ) {
2202
- if ( empty( $_POST[ $fields[0] ] ) || $_POST[ $fields[0] ] != $fields[1] ) {
2203
- $ret = true;
2204
- break;
2205
- }
2206
- }
2207
- }
2208
-
2209
- if ( ! $ret ) {
2210
- foreach ( $antibot[1] as $fields ) {
2211
- if ( empty( $_COOKIE[ $fields[0] ] ) || $_COOKIE[ $fields[0] ] != $fields[1] ) {
2212
- $ret = true;
2213
- break;
2214
- }
2215
- }
2216
- }
2217
-
2218
- if ( $ret ) {
2219
- $cerber_status = 11;
2220
- lab_save_push( $remote_ip, 333, '' );
2221
- }
2222
- }
2223
-
2224
- return $ret;
2225
- }
2226
-
2227
- function cerber_geo_allowed( $rule_id = '' ) {
2228
-
2229
- if ( ! $rule_id || cerber_is_wp_cron() || ! lab_lab() ) {
2230
- return true;
2231
- }
2232
-
2233
- if ( crb_acl_is_white() ) {
2234
- return true;
2235
- }
2236
-
2237
- $rule = cerber_geo_rules( $rule_id );
2238
- $wp_cerber = get_wp_cerber();
2239
- if ( $rule && $country = lab_get_country( $wp_cerber->getRemoteIp(), false ) ) {
2240
- if ( in_array( $country, $rule['list'] ) ) {
2241
- if ( $rule['type'] == 'W' ) {
2242
- return true;
2243
- }
2244
-
2245
- return false;
2246
- }
2247
- if ( $rule['type'] == 'W' ) {
2248
- return false;
2249
- }
2250
-
2251
- return true;
2252
- }
2253
-
2254
- return true;
2255
- }
2256
-
2257
- /**
2258
- * Retrieve and return GEO rule(s) from the DB
2259
- *
2260
- * @param string $rule_id Slug of a rule
2261
- *
2262
- * @return bool|array If a rule exists return array of countries
2263
- */
2264
- function cerber_geo_rules( $rule_id = '' ) {
2265
- global $wpdb;
2266
-
2267
- if (is_multisite()) {
2268
- //$geo = $wpdb->get_var( 'SELECT meta_value FROM ' . $wpdb->sitemeta . ' WHERE meta_key = "geo_rule_set"' );
2269
- $geo = cerber_db_get_var( 'SELECT meta_value FROM ' . $wpdb->sitemeta . ' WHERE meta_key = "geo_rule_set"' );
2270
- }
2271
- else {
2272
- //$geo = $wpdb->get_var( 'SELECT option_value FROM ' . $wpdb->options . ' WHERE option_name = "geo_rule_set"' );
2273
- $geo = cerber_db_get_var( 'SELECT option_value FROM ' . $wpdb->options . ' WHERE option_name = "geo_rule_set"' );
2274
- }
2275
-
2276
- if ( $geo ) {
2277
- $rules = unserialize( $geo );
2278
- if ( $rule_id ) {
2279
- if ( ! empty( $rules[ $rule_id ] ) ) {
2280
- $ret = $rules[ $rule_id ];
2281
- }
2282
- else {
2283
- $ret = false;
2284
- }
2285
- }
2286
- else {
2287
- $ret = $rules;
2288
- }
2289
- }
2290
- else {
2291
- $ret = false;
2292
- }
2293
-
2294
- return $ret;
2295
- }
2296
-
2297
- /**
2298
- * Set user session expiration
2299
- *
2300
- */
2301
- add_filter( 'auth_cookie_expiration', function ( $expire ) {
2302
- $time = crb_get_settings( 'auth_expire' );
2303
- if ( $time ) {
2304
- $expire = 60 * $time;
2305
- }
2306
-
2307
- return $expire;
2308
- } );
2309
-
2310
- // Track various activity -------------------------------------------------------------------------
2311
-
2312
- add_action( 'wp_login', function ( $login, $user ) {
2313
- global $wp_cerber_user_id;
2314
- if ( ! empty( $_POST['log'] ) ) { // default WP form
2315
- $user_login = htmlspecialchars( $_POST['log'] );
2316
- }
2317
- else {
2318
- $user_login = $login;
2319
- }
2320
- $wp_cerber_user_id = $user->ID;
2321
- cerber_log( 5, $user_login, $user->ID );
2322
- }, 10, 2 );
2323
-
2324
- /**
2325
- * Catching some cases of authentication without using login form or not a default user login process
2326
- */
2327
- add_action( 'set_auth_cookie', function () {
2328
- add_action( 'shutdown', function () { // deferred to allow the possible 'wp_login' action be logged first
2329
- if ($user_id = get_current_user_id()) {
2330
- cerber_log( 5, '', $user_id );
2331
- }
2332
- } );
2333
- } );
2334
-
2335
- /*add_action( 'wp_logout', function() {
2336
- global $user_ID;
2337
- if ( ! $user_ID ) {
2338
- $user = wp_get_current_user();
2339
- $user_ID = $user->ID;
2340
- }
2341
- cerber_log( 6, '', $user_ID );
2342
- });*/
2343
-
2344
- add_action( 'clear_auth_cookie', function () {
2345
- $uid = get_current_user_id();
2346
- if ( $uid ) {
2347
- cerber_log( 6, '', $uid );
2348
- }
2349
- } );
2350
-
2351
- //add_action( 'lostpassword_post', 'cerber_password_post' );
2352
- add_action( 'retrieve_password', function ( $user_login ) {
2353
- cerber_log( 21, $user_login );
2354
- } );
2355
-
2356
- add_action( 'password_reset', 'crb_pass_reset' );
2357
- add_action( 'crb_after_reset', 'crb_pass_reset', 10, 2);
2358
-
2359
- function crb_pass_reset( $user, $user_id = null) {
2360
- if ( ! $user && $user_id ) {
2361
- $user = get_user_by( 'id', $user_id );
2362
- }
2363
- if ( ! $user ) {
2364
- return;
2365
- }
2366
- cerber_log( 20, $user->user_login, $user->ID );
2367
- }
2368
-
2369
- //add_action( 'register_new_user', function ( $user_id ) { // OLD
2370
- // Fires in wp_insert_user()
2371
- add_action( 'user_register', function ( $user_id ) { // @since 5.6
2372
- $cid = get_current_user_id();
2373
- if ($user = get_user_by( 'ID', $user_id )) {
2374
- if ( $cid && $cid != $user_id ) {
2375
- $ac = 1;
2376
- }
2377
- else {
2378
- $ac = 2;
2379
- }
2380
- cerber_log( $ac, $user->user_login, $user_id );
2381
- crb_log_user_ip( $user_id, $cid );
2382
- }
2383
- });
2384
-
2385
- // Fires after a new user has been created in WP dashboard.
2386
- add_action( 'edit_user_created_user', function ( $user_id, $notify = null ) {
2387
- if ( $user_id && $user = get_user_by( 'ID', $user_id ) ) {
2388
- cerber_log( 1, $user->user_login, $user_id );
2389
- crb_log_user_ip( $user_id );
2390
- }
2391
- }, 10, 2 );
2392
-
2393
- // Log IP address of user registration independently
2394
- function crb_log_user_ip( $user_id, $by_user = null ) {
2395
- global $wp_cerber;
2396
- if ( ! $user_id ) {
2397
- return;
2398
- }
2399
- if ( ! $by_user ) {
2400
- $by_user = get_current_user_id();
2401
- }
2402
- add_user_meta( $user_id, '_crb_reg_', array( 'IP' => $wp_cerber->getRemoteIp(), 'user' => $by_user ) );
2403
- }
2404
-
2405
- // Lockouts routines ---------------------------------------------------------------------
2406
-
2407
- /**
2408
- * Lock out IP address if it is an alien IP only (browser does not have valid Cerber groove)
2409
- *
2410
- * @param $ip string IP address to block
2411
- * @param integer $reason_id ID of reason of blocking
2412
- * @param string $details Reason of blocking
2413
- * @param null $duration Duration of blocking
2414
- *
2415
- * @return bool|false|int
2416
- */
2417
- function cerber_soft_block_add( $ip, $reason_id, $details = '', $duration = null ) {
2418
- if ( cerber_check_groove() ) {
2419
- return false;
2420
- }
2421
-
2422
- return cerber_block_add( $ip, $reason_id, $details, $duration );
2423
- }
2424
-
2425
- /**
2426
- * Lock out IP address
2427
- *
2428
- * @param $ip string IP address to block
2429
- * @param integer $reason_id ID of reason of blocking
2430
- * @param string $details Reason of blocking
2431
- * @param int $duration Duration of blocking
2432
- *
2433
- * @return bool|false|int
2434
- */
2435
- function cerber_block_add( $ip = '', $reason_id = 1, $details = '', $duration = null ) {
2436
- global $cerber_blocked;
2437
-
2438
- if ( cerber_is_cloud_request() ) {
2439
- return false;
2440
- }
2441
-
2442
- $wp_cerber = get_wp_cerber();
2443
-
2444
- //$wp_cerber->setProcessed();
2445
-
2446
- if ( empty( $ip ) || ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2447
- $ip = $wp_cerber->getRemoteIp();
2448
- }
2449
-
2450
- if ( cerber_get_block( $ip ) ) {
2451
- return false;
2452
- }
2453
-
2454
- if ( cerber_acl_check( $ip ) ) {
2455
- return false;
2456
- }
2457
-
2458
- $ip_address = $ip;
2459
-
2460
- lab_save_push( $ip, $reason_id, $details );
2461
-
2462
- if ( $wp_cerber->getSettings( 'subnet' ) ) {
2463
- $ip = cerber_get_subnet( $ip );
2464
- $activity = 11;
2465
- }
2466
- else {
2467
- $activity = 10;
2468
- }
2469
-
2470
- /*if ( $wpdb->get_var( $wpdb->prepare( 'SELECT count(ip) FROM ' . CERBER_BLOCKS_TABLE . ' WHERE ip = %s', $ip ) ) ) {
2471
- return false;
2472
- }*/
2473
-
2474
- $reason = cerber_get_reason( $reason_id );
2475
- if ( $details ) {
2476
- $reason .= ': <b>' . $details . '</b>';
2477
- }
2478
-
2479
- if ( ! $duration ) {
2480
- $duration = cerber_calc_duration( $ip );
2481
- }
2482
- $until = time() + $duration;
2483
-
2484
- //$result = $wpdb->query($wpdb->prepare('INSERT INTO '. CERBER_BLOCKS_TABLE . ' (ip,block_until,reason) VALUES (%s,%d,%s)',$ip,$until,$reason));
2485
- /*
2486
- $result = $wpdb->insert( CERBER_BLOCKS_TABLE, array(
2487
- 'ip' => $ip,
2488
- 'block_until' => $until,
2489
- 'reason' => $reason,
2490
- 'reason_id' => absint( $reason_id )
2491
- ), array( '%s', '%d', '%s' ) );*/
2492
-
2493
- $reason = cerber_real_escape( $reason );
2494
- $result = cerber_db_query( 'INSERT INTO ' . CERBER_BLOCKS_TABLE . ' (ip,block_until,reason,reason_id) VALUES ("' . $ip . '",' . $until . ',"' . $reason . '",' . absint( $reason_id ) . ')' );
2495
-
2496
- if ( $result ) {
2497
- $cerber_blocked = $reason_id;
2498
- cerber_log( $activity, null, null, $ip_address );
2499
- $wp_cerber->setLocked();
2500
- do_action( 'cerber_ip_locked', array( 'IP' => $ip_address, 'reason' => $reason ) );
2501
- $result = true;
2502
- }
2503
- else {
2504
- cerber_db_error_log();
2505
- $result = false;
2506
- }
2507
-
2508
- if ( $wp_cerber->getSettings( 'notify' ) ) {
2509
- $count = cerber_blocked_num();
2510
- if ( $count > $wp_cerber->getSettings( 'above' ) ) {
2511
- cerber_send_email( 'lockout', '', $ip_address );
2512
- }
2513
- }
2514
-
2515
- return $result;
2516
- }
2517
-
2518
- /**
2519
- *
2520
- * Check if an IP address is currently blocked. With C subnet also.
2521
- *
2522
- * @param string $ip an IP address
2523
- *
2524
- * @return bool true if IP is locked out
2525
- */
2526
- function cerber_block_check( $ip = '' ) {
2527
-
2528
- // @since 4.8
2529
- if ( cerber_get_block( $ip ) ) {
2530
- return true;
2531
- }
2532
-
2533
- return false;
2534
- }
2535
-
2536
- /**
2537
- *
2538
- * Return the lockout row for an IP if it is blocked. With C subnet also.
2539
- *
2540
- * @param string $ip an IP address
2541
- *
2542
- * @return object|bool object if IP is locked out, false otherwise
2543
- */
2544
- function cerber_get_block( $ip = '' ) {
2545
- global $wp_cerber;
2546
-
2547
- if ( ! $ip ) {
2548
- $wp_cerber = get_wp_cerber();
2549
- $ip = $wp_cerber->getRemoteIp();
2550
- }
2551
-
2552
- if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2553
- return false;
2554
- }
2555
-
2556
- $where = ' WHERE ip = "' . $ip . '"';
2557
- if ( cerber_is_ipv4( $ip ) ) {
2558
- $subnet = cerber_get_subnet( $ip );
2559
- $where .= ' OR ip = "' . $subnet . '"';
2560
- }
2561
- /*if ( $ret = $wpdb->get_row( 'SELECT * FROM ' . CERBER_BLOCKS_TABLE . $where ) ) {
2562
- return $ret;
2563
- }*/
2564
- if ( $ret = cerber_db_get_row( 'SELECT * FROM ' . CERBER_BLOCKS_TABLE . $where, MYSQL_FETCH_OBJECT ) ) {
2565
- return $ret;
2566
- }
2567
- return false;
2568
- }
2569
-
2570
- /**
2571
- * Return the number of currently locked out IPs
2572
- *
2573
- * @return int the number of currently locked out IPs
2574
- * @since 3.0
2575
- */
2576
- function cerber_blocked_num() {
2577
- return absint( cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_BLOCKS_TABLE ) );
2578
- }
2579
-
2580
- /**
2581
- * Calculate duration for a lockout of an IP address based on settings
2582
- *
2583
- * @param string $ip
2584
- *
2585
- * @return integer Duration in seconds
2586
- */
2587
- function cerber_calc_duration( $ip ) {
2588
- $range = time() - crb_get_settings( 'aglast' ) * 3600;
2589
- //$lockouts = $wpdb->get_var( $wpdb->prepare( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = %s AND activity IN (10,11) AND stamp > %d', $ip, $range ) );
2590
- //$lockouts = $wpdb->get_var( 'SELECT COUNT(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity IN (10,11) AND stamp > ' . $range );
2591
- $lockouts = cerber_db_get_var( 'SELECT COUNT(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity IN (10,11) AND stamp > ' . $range );
2592
- if ( $lockouts >= crb_get_settings( 'aglocks' ) ) {
2593
- $ret = crb_get_settings( 'agperiod' ) * 3600;
2594
- }
2595
- else {
2596
- $ret = crb_get_settings( 'lockout' ) * 60;
2597
- }
2598
- $ret = absint( $ret );
2599
- if ( $ret < 60 ) {
2600
- $ret = 60;
2601
- }
2602
-
2603
- return $ret;
2604
- }
2605
-
2606
- /**
2607
- * Calculation of remaining attempts
2608
- *
2609
- * @param $ip string an IP address
2610
- * @param $check_acl bool if true will check the White IP ACL first
2611
- * @param $activity array List of activity IDs to calculate for
2612
- * @param $allowed int Allowed attempts within $period
2613
- * @param $period int Period for count attempts
2614
- *
2615
- * @return int Allowed attempts for present moment
2616
- */
2617
- function cerber_get_remain_count( $ip = '', $check_acl = true, $activity = array( '7,51,52' ), $allowed = null, $period = null ) {
2618
- global $wpdb, $wp_cerber;
2619
- if ( ! $ip ) {
2620
- $ip = $wp_cerber->getRemoteIp();
2621
- }
2622
- else {
2623
- if ( ! $ip = filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2624
- return 0;
2625
- }
2626
- }
2627
-
2628
- if ( ! $allowed ) {
2629
- $allowed = absint( crb_get_settings( 'attempts' ) );
2630
- }
2631
-
2632
- if ( $check_acl && crb_acl_is_white( $ip ) ) {
2633
- return $allowed; // whitelist = infinity attempts
2634
- }
2635
-
2636
- if ( ! $period ) {
2637
- $period = absint( crb_get_settings( 'period' ) );
2638
- }
2639
-
2640
- $range = time() - $period * 60;
2641
- $in = implode( ',', array_filter( array_map( 'absint', $activity ) ) );
2642
- $attempts = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity IN (' . $in . ') AND stamp > ' . $range );
2643
-
2644
- if ( ! $attempts ) {
2645
- return $allowed;
2646
- }
2647
- else {
2648
- $ret = $allowed - $attempts;
2649
- }
2650
- $ret = $ret < 0 ? 0 : $ret;
2651
-
2652
- return $ret;
2653
- }
2654
-
2655
- /**
2656
- * Is a given IP is allowed to do restricted things?
2657
- * Here Cerber makes its decision.
2658
- *
2659
- * @param string $ip IP address
2660
- * @param array $allowed a list of reason ids @since 7.5.2
2661
- *
2662
- * @return bool
2663
- */
2664
- function cerber_is_allowed( $ip = '', $allowed = array() ) {
2665
-
2666
- if ( ! $ip ) {
2667
- $wp_cerber = get_wp_cerber();
2668
- $ip = $wp_cerber->getRemoteIp();
2669
- }
2670
- elseif ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2671
- return false;
2672
- }
2673
-
2674
- // @since 7.5.2
2675
- $tag = cerber_acl_check( $ip );
2676
- if ( $tag == 'W' ) {
2677
- return true;
2678
- }
2679
- if ( $tag == 'B' ) {
2680
- return false;
2681
- }
2682
-
2683
- // @since 4.7.9
2684
- if ( $b = cerber_get_block( $ip ) ) {
2685
- if ( empty( $allowed ) ) {
2686
- return false;
2687
- }
2688
- elseif ( ! in_array( $b->reason_id, $allowed ) ) {
2689
- return false;
2690
- }
2691
- }
2692
-
2693
- /* @since 4.7.9
2694
- if ( cerber_block_check( $ip ) ) {
2695
- return false;
2696
- }*/
2697
-
2698
- if ( cerber_is_citadel() ) {
2699
- return false;
2700
- }
2701
-
2702
- if ( lab_is_blocked( $ip, false ) ) {
2703
- return false;
2704
- }
2705
-
2706
- return true;
2707
- }
2708
-
2709
- /**
2710
- * Check if a given username is not permitted to login or register
2711
- *
2712
- * @param $username string
2713
- *
2714
- * @return bool true if username is prohibited
2715
- */
2716
- function cerber_is_prohibited( $username ) {
2717
- if ( ! $username ) {
2718
- return false;
2719
- }
2720
-
2721
- if ( $list = (array) crb_get_settings( 'prohibited' ) ) {
2722
- foreach ( $list as $item ) {
2723
- if ( mb_substr( $item, 0, 1 ) == '/' && mb_substr( $item, - 1 ) == '/' ) {
2724
- $pattern = trim( $item, '/' );
2725
- if ( @mb_ereg_match( $pattern, $username, 'i' ) ) {
2726
- return true;
2727
- }
2728
- }
2729
- elseif ($username === $item){
2730
- return true;
2731
- }
2732
- }
2733
- }
2734
-
2735
- return false;
2736
- }
2737
-
2738
- // TODO: Merge with $wp_cerber->getStatus();
2739
- function cerber_get_status( $ip ) {
2740
- global $cerber_status;
2741
-
2742
- if ( ! empty( $cerber_status ) ) {
2743
- return absint($cerber_status);
2744
- }
2745
-
2746
- if ( cerber_block_check( $ip ) ) {
2747
- return 13;
2748
- }
2749
-
2750
- $tag = cerber_acl_check( $ip );
2751
- if ( $tag == 'W' ) {
2752
- return 0;
2753
- }
2754
- if ( $tag == 'B' ) {
2755
- return 14;
2756
- }
2757
-
2758
- if ( cerber_is_citadel() ) {
2759
- return 12;
2760
- }
2761
-
2762
- if ( lab_is_blocked( $ip, false ) ) {
2763
- return 15;
2764
- }
2765
-
2766
-
2767
- return 0;
2768
- }
2769
-
2770
- // Access lists (ACL) routines --------------------------------------------------------------------------------
2771
-
2772
- // TODO: move to dashboard.php
2773
- /**
2774
- * Add IP to specified access list
2775
- *
2776
- * @param $ip string|array single IP address, string with IP network, range or associative range array
2777
- * @param $tag string 'B'|'W'
2778
- *
2779
- * @return bool|int|object Result of operation
2780
- */
2781
- function cerber_acl_add( $ip, $tag, $comment = '') {
2782
- global $wpdb;
2783
- if ( is_string( $ip ) ) {
2784
- if ( ! cerber_is_ipv4( $ip ) ) {
2785
- $ip = cerber_short_ipv6( $ip );
2786
- }
2787
- if ( cerber_db_get_var( $wpdb->prepare( 'SELECT COUNT(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s', $ip ) ) ) {
2788
- return false; //__( 'Element is already in list', 'wp-cerber' );
2789
- }
2790
- $range = cerber_any2range( $ip );
2791
- if ( is_array( $range ) ) {
2792
- $begin = $range['begin'];
2793
- $end = $range['end'];
2794
- }
2795
- else {
2796
- if (cerber_is_ipv4($ip)) {
2797
- $begin = ip2long( $ip );
2798
- $end = ip2long( $ip );
2799
- }
2800
- else{
2801
- $begin = 0;
2802
- $end = 0;
2803
- }
2804
- }
2805
-
2806
- $result = $wpdb->insert( CERBER_ACL_TABLE, array( 'ip' => $ip,
2807
- 'ip_long_begin' => $begin,
2808
- 'ip_long_end' => $end,
2809
- 'tag' => $tag,
2810
- 'comments' => $comment
2811
- ), array( '%s', '%d', '%d', '%s', '%s' ) );
2812
- return $result;
2813
- }
2814
- elseif ( is_array( $ip ) ) {
2815
- $range = $ip['range'];
2816
- $begin = $ip['begin'];
2817
- $end = $ip['end'];
2818
- if ( cerber_db_get_var( $wpdb->prepare( 'SELECT COUNT(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = %d AND ip_long_end = %d', $begin, $end ) ) ) {
2819
- return false;
2820
- }
2821
-
2822
- $result = $wpdb->insert( CERBER_ACL_TABLE, array( 'ip' => $range,
2823
- 'ip_long_begin' => $begin,
2824
- 'ip_long_end' => $end,
2825
- 'tag' => $tag,
2826
- 'comments' => $comment
2827
- ), array( '%s', '%d', '%d', '%s', '%s' ) );
2828
-
2829
- return $result;
2830
-
2831
- //return $wpdb->query( $wpdb->prepare( 'INSERT INTO ' . CERBER_ACL_TABLE . ' (ip, ip_long_begin, ip_long_end, tag) VALUES (%s,%d,%d,%s)', $range, $begin, $end, $tag ) );
2832
- }
2833
-
2834
- return false;
2835
- }
2836
- // TODO: move to dashboard.php
2837
- function cerber_add_white( $ip, $comment = '' ) {
2838
- return cerber_acl_add( $ip, 'W', $comment );
2839
- }
2840
- // TODO: move to dashboard.php
2841
- function cerber_add_black( $ip, $comment = '') {
2842
- return cerber_acl_add( $ip, 'B', $comment );
2843
- }
2844
- // TODO: move to dashboard.php
2845
- function cerber_acl_remove( $ip ) {
2846
- global $wpdb;
2847
- if ( is_string( $ip ) ) {
2848
- return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s ', $ip ) );
2849
- } elseif ( is_array( $ip ) ) {
2850
- return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = %d AND ip_long_end = %d', $ip['begin'], $ip['end'] ) );
2851
- }
2852
-
2853
- return false;
2854
- }
2855
-
2856
- // TODO: move to dashboard.php
2857
- /**
2858
- * Can a given IP (user input) be added to the blacklist
2859
- *
2860
- * @param $ip
2861
- * @param string $list
2862
- *
2863
- * @return bool
2864
- */
2865
- function cerber_can_be_listed( $ip, $list = 'B' ) {
2866
- global $wp_cerber;
2867
- if ( $list == 'B' ) {
2868
- if ( crb_acl_is_white( $wp_cerber->getRemoteIp() ) ) {
2869
- return true;
2870
- }
2871
- if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2872
- if ( cerber_is_myip( $ip ) ) {
2873
- return false;
2874
- }
2875
- }
2876
- $range = cerber_any2range( $ip );
2877
- if ( cerber_is_ip_in_range( $range ) ) {
2878
- return false;
2879
- }
2880
-
2881
- return true;
2882
- }
2883
-
2884
- return true;
2885
- }
2886
-
2887
- /**
2888
- * Is an IP whitelisted?
2889
- *
2890
- * @param $ip string
2891
- *
2892
- * @return bool
2893
- */
2894
- function crb_acl_is_white( $ip = null ){
2895
-
2896
- if ( cerber_acl_check( $ip, 'W' ) ) {
2897
- return true;
2898
- }
2899
-
2900
- return false;
2901
- }
2902
-
2903
- /**
2904
- * Is an IP blacklisted?
2905
- *
2906
- * @param $ip string
2907
- *
2908
- * @return bool
2909
- */
2910
- function crb_acl_is_black( $ip = '' ) {
2911
- $tag = cerber_acl_check( $ip );
2912
- if ( $tag === 'W' ) {
2913
- return false;
2914
- }
2915
- elseif ( $tag === 'B' ) {
2916
- return true;
2917
- }
2918
-
2919
- return false;
2920
- }
2921
-
2922
- /**
2923
- * Check ACLs for given IP. Some extra lines for performance reason.
2924
- *
2925
- * @param string $ip
2926
- * @param string $tag
2927
- *
2928
- * @return bool|string
2929
- */
2930
- function cerber_acl_check( $ip = null, $tag = '' ) {
2931
- global $wp_cerber;
2932
- static $cache;
2933
-
2934
- if ( ! $ip ) {
2935
- $wp_cerber = get_wp_cerber();
2936
- $ip = $wp_cerber->getRemoteIp();
2937
- //$ip = cerber_get_remote_ip();
2938
- }
2939
-
2940
- $key = cerber_get_id_ip( $ip ) . (string)$tag;
2941
-
2942
- if ( isset( $cache[ $key ] ) ) {
2943
- return $cache[ $key ];
2944
- }
2945
-
2946
- if ( ! cerber_is_ipv4( $ip ) ) {
2947
- $ret = cerber_acl_checkV6( $ip, $tag );
2948
- $cache[ $key ] = $ret;
2949
- return $ret;
2950
- }
2951
-
2952
- $long = ip2long( $ip );
2953
-
2954
- if ( $tag ) {
2955
- if ( $tag !== 'W' && $tag !== 'B' ) {
2956
- $ret = false;
2957
- }
2958
- elseif ( cerber_db_get_var( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= '.$long.' AND '.$long.' <= ip_long_end AND tag = "'.$tag.'" LIMIT 1' ) ) {
2959
- $ret = true;
2960
- }
2961
- else {
2962
- $ret = false;
2963
- }
2964
-
2965
- $cache[ $key ] = $ret;
2966
- return $ret;
2967
- }
2968
- else {
2969
- // We use two queries because of possible overlapping an IP and its network
2970
- if ( $ret = cerber_db_get_var( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= ' . $long . ' AND ' . $long . ' <= ip_long_end AND tag = "W" LIMIT 1' ) ) {
2971
- $cache[ $key ] = $ret;
2972
- return $ret;
2973
- }
2974
- if ( $ret = cerber_db_get_var( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= ' . $long . ' AND ' . $long . ' <= ip_long_end AND tag = "B" LIMIT 1' ) ) {
2975
- $cache[ $key ] = $ret;
2976
- return $ret;
2977
- }
2978
-
2979
- $cache[ $key ] = false;
2980
- return false;
2981
- }
2982
- }
2983
-
2984
- /**
2985
- * IPv6 version of cerber_acl_check() without subnets and ranges
2986
- *
2987
- * @param null $ip
2988
- * @param string $tag
2989
- *
2990
- * @return bool|null|string
2991
- */
2992
- function cerber_acl_checkV6( $ip = null, $tag = '' ) {
2993
- global $wp_cerber;
2994
-
2995
- if ( ! $ip ) {
2996
- //$ip = $wp_cerber->getRemoteIp();
2997
- $ip = cerber_get_remote_ip();
2998
- }
2999
- elseif ( ! cerber_is_ip( $ip ) ) {
3000
- return false;
3001
- }
3002
-
3003
- if ( $tag ) {
3004
- if ( $tag != 'W' && $tag != 'B' ) {
3005
- return false;
3006
- }
3007
- if ( cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip = "' . $ip . '" AND tag = "' . $tag . '"' ) ) {
3008
- return true;
3009
- }
3010
-
3011
- return false;
3012
- }
3013
- else {
3014
- if ( $ret = cerber_db_get_var( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip = "' . $ip . '"' ) ) {
3015
- return $ret;
3016
- }
3017
-
3018
- return false;
3019
- }
3020
- }
3021
-
3022
- /*
3023
- * Logging directly to the file
3024
- *
3025
- * CERBER_FAIL_LOG optional, full path including filename to the log file
3026
- * CERBER_LOG_FACILITY optional, use to specify what type of program is logging the messages
3027
- *
3028
- * */
3029
- function cerber_file_log( $user_login, $ip ) {
3030
- if ( defined( 'CERBER_FAIL_LOG' ) ) {
3031
- if ( $log = @fopen( CERBER_FAIL_LOG, 'a' ) ) {
3032
- $pid = absint( @posix_getpid() );
3033
- @fwrite( $log, date( 'M j H:i:s ' ) . $_SERVER['SERVER_NAME'] . ' Cerber(' . $_SERVER['HTTP_HOST'] . ')[' . $pid . ']: Authentication failure for ' . $user_login . ' from ' . $ip . "\n" );
3034
- @fclose( $log );
3035
- }
3036
- } else {
3037
- @openlog( 'Cerber(' . $_SERVER['HTTP_HOST'] . ')', LOG_NDELAY | LOG_PID, defined( 'CERBER_LOG_FACILITY' ) ? CERBER_LOG_FACILITY : LOG_AUTH );
3038
- @syslog( LOG_NOTICE, 'Authentication failure for ' . $user_login . ' from ' . $ip );
3039
- @closelog();
3040
- }
3041
- }
3042
-
3043
- /*
3044
- Return wildcard - string like subnet Class C
3045
- */
3046
- function cerber_get_subnet( $ip ) {
3047
- return preg_replace( '/\.\d{1,3}$/', '.*', $ip );
3048
- }
3049
-
3050
- /*
3051
- Check if given IP address or wildcard or CIDR is valid
3052
- */
3053
- function cerber_is_ip_or_net( $ip ) {
3054
- if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
3055
- return true;
3056
- }
3057
- // WILDCARD: 192.168.1.*
3058
- $ip = str_replace( '*', '0', $ip );
3059
- //if ( @inet_pton( $ip ) ) {
3060
- if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
3061
- return true;
3062
- }
3063
- // CIDR: 192.168.1/24
3064
- if ( strpos( $ip, '/' ) ) {
3065
- $cidr = explode( '/', $ip );
3066
- $net = $cidr[0];
3067
- $mask = absint( $cidr[1] );
3068
- $dots = substr_count( $net, '.' );
3069
- if ( $dots < 3 ) {
3070
- if ( $dots == 1 ) {
3071
- $net .= '.0.0';
3072
- } elseif ( $dots == 2 ) {
3073
- $net .= '.0';
3074
- }
3075
- }
3076
- if ( ! cerber_is_ipv4( $net ) ) {
3077
- return false;
3078
- }
3079
- if ( ! is_numeric( $mask ) ) {
3080
- return false;
3081
- }
3082
-
3083
- return true;
3084
- }
3085
-
3086
- return false;
3087
- }
3088
-
3089
- /**
3090
- * Tries to recognize single IP address or IP v4 range (with dash) in a given string.
3091
- *
3092
- * @param string $string String to recognize IP address in
3093
- *
3094
- * @return array|bool|string Return single IP address or wildcard or CIDR as a string, and IP range as an array.
3095
- */
3096
- function cerber_parse_ip( $string = '' ) {
3097
- $string = trim( $string );
3098
- if ( cerber_is_ip_or_net( $string ) ) {
3099
- return $string;
3100
- }
3101
- $explode = explode( '-', $string );
3102
- if ( ! is_array( $explode ) || ! $explode ) {
3103
- return false;
3104
- }
3105
- $range = array();
3106
- $count = 0;
3107
- foreach ( $explode as $ip ) {
3108
- $ip = trim( $ip );
3109
- if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
3110
- $range[] = $ip;
3111
- $count ++;
3112
- if ( $count >= 2 ) {
3113
- break;
3114
- }
3115
- }
3116
- }
3117
- if ( count( $range ) < 2 ) {
3118
- return false;
3119
- }
3120
- if ( ip2long( $range[1] ) <= ip2long( $range[0] ) ) {
3121
- return false;
3122
- }
3123
-
3124
- return array(
3125
- 'range' => $range[0] . ' - ' . $range[1],
3126
- 'begin_ip' => $range[0],
3127
- 'end_ip' => $range[1],
3128
- 'begin' => ip2long( $range[0] ),
3129
- 'end' => ip2long( $range[1] ),
3130
- );
3131
- }
3132
-
3133
- /**
3134
- * Convert a network wildcard string like x.x.x.* to an IP v4 range
3135
- *
3136
- * @param $wildcard string
3137
- *
3138
- * @return array|bool|string False if no wildcard found, otherwise result of cerber_parse_ip()
3139
- */
3140
- function cerber_wildcard2range( $wildcard = '' ) {
3141
- $begin = str_replace( '*', '0', $wildcard );
3142
- $end = str_replace( '*', '255', $wildcard );
3143
- if ( ! cerber_is_ipv4( $begin ) ) {
3144
- return false;
3145
- }
3146
- if ( ! cerber_is_ipv4( $end ) ) {
3147
- return false;
3148
- }
3149
-
3150
- return cerber_parse_ip( $begin . ' - ' . $end );
3151
- }
3152
-
3153
- /**
3154
- * Convert a CIDR to an IP v4 range
3155
- *
3156
- * @param $cidr string
3157
- *
3158
- * @return array|bool|string
3159
- */
3160
- function cerber_cidr2range( $cidr = '' ) {
3161
- if ( ! strpos( $cidr, '/' ) ) {
3162
- return false;
3163
- }
3164
- $cidr = explode( '/', $cidr );
3165
- $net = $cidr[0];
3166
- $mask = absint( $cidr[1] );
3167
- $dots = substr_count( $net, '.' );
3168
- if ( $dots < 3 ) { // not completed CIDR
3169
- if ( $dots == 1 ) {
3170
- $net .= '.0.0';
3171
- } elseif ( $dots == 2 ) {
3172
- $net .= '.0';
3173
- }
3174
- }
3175
- if ( ! cerber_is_ipv4( $net ) ) {
3176
- return false;
3177
- }
3178
- if ( ! is_numeric( $mask ) ) {
3179
- return false;
3180
- }
3181
- $begin = long2ip( ( ip2long( $net ) ) & ( ( - 1 << ( 32 - (int) $mask ) ) ) );
3182
- $end = long2ip( ( ip2long( $net ) ) + pow( 2, ( 32 - (int) $mask ) ) - 1 );
3183
-
3184
- return cerber_parse_ip( $begin . ' - ' . $end );
3185
- }
3186
-
3187
- /**
3188
- * Try to recognize an IP range or a single IP in a string.
3189
- *
3190
- * @param $string string Network wildcard, CIDR or IP range.
3191
- *
3192
- * @return array|bool|string
3193
- */
3194
- function cerber_any2range( $string = '' ) {
3195
- // Do not change the order!
3196
- $ret = cerber_wildcard2range( $string );
3197
- if ( ! $ret ) {
3198
- $ret = cerber_cidr2range( $string );
3199
- }
3200
- if ( ! $ret ) {
3201
- $ret = cerber_parse_ip( $string ); // must be last due to checking for cidr and wildcard
3202
- }
3203
-
3204
- return $ret;
3205
- }
3206
-
3207
- /*
3208
- Check for given IP address or subnet belong to this session.
3209
- */
3210
- function cerber_is_myip( $ip ) {
3211
- global $wp_cerber;
3212
- if ( ! is_string( $ip ) ) {
3213
- return false;
3214
- }
3215
- $remote_ip = $wp_cerber->getRemoteIp();
3216
- if ( $ip == $remote_ip ) {
3217
- return true;
3218
- }
3219
- if ( $ip == cerber_get_subnet( $remote_ip ) ) {
3220
- return true;
3221
- }
3222
-
3223
- return false;
3224
- }
3225
-
3226
- function cerber_is_ip_in_range( $range, $ip = null ) {
3227
- global $wp_cerber;
3228
- if ( ! is_array( $range ) ) {
3229
- return false;
3230
- }
3231
- if ( ! $ip ) {
3232
- $ip = $wp_cerber->getRemoteIp();
3233
- }
3234
- $long = ip2long( $ip );
3235
- if ( $range['begin'] <= $long && $long <= $range['end'] ) {
3236
- return true;
3237
- }
3238
-
3239
- return false;
3240
- }
3241
-
3242
- /**
3243
- * Display 404 page to bump bots and bad guys
3244
- *
3245
- * @param bool $simple If true force displaying basic 404 page
3246
- */
3247
- function cerber_404_page($simple = false) {
3248
- global $wp_query;
3249
-
3250
- if ( !$simple ) {
3251
- if ( function_exists( 'status_header' ) ) {
3252
- status_header( '404' );
3253
- }
3254
- if ( isset( $wp_query ) && is_object( $wp_query ) ) {
3255
- $wp_query->set_404();
3256
- }
3257
- if ( 0 == crb_get_settings( 'page404' ) ) {
3258
- $template = null;
3259
- if ( function_exists( 'get_404_template' ) ) {
3260
- $template = get_404_template();
3261
- }
3262
- if ( function_exists( 'apply_filters' ) ) {
3263
- $template = apply_filters( 'cerber_404_template', $template );
3264
- }
3265
- if ( $template && @file_exists( $template ) ) {
3266
- include( $template );
3267
- exit;
3268
- }
3269
- }
3270
- }
3271
-
3272
- header( 'HTTP/1.0 404 Not Found', true, 404 );
3273
- echo '<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL ' . esc_url( $_SERVER['REQUEST_URI'] ) . ' was not found on this server.</p></body></html>';
3274
- cerber_traffic_log(); // do not remove!
3275
- exit;
3276
- }
3277
- /*
3278
- Display Forbidden page
3279
- */
3280
- function cerber_forbidden_page() {
3281
- status_header( '403' );
3282
- header( 'HTTP/1.0 403 Access Forbidden', true, 403 );
3283
- ?>
3284
- <!DOCTYPE html>
3285
- <html style="height: 100%;">
3286
- <meta charset="UTF-8">
3287
- <head><title>403 Access Forbidden</title></head>
3288
- <body style="height: 100%;">
3289
- <div style="display: flex; align-items: center; justify-content: center; height: 70%;">
3290
- <div style="background-color: #eee; width: 70%; border: solid 3px #ddd; padding: 1.5em 3em 3em 3em; font-family: Arial, Helvetica, sans-serif;">
3291
- <div style="display: table-row;">
3292
- <div style="display: table-cell; font-size: 150px; color: red; vertical-align: middle; padding-right: 50px;">
3293
- &#9995;
3294
- </div>
3295
- <div style="display: table-cell; vertical-align: middle;">
3296
- <h1><?php _e("We're sorry, you are not allowed to proceed", 'wp-cerber'); ?></h1>
3297
- <p>Our server stopped processing your request. Your request looks suspicious or similar to automated
3298
- requests from spam posting software.</p>
3299
- <p>If you believe you should be able to perform this request, please let us know.</p>
3300
- </div>
3301
- </div>
3302
- </div>
3303
- </div>
3304
- </body>
3305
- </html>
3306
- <?php
3307
- cerber_traffic_log(); // do not remove!
3308
- exit;
3309
- }
3310
-
3311
- // Citadel mode -------------------------------------------------------------------------------------
3312
-
3313
- function cerber_enable_citadel() {
3314
- global $wp_cerber;
3315
- if ( get_transient( 'cerber_citadel' ) ) {
3316
- return;
3317
- }
3318
- set_transient( 'cerber_citadel', true, crb_get_settings( 'ciduration' ) * 60 );
3319
- cerber_log( 12 );
3320
-
3321
- // Notify admin
3322
- if ( $wp_cerber->getSettings( 'cinotify' ) ) {
3323
- cerber_send_email( 'citadel' );
3324
- }
3325
- }
3326
-
3327
- function cerber_disable_citadel() {
3328
- delete_transient( 'cerber_citadel' );
3329
- }
3330
-
3331
- function cerber_is_citadel() {
3332
- if ( get_transient( 'cerber_citadel' ) ) {
3333
- return true;
3334
- }
3335
-
3336
- return false;
3337
- }
3338
-
3339
- // Hardening -------------------------------------------------------------------------------------
3340
-
3341
- //if (!cerber_acl_check(cerber_get_ip(),'W') && false) {
3342
-
3343
- /*
3344
- if ($hardening['ping']) {
3345
- add_filter( 'xmlrpc_methods', 'remove_xmlrpc_pingback' );
3346
- function remove_xmlrpc_pingback( $methods ) {
3347
- unset($methods['pingback.ping']);
3348
- unset($methods['pingback.extensions.getPingbacks']);
3349
- return $methods;
3350
- }
3351
- add_filter( 'wp_headers', 'remove_pingback_header' );
3352
- function remove_pingback_header( $headers ) {
3353
- unset( $headers['X-Pingback'] );
3354
- return $headers;
3355
- }
3356
- }
3357
- */
3358
- //pingback_ping();
3359
-
3360
-
3361
- /*
3362
- // Remove shortlink from HEAD <link rel='shortlink' href='http://адрес-сайта/?p=45' />
3363
- remove_action('wp_head', 'wp_shortlink_wp_head', 10, 0 );
3364
- */
3365
-
3366
- /**
3367
- *
3368
- * Send notification letter
3369
- *
3370
- * @param string $type Notification type
3371
- * @param string|array $msg Additional message
3372
- * @param string $ip Remote IP address, if applicable
3373
- *
3374
- * @return bool
3375
- */
3376
- function cerber_send_email( $type = '', $msg = '', $ip = '' ) {
3377
- global $wp_cerber;
3378
- if ( ! $type ) {
3379
- return false;
3380
- }
3381
-
3382
- /*
3383
- $super = false;
3384
- if ( function_exists( 'is_super_admin' ) ) {
3385
- $super = is_super_admin();
3386
- }
3387
- if ( $type == 'lockout' && !$usper()) {
3388
- */
3389
-
3390
- if ( $type == 'lockout' && ! is_admin() ) {
3391
- $rate = absint( $wp_cerber->getSettings( 'emailrate' ) );
3392
- if ( $rate ) {
3393
- $last_em = cerber_get_set( '_cerber_last', 1, false );
3394
- $period = 60 * 60; // per hour
3395
- if ( $last_em ) {
3396
- if ( $last_em > ( time() - $period / $rate ) ) {
3397
- return false;
3398
- }
3399
- }
3400
- cerber_update_set( '_cerber_last', time(), 1, false, time() + $period );
3401
- }
3402
- }
3403
-
3404
- $html_mode = false;
3405
-
3406
- $subj = '[' . get_option( 'blogname' ) . '] ' . __( 'WP Cerber notify', 'wp-cerber' ) . ': ';
3407
- $body = '';
3408
-
3409
- if ( is_array( $msg ) ) {
3410
- $msg = implode( "\n\n", $msg );
3411
- }
3412
-
3413
- $last = null;
3414
-
3415
- switch ( $type ) {
3416
- case 'citadel':
3417
- $max = cerber_db_get_var( 'SELECT MAX(stamp) FROM ' . CERBER_LOG_TABLE . ' WHERE activity = 7' );
3418
- if ( $max ) {
3419
- $last_date = cerber_date( $max );
3420
- //$last = $wpdb->get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE stamp = ' . $max . ' AND activity = 7' );
3421
- $last = cerber_db_get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE stamp = ' . $max . ' AND activity = 7', MYSQL_FETCH_OBJECT );
3422
- }
3423
-
3424
- if ( ! $last ) { // workaround for the empty log table
3425
- $last = new stdClass();
3426
- $last->ip = CERBER_NO_REMOTE_IP;
3427
- $last->user_login = 'test';
3428
- }
3429
-
3430
- $subj .= __( 'Citadel mode is activated', 'wp-cerber' );
3431
-
3432
- $body = sprintf( __( 'Citadel mode is activated after %d failed login attempts in %d minutes.', 'wp-cerber' ), $wp_cerber->getSettings( 'cilimit' ), $wp_cerber->getSettings( 'ciperiod' ) ) . "\n\n";
3433
- $body .= sprintf( __( 'Last failed attempt was at %s from IP %s with user login: %s.', 'wp-cerber' ), $last_date, $last->ip, $last->user_login ) . "\n\n";
3434
- $body .= __( 'View activity in dashboard', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . "\n\n";
3435
- //$body .= __('Change notification settings','wp-cerber').': '.cerber_admin_link();
3436
- break;
3437
- case 'lockout':
3438
- $max = cerber_db_get_var( 'SELECT MAX(stamp) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (10,11)' );
3439
- if ( $max ) {
3440
- $last_date = cerber_date( $max );
3441
- $last = cerber_db_get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE stamp = ' . $max . ' AND activity IN (10,11)', MYSQL_FETCH_OBJECT );
3442
- }
3443
-
3444
- if ( ! $last ) { // workaround for the empty log table
3445
- $last = new stdClass();
3446
- $last->ip = CERBER_NO_REMOTE_IP;
3447
- $last->user_login = 'test';
3448
- }
3449
-
3450
- if ( ! $active = cerber_blocked_num() ) {
3451
- $active = 0;
3452
- }
3453
-
3454
- if ( $last->ip && ( $block = cerber_get_block( $last->ip ) ) ) {
3455
- $reason = $block->reason;
3456
- }
3457
- else {
3458
- $reason = __( 'unspecified', 'wp-cerber' );
3459
- }
3460
-
3461
- $subj .= __( 'Number of lockouts is increasing', 'wp-cerber' ) . ' (' . $active . ')';
3462
-
3463
- $body = __( 'Number of active lockouts', 'wp-cerber' ) . ': ' . $active . "\n\n";
3464
- $body .= sprintf( __( 'Last lockout was added: %s for IP %s', 'wp-cerber' ), $last_date, $last->ip . ' (' . @gethostbyaddr( $last->ip ) . ')' ) . "\n\n";
3465
- $body .= __( 'Reason', 'wp-cerber' ) . ': ' . strip_tags($reason) . "\n\n";
3466
- $body .= __( 'View activity for this IP', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . '&filter_ip=' . $last->ip . "\n\n";
3467
- $body .= __( 'View lockouts in dashboard', 'wp-cerber' ) . ': ' . cerber_admin_link( 'lockouts' ) . "\n\n";
3468
- break;
3469
- case 'new_version':
3470
- $subj = __( 'A new version of WP Cerber is available to install', 'wp-cerber' );
3471
- $body = __( 'Hi!', 'wp-cerber' ) . "\n\n";
3472
- $body .= __( 'A new version of WP Cerber is available to install', 'wp-cerber' ) . "\n\n";
3473
- $body .= $msg . "\n\n";
3474
- $body .= __( 'Website', 'wp-cerber' ) . ': ' . crb_get_bloginfo( 'name' );
3475
- break;
3476
- case 'shutdown':
3477
- $subj = '[' . get_option( 'blogname' ) . '] ' . __( 'The WP Cerber security plugin has been deactivated', 'wp-cerber' );
3478
- $body .= __( 'The WP Cerber security plugin has been deactivated', 'wp-cerber' ) . "\n\n";
3479
- if ( ! is_user_logged_in() ) {
3480
- $u = __( 'Not logged in', 'wp-cerber' );
3481
- } else {
3482
- $user = wp_get_current_user();
3483
- $u = $user->display_name;
3484
- }
3485
- $body .= __( 'Website', 'wp-cerber' ) . ': ' . crb_get_bloginfo( 'name' ) . "\n";
3486
- $body .= __( 'By user', 'wp-cerber' ) . ': ' . $u . "\n";
3487
- $body .= __( 'From IP address', 'wp-cerber' ) . ': ' . $wp_cerber->getRemoteIp() . "\n";
3488
- $whois = cerber_ip_whois_info( $wp_cerber->getRemoteIp() );
3489
- if ( ! empty( $whois['data']['country'] ) ) {
3490
- $body .= __( 'From country', 'wp-cerber' ) . ': ' . cerber_country_name( $whois['data']['country'] );
3491
- }
3492
- break;
3493
- case 'activated':
3494
- $subj = '[' . get_option( 'blogname' ) . '] ' . __( 'The WP Cerber security plugin is now active', 'wp-cerber' );
3495
- $body .= __( 'WP Cerber is now active and has started protecting your site', 'wp-cerber' ) . "\n\n";
3496
- //$body .= __( 'Change notification settings', 'wp-cerber' ) . ': ' . cerber_admin_link('notifications') . "\n\n";
3497
- $body .= __( 'Getting Started Guide', 'wp-cerber' ) . "\n\n";
3498
- $body .= 'https://wpcerber.com/getting-started/' . "\n\n";
3499
- $body .= 'Be in touch with the developer. Subscribe to Cerber\'s newsletter: http://wpcerber.com/subscribe-newsletter/';
3500
- break;
3501
- case 'newlurl':
3502
- $subj .= __( 'New Custom login URL', 'wp-cerber' );
3503
- $body .= $msg;
3504
- break;
3505
- case 'subs':
3506
- $subj .= __( 'A new activity has been recorded', 'wp-cerber' );
3507
- $body = __( 'A new activity has been recorded', 'wp-cerber' ) . "\n\n";
3508
- $body .= $msg;
3509
- break;
3510
- case 'report':
3511
- $html_mode = true;
3512
- $subj = '[' . get_option( 'blogname' ) . '] WP Cerber Security: ' . __( 'Weekly report', 'wp-cerber' );
3513
- $body = cerber_generate_report();
3514
- $link = cerber_admin_link( 'notifications' );
3515
- $body .= '<br/>' . __( 'To change reporting settings visit', 'wp-cerber' ) . ' <a href="' . $link . '">' . $link . '</a>';
3516
- if ($msg) {
3517
- $body .= nl2br($msg);
3518
- }
3519
- break;
3520
- case 'scan':
3521
- $html_mode = true;
3522
- $subj = '[' . get_option( 'blogname' ) . '] WP Cerber Security: ' . __( 'Scanner Report', 'wp-cerber' );
3523
- $body = $msg;
3524
- $link = cerber_admin_link( 'scan_schedule' );
3525
- $body .= '<br/>' . __( 'To change reporting settings visit', 'wp-cerber' ) . ' <a href="' . $link . '">' . $link . '</a>';
3526
- break;
3527
- }
3528
-
3529
- $to_list = cerber_get_email( $type, true );
3530
- $to = implode( ', ', $to_list );
3531
-
3532
- $body_filtered = apply_filters( 'cerber_notify_body', $body, array( 'type' => $type,
3533
- 'IP' => $ip,
3534
- 'to' => $to,
3535
- 'subject' => $subj
3536
- ) );
3537
- if ( $body_filtered && is_string( $body_filtered ) ) {
3538
- $body = $body_filtered;
3539
- }
3540
-
3541
- $footer = '';
3542
-
3543
- if ( $lolink = cerber_get_login_url() ) {
3544
- $lourl = urldecode( $lolink );
3545
- if ( $html_mode ) {
3546
- $lourl = '<a href="' . $lolink . '">' . $lourl . '</a>';
3547
- }
3548
- $footer .= "\n\n" . __( 'Your login page:', 'wp-cerber' ) . ' ' . $lourl;
3549
- }
3550
-
3551
- if ( $type == 'report' && $date = lab_lab(true) ) {
3552
- $footer .= "\n\n" . __( 'Your license is valid until', 'wp-cerber' ) . ' ' . $date;
3553
- }
3554
-
3555
- $footer .= "\n\n\n" . __( 'This message was sent by', 'wp-cerber' ) . ' WP Cerber Security ' . CERBER_VER . "\n";
3556
- $footer .= 'https://wpcerber.com';
3557
-
3558
- if ( $html_mode ) {
3559
- add_filter( 'wp_mail_content_type', 'cerber_enable_html' );
3560
- $footer = str_replace( "\n", '<br/>', $footer );
3561
- }
3562
-
3563
- // Everything is prepared, let's send it out
3564
-
3565
- $result = null;
3566
- if ( $to && $subj && $body ) {
3567
- if ( ! $html_mode ) {
3568
- cerber_pb_send( $subj, $body.$footer );
3569
- }
3570
-
3571
- if ( $type == 'report') {
3572
- $result = true;
3573
- foreach ( $to_list as $email ) {
3574
- $lastus = '';
3575
- if ( $rec = cerber_get_last_login( null, $email ) ) {
3576
- $lastus = sprintf( __( 'Your last sign-in was %s from %s', 'wp-cerber' ), cerber_date( $rec->stamp ), $rec->ip . ' (' . cerber_country_name( $rec->country ) . ')' );
3577
- if ( $html_mode ) {
3578
- $lastus = '<br/><br/>' . $lastus;
3579
- }
3580
- else {
3581
- $lastus = "\n\n" . $lastus;
3582
- }
3583
- }
3584
-
3585
- if ( ! wp_mail( $email, $subj, '<html>' . $body . $lastus . $footer . '</html>' ) ) {
3586
- $result = false;
3587
- }
3588
- }
3589
- }
3590
- else {
3591
- if ( function_exists( 'wp_mail' ) ) {
3592
- $body = $body . $footer;
3593
- if ( $html_mode ) {
3594
- $body = '<html>' . $body . '</html>';
3595
- }
3596
- $result = wp_mail( $to, $subj, $body );
3597
- }
3598
- }
3599
- }
3600
-
3601
- remove_filter('wp_mail_content_type', 'cerber_enable_html');
3602
-
3603
- $params = array( 'type' => $type, 'IP' => $ip, 'to' => $to, 'subject' => $subj );
3604
- if ( $result ) {
3605
- do_action( 'cerber_notify_sent', $body, $params );
3606
- }
3607
- else {
3608
- do_action( 'cerber_notify_fail', $body, $params );
3609
- }
3610
-
3611
- return $result;
3612
- }
3613
-
3614
- function cerber_enable_html() {
3615
- return 'text/html';
3616
- }
3617
-
3618
- /**
3619
- * Generates a performance report
3620
- *
3621
- * @param int $period Days to look back
3622
- *
3623
- * @return string
3624
- */
3625
- function cerber_generate_report($period = 7){
3626
- global $wpdb;
3627
-
3628
- $period = absint( $period );
3629
-
3630
- if ( ! $period ) {
3631
- $period = 7;
3632
- }
3633
-
3634
- $ret = '';
3635
- $rows = array();
3636
- $stamp = time() - $period * 24 * 3600;
3637
- //$in = implode( ',', crb_get_activity_set( 'malicious' ) );
3638
- //$link_base = '<a href="' . cerber_activity_link( array( 2 ) ) . '">';
3639
- $base_url = cerber_admin_link( 'activity' );
3640
- $css_table = 'width: 95%; max-width: 1000px; margin:0 auto; margin-bottom: 10px; background-color: #f5f5f5; text-align: center; font-family: Arial, Helvetica, sans-serif;';
3641
- $css_td = 'padding: 0.5em 0.5em 0.5em 1em; text-align: left;';
3642
- $css_border = 'border-bottom: solid 2px #f9f9f9;';
3643
-
3644
- $site_name = ( is_multisite() ) ? get_site_option( 'site_name' ) : get_option( 'blogname' );
3645
-
3646
- $ret .= '<div style="' . $css_table . '"><div style="margin:0 auto; text-align: center;"><p style="font-size: 130%; padding-top: 0.5em;">' . $site_name .'</p><p style="padding-bottom: 1em;">'. __('Weekly Report','wp-cerber'). '</p></div></div>';
3647
-
3648
- $kpi_list = cerber_calculate_kpi( $period );
3649
-
3650
- foreach ($kpi_list as $kpi){
3651
- $rows[] = '<td style="'.$css_td.' text-align: right;">'.$kpi[1].'</td><td style="padding: 0.5em; text-align: left;">'.$kpi[0].'</td>';
3652
- }
3653
-
3654
- $ret .= '<div style="text-align: center; '.$css_table.'"><table style="font-size: 130%; margin:0 auto;"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table></div>';
3655
-
3656
- // Activities counters
3657
- $rows = array();
3658
- $rows[] = '<td style="'.$css_td.$css_border.'" colspan="2"><p style="line-height: 1.5em; font-weight: bold;">'.__('Activity details','wp-cerber').'</p></td>';
3659
- $activites = $wpdb->get_results( 'SELECT activity, COUNT(activity) cnt FROM ' . CERBER_LOG_TABLE . ' WHERE stamp > ' . $stamp . ' GROUP by activity ORDER BY cnt DESC' );
3660
- if ( $activites ) {
3661
- $lables = cerber_get_labels();
3662
- foreach ( $activites as $a ) {
3663
- $rows[] = '<td style="'.$css_border.$css_td.'">' . $lables[ $a->activity ] . '</td><td style="padding: 0.5em; text-align: center; width:10%;'.$css_border.'"><a href="'.$base_url.'&filter_activity='.$a->activity.'">' . $a->cnt . '</a></td>';
3664
- }
3665
- }
3666
- $ret .= '<table style="border-collapse: collapse; '.$css_table.'"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table>';
3667
-
3668
- // Activities counters
3669
- $activites = $wpdb->get_results( 'SELECT user_login, COUNT(user_login) cnt FROM ' . CERBER_LOG_TABLE . ' WHERE activity = 51 AND stamp > ' . $stamp . ' GROUP by user_login ORDER BY cnt DESC LIMIT 10' );
3670
- if ( $activites ) {
3671
- $rows = array();
3672
- $rows[] = '<td style="'.$css_td.$css_border.'" colspan="2"><p style="line-height: 1.5em; font-weight: bold;">'.__('Attempts to log in with non-existent username','wp-cerber').'</p></td>';
3673
- foreach ( $activites as $a ) {
3674
- $rows[] = '<td style="'.$css_border.$css_td.'">' . htmlspecialchars($a->user_login) . '</td><td style="padding: 0.5em; text-align: center; width:10%;'.$css_border.'"><a href="'.$base_url.'&filter_login='.$a->user_login.'">' . $a->cnt . '</a></td>';
3675
- }
3676
- $ret .= '<table style="border-collapse: collapse; '.$css_table.'"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table>';
3677
- }
3678
-
3679
- $ret = '<div style="width:100%; padding: 1em; text-align: center; background-color: #f9f9f9;">' . $ret . '</div>';
3680
-
3681
- return $ret;
3682
- }
3683
-
3684
-
3685
- // Maintenance routines ----------------------------------------------------------------
3686
-
3687
- function cerber_init_cron(){
3688
- $next_hour = intval( floor( ( time() + 3600 ) / 3600 ) * 3600 );
3689
-
3690
- if ( ! wp_next_scheduled( 'cerber_hourly_1' ) ) {
3691
- wp_schedule_event( $next_hour, 'hourly', 'cerber_hourly_1' );
3692
- }
3693
-
3694
- if ( ! wp_next_scheduled( 'cerber_hourly_2' ) ) {
3695
- wp_schedule_event( $next_hour + 600 , 'hourly', 'cerber_hourly_2' );
3696
- }
3697
-
3698
- if ( ! wp_next_scheduled( 'cerber_daily' ) ) {
3699
- wp_schedule_event( $next_hour + 1200, 'daily', 'cerber_daily' );
3700
- }
3701
- }
3702
-
3703
- add_action( 'cerber_hourly_1', 'cerber_do_hourly' );
3704
- function cerber_do_hourly( $force = false ) {
3705
- global $wpdb, $wp_cerber;
3706
-
3707
- $t = 'cerber_hourly_1';
3708
- $start = time();
3709
-
3710
- // Avoid multiple executions on a weird hosting
3711
- if ( ( $last = get_site_transient( $t ) ) && date( 'G', $last[0] ) == date( 'G' ) ) {
3712
- return;
3713
- }
3714
-
3715
- set_site_transient( $t, array( $start ), 2 * 3600 );
3716
-
3717
- if ( is_multisite() ) {
3718
- if ( ! $force && get_site_transient( 'cerber_multisite' ) ) {
3719
- return;
3720
- }
3721
- set_site_transient( 'cerber_multisite', 'executed', 3600 );
3722
- }
3723
-
3724
- $time = time();
3725
- $days = absint( crb_get_settings( 'keeplog' ) );
3726
- if ( $days > 0 ) {
3727
- $wpdb->query( 'DELETE FROM ' . CERBER_LOG_TABLE . ' WHERE stamp < ' . ( $time - $days * 24 * 3600 ) );
3728
- }
3729
- $days = absint( crb_get_settings( 'tikeeprec' ) );
3730
- if ( $days > 0 ) {
3731
- $wpdb->query( 'DELETE FROM ' . CERBER_TRAF_TABLE . ' WHERE stamp < ' . ( $time - $days * 24 * 3600 ) );
3732
- }
3733
-
3734
- $wpdb->query( 'DELETE FROM ' . CERBER_LAB_IP_TABLE . ' WHERE expires < ' . $time );
3735
-
3736
- if ( $wp_cerber->getSettings( 'trashafter-enabled') && absint($wp_cerber->getSettings('trashafter'))) {
3737
- $list = get_comments( array( 'status' => 'spam' ) );
3738
- if ( $list ) {
3739
- $time = time() - DAY_IN_SECONDS * absint($wp_cerber->getSettings( 'trashafter' ));
3740
- foreach ( $list as $item ) {
3741
- if ( $time > strtotime( $item->comment_date_gmt ) ) {
3742
- wp_trash_comment( $item->comment_ID );
3743
- }
3744
- }
3745
- }
3746
- }
3747
-
3748
- cerber_up_data();
3749
-
3750
- // Keep the size of the log file small
3751
- cerber_truncate_log();
3752
-
3753
- set_site_transient( $t, array( $start, time() ), 2 * 3600 );
3754
- }
3755
-
3756
- add_action( 'cerber_hourly_2', function () {
3757
- $t = 'cerber_hourly_2';
3758
- $start = time();
3759
-
3760
- if ( ( $last = get_site_transient( $t ) ) && date( 'G', $last[0] ) == date( 'G' ) ) {
3761
- return;
3762
- }
3763
-
3764
- set_site_transient( $t, array( $start ), 2 * 3600 );
3765
-
3766
- $gmt_offset = get_option( 'gmt_offset' ) * 3600;
3767
-
3768
- if ( crb_get_settings( 'enable-report' )
3769
- && date( 'w', time() + $gmt_offset ) == crb_get_settings( 'wreports-day' )
3770
- && date( 'G', time() + $gmt_offset ) == crb_get_settings( 'wreports-time' )
3771
- //&& ! get_site_transient( 'cerber_wreport' )
3772
- ) {
3773
- $result = cerber_send_email( 'report' );
3774
- //set_site_transient( 'cerber_wreport', 'sent', 7200 );
3775
- update_site_option( '_cerber_report', array( time(), $result ) );
3776
- }
3777
-
3778
- cerber_watchdog( true );
3779
-
3780
- if ( function_exists( 'cerber_delete_expired_set' ) ) {
3781
- cerber_delete_expired_set();
3782
- }
3783
-
3784
- // Cleanup the quarantine folder
3785
- if ( $dirs = glob( cerber_get_the_folder() . 'quarantine' . '/*', GLOB_ONLYDIR ) ) {
3786
- foreach ( $dirs as $dir ) {
3787
- $d = basename( $dir );
3788
- if ( is_numeric( $d ) ) {
3789
- if ( $d < ( time() - DAY_IN_SECONDS * crb_get_settings( 'scan_qcleanup' ) ) ) {
3790
- $fs = cerber_init_wp_filesystem();
3791
- if ( ! is_wp_error( $fs ) ) {
3792
- $fs->delete( $dir, true );
3793
- }
3794
- }
3795
- }
3796
- }
3797
- }
3798
-
3799
- if ( crb_get_settings( 'cerberlab' ) || lab_lab() ) {
3800
- lab_check_nodes( true, true );
3801
- }
3802
-
3803
- cerber_push_lab();
3804
-
3805
- cerber_cloud_sync();
3806
-
3807
- // Simply keep folder locked
3808
- cerber_get_the_folder();
3809
-
3810
- cerber_db_query( 'DELETE FROM ' . CERBER_QMEM_TABLE . ' WHERE stamp < ' . ( time() - 30 * 60 ) );
3811
-
3812
- set_site_transient( $t, array( $start, time() ), 2 * 3600 );
3813
- });
3814
-
3815
- add_action( 'cerber_daily', 'cerber_do_daily' );
3816
- function cerber_do_daily() {
3817
- $t = 'cerber_daily_1';
3818
- $start = time();
3819
- set_site_transient( $t, array( $start ), 48 * 3600 );
3820
-
3821
- cerber_do_hourly( true );
3822
-
3823
- $time = time();
3824
-
3825
- lab_validate_lic();
3826
-
3827
- cerber_db_query( 'DELETE FROM ' . CERBER_LAB_NET_TABLE . ' WHERE expires < ' . $time );
3828
- cerber_db_query( 'DELETE FROM ' . CERBER_LAB_TABLE . ' WHERE stamp < ' . ( $time - 3600 ) ); // workaround for weird/misconfigured hostings
3829
-
3830
- cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_LOG_TABLE );
3831
- cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_QMEM_TABLE );
3832
- cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_TRAF_TABLE );
3833
- cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_ACL_TABLE );
3834
- cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_BLOCKS_TABLE );
3835
- cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_LAB_TABLE );
3836
- cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_LAB_IP_TABLE );
3837
- cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_LAB_NET_TABLE );
3838
- cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_SCAN_TABLE );
3839
- cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_SETS_TABLE );
3840
-
3841
- if ( $new = cerber_check_version() ) {
3842
- $history = get_site_option( '_cerber_notify_new' );
3843
- if ( ! $history || ! is_array( $history ) ) {
3844
- $history = array();
3845
- }
3846
- if ( ! in_array( $new['ver'], $history ) ) {
3847
- if ( crb_get_settings( 'notify-new-ver' ) ) {
3848
- cerber_send_email( 'new_version', 'Read more: https://wpcerber.com/?plugin_version=' . $new['ver'] );
3849
- }
3850
- $history[] = $new['ver'];
3851
- update_site_option( '_cerber_notify_new', $history );
3852
- }
3853
- }
3854
-
3855
- // TODO: implement holding previous values for a while
3856
- // cerber_antibot_gene();
3857
-
3858
- set_site_transient( $t, array( $start, time() ), 48 * 3600 );
3859
- }
3860
-
3861
- /**
3862
- * Log activity
3863
- *
3864
- * @param int $activity Activity ID
3865
- * @param string $login Login used or any additional information
3866
- * @param int $user_id User ID
3867
- * @param null $ip IP Address
3868
- *
3869
- * @return false|int
3870
- * @since 3.0
3871
- */
3872
- function cerber_log( $activity, $login = '', $user_id = 0, $ip = null ) {
3873
- global $user_ID, $cerber_logged, $cerber_blocked;
3874
- static $logged = array();
3875
-
3876
- $wp_cerber = get_wp_cerber();
3877
-
3878
- $activity = absint( $activity );
3879
-
3880
- if ( isset( $logged[ $activity ] ) ) {
3881
- return false;
3882
- }
3883
- else {
3884
- $logged[ $activity ] = true;
3885
- }
3886
-
3887
- $cerber_logged[ $activity ] = $activity;
3888
-
3889
- //$wp_cerber->setProcessed();
3890
-
3891
- if ( empty( $ip ) ) {
3892
- $ip = $wp_cerber->getRemoteIp();
3893
- }
3894
- elseif ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
3895
- return false;
3896
- }
3897
-
3898
- if ( cerber_is_ipv4( $ip ) ) {
3899
- $ip_long = ip2long( $ip );
3900
- }
3901
- else {
3902
- $ip_long = 1;
3903
- }
3904
-
3905
- if ( empty( $user_id ) ) {
3906
- $user_id = ( $user_ID ) ? $user_ID : 0;
3907
- }
3908
-
3909
- $user_id = absint( $user_id );
3910
-
3911
- $stamp = microtime( true );
3912
-
3913
- $pos = strpos($_SERVER['REQUEST_URI'],'?');
3914
- if ($pos) {
3915
- $path = substr( $_SERVER['REQUEST_URI'], 0, $pos );
3916
- }
3917
- else {
3918
- $path = $_SERVER['REQUEST_URI'];
3919
- }
3920
- $url = strip_tags($_SERVER['HTTP_HOST'] . $path);
3921
-
3922
- $status = 0;
3923
- if ( $activity != 10 && $activity != 11 ) {
3924
- $status = cerber_get_status( $ip );
3925
- }
3926
- elseif ( $cerber_blocked ) {
3927
- $status = $cerber_blocked;
3928
- }
3929
-
3930
- $details = $status .'|0|0|0|'. $url;
3931
-
3932
- $country = lab_get_country( $ip );
3933
-
3934
- $login = cerber_real_escape( $login );
3935
- $details = cerber_real_escape( $details );
3936
- $ret = cerber_db_query( 'INSERT INTO ' . CERBER_LOG_TABLE . ' (ip, ip_long, user_login, user_id, stamp, activity, session_id, country, details)
3937
- VALUES ("' . $ip . '",' . $ip_long . ',"' . $login . '",' . $user_id . ',"' . $stamp . '",' . $activity . ',"' . $wp_cerber->getSessionID() . '","' . $country . '","' . $details . '")' );
3938
-
3939
- if ( ! $ret ) {
3940
- cerber_watchdog();
3941
- }
3942
-
3943
- // Subscriptions - notifications for admin ---------------------------------------------------
3944
-
3945
- $subs = cerber_get_site_option( '_cerber_subs' );
3946
-
3947
- if (!empty($subs)) {
3948
- foreach ( $subs as $hash => $sub ) {
3949
-
3950
- // Loop through subscription parameters
3951
- if ( ! empty( $sub[0] )) {
3952
- if ( ! in_array( $activity, $sub[0] ) ) {
3953
- continue;
3954
- }
3955
- }
3956
- if ( ! empty( $sub[1] ) && $sub[1] != $user_id ) {
3957
- continue;
3958
- }
3959
- if ( ! empty( $sub[3] ) && ( $ip_long < $sub[2] || $sub[3] < $ip_long ) ) {
3960
- continue;
3961
- }
3962
- if ( ! empty( $sub[4] ) && $sub[4] != $ip ) {
3963
- continue;
3964
- }
3965
- if ( ! empty( $sub[5] ) && $sub[5] != $login ) {
3966
- continue;
3967
- }
3968
- if ( ! empty( $sub[6] ) ) {
3969
- $none = true;
3970
- if ( false !== strpos( $ip, $sub[6] ) ) {
3971
- $none = false;
3972
- }
3973
- elseif ( false !== mb_stripos( $login, $sub[6] ) ) {
3974
- $none = false;
3975
- }
3976
- elseif ( $user_id ) {
3977
- if ( ! $user = wp_get_current_user() ) {
3978
- $user = get_userdata( $user_id );
3979
- }
3980
- if ( false !== mb_stripos( $user->user_firstname, $sub[6] )
3981
- || false !== mb_stripos( $user->user_lastname, $sub[6] )
3982
- || false !== mb_stripos( $user->nickname, $sub[6] )) {
3983
- $none = false;
3984
- }
3985
- }
3986
- /*elseif ( $user_id && in_array( $user_id, $sub[8] ) ) {
3987
- $none = false;
3988
- }*/
3989
- if ( $none ) {
3990
- continue;
3991
- }
3992
- }
3993
-
3994
- // Some parameter(s) matched, prepare and send notification
3995
-
3996
- $labels = cerber_get_labels( 'activity' );
3997
-
3998
- $msg = __( 'Activity', 'wp-cerber' ) . ': ' . $labels[$activity] . "\n\n";
3999
-
4000
- if ( $country ) {
4001
- $coname = ' ('.cerber_country_name( $country ).')';
4002
- }
4003
- else {
4004
- $coname = '';
4005
- }
4006
-
4007
- $msg .= __( 'IP', 'wp-cerber' ) . ': ' . $ip . $coname. "\n\n";
4008
-
4009
- if ( $user_id && function_exists('get_userdata')) {
4010
- $u = get_userdata( $user_id );
4011
- $msg .= __( 'User', 'wp-cerber' ) . ': ' . $u->display_name . "\n\n";
4012
- }
4013
-
4014
- if ( $login ) {
4015
- $msg .= __( 'Username used', 'wp-cerber' ) . ': ' . $login . "\n\n";
4016
- }
4017
-
4018
- if ( ! empty( $sub['6'] ) ) {
4019
- $msg .= __( 'Search string', 'wp-cerber' ) . ': ' . $sub['6'] . "\n\n";
4020
- }
4021
-
4022
- // Link to the Activity admin page
4023
- $args = cerber_subscribe_params();
4024
- $i = 0;
4025
- $link_params = '';
4026
- foreach ($args as $arg => $val){
4027
- if (is_array($sub[$i])){
4028
- foreach ( $sub[ $i ] as $item ) {
4029
- $link_params .= '&' . $arg . '[]=' . $item;
4030
- }
4031
- }
4032
- else {
4033
- $link_params .= '&' . $arg . '=' . $sub[ $i ];
4034
- }
4035
- $i++;
4036
- }
4037
- $link = cerber_admin_link( 'activity' ) . $link_params;
4038
-
4039
- $msg .= __( 'View activity in dashboard', 'wp-cerber' ) . ': ' . $link;
4040
- $msg .= "\n\n" . __( 'To unsubscribe click here', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . '&unsubscribeme=' . $hash;
4041
-
4042
- cerber_send_email( 'subs', $msg, $ip );
4043
-
4044
- break; // Just one notification letter per event
4045
- }
4046
- }
4047
-
4048
- if ( in_array( $activity, array( 16, 17, 40, 56, 100 ) ) ) {
4049
- lab_save_push( $ip, $activity, '' );
4050
- }
4051
-
4052
- return $ret;
4053
- }
4054
-
4055
- /**
4056
- * Get records from the log
4057
- *
4058
- * @param array $activity
4059
- * @param array $user
4060
- * @param array $order
4061
- * @param string $limit
4062
- *
4063
- * @return array|null
4064
- */
4065
- function cerber_get_log($activity = array(), $user = array(), $order = array(), $limit = ''){
4066
- global $wpdb;
4067
-
4068
- $where = array();
4069
- if ( $activity ) {
4070
- $activity = array_map( 'absint', $activity );
4071
- $where[] = 'activity IN (' . implode( ', ', $activity ) . ')';
4072
- }
4073
-
4074
- if ( ! empty( $user['email'] ) ) {
4075
- $user = get_user_by( 'email', $user['email'] );
4076
- $where[] = 'user_id = ' . absint( $user->ID );
4077
- }
4078
- elseif ( ! empty( $user['id'] ) ) {
4079
- $where[] = 'user_id = ' . absint( $user['id'] );
4080
- }
4081
-
4082
- $where_sql = '';
4083
- if ( $where ) {
4084
- $where_sql = ' WHERE ' . implode( ' AND ', $where );
4085
- }
4086
-
4087
- $order_sql = '';
4088
- if ( $order ) {
4089
- if ( ! empty( $order['DESC'] ) ) {
4090
- $order_sql = ' ORDER BY ' . preg_replace( '/[^\w]/', '', $order['DESC'] ) . ' DESC ';
4091
- }
4092
- elseif ( ! empty( $order['ASC'] ) ) {
4093
- $order_sql = ' ORDER BY ' . preg_replace( '/[^\w]/', '', $order['ASC'] ) . ' ASC ';
4094
- }
4095
- }
4096
-
4097
- $limit_sql = '';
4098
- if ( $limit ) {
4099
- $limit_sql = ' LIMIT ' . preg_replace( '/[^0-9\.]/', '', $limit );
4100
- }
4101
-
4102
- // $row = $wpdb->get_row('SELECT * FROM '.CERBER_LOG_TABLE.' WHERE activity = 5 AND user_id = '.absint($user_id) . ' ORDER BY stamp DESC LIMIT 1');
4103
- return $wpdb->get_results( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' ' . $where_sql . $order_sql . $limit_sql );
4104
-
4105
- }
4106
-
4107
- /**
4108
- * Return the last login record for a given user
4109
- *
4110
- * @param $user_id int|null
4111
- * @param $user_email string
4112
- *
4113
- * @return array|null|object|string
4114
- */
4115
- function cerber_get_last_login( $user_id, $user_email = '' ) {
4116
- if ( $user_id ) {
4117
- $u = array( 'id' => $user_id );
4118
- }
4119
- elseif ( $user_email ) {
4120
- $u = array( 'email' => $user_email );
4121
- }
4122
-
4123
- if ( ! $u ) {
4124
- return false;
4125
- }
4126
-
4127
- if ( $recs = cerber_get_log( array( 5 ), $u, array( 'DESC' => 'stamp' ), 1 ) ) {
4128
- return $recs[0];
4129
- }
4130
-
4131
- return false;
4132
- }
4133
-
4134
- function cerber_count_log($activity = array(), $period = 1) {
4135
-
4136
- $period = absint( $period );
4137
- if ( ! $period ) {
4138
- $period = 1;
4139
- }
4140
-
4141
- $stamp = time() - $period * 24 * 3600;
4142
-
4143
- // TODO: replace with SELECT COUNT(DISTINCT session_id)
4144
- $ret = cerber_db_get_var('SELECT COUNT(ip) FROM '. CERBER_LOG_TABLE .' WHERE activity IN ('.implode(',',$activity).') AND stamp > '. $stamp);
4145
- if (!$ret) $ret = 0;
4146
-
4147
- return $ret;
4148
- }
4149
-
4150
- /**
4151
- * Create a set of parameters for using it in Subscriptions
4152
- * The keys are used to built an URL. Values to calculate a hash.
4153
- *
4154
- * @return array The set of parameters
4155
- */
4156
- function cerber_subscribe_params() {
4157
- // Mandatory parameters in a particular order.
4158
- $params = array( 'filter_activity' => 0, 'filter_user' => 0, 'begin' => 0, 'end' => 0, 'filter_ip' => 0, 'filter_login' => 0, 'search_activity' => 0, 'filter_role' => 0, 'user_ids' => 0 );
4159
-
4160
- $begin = 0;
4161
- $end = 0;
4162
- $ip = 0;
4163
- if ( ! empty( $_GET['filter_ip'] ) ) {
4164
- $ip = cerber_any2range( $_GET['filter_ip'] );
4165
- if ( is_array( $ip ) ) {
4166
- $begin = $ip['begin'];
4167
- $end = $ip['end'];
4168
- $ip = 0;
4169
- } elseif ( ! $ip ) {
4170
- $ip = 0;
4171
- }
4172
- }
4173
- $params['begin'] = $begin;
4174
- $params['end'] = $end;
4175
- $params['filter_ip'] = $ip;
4176
-
4177
- $get_list = array( 'filter_activity', 'filter_user', 'filter_login', 'search_activity', 'filter_role', 'filter_set' );
4178
- foreach ( $get_list as $item ) {
4179
- if ( ! empty( $_GET[ $item ] ) ) {
4180
- if ( is_array( $_GET[ $item ] ) ) {
4181
- $params[ $item ] = array_map( 'trim', $_GET[ $item ] );
4182
- }
4183
- else {
4184
- $params[ $item ] = trim( $_GET[ $item ] );
4185
- }
4186
- }
4187
- else {
4188
- $params[ $item ] = 0;
4189
- }
4190
- //$params[ $item ] = ( empty( $_GET[ $item ] ) ) ? 0 : trim( $_GET[ $item ] );
4191
- }
4192
-
4193
- if ( ! is_array( $params['filter_activity'] ) ) {
4194
- $params['filter_activity'] = array( $params['filter_activity'] );
4195
- }
4196
- $params['filter_activity'] = array_filter( $params['filter_activity'] );
4197
-
4198
- // 'begin' and 'end' array keys are not used, added for compatibility
4199
- //return array( 'filter_activity' => $filter_activity, 'filter_user' => $filter_user, 'begin' => $begin, 'end' => $end, 'filter_ip' => $ip, 'filter_login' => $filter_login, 'search_activity' => $search_activity, 'filter_role' => $filter_role );
4200
- return $params;
4201
- }
4202
-
4203
- /**
4204
- * Loads must have settings
4205
- * @since 7.8.3
4206
- *
4207
- */
4208
- function cerber_pre_checks() {
4209
- // Load must have settings before the rest of the stuff during the plugin activation
4210
-
4211
- // The only way to get it done earlier
4212
- if ( cerber_get_get( 'action' ) === 'activate'
4213
- && cerber_get_get( 'plugin' ) === 'wp-cerber/wp-cerber.php' ) {
4214
- // The plugin is activated in wp-admin
4215
- if ( ! crb_get_settings() ) {
4216
- define('CRB_JUST_MARRIED', 1);
4217
- cerber_load_defaults();
4218
- }
4219
- }
4220
-
4221
- // A backup way
4222
- add_action( 'activated_plugin', function ( $plugin ) {
4223
- if ( $plugin !== 'wp-cerber/wp-cerber.php' ) {
4224
- return;
4225
- }
4226
- if ( ! crb_get_settings() ) {
4227
- if ( ! defined( 'CRB_JUST_MARRIED' ) ) {
4228
- define( 'CRB_JUST_MARRIED', 1 );
4229
- }
4230
- cerber_load_defaults();
4231
- }
4232
- } );
4233
- }
4234
-
4235
- /**
4236
- * Post plugin activation stuff
4237
- *
4238
- */
4239
- register_activation_hook( cerber_plugin_file(), function () {
4240
-
4241
- $assets_url = cerber_plugin_dir_url() . 'assets';
4242
-
4243
- load_plugin_textdomain( 'wp-cerber', false, basename( dirname( __FILE__ ) ) . '/languages' );
4244
-
4245
- if ( version_compare( CERBER_REQ_PHP, phpversion(), '>' ) ) {
4246
- cerber_stop_activating( '<h3>' . sprintf( __( 'The WP Cerber requires PHP %s or higher. You are running', 'wp-cerber' ), CERBER_REQ_PHP ) . ' ' . phpversion() . '</h3>' );
4247
- }
4248
-
4249
- if ( version_compare( CERBER_REQ_WP, cerber_get_wp_version(), '>' ) ) {
4250
- cerber_stop_activating( '<h3>' . sprintf( __( 'The WP Cerber requires WordPress %s or higher. You are running', 'wp-cerber' ), CERBER_REQ_WP ) . ' ' . cerber_get_wp_version() . '</h3>' );
4251
- }
4252
-
4253
- $db_errors = cerber_create_db();
4254
- if ( $db_errors ) {
4255
- $e = '';
4256
- foreach ( $db_errors as $db_error ) {
4257
- $e .= '<p>' . implode( '</p><p>', $db_error ) . '</p>';
4258
- }
4259
- cerber_stop_activating( '<h3>' . __( "Can't activate WP Cerber due to a database error.", 'wp-cerber' ) . '</h3>'.$e);
4260
- }
4261
-
4262
- lab_get_key( true );
4263
-
4264
- cerber_upgrade_all();
4265
-
4266
- cerber_cookie_one();
4267
- cerber_disable_citadel();
4268
-
4269
- $wp_cerber = get_wp_cerber();
4270
-
4271
- cerber_add_white( cerber_get_subnet( $wp_cerber->getRemoteIp() ) , 'My subnet' ); // Protection for non-experienced user
4272
-
4273
- cerber_htaccess_sync( 'main' );
4274
- cerber_htaccess_sync( 'media' );
4275
-
4276
- cerber_set_boot_mode();
4277
-
4278
- cerber_admin_message(
4279
- '<img style="float:left; margin-left:-10px;" src="' . $assets_url . '/icon-128x128.png">' .
4280
- '<p style="font-size:120%;">' . __( 'WP Cerber is now active and has started protecting your site', 'wp-cerber' ) . '</p>' .
4281
- ' <p>' . __( 'Your IP address is added to the', 'wp-cerber' ) . ' ' . __( 'White IP Access List', 'wp-cerber' ) .
4282
-
4283
- ' <p style="font-size:130%;"><a href="http://wpcerber.com/getting-started/" target="_blank">' . __( 'Getting Started Guide', 'wp-cerber' ) . '</a></p>' .
4284
-
4285
- //' <p><b>' . __( "It's important to check security settings.", 'wp-cerber' ) . '</b> &nbsp;<a href="http://wpcerber.com/" target="_blank">Read Cerber\'s blog</a> ' .
4286
- //'&nbsp; <a href="http://wpcerber.com/subscribe-newsletter/" target="_blank">Subscribe to Cerber\'s newsletter</a></p>' .
4287
-
4288
- ' <p>
4289
- </p>
4290
- <p id="crb-activation-msg">
4291
- <i class="crb-icon crb-icon-bx-slider"></i> <a href="' . cerber_admin_link( 'main' ) . '">' . __( 'Main Settings', 'wp-cerber' ) . '</a>' .
4292
- ' <i class="crb-icon crb-icon-bx-radar"></i> <a href="' . cerber_admin_link( 'scanner' ) . '">' . __( 'Security Scanner', 'wp-cerber' ) . '</a>' .
4293
- ' <i class="crb-icon crb-icon-bx-lock"></i> <a href="' . cerber_admin_link( 'acl' ) . '">' . __( 'Access Lists', 'wp-cerber' ) . '</a>' .
4294
- ' <i class="crb-icon crb-icon-bxs-shield"></i> <a href="' . cerber_admin_link( 'antispam' ) . '">' . __( 'Antispam', 'wp-cerber' ) . '</a>' .
4295
- ' <i class="crb-icon crb-icon-bx-shield-alt"></i> <a href="' . cerber_admin_link( 'hardening' ) . '">' . __( 'Hardening', 'wp-cerber' ) . '</a>' .
4296
- ' <i class="crb-icon crb-icon-bx-bell"></i> <a href="' . cerber_admin_link( 'notifications' ) . '">' . __( 'Notifications', 'wp-cerber' ) . '</a>' .
4297
- ' <i class="crb-icon crb-icon-bx-layer"></i> <a href="' . cerber_admin_link( 'imex' ) . '">' . __( 'Import settings', 'wp-cerber' ) . '</a>' .
4298
- '</p>' );
4299
-
4300
-
4301
- if ( ! defined( 'CRB_JUST_MARRIED' ) || ! CRB_JUST_MARRIED ) {
4302
- return;
4303
- }
4304
-
4305
- cerber_send_email( 'activated' );
4306
-
4307
- $p = get_file_data( cerber_plugin_file(), array( 'Version' => 'Version' ), 'plugin' );
4308
- $p['time'] = time();
4309
- $p['user'] = get_current_user_id();
4310
- cerber_update_set( '_activated', $p );
4311
-
4312
- });
4313
-
4314
- /*
4315
- Abort activating plugin!
4316
- */
4317
- function cerber_stop_activating( $msg ) {
4318
- //deactivate_plugins( plugin_basename( __FILE__ ) );
4319
- deactivate_plugins( cerber_plug_in() );
4320
- wp_die( $msg );
4321
- }
4322
-
4323
- /**
4324
- * Upgrade database tables, data and plugin settings
4325
- *
4326
- * @since 3.0
4327
- *
4328
- */
4329
- function cerber_upgrade_all() {
4330
- global $cerber_doing_upgrade;
4331
- $ver = cerber_get_site_option( '_cerber_up' );
4332
- if ( ! $ver || $ver['v'] != CERBER_VER ) {
4333
- $d = @ini_get( 'display_errors');
4334
- @ini_set( 'display_errors', 0 );
4335
- $cerber_doing_upgrade = true;
4336
- define( 'CRB_DOING_UPGRADE', 1 );
4337
- crb_clear_admin_msg();
4338
- cerber_create_db();
4339
- cerber_upgrade_db();
4340
- cerber_acl_fixer( true );
4341
- cerber_antibot_gene( true );
4342
- cerber_upgrade_options();
4343
- wp_clear_scheduled_hook( 'cerber_hourly' ); // @since 5.8
4344
- update_site_option( '_cerber_up', array( 'v' => CERBER_VER, 't' => time() ) );
4345
- cerber_push_the_news( CERBER_VER );
4346
- cerber_delete_expired_set( true );
4347
- lab_get_key( true );
4348
- $cerber_doing_upgrade = false;
4349
- @ini_set( 'display_errors', $d );
4350
- }
4351
- }
4352
-
4353
- /**
4354
- * Creates DB tables if they don't exist
4355
- *
4356
- * @param bool $recreate If true, recreate some tables completely (with data lost)
4357
- *
4358
- * @return array Errors
4359
- */
4360
- function cerber_create_db($recreate = true) {
4361
- global $wpdb;
4362
-
4363
- $wpdb->hide_errors();
4364
- $db_errors = array();
4365
- $sql = array();
4366
-
4367
- if (!cerber_is_table(CERBER_LOG_TABLE)){
4368
- $sql[] = "
4369
- CREATE TABLE IF NOT EXISTS " . CERBER_LOG_TABLE . " (
4370
- ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
4371
- user_login varchar(60) NOT NULL COMMENT 'Username from HTTP request',
4372
- user_id bigint(20) unsigned NOT NULL DEFAULT '0',
4373
- stamp bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
4374
- activity int(10) unsigned NOT NULL DEFAULT '0',
4375
- KEY ip (ip)
4376
- ) DEFAULT CHARSET=utf8 COMMENT='Cerber activity log';
4377
- ";
4378
- }
4379
-
4380
- if (!cerber_is_table(CERBER_ACL_TABLE)){
4381
- $sql[] = "
4382
- CREATE TABLE IF NOT EXISTS " . CERBER_ACL_TABLE . " (
4383
- ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'IP',
4384
- tag char(1) NOT NULL COMMENT 'Type: B or W',
4385
- comments varchar(250) NOT NULL,
4386
- UNIQUE KEY ip (ip)
4387
- ) DEFAULT CHARSET=utf8 COMMENT='Cerber IP Access Lists';
4388
- ";
4389
- }
4390
-
4391
- if (!cerber_is_table(CERBER_BLOCKS_TABLE)){
4392
- $sql[] = "
4393
- CREATE TABLE IF NOT EXISTS " . CERBER_BLOCKS_TABLE . " (
4394
- ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
4395
- block_until bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
4396
- reason varchar(250) NOT NULL COMMENT 'Why IP was blocked',
4397
- reason_id int(11) unsigned NOT NULL DEFAULT '0',
4398
- UNIQUE KEY ip (ip)
4399
- ) DEFAULT CHARSET=utf8 COMMENT='Cerber list of currently blocked IPs';
4400
- ";
4401
- }
4402
-
4403
- if (!cerber_is_table(CERBER_LAB_TABLE)){
4404
- $sql[] = "
4405
- CREATE TABLE IF NOT EXISTS " . CERBER_LAB_TABLE . " (
4406
- ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
4407
- reason_id int(11) unsigned NOT NULL DEFAULT '0',
4408
- stamp bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
4409
- details text NOT NULL
4410
- ) DEFAULT CHARSET=utf8 COMMENT='Cerber lab cache';
4411
- ";
4412
- }
4413
-
4414
-
4415
- if ($recreate || !cerber_is_table(CERBER_LAB_IP_TABLE)){
4416
- if ( $recreate && cerber_is_table( CERBER_LAB_IP_TABLE ) ) {
4417
- $sql[] = 'DROP TABLE IF EXISTS ' . CERBER_LAB_IP_TABLE;
4418
- }
4419
- $sql[] = "
4420
- CREATE TABLE IF NOT EXISTS " . CERBER_LAB_IP_TABLE . " (
4421
- ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'IP',
4422
- reputation INT(11) UNSIGNED NOT NULL COMMENT 'Reputation of IP',
4423
- expires INT(11) UNSIGNED NOT NULL COMMENT 'Unix timestamp',
4424
- PRIMARY KEY (ip)
4425
- ) DEFAULT CHARSET=utf8 COMMENT='Cerber lab IP cache';
4426
- ";
4427
- }
4428
-
4429
- if ( $recreate || ! cerber_is_table( CERBER_LAB_NET_TABLE ) ) {
4430
- if ( $recreate && cerber_is_table( CERBER_LAB_NET_TABLE ) ) {
4431
- $sql[] = 'DROP TABLE IF EXISTS ' . CERBER_LAB_NET_TABLE;
4432
- }
4433
- $sql[] = '
4434
- CREATE TABLE IF NOT EXISTS ' . CERBER_LAB_NET_TABLE . ' (
4435
- ip varchar(39) CHARACTER SET ascii NOT NULL DEFAULT "" COMMENT "IP address",
4436
- ip_long_begin BIGINT UNSIGNED NOT NULL DEFAULT "0",
4437
- ip_long_end BIGINT UNSIGNED NOT NULL DEFAULT "0",
4438
- country CHAR(3) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Country code",
4439
- expires INT(11) UNSIGNED NOT NULL DEFAULT "0",
4440
- PRIMARY KEY (ip),
4441
- UNIQUE KEY begin_end (ip_long_begin, ip_long_end)
4442
- ) DEFAULT CHARSET=utf8 COMMENT="Cerber lab network cache";
4443
- ';
4444
- }
4445
-
4446
- if (!cerber_is_table(CERBER_GEO_TABLE)){
4447
- $sql[] = '
4448
- CREATE TABLE IF NOT EXISTS ' . CERBER_GEO_TABLE . ' (
4449
- country CHAR(3) NOT NULL DEFAULT "" COMMENT "Country code",
4450
- locale CHAR(10) NOT NULL DEFAULT "" COMMENT "Locale i18n",
4451
- country_name VARCHAR(250) NOT NULL DEFAULT "" COMMENT "Country name",
4452
- PRIMARY KEY (country, locale)
4453
- ) DEFAULT CHARSET=utf8;
4454
- ';
4455
- }
4456
-
4457
- if (!cerber_is_table(CERBER_TRAF_TABLE)){
4458
- $sql[] = '
4459
- CREATE TABLE IF NOT EXISTS ' . CERBER_TRAF_TABLE . ' (
4460
- ip varchar(39) CHARACTER SET ascii NOT NULL,
4461
- ip_long BIGINT UNSIGNED NOT NULL DEFAULT "0",
4462
- hostname varchar(250) NOT NULL DEFAULT "",
4463
- uri text NOT NULL,
4464
- request_fields MEDIUMTEXT NOT NULL,
4465
- request_details MEDIUMTEXT NOT NULL,
4466
- session_id char(32) CHARACTER SET ascii NOT NULL,
4467
- user_id bigint(20) UNSIGNED NOT NULL DEFAULT 0,
4468
- stamp decimal(14,4) NOT NULL,
4469
- processing int(10) NOT NULL DEFAULT 0,
4470
- country char(3) CHARACTER SET ascii NOT NULL DEFAULT "",
4471
- request_method char(8) CHARACTER SET ascii NOT NULL,
4472
- http_code int(10) UNSIGNED NOT NULL,
4473
- wp_id bigint(20) UNSIGNED NOT NULL DEFAULT 0,
4474
- wp_type int(10) UNSIGNED NOT NULL DEFAULT 0,
4475
- is_bot int(10) UNSIGNED NOT NULL DEFAULT 0,
4476
- blog_id int(10) UNSIGNED NOT NULL DEFAULT 0,
4477
- KEY stamp (stamp)
4478
- ) DEFAULT CHARSET=utf8;
4479
- ';
4480
- }
4481
-
4482
- if ( ! cerber_is_table( cerber_get_db_prefix() . CERBER_SCAN_TABLE ) ) {
4483
- $sql[] = '
4484
- CREATE TABLE IF NOT EXISTS ' . cerber_get_db_prefix(). CERBER_SCAN_TABLE . ' (
4485
- scan_id INT(10) UNSIGNED NOT NULL,
4486
- scan_type INT(10) UNSIGNED NOT NULL DEFAULT 1,
4487
- scan_mode INT(10) UNSIGNED NOT NULL DEFAULT 0,
4488
- scan_status INT(10) UNSIGNED NOT NULL DEFAULT 0,
4489
- file_name_hash VARCHAR(255) CHARACTER SET ascii NOT NULL DEFAULT "",
4490
- file_name TEXT NOT NULL,
4491
- file_type INT(10) UNSIGNED NOT NULL DEFAULT 0,
4492
- file_hash VARCHAR(255) CHARACTER SET ascii NOT NULL DEFAULT "",
4493
- file_md5 VARCHAR(255) CHARACTER SET ascii NOT NULL DEFAULT "",
4494
- file_hash_repo VARCHAR(255) CHARACTER SET ascii NOT NULL DEFAULT "",
4495
- hash_match INT(10) UNSIGNED NOT NULL DEFAULT 0,
4496
- file_size BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
4497
- file_perms INT(11) NOT NULL DEFAULT 0,
4498
- file_writable INT(10) UNSIGNED NOT NULL DEFAULT 0,
4499
- file_mtime INT(10) UNSIGNED NOT NULL DEFAULT 0,
4500
- extra TEXT NOT NULL,
4501
- PRIMARY KEY (scan_id, file_name_hash)
4502
- ) DEFAULT CHARSET=utf8;
4503
- ';
4504
- }
4505
-
4506
- if ( ! cerber_is_table( cerber_get_db_prefix() . CERBER_SETS_TABLE ) ) {
4507
- $sql[] = '
4508
- CREATE TABLE IF NOT EXISTS ' . cerber_get_db_prefix() . CERBER_SETS_TABLE . ' (
4509
- the_key VARCHAR(255) CHARACTER SET ascii NOT NULL,
4510
- the_id BIGINT(20) NOT NULL DEFAULT 0,
4511
- the_value LONGTEXT NOT NULL,
4512
- expires BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
4513
- PRIMARY KEY (the_key, the_id)
4514
- ) DEFAULT CHARSET=utf8;
4515
- ';
4516
- }
4517
-
4518
- if ( ! cerber_is_table( CERBER_QMEM_TABLE ) ) {
4519
- $sql[] = '
4520
- CREATE TABLE IF NOT EXISTS ' . CERBER_QMEM_TABLE . ' (
4521
- ip varchar(39) CHARACTER SET ascii NOT NULL,
4522
- http_code int(10) UNSIGNED NOT NULL,
4523
- stamp int(10) UNSIGNED NOT NULL,
4524
- KEY ip_stamp (ip, stamp)
4525
- ) DEFAULT CHARSET=utf8;
4526
- ';
4527
- }
4528
-
4529
- foreach ( $sql as $query ) {
4530
- if ( ! $wpdb->query( $query ) && $wpdb->last_error ) {
4531
- $db_errors[] = array( $wpdb->last_error, $wpdb->last_query );
4532
- }
4533
- }
4534
-
4535
- return $db_errors;
4536
- }
4537
-
4538
- /**
4539
- * Upgrade structure of existing DB tables
4540
- *
4541
- * @return array Errors during upgrading
4542
- * @since 3.0
4543
- */
4544
- function cerber_upgrade_db( $force = false ) {
4545
- global $wpdb;
4546
- $wpdb->hide_errors();
4547
- if ( $force ) {
4548
- $wpdb->suppress_errors();
4549
- }
4550
- $db_errors = array();
4551
- $sql = array();
4552
-
4553
- // @since 3.0
4554
- $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' CHANGE stamp stamp DECIMAL(14,4) NOT NULL';
4555
-
4556
- // @since 3.1
4557
- if ( $force || ! cerber_is_column( CERBER_LOG_TABLE, 'ip_long' ) ) {
4558
- $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' ADD ip_long BIGINT UNSIGNED NOT NULL DEFAULT "0" COMMENT "IPv4 long" AFTER ip, ADD INDEX (ip_long)';
4559
- }
4560
- if ( $force || ! cerber_is_column( CERBER_ACL_TABLE, 'ip_long_begin' ) ) {
4561
- $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . " ADD ip_long_begin BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT 'IPv4 range begin' AFTER ip, ADD ip_long_end BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT 'IPv4 range end' AFTER ip_long_begin";
4562
- }
4563
- if ( $force || !cerber_is_index( CERBER_ACL_TABLE, 'ip_begin_end' ) ) {
4564
- $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' ADD UNIQUE ip_begin_end (ip, ip_long_begin, ip_long_end)';
4565
- }
4566
- if ( $force || cerber_is_index( CERBER_ACL_TABLE, 'ip' ) ) {
4567
- $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' DROP INDEX ip';
4568
- }
4569
-
4570
- // @since 4.8.2
4571
- if ( $force || cerber_is_index( CERBER_ACL_TABLE, 'begin_end' ) ) {
4572
- $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' DROP INDEX begin_end';
4573
- }
4574
- if ( $force || !cerber_is_index( CERBER_ACL_TABLE, 'begin_end_tag' ) ) {
4575
- $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' ADD INDEX begin_end_tag (ip_long_begin, ip_long_end, tag)';
4576
- }
4577
-
4578
- // @since 4.9
4579
- if ( $force || ! cerber_is_column( CERBER_LOG_TABLE, 'session_id' ) ) {
4580
- $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . '
4581
- ADD session_id CHAR(32) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "",
4582
- ADD country CHAR(3) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Country code",
4583
- ADD details VARCHAR(250) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Details about HTTP request";
4584
- ';
4585
- }
4586
-
4587
- // @since 6.1
4588
- if ( $force || ! cerber_is_index( CERBER_LOG_TABLE, 'session_index' ) ) {
4589
- $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' ADD INDEX session_index (session_id)';
4590
- }
4591
-
4592
- // @since 7.0.3
4593
- $sql[] = 'DROP TABLE IF EXISTS ' . CERBER_SCAN_TABLE;
4594
-
4595
- // @since 7.1
4596
- if ( $force || ! cerber_is_column( cerber_get_db_prefix() . CERBER_SCAN_TABLE, 'file_status' ) ) {
4597
- $sql[] = 'ALTER TABLE ' . cerber_get_db_prefix() . CERBER_SCAN_TABLE . " ADD file_status INT UNSIGNED NOT NULL DEFAULT '0' AFTER scan_status";
4598
- }
4599
-
4600
- // @since 7.5.2
4601
- if ( $force || ! cerber_is_column( CERBER_BLOCKS_TABLE, 'reason_id' ) ) {
4602
- $sql[] = 'ALTER TABLE ' . CERBER_BLOCKS_TABLE . ' ADD reason_id int(11) unsigned NOT NULL DEFAULT "0"';
4603
- }
4604
-
4605
- // @since 7.8.6
4606
- if ( $force || ! cerber_is_column( CERBER_TRAF_TABLE, 'php_errors' ) ) {
4607
- $sql[] = 'ALTER TABLE ' . CERBER_TRAF_TABLE . ' ADD php_errors TEXT NOT NULL AFTER blog_id';
4608
- }
4609
-
4610
- if (!empty($sql)) {
4611
- foreach ( $sql as $query ) {
4612
- if ( !$wpdb->query( $query ) && $wpdb->last_error ) {
4613
- $db_errors[] = array( $wpdb->last_error, $wpdb->last_query );
4614
- }
4615
- }
4616
- }
4617
-
4618
- // Convert existing data into the new format
4619
-
4620
- cerber_acl_fixer();
4621
-
4622
- if ( $db_errors ) {
4623
- update_site_option( '_cerber_db_errors', $db_errors );
4624
- }
4625
- else {
4626
- update_site_option( '_cerber_db_errors', '' );
4627
- }
4628
-
4629
- return $db_errors;
4630
- }
4631
-
4632
- /**
4633
- * Updating old activity log records to the new row format (has been introduced in v 3.1)
4634
- *
4635
- * @since 4.0
4636
- *
4637
- */
4638
- function cerber_up_data() {
4639
- $ips = cerber_db_get_col( 'SELECT DISTINCT ip FROM ' . CERBER_LOG_TABLE . ' WHERE ip_long = 0 LIMIT 50' );
4640
- if ( ! $ips ) {
4641
- return;
4642
- }
4643
- foreach ( $ips as $ip ) {
4644
- if ( cerber_is_ipv4( $ip ) ) {
4645
- $ip_long = ip2long( $ip );
4646
- } else {
4647
- $ip_long = 1;
4648
- }
4649
- cerber_db_query( 'UPDATE ' . CERBER_LOG_TABLE . ' SET ip_long = ' . $ip_long . ' WHERE ip = "' . $ip .'" AND ip_long = 0');
4650
- }
4651
- }
4652
-
4653
- /**
4654
- * Upgrade corrupted / outdated rows in ACL
4655
- *
4656
- * @param bool $ipv6 if true Process IPv6 addresses
4657
- *
4658
- */
4659
- function cerber_acl_fixer( $ipv6 = false ) {
4660
- global $wpdb;
4661
-
4662
- // Repair/update IPs without long values
4663
- $ips = cerber_db_get_col( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = 0 OR ip_long_end = 0' );
4664
- if ( ! $ips ) {
4665
- return;
4666
- }
4667
- foreach ( $ips as $ip ) {
4668
- if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
4669
- continue;
4670
- }
4671
- $range = cerber_any2range( $ip );
4672
- if ( is_array( $range ) ) {
4673
- $begin = $range['begin'];
4674
- $end = $range['end'];
4675
- }
4676
- else {
4677
- $begin = ip2long( $ip );
4678
- $end = ip2long( $ip );
4679
- }
4680
-
4681
- cerber_db_query( 'UPDATE ' . CERBER_ACL_TABLE . ' SET ip_long_begin = ' . $begin . ', ip_long_end = ' . $end . ' WHERE ip = "' . $ip . '"' );
4682
- }
4683
-
4684
- // Convert old IPv6 to all shortened
4685
- if ( $ipv6 ) {
4686
- $ips = cerber_db_get_col( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = 0' );
4687
- if ( $ips ) {
4688
- foreach ( $ips as $ip ) {
4689
- if ( ! filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
4690
- continue;
4691
- }
4692
- $short_ip = cerber_short_ipv6( $ip );
4693
- if ( $short_ip != $ip ) {
4694
- cerber_db_query( 'UPDATE ' . CERBER_ACL_TABLE . ' SET ip = "' . $short_ip . '" WHERE ip = "' . $ip . '"' );
4695
- }
4696
- }
4697
- }
4698
- }
4699
- }
4700
-
4701
- add_action( 'deac' . 'tivate_' . cerber_plug_in(), 'cerber_clean' );
4702
- function cerber_clean( $ip ) {
4703
- wp_clear_scheduled_hook( 'cerber_hourly_1' );
4704
- wp_clear_scheduled_hook( 'cerber_hourly_2' );
4705
- wp_clear_scheduled_hook( 'cerber_daily' );
4706
-
4707
- cerber_htaccess_clean_up();
4708
- cerber_set_boot_mode( 0 );
4709
- cerber_delete_expired_set( true );
4710
-
4711
- $pi = get_file_data( cerber_plugin_file(), array( 'Version' => 'Version' ), 'plugin' );
4712
- $pi ['v'] = time();
4713
- $pi ['u'] = get_current_user_id();
4714
- update_site_option( '_cerber_o' . 'ff', $pi );
4715
- $f = 'cerb' . 'er_se' . 'nd_em' . 'ail';
4716
- $f( 'sh' . 'utd' . 'own' );
4717
- }
4718
-
4719
- /*
4720
- Fix an issue with the empty user_id field in the comments table.
4721
- */
4722
- add_filter( 'preprocess_comment', 'cerber_add_uid' );
4723
- function cerber_add_uid( $commentdata ) {
4724
- $current_user = wp_get_current_user();
4725
- $commentdata['user_ID'] = $current_user->ID;
4726
-
4727
- return $commentdata;
4728
- }
4729
-
4730
- /**
4731
- * Load jQuery on the page
4732
- *
4733
- */
4734
- add_action( 'login_enqueue_scripts', 'cerber_login_scripts' );
4735
- function cerber_login_scripts() {
4736
- if ( cerber_antibot_enabled( array('botsreg', 'botsany') ) ) {
4737
- wp_enqueue_script( 'jquery' );
4738
- }
4739
- }
4740
- add_action( 'wp_enqueue_scripts', 'cerber_scripts' );
4741
- function cerber_scripts() {
4742
- global $wp_cerber;
4743
- if ( ( is_singular() && cerber_antibot_enabled( array( 'botscomm', 'botsany' ) ) )
4744
- || ( $wp_cerber->getSettings( 'sitekey' ) && $wp_cerber->getSettings( 'secretkey' ) )
4745
- ) {
4746
- wp_enqueue_script( 'jquery' );
4747
- }
4748
- }
4749
-
4750
- /**
4751
- * Footer stuff like JS code
4752
- * Explicit rendering reCAPTCHA
4753
- *
4754
- */
4755
- add_action( 'login_footer', 'cerber_login_register_stuff', 1000 );
4756
- function cerber_login_register_stuff() {
4757
- global $wp_cerber;
4758
-
4759
- cerber_antibot_code(array( 'botsreg', 'botsany' ));
4760
-
4761
- // Universal JS
4762
- if (!$wp_cerber->recaptcha_here) return;
4763
-
4764
- $sitekey = $wp_cerber->getSettings('sitekey');
4765
-
4766
- if (!$wp_cerber->getSettings('invirecap')){
4767
- // Classic version (visible reCAPTCHA)
4768
- echo '<script src = https://www.google.com/recaptcha/api.js?hl='.cerber_recaptcha_lang().' async defer></script>';
4769
- }
4770
- else {
4771
- // Pure JS version with explicit rendering
4772
- ?>
4773
- <script src="https://www.google.com/recaptcha/api.js?onload=init_recaptcha_widgets&render=explicit&hl=<?php echo cerber_recaptcha_lang(); ?>" async defer></script>
4774
- <script type='text/javascript'>
4775
-
4776
- document.getElementById("cerber-recaptcha").remove();
4777
-
4778
- var init_recaptcha_widgets = function () {
4779
- for (var i = 0; i < document.forms.length; ++i) {
4780
- var form = document.forms[i];
4781
- var place = form.querySelector('.cerber-form-marker');
4782
- if (null !== place) render_recaptcha_widget(form, place);
4783
- }
4784
- };
4785
-
4786
- function render_recaptcha_widget(form, place) {
4787
- var place_id = grecaptcha.render(place, {
4788
- 'callback': function (g_recaptcha_response) {
4789
- HTMLFormElement.prototype.submit.call(form);
4790
- },
4791
- 'sitekey': '<?php echo $sitekey; ?>',
4792
- 'size': 'invisible',
4793
- 'badge': 'bottomright'
4794
- });
4795
-
4796
- form.onsubmit = function (event) {
4797
- event.preventDefault();
4798
- grecaptcha.execute(place_id);
4799
- };
4800
-
4801
- }
4802
- </script>
4803
- <?php
4804
- }
4805
- }
4806
-
4807
- /**
4808
- * Inline reCAPTCHA widget
4809
- *
4810
- */
4811
- add_action( 'wp_footer', 'cerber_foo', 1000 );
4812
- function cerber_foo() {
4813
- global $wp_cerber;
4814
-
4815
- if (is_singular()) cerber_antibot_code( array( 'botscomm', 'botsany' ) );
4816
-
4817
- if (!$wp_cerber->recaptcha_here) return;
4818
-
4819
- // jQuery version with support visible and invisible reCAPTCHA
4820
- // TODO: convert it into pure JS
4821
- ?>
4822
- <script type="text/javascript">
4823
-
4824
- jQuery(document).ready(function ($) {
4825
-
4826
- var recaptcha_ok = false;
4827
- var the_recaptcha_widget = $("#cerber-recaptcha");
4828
- var is_recaptcha_visible = ($(the_recaptcha_widget).data('size') !== 'invisible');
4829
-
4830
- var the_form = $(the_recaptcha_widget).closest("form");
4831
- var the_button = $(the_form).find('input[type="submit"]');
4832
- if (!the_button.length) {
4833
- the_button = $(the_form).find(':button');
4834
- }
4835
-
4836
- // visible
4837
- if (the_button.length && is_recaptcha_visible) {
4838
- the_button.prop("disabled", true);
4839
- the_button.css("opacity", 0.5);
4840
- }
4841
-
4842
- window.form_button_enabler = function () {
4843
- if (!the_button.length) return;
4844
- the_button.prop("disabled", false);
4845
- the_button.css( "opacity", 1 );
4846
- };
4847
-
4848
- // invisible
4849
- if (!is_recaptcha_visible) {
4850
- $(the_button).click(function (event) {
4851
- if (recaptcha_ok) return;
4852
- event.preventDefault();
4853
- grecaptcha.execute();
4854
- });
4855
- }
4856
-
4857
- window.now_submit_the_form = function () {
4858
- recaptcha_ok = true;
4859
- $(the_button).click(); // this is only way to submit a form that contains "submit" inputs
4860
- };
4861
- });
4862
- </script>
4863
- <script src = "https://www.google.com/recaptcha/api.js?hl=<?php echo cerber_recaptcha_lang(); ?>" async defer></script>
4864
- <?php
4865
- }
4866
-
4867
- register_shutdown_function( function () {
4868
-
4869
- cerber_extra_vision();
4870
-
4871
- // Error monitoring
4872
- if ( 400 <= http_response_code()
4873
- && ! cerber_is_wp_cron()
4874
- && ( $mode = crb_get_settings( 'tierrmon' ) ) ) {
4875
- cerber_error_shield( $mode );
4876
- }
4877
-
4878
- cerber_push_lab();
4879
- cerber_traffic_log();
4880
- } );
4881
-
4882
- function cerber_error_shield( $mode = 1 ) {
4883
- global $cerber_status, $cerber_blocked;
4884
-
4885
- if ( ! $mode || ( crb_get_settings( 'tierrnoauth' ) && is_user_logged_in() ) ) {
4886
- return;
4887
- }
4888
-
4889
- $time = 900;
4890
- $limit = 3; // allowed within $time
4891
- $codes = array();
4892
- if ( $mode == 1 ) { // safe mode
4893
- $time = 300;
4894
- $limit = 7;
4895
- $codes = array( 404, 500 );
4896
- }
4897
-
4898
- $code = http_response_code();
4899
- if ( $code < 400 || ( $codes && ! in_array( $code, $codes ) ) ) {
4900
- return;
4901
- }
4902
-
4903
- $go = false;
4904
- if ( cerber_is_http_post() ) {
4905
- $go = true;
4906
- }
4907
-
4908
- if ( ! $go && cerber_get_uri_script() ) {
4909
- $go = true;
4910
- }
4911
-
4912
- if ( ! $go ) {
4913
- if ( $mode == 1 ) {
4914
- if ( cerber_get_non_wp_fields() ) {
4915
- $go = true;
4916
- }
4917
- }
4918
- else {
4919
- if ( ! empty( $_GET ) ) {
4920
- $go = true;
4921
- }
4922
- }
4923
- }
4924
-
4925
- if ( ! $go && cerber_is_rest_url() ) {
4926
- $go = true;
4927
- }
4928
-
4929
- if ( ! $go ) {
4930
- return;
4931
- }
4932
-
4933
- $ip = cerber_get_remote_ip();
4934
- cerber_db_query( 'INSERT INTO ' . CERBER_QMEM_TABLE . ' (ip, http_code, stamp)
4935
- VALUES ("' . $ip . '",' . intval( http_response_code() ) . ',' . time() . ')' );
4936
-
4937
- if ( ! $cerber_blocked ) {
4938
- $t = time() - $time;
4939
- $c = cerber_db_get_var( 'SELECT COUNT(ip) FROM ' . CERBER_QMEM_TABLE . ' WHERE ip = "' . $ip . '" AND stamp > ' . $t );
4940
- if ( $c >= $limit ) {
4941
- cerber_soft_block_add( $ip, 711 );
4942
- $cerber_status = 18;
4943
- }
4944
- }
4945
-
4946
- }
4947
-
4948
- function cerber_catch_error( $errno, $errstr = null, $errfile = null, $errline = null ) {
4949
- global $cerber_php_errors;
4950
- if ( ! $errno ) {
4951
- return false;
4952
- }
4953
- if ( ! isset( $cerber_php_errors ) || ! is_array( $cerber_php_errors ) ) {
4954
- $cerber_php_errors = array();
4955
- }
4956
- $cerber_php_errors[] = array( $errno, $errstr, $errfile, $errline );
4957
-
4958
- return false;
4959
-
4960
- }
4961
-
4962
- function cerber_traffic_log(){
4963
- global $cerber_php_errors, $cerber_db_errors, $wp_query, $wp_cerber_user_id, $wp_cerber_start_stamp, $blog_id;
4964
- static $logged = false;
4965
-
4966
- if ( $logged || cerber_is_cloud_request() ) {
4967
- return;
4968
- }
4969
-
4970
- $wp_cerber = get_wp_cerber();
4971
-
4972
- $wp_type = 700;
4973
-
4974
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
4975
- /*
4976
- if ( isset( $_POST['action'] ) && $_POST['action'] == 'heartbeat' ) {
4977
- return;
4978
- }*/
4979
- $wp_type = 500;
4980
- }
4981
- elseif ( is_admin() ) {
4982
- $wp_type = 501;
4983
- }
4984
- elseif ( cerber_is_wp_cron() ) {
4985
- $wp_type = 502;
4986
- }
4987
- elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
4988
- $wp_type = 515;
4989
- }
4990
- elseif ( cerber_is_rest_url() ) {
4991
- $wp_type = 520;
4992
- }
4993
- // Public part starts with 600
4994
- elseif ( $wp_query && is_object( $wp_query ) ) {
4995
- $wp_type = 600;
4996
- if ( $wp_query->is_singular ) {
4997
- $wp_type = 601;
4998
- }
4999
- elseif ( $wp_query->is_tag ) {
5000
- $wp_type = 603;
5001
- }
5002
- elseif ( $wp_query->is_category ) {
5003
- $wp_type = 604;
5004
- }
5005
- elseif ( $wp_query->is_search ) {
5006
- $wp_type = 605;
5007
- }
5008
- }
5009
-
5010
- if ( function_exists( 'http_response_code' ) ) { // PHP >= 5.4.0, PHP 7
5011
- $http_code = http_response_code();
5012
- }
5013
- else {
5014
- $http_code = 200;
5015
- if ( $wp_type > 600 ) {
5016
- if ( $wp_query->is_404 ) {
5017
- $http_code = 404;
5018
- }
5019
- }
5020
- }
5021
-
5022
- $user_id = 0;
5023
- if ( function_exists( 'get_current_user_id' ) ) {
5024
- $user_id = get_current_user_id();
5025
- }
5026
- if ( ! $user_id && $wp_cerber_user_id ) {
5027
- $user_id = absint( $wp_cerber_user_id );
5028
- }
5029
-
5030
- if ( ! cerber_to_log( $wp_type, $http_code, $user_id ) ) {
5031
- return;
5032
- }
5033
-
5034
- $logged = true;
5035
-
5036
- $ua = '';
5037
- if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
5038
- $ua = substr ($_SERVER['HTTP_USER_AGENT'], 0, 1000);
5039
- }
5040
-
5041
- $bot = cerber_is_crawler( $ua );
5042
- if ( $bot && crb_get_settings( 'tinocrabs' ) ) {
5043
- return;
5044
- }
5045
-
5046
- $ip = $wp_cerber->getRemoteIp();
5047
- $ip_long = 0;
5048
- if ( cerber_is_ipv4( $ip ) ) {
5049
- $ip_long = ip2long( $ip );
5050
- }
5051
-
5052
- $wp_id = 0;
5053
- if ( $wp_query && is_object( $wp_query ) ) {
5054
- $wp_id = absint( $wp_query->get_queried_object_id() );
5055
- }
5056
-
5057
- $session_id = $wp_cerber->getSessionID();
5058
- if ( is_ssl() ) {
5059
- $scheme = 'https';
5060
- }
5061
- else {
5062
- $scheme = 'http';
5063
- }
5064
- $uri = $scheme . '://'. $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
5065
- $method = preg_replace( '/[^\w]/', '', $_SERVER['REQUEST_METHOD'] );
5066
-
5067
- // Request fields
5068
-
5069
- $fields = '';
5070
- if ( crb_get_settings( 'tifields' ) ) {
5071
- $fields = array();
5072
- if ( ! empty( $_POST ) ) {
5073
- $fields[1] = cerber_prepare_fields( cerber_mask_fields( (array) $_POST ) );
5074
- }
5075
- if ( ! empty( $_GET ) ) {
5076
- $fields[2] = cerber_prepare_fields( (array) $_GET );
5077
- }
5078
- if ( ! empty( $_FILES ) ) {
5079
- $fields[3] = $_FILES;
5080
- }
5081
- if ( ! empty( $fields ) ) {
5082
- $fields = serialize( $fields );
5083
- }
5084
- else {
5085
- $fields = '';
5086
- }
5087
- }
5088
-
5089
- // Extra request details
5090
-
5091
- $details = array();
5092
- $details[1] = $ua;
5093
-
5094
- if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
5095
- //$ref = mb_substr( $_SERVER['HTTP_REFERER'], 0, 1048576 ); // 1 Mb for ASCII
5096
- $details[2] = filter_var( $_SERVER['HTTP_REFERER'], FILTER_SANITIZE_URL );
5097
- }
5098
- /*
5099
- if ( ! empty( $_FILES ) ) {
5100
- $details[3] = $_FILES;
5101
- }*/
5102
- if ( $wp_type == 605 && ! empty( $_GET['s'] ) ) {
5103
- $details[4] = $_GET['s'];
5104
- }
5105
- if ( $wp_type == 515 ) {
5106
- // TODO: add a setting to enable it because there is a user/password in the php://input
5107
- //$details[5] = file_get_contents('php://input');
5108
- }
5109
- if ( crb_get_settings( 'tihdrs' ) ) {
5110
- $hds = getallheaders();
5111
- unset( $hds['Cookie'] );
5112
- $details[6] = $hds;
5113
- }
5114
- if ( crb_get_settings( 'tisenv' ) ) {
5115
- $srv = $_SERVER;
5116
- unset( $srv['HTTP_COOKIE'] );
5117
- $details[7] = $srv;
5118
- }
5119
- if ( crb_get_settings( 'ticandy' ) && ! empty( $_COOKIE ) ) {
5120
- $details[8] = $_COOKIE;
5121
- }
5122
- if ( !empty( $details ) ) {
5123
- $details = cerber_prepare_fields( $details );
5124
- $details = serialize($details);
5125
- }
5126
- else {
5127
- $details = '';
5128
- }
5129
-
5130
- // Software errors
5131
- $php_err = '';
5132
- if ( crb_get_settings( 'tiphperr' ) ) {
5133
- if ( $cerber_php_errors && is_array( $cerber_php_errors ) ) {
5134
- //$err_not = array( E_NOTICE, E_WARNING );
5135
- $i = 0;
5136
- foreach ( $cerber_php_errors as $key => $e ) {
5137
- if ( $e[0] == E_NOTICE ) {
5138
- //unset( $cerber_php_errors[ $key ] );
5139
- }
5140
- else {
5141
- $i ++;
5142
- }
5143
- if ( $i > 25 ) { // Save no more errors
5144
- break;
5145
- }
5146
- }
5147
- if ( $cerber_php_errors ) {
5148
- $cerber_php_errors = array_values( $cerber_php_errors );
5149
- $cerber_php_errors = array_slice( $cerber_php_errors, 0, 25 );
5150
- $php_err = serialize( $cerber_php_errors );
5151
- }
5152
- }
5153
- }
5154
-
5155
- // Timestamps
5156
- if ( ! empty( $wp_cerber_start_stamp ) && is_numeric( $wp_cerber_start_stamp ) ) {
5157
- $start = (float) $wp_cerber_start_stamp; // define this variable: $wp_cerber_start_stamp = microtime( true ); in wp-config.php
5158
- }
5159
- else {
5160
- $start = cerber_request_time();
5161
- }
5162
-
5163
- $processing = (int) ( 1000 * ( microtime( true ) - $start ) );
5164
-
5165
- $uri = cerber_real_escape( $uri );
5166
- $fields = cerber_real_escape( $fields );
5167
- $details = cerber_real_escape( $details );
5168
- $php_err = cerber_real_escape( $php_err );
5169
-
5170
- $query = 'INSERT INTO ' . CERBER_TRAF_TABLE . '
5171
- (ip, ip_long, uri, request_fields , request_details, session_id, user_id, stamp, processing, request_method, http_code, wp_id, wp_type, is_bot, blog_id, php_errors )
5172
- VALUES ("' . $ip . '", ' . $ip_long . ',"' . $uri . '","' . $fields . '","' . $details . '", "' . $session_id . '", ' . $user_id . ', ' . $start . ',' . $processing . ', "' . $method . '", ' . $http_code . ',' . $wp_id . ', ' . $wp_type . ', ' . $bot . ', ' . absint( $blog_id ) . ',"' . $php_err . '")';
5173
-
5174
- $ret = cerber_db_query( $query );
5175
-
5176
- if ( ! $ret ) {
5177
- //cerber_diag_log( print_r( $cerber_db_errors, 1 ) );
5178
-
5179
- // mysqli_error($wpdb->dbh);
5180
-
5181
- // TODO: Daily software error report
5182
- /*
5183
- echo mysqli_sqlstate($wpdb->dbh);
5184
- echo $wpdb->last_error;
5185
- echo "<p>\n";
5186
- echo $uri;
5187
- echo "<p>\n";
5188
- echo '<p>ERR '.$query.$wpdb->last_error;
5189
- echo '<p>'.$wpdb->_real_escape( $uri );
5190
- */
5191
- }
5192
-
5193
- }
5194
-
5195
- /**
5196
- * To log or not to log current request?
5197
- *
5198
- * @param $wp_type integer
5199
- * @param $http_code integer
5200
- * @param $user_id integer
5201
- *
5202
- * @return bool
5203
- * @since 6.0
5204
- */
5205
- function cerber_to_log( $wp_type, $http_code, $user_id ) {
5206
- global $cerber_logged, $cerber_blocked, $wp_cerber;
5207
-
5208
- $mode = crb_get_settings( 'timode' );
5209
-
5210
- if ( $mode == 0 ) {
5211
- return false;
5212
- }
5213
- if ( $mode == 2 ) {
5214
- if ( $wp_type < 515 ) { // Pure admin requests
5215
- if ( $wp_type < 502 && ! $user_id ) { // @since 6.3
5216
- return true;
5217
- }
5218
- //if ( $wp_type == 500 && 'admin-ajax.php' != cerber_get_uri_script() ) { // @since 7.8
5219
- if ( $wp_type == 500 && ! CRB_Request::is_script( '/wp-admin/admin-ajax.php' ) ) { // @since 7.9.1
5220
- return true;
5221
- }
5222
-
5223
- return false;
5224
- }
5225
-
5226
- return true;
5227
- }
5228
-
5229
- // Smart mode ---------------------------------------------------------
5230
-
5231
- if ( ! empty( $cerber_logged ) ) {
5232
- $tmp = $cerber_logged;
5233
- unset( $tmp[7] );
5234
- unset( $tmp[51] );
5235
- if ( ! empty( $tmp ) ) {
5236
- return true;
5237
- }
5238
- }
5239
-
5240
- if ( $cerber_blocked ) {
5241
- return true;
5242
- }
5243
-
5244
- if ( $wp_type < 515 ) {
5245
- if ( $wp_type < 502 && ! $user_id ) { // @since 6.3
5246
- if ( ! empty( $_GET ) || ! empty( $_POST ) || ! empty( $_FILES ) ) {
5247
- return true;
5248
- }
5249
- }
5250
- if ( $wp_type == 500 && ! CRB_Request::is_script( '/wp-admin/admin-ajax.php' ) ) { // @since 7.8
5251
- return true;
5252
- }
5253
-
5254
- return false;
5255
- }
5256
-
5257
- if ( $http_code >= 400 ||
5258
- $wp_type < 600 ||
5259
- $user_id ||
5260
- ! empty( $_POST ) ||
5261
- ! empty( $_FILES ) ||
5262
- isset( $_GET['s'] )
5263
- || cerber_get_non_wp_fields() ) {
5264
- return true;
5265
- }
5266
-
5267
- if ( cerber_is_http_post()
5268
- || cerber_get_uri_script() ) {
5269
- return true;
5270
- }
5271
-
5272
- return false;
5273
- }
5274
-
5275
- /**
5276
- * Mask sensitive request fields before saving in DB (avoid information leaks)
5277
- *
5278
- * @param $fields array
5279
- *
5280
- * @return array
5281
- * @since 6.0
5282
- */
5283
- function cerber_mask_fields( $fields ) {
5284
- $to_mask = array( 'pwd', 'pass', 'password', 'password_1', 'password_2', 'cerber-cloud-key' );
5285
- if ( $list = (array) crb_get_settings( 'timask' ) ) {
5286
- $to_mask = array_merge( $to_mask, $list );
5287
- }
5288
- foreach ( $to_mask as $mask_field ) {
5289
- if ( ! empty( $fields[ $mask_field ] ) ) {
5290
- $fields[ $mask_field ] = str_pad( '', mb_strlen( $fields[ $mask_field ] ), '*' );
5291
- }
5292
- }
5293
-
5294
- return $fields;
5295
- }
5296
-
5297
- /**
5298
- * Recursive prepare values in array for inserting into DB
5299
- *
5300
- * @param $list
5301
- *
5302
- * @return mixed
5303
- * @since 6.0
5304
- */
5305
- function cerber_prepare_fields( $list ) {
5306
- foreach ( $list as &$field ) {
5307
- if ( is_array( $field ) ) {
5308
- $field = cerber_prepare_fields( $field );
5309
- }
5310
- else {
5311
- if ( ! $field ) {
5312
- $field = '';
5313
- }
5314
- else {
5315
- $field = mb_substr( $field, 0, 1048576 ); // 1 Mb for ASCII
5316
- }
5317
- }
5318
- }
5319
-
5320
- $list = stripslashes_deep( $list );
5321
-
5322
- return $list;
5323
- }
5324
-
5325
- /**
5326
- * Request time
5327
- *
5328
- * @return mixed
5329
- * @since 6.0
5330
- */
5331
- function cerber_request_time() {
5332
- static $stamp = null;
5333
-
5334
- if ( ! isset( $stamp ) ) {
5335
-
5336
- if ( ! empty( $_SERVER['REQUEST_TIME_FLOAT'] ) ) { // PHP >= 5.4
5337
- $stamp = filter_var( $_SERVER['REQUEST_TIME_FLOAT'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
5338
- }
5339
- $mt = microtime( true );
5340
- if ( ! $stamp || $stamp > ( $mt + 300 ) ) { // Some platforms may have wrong value in 'REQUEST_TIME_FLOAT'
5341
- $stamp = $mt;
5342
- }
5343
- }
5344
-
5345
- return $stamp;
5346
- }
5347
-
5348
- /**
5349
- * Return non WordPress public query $_GET fields (parameters)
5350
- *
5351
- * @param array $fields An associative array field => value to check
5352
- *
5353
- * @return array
5354
- * @since 6.0
5355
- */
5356
- function cerber_get_non_wp_fields( $fields = array() ) {
5357
- global $wp_query;
5358
- static $result;
5359
-
5360
- if ( isset( $result ) ) {
5361
- return $result;
5362
- }
5363
-
5364
- if ( empty( $fields ) ) {
5365
- $get_keys = array_keys( $_GET );
5366
- }
5367
- else {
5368
- $get_keys = array_keys( $fields );
5369
- }
5370
-
5371
- if ( empty( $get_keys ) ) {
5372
- $result = array();
5373
- }
5374
-
5375
- if ( is_object( $wp_query ) ) {
5376
- $keys = $wp_query->fill_query_vars( array() );
5377
- }
5378
- elseif ( class_exists( 'WP_Query' ) ) {
5379
- $tmp = new WP_Query();
5380
- $keys = $tmp->fill_query_vars( array() );
5381
- }
5382
- else {
5383
- $keys = array();
5384
- }
5385
-
5386
- $wp_keys = array_keys( $keys ); // WordPress GET fields for frontend
5387
-
5388
- // Some well-known fields
5389
- $wp_keys[] = 'redirect_to';
5390
- $wp_keys[] = 'reauth';
5391
- $wp_keys[] = 'action';
5392
- $wp_keys[] = '_wpnonce';
5393
- $wp_keys[] = 'loggedout';
5394
- $wp_keys[] = 'doing_wp_cron';
5395
-
5396
- // WP Customizer fields
5397
- $wp_keys = array_merge( $wp_keys, array(
5398
- 'nonce',
5399
- '_method',
5400
- 'wp_customize',
5401
- 'changeset_uuid',
5402
- 'customize_changeset_uuid',
5403
- 'customize_theme',
5404
- 'theme',
5405
- 'customize_messenger_channel',
5406
- 'customize_autosaved'
5407
- ) );
5408
-
5409
- $result = array_diff( $get_keys, $wp_keys );
5410
-
5411
- if ( ! $result ) {
5412
- $result = array();
5413
- }
5414
-
5415
- return $result;
5416
-
5417
- }
5418
-
5419
-
5420
- /**
5421
- *
5422
- * @since 6.0
5423
- */
5424
- function cerber_beast() {
5425
- global $cerber_status;
5426
-
5427
- if ( is_admin()
5428
- || cerber_is_wp_cron()
5429
- || ( defined( 'WP_CLI' ) && WP_CLI )
5430
- ) {
5431
- return;
5432
- }
5433
-
5434
- $wp_cerber = get_wp_cerber();
5435
-
5436
- $wp_cerber->CheckProhibitedURI();
5437
-
5438
- // TI --------------------------------------------------------------------
5439
-
5440
- if ( ! $ti_mode = crb_get_settings( 'tienabled' ) ) {
5441
- return;
5442
- }
5443
-
5444
- // White list by IP
5445
- if ( crb_get_settings( 'tiipwhite' ) && crb_acl_is_white() ) {
5446
- return; // @since 7.9
5447
- }
5448
-
5449
- // White list by URI
5450
- //$uri = cerber_purify_uri();
5451
- $uri = CRB_Request::URI();
5452
- if ( $tiwhite = crb_get_settings( 'tiwhite' ) ) {
5453
- foreach ( (array) $tiwhite as $item ) {
5454
- if ( substr( $item, 0, 1 ) == '{' && substr( $item, - 1 ) == '}' ) {
5455
- $pattern = '/' . substr( $item, 1, - 1 ) . '/i';
5456
- if ( @preg_match( $pattern, $uri ) ) {
5457
- return;
5458
- }
5459
- }
5460
- elseif ( $item == $uri ) {
5461
- return;
5462
- }
5463
- }
5464
- }
5465
-
5466
- // Step one
5467
- $wp_cerber->InspectRequest();
5468
-
5469
- // Step two
5470
- //$uri_script = cerber_get_uri_script();
5471
- $uri_script = CRB_Request::script();
5472
-
5473
- if ( $uri_script && $script_filename = cerber_script_filename() ) {
5474
- // Scanning for executable scripts?
5475
- if ( ! cerber_script_exists( $uri ) && ! cerber_is_login_request() ) {
5476
- $cerber_status = 19;
5477
- cerber_log( 55 );
5478
- if ( $ti_mode > 1 ) {
5479
- cerber_soft_block_add( null, 708 );
5480
- }
5481
- cerber_forbidden_page();
5482
- }
5483
- // Direct access to a PHP script
5484
- $deny = false;
5485
- if ( crb_acl_is_black() ) {
5486
- $deny = true;
5487
- $cerber_status = 14;
5488
- }
5489
- //elseif ( ! in_array( $uri_script, cerber_get_wp_scripts() ) ) {
5490
- elseif ( ! CRB_Request::is_script( cerber_get_wp_scripts() ) ) {
5491
- if ( ! cerber_is_allowed() ) {
5492
- $deny = true;
5493
- $cerber_status = 13;
5494
- }
5495
- elseif ( lab_is_blocked( null, true ) ) {
5496
- $deny = true;
5497
- $cerber_status = 15;
5498
- }
5499
- }
5500
- if ( $deny ) {
5501
- cerber_log( 50 );
5502
- cerber_forbidden_page();
5503
- }
5504
- }
5505
-
5506
- // Step three
5507
- cerber_screen_request_fields();
5508
-
5509
- // Step four
5510
- cerber_inspect_uploads();
5511
- }
5512
-
5513
- /**
5514
- * Inspects POST & GET fields
5515
- *
5516
- */
5517
- function cerber_screen_request_fields(){
5518
- global $cerber_in_context;
5519
-
5520
- $white = array();
5521
- $found = false;
5522
-
5523
- if ( ! empty( $_GET ) ) {
5524
- $cerber_in_context = 1;
5525
- $found = cerber_inspect_array( $_GET, array( 's' ) );
5526
- }
5527
-
5528
- if ( ! empty( $_POST ) && ! $found ) {
5529
- if ( CRB_Request::is_script( '/' . WP_COMMENT_SCRIPT ) ) {
5530
- $white = array( 'comment' );
5531
- }
5532
- $cerber_in_context = 2;
5533
- $found = cerber_inspect_array( $_POST, $white );
5534
- }
5535
-
5536
- if ( $found ) {
5537
- cerber_log( $found );
5538
- cerber_soft_block_add( null, 709);
5539
- cerber_forbidden_page();
5540
- }
5541
- }
5542
-
5543
- /**
5544
- * Recursively inspects values in a given multi-dimensional array
5545
- *
5546
- * @param array $array
5547
- * @param array $white A list of elements to skip
5548
- *
5549
- * @return bool|int
5550
- */
5551
- function cerber_inspect_array( &$array, $white = array() ) {
5552
- global $cerber_status;
5553
- static $rec_limit = null;
5554
-
5555
- if ( ! $array ) {
5556
- return false;
5557
- }
5558
-
5559
- if ( $rec_limit === null ) {
5560
- $rec_limit = CERBER_CIREC_LIMIT;
5561
- }
5562
- else {
5563
- $rec_limit --;
5564
- if ( $rec_limit <= 0 ) {
5565
- $rec_limit = null;
5566
- $cerber_status = 20;
5567
-
5568
- return 100;
5569
- }
5570
- }
5571
-
5572
- foreach ( $array as $key => $value ) {
5573
- if ( in_array( $key, $white ) ) {
5574
- continue;
5575
- }
5576
- if ( is_array( $value ) ) {
5577
- $found = cerber_inspect_array( $value );
5578
- }
5579
- else {
5580
- $found = cerber_inspect_value( $value, true );
5581
- }
5582
- if ( $found ) {
5583
- return $found;
5584
- }
5585
- }
5586
-
5587
- $rec_limit ++;
5588
-
5589
- return false;
5590
- }
5591
-
5592
- function cerber_inspect_value( &$value = '', $reset = false ) {
5593
- global $cerber_status, $crb_x64;
5594
- static $rec_limit = null; // Real recursion limit
5595
-
5596
- if ( ! $value || is_numeric( $value ) ) {
5597
- return false;
5598
- }
5599
-
5600
- if ( $reset ) {
5601
- $rec_limit = null;
5602
- }
5603
-
5604
- if ( $rec_limit === null ) {
5605
- $rec_limit = CERBER_CIREC_LIMIT;
5606
- }
5607
- else {
5608
- $rec_limit --;
5609
- if ( $rec_limit <= 0 ) {
5610
- $rec_limit = null;
5611
- $cerber_status = 21;
5612
-
5613
- return 100;
5614
- }
5615
- }
5616
-
5617
- $found = false;
5618
-
5619
- if ( $varbyref = cerber_is_base64_encoded( $value ) ) {
5620
- $found = cerber_inspect_value( $varbyref );
5621
- }
5622
- else {
5623
- $parsed = cerber_detect_php_code( $value );
5624
- if ( ! empty( $parsed[0] ) ) {
5625
- $cerber_status = 22;
5626
- $found = 100;
5627
- }
5628
- elseif ( ! empty( $parsed[1] ) ) {
5629
- foreach ( $parsed[1] as $string ) {
5630
- $found = cerber_inspect_value( $string );
5631
- if ( $found ) {
5632
- break;
5633
- }
5634
- }
5635
- }
5636
- if ( ! $found && cerber_detect_other_code( $value ) ) {
5637
- $cerber_status = 23;
5638
- $found = 100;
5639
- }
5640
- if ( ! $found && cerber_detect_js_code( $value ) ) {
5641
- $cerber_status = 24;
5642
- $found = 100;
5643
- }
5644
- }
5645
-
5646
- $rec_limit ++;
5647
-
5648
- return $found;
5649
- }
5650
-
5651
- /**
5652
- * @param $value string
5653
- *
5654
- * @return array A list of suspicious code patterns
5655
- */
5656
- function cerber_detect_php_code( &$value ) {
5657
- static $list;
5658
- if ( ! $list ) {
5659
- $list = cerber_get_php_unsafe();
5660
- }
5661
- $ret = array( array(), array() );
5662
- $code_tokens = array( T_STRING, T_EVAL );
5663
-
5664
- $clean = preg_replace( "/[\r\n\s]+/", '', cerber_remove_comments( $value ) );
5665
-
5666
- if ( $tokens = @token_get_all( '<?php ' . $clean ) ) {
5667
- foreach ( $tokens as $token ) {
5668
- if ( ! is_array( $token ) ) {
5669
- continue;
5670
- }
5671
- if ( in_array( $token[0], $code_tokens ) && isset( $list[ $token[1] ] ) ) {
5672
- if ( preg_match( '/' . $token[1] . '\((?!\)).+\)/i', $clean ) ) {
5673
- $ret[0] = array( $token[0], $list[ $token[1] ] );
5674
- break;
5675
- }
5676
- }
5677
- elseif ( $token[0] == T_CONSTANT_ENCAPSED_STRING ) {
5678
- $string = trim( $token[1], '\'"' );
5679
- if ( ! $string || is_numeric( $string ) ) {
5680
- continue;
5681
- }
5682
- $ret[1][] = $string;
5683
- }
5684
- }
5685
- }
5686
-
5687
- return $ret;
5688
- }
5689
-
5690
- function cerber_detect_other_code( &$value ) {
5691
- global $cerber_in_context;
5692
- //static $sql = array( 'information_schema.', 'xp_cmdshell', 'FROM_BASE64', '@@' );
5693
- $co = ( isset( $cerber_in_context ) ) ? $cerber_in_context : 0;
5694
- $score = 0;
5695
- $str = $value;
5696
- if ( $co > 0 ) {
5697
- $str = preg_replace( '#/\*(?:[^*]*(?:\*(?!/))*)*\*/#', '', $str ); // Remove comments
5698
- if ( $co == 1 ) {
5699
- if ( strlen( $value ) != strlen( $str ) ) {
5700
- $score ++;
5701
- }
5702
- }
5703
- }
5704
- if ( preg_match( '/\b(?:SELECT|INSERT|UPDATE|DELETE)\b/i', $str ) ) { // SQL?
5705
- $score ++;
5706
- $p = stripos( $str, 'UNION' );
5707
- if ( $p !== false ) {
5708
- $score ++;
5709
- if ( $co == 1 ) {
5710
- return true;
5711
- }
5712
- }
5713
- if ( preg_match( '/\b(?:information_schema|FROM_BASE64|wp_users|xp_cmdshell|LOAD_FILE)\b/i', $value ) ) {
5714
- return true;
5715
- }
5716
- if ( $co < 1 ) {
5717
- return false;
5718
- }
5719
- // $_GET & $_POST
5720
- if ( preg_match( '/\b(?:name_const|unhex)\b/i', $value ) ) {
5721
- $score ++;
5722
- }
5723
- if ( $score > 3 ) {
5724
- return true;
5725
- }
5726
- $char = substr_count( strtoupper( $value ), 'CHAR' );
5727
- if ( $char > 1 ) {
5728
- return true;
5729
- }
5730
- $score += $char;
5731
- if ( $score > 3 ) {
5732
- return true;
5733
- }
5734
- }
5735
-
5736
- return false;
5737
- }
5738
-
5739
- /**
5740
- * Detects ob/fus/cated JS
5741
- *
5742
- * @param $val
5743
- *
5744
- * @return bool
5745
- */
5746
- function cerber_detect_js_code( $val ) {
5747
- $val = trim( $val );
5748
- if ( empty( $val ) || is_numeric( $val ) ) {
5749
- return false;
5750
- }
5751
- $val = preg_replace( "/[\s]+/", '', $val );
5752
- if ( strlen( $val ) < 32 ) {
5753
- return false;
5754
- }
5755
- // HEX
5756
- if ( preg_match_all( '/(["\'])(\\\\x[0-9a-fA-F]{2})+?\1/m', $val, $matches ) ) {
5757
- $found = array_map( function ( $v ) {
5758
- return trim( $v, '\'"' );
5759
- }, $matches[0] );
5760
- $found = str_replace( '\x', '', $found );
5761
-
5762
- // -- V2
5763
- /*
5764
- $pieces = array();
5765
- foreach ( $found as $str) {
5766
- echo $str.'-';
5767
- $hexs = str_split( $str, 2 );
5768
- $pieces[] = implode( '', array_map( function ( $v ) {
5769
- return chr( hexdec( $v ) );
5770
- }, $hexs ) );
5771
- }*/
5772
-
5773
- // V1
5774
- $hexs = str_split( implode( '', $found ), 2 );
5775
- $decoded = implode( '', array_map( function ( $hex ) {
5776
- return chr( hexdec( $hex ) );
5777
- }, $hexs ) );
5778
-
5779
- if ( preg_match( '/(fromCharCode|createElement|appendChild|script|eval|unescape|getElement|querySelector|XMLHttpRequest|FileSystemObject)/i', $decoded ) ) {
5780
- return true;
5781
- }
5782
-
5783
- }
5784
-
5785
- if ( preg_match_all( '/((?:\d|0x)[\da-fA-F]{1,4})\s*(?:,|\))/m', $val, $matches ) ) {
5786
- $decoded = cerber_fromcharcode( implode( ',', $matches[1] ) );
5787
- $p = cerber_get_js_patterns();
5788
- list ($xdata, $severity) = cerber_process_patterns( $decoded, $p );
5789
- if ( $xdata ) {
5790
- return true;
5791
- }
5792
- }
5793
-
5794
- return false;
5795
- }
5796
-
5797
- function cerber_process_patterns( $str, $patterns ) {
5798
- $xdata = array();
5799
- $severity = array();
5800
-
5801
- foreach ( $patterns as $pa ) {
5802
- if ($pa[1] == 2) { // 2 = REGEX
5803
- $matches = array();
5804
- if ( preg_match_all( '/' . $pa[2] . '/i', $str, $matches, PREG_OFFSET_CAPTURE ) ) {
5805
-
5806
- if ( ! empty( $pa['not_func'] ) && function_exists( $pa['not_func'] ) ) {
5807
- foreach ( $matches[0] as $key => $match ) {
5808
- if ( call_user_func( $pa['not_func'], $match[0] ) ) {
5809
- unset( $matches[0][ $key ] );
5810
- }
5811
- }
5812
- }
5813
-
5814
- if ( ! empty( $pa['func'] ) && function_exists( $pa['func'] ) ) {
5815
- foreach ( $matches[0] as $key => $match ) {
5816
- if ( ! call_user_func( $pa['func'], $match[0] ) ) {
5817
- unset( $matches[0][ $key ] );
5818
- }
5819
- }
5820
- }
5821
-
5822
- if ( ! empty( $matches[0] ) ) {
5823
- $xdata[] = array( 2, $pa[0], array_values( $matches[0] ) );
5824
- $severity[] = $pa[3];
5825
- }
5826
- }
5827
- }
5828
- else {
5829
- if ( false !== stripos( $str, $pa[2] ) ) {
5830
- $xdata[] = array( 2, $pa[0], array( array( $pa[2] ) ) );
5831
- $severity[] = $pa[3];
5832
- }
5833
- }
5834
- }
5835
-
5836
- return array( $xdata, $severity );
5837
- }
5838
-
5839
- function cerber_inspect_uploads() {
5840
- static $found = null;
5841
-
5842
- if ( $found !== null ) {
5843
- return $found; // avoid double inspection
5844
- }
5845
-
5846
- if ( empty( $_FILES ) ) {
5847
- return $found;
5848
- }
5849
-
5850
- $files = array();
5851
-
5852
- foreach ( $_FILES as $file ) {
5853
- if ( is_array( $file['tmp_name'] ) ) {
5854
- $files[] = array_merge( $files, $file['tmp_name'] );
5855
- }
5856
- else {
5857
- $files[] = $file['tmp_name'];
5858
- }
5859
- }
5860
-
5861
- $found = false;
5862
-
5863
- foreach ( $files as $file_name ) {
5864
- if ( $f = @fopen( $file_name, 'r' ) ) {
5865
- $str = @fread( $f, 100000 );
5866
- @fclose( $f );
5867
- if ( cerber_inspect_value( $str ) ) {
5868
- $found = 56;
5869
- if ( ! @unlink( $file_name ) ) {
5870
- // if a system doesn't permit us to delete the file in the tmp uploads folder
5871
- $target = cerber_get_the_folder() . 'must_be_deleted.tmp';
5872
- @move_uploaded_file( $file_name, $target );
5873
- @unlink( $target );
5874
- }
5875
- }
5876
- }
5877
- }
5878
-
5879
- if ( $found ) {
5880
- cerber_log( $found );
5881
- cerber_soft_block_add( null, 710);
5882
- }
5883
-
5884
- return $found;
5885
- }
5886
-
5887
- function cerber_error_control() {
5888
- if ( crb_get_settings( 'nophperr' ) ) {
5889
- @ini_set( 'display_startup_errors', 0 );
5890
- @ini_set( 'display_errors', 0 );
5891
- }
5892
- }
5893
-
5894
- // Menu routines ---------------------------------------------------------------
5895
-
5896
- // Hide/show menu items in public
5897
- add_filter( 'wp_get_nav_menu_items', function ( $items, $menu, $args ) {
5898
- if ( is_admin() ) {
5899
- return $items;
5900
- }
5901
- $logged = is_user_logged_in();
5902
- foreach ( $items as $key => $item ) {
5903
- // For *MENU*CERBER* See cerber_nav_menu_box() !!!
5904
- if ( 0 === strpos( $item->attr_title, '*MENU*CERBER*' ) ) {
5905
- $menu_id = explode( '|', $item->attr_title );
5906
- switch ( $menu_id[1] ) {
5907
- case 'wp-cerber-login-url':
5908
- if ( $logged ) {
5909
- unset( $items[ $key ] );
5910
- }
5911
- break;
5912
- case 'wp-cerber-logout-url':
5913
- if ( ! $logged ) {
5914
- unset( $items[ $key ] );
5915
- }
5916
- break;
5917
- case 'wp-cerber-reg-url':
5918
- if ( $logged ) {
5919
- unset( $items[ $key ] );
5920
- }
5921
- break;
5922
- case 'wp-cerber-wc-login-url':
5923
- if ( $logged ) {
5924
- unset( $items[ $key ] );
5925
- }
5926
- break;
5927
- case 'wp-cerber-wc-logout-url':
5928
- if ( ! $logged ) {
5929
- unset( $items[ $key ] );
5930
- }
5931
- break;
5932
- }
5933
- }
5934
- }
5935
-
5936
- return $items;
5937
- }, 10, 3 );
5938
-
5939
- // Set actual URL for a menu item based on a special value in title attribute
5940
- add_filter( 'nav_menu_link_attributes', function ( $atts ) {
5941
-
5942
- // For *MENU*CERBER* See cerber_nav_menu_box() !!!
5943
- if ( 0 === strpos( $atts['title'], '*MENU*CERBER*' ) ) {
5944
- $title = explode( '|', $atts['title'] );
5945
- $atts['title'] = '';
5946
-
5947
- $url = '#';
5948
- // See cerber_nav_menu_items() !!!
5949
- switch ( $title[1] ) {
5950
- case 'wp-cerber-login-url':
5951
- $url = wp_login_url();
5952
- break;
5953
- case 'wp-cerber-logout-url':
5954
- $url = wp_logout_url();
5955
- break;
5956
- case 'wp-cerber-reg-url':
5957
- if ( get_option( 'users_can_register' ) ) {
5958
- $url = wp_registration_url();
5959
- }
5960
- break;
5961
- case 'wp-cerber-wc-login-url':
5962
- if ( class_exists( 'WooCommerce' ) ) {
5963
- $url = get_permalink( get_option( 'woocommerce_myaccount_page_id' ) );
5964
- }
5965
- break;
5966
- case 'wp-cerber-wc-logout-url':
5967
- if ( class_exists( 'WooCommerce' ) ) {
5968
- $url = wc_logout_url();
5969
- }
5970
- break;
5971
- }
5972
-
5973
- $atts['href'] = $url;
5974
- }
5975
-
5976
- return $atts;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5977
  }, 1 );
1
+ <?php
2
+ /*
3
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
4
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
5
+
6
+ Licenced under the GNU GPL.
7
+
8
+ This program is free software; you can redistribute it and/or modify
9
+ it under the terms of the GNU General Public License as published by
10
+ the Free Software Foundation; either version 3 of the License, or
11
+ (at your option) any later version.
12
+
13
+ This program is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ GNU General Public License for more details.
17
+
18
+ You should have received a copy of the GNU General Public License
19
+ along with this program; if not, write to the Free Software
20
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+
22
+ */
23
+
24
+ /*
25
+
26
+
27
+
28
+ ▄████▄ ▓█████ ██▀███ ▄▄▄▄ ▓█████ ██▀███
29
+ ▒██▀ ▀█ ▓█ ▀ ▓██ ▒ ██▒ ▓█████▄ ▓█ ▀ ▓██ ▒ ██▒
30
+ ▒▓█ ▄ ▒███ ▓██ ░▄█ ▒ ▒██▒ ▄██ ▒███ ▓██ ░▄█ ▒
31
+ ▒▓▓▄ ▄██▒ ▒▓█ ▄ ▒██▀▀█▄ ▒██░█▀ ▒▓█ ▄ ▒██▀▀█▄
32
+ ▒ ▓███▀ ░ ░▒████▒ ░██▓ ▒██▒ ░▓█ ▀█▓ ░▒████▒ ░██▓ ▒██▒
33
+ ░ ░▒ ▒ ░ ░░ ▒░ ░ ░ ▒▓ ░▒▓░ ░▒▓███▀▒ ░░ ▒░ ░ ░ ▒▓ ░▒▓░
34
+ ░ ▒ ░ ░ ░ ░▒ ░ ▒░ ▒░▒ ░ ░ ░ ░ ░▒ ░ ▒░
35
+ ░ ░ ░░ ░ ░ ░ ░ ░░ ░
36
+ ░ ░ ░ ░ ░ ░ ░ ░ ░
37
+ ░ ░
38
+
39
+
40
+
41
+
42
+ *========================================================================*
43
+ | |
44
+ | ATTENTION! Do not change or edit this file! |
45
+ | |
46
+ *========================================================================*
47
+
48
+ */
49
+
50
+ // If this file is called directly, abort executing.
51
+ if ( ! defined( 'WPINC' ) ) {
52
+ exit;
53
+ }
54
+
55
+ define( 'CERBER_LOG_TABLE', 'cerber_log' );
56
+ define( 'CERBER_QMEM_TABLE', 'cerber_qmem' );
57
+ define( 'CERBER_TRAF_TABLE', 'cerber_traffic' );
58
+ define( 'CERBER_ACL_TABLE', 'cerber_acl' );
59
+ define( 'CERBER_BLOCKS_TABLE', 'cerber_blocks' );
60
+ define( 'CERBER_LAB_TABLE', 'cerber_lab' );
61
+ define( 'CERBER_LAB_IP_TABLE', 'cerber_lab_ip' );
62
+ define( 'CERBER_LAB_NET_TABLE', 'cerber_lab_net' );
63
+ define( 'CERBER_GEO_TABLE', 'cerber_countries' );
64
+ define( 'CERBER_SCAN_TABLE', 'cerber_files' );
65
+ define( 'CERBER_SETS_TABLE', 'cerber_sets' );
66
+
67
+ define( 'CERBER_BUKEY', '_crb_blocked' );
68
+ define( 'CERBER_PREFIX', '_cerber_' );
69
+ define( 'CERBER_MARKER1', 'WP CERBER GROOVE' );
70
+ define( 'CERBER_MARKER2', 'WP CERBER CLAMPS' );
71
+ define( 'CERBER_NO_REMOTE_IP', '0.0.0.0' );
72
+
73
+ define( 'WP_LOGIN_SCRIPT', 'wp-login.php' );
74
+ define( 'WP_REG_URI', 'wp-register.php' );
75
+ define( 'WP_XMLRPC_SCRIPT', 'xmlrpc.php' );
76
+ define( 'WP_TRACKBACK_SCRIPT', 'wp-trackback.php' );
77
+ define( 'WP_PING_SCRIPT', 'wp-trackback.php' );
78
+ define( 'WP_SIGNUP_SCRIPT', 'wp-signup.php' );
79
+ define( 'WP_COMMENT_SCRIPT', 'wp-comments-post.php' );
80
+
81
+ define( 'GOO_RECAPTCHA_URL', 'https://www.google.com/recaptcha/api/siteverify' );
82
+ define( 'CERBER_VULNDB_API', 'https://wpvulndb.com/api/v2/plugins/' );
83
+
84
+ define( 'CERBER_REQ_PHP', '5.4.0' );
85
+ define( 'CERBER_REQ_WP', '4.5' );
86
+ define( 'CERBER_TECH', 'https://cerber.tech/' );
87
+
88
+ define( 'CERBER_CIREC_LIMIT', 30 ); // Upper limit for allowed nested values during inspection for malware
89
+
90
+ define( 'CERBER_AGGRESSIVE', 1 );
91
+
92
+ require_once( dirname( __FILE__ ) . '/cerber-pluggable.php' );
93
+ require_once( dirname( __FILE__ ) . '/common.php' );
94
+ require_once( dirname( __FILE__ ) . '/settings.php' );
95
+ include_once( dirname( __FILE__ ) . '/cerber-request.php' );
96
+ require_once( dirname( __FILE__ ) . '/cerber-lab.php' );
97
+ require_once( dirname( __FILE__ ) . '/whois.php' );
98
+ require_once( dirname( __FILE__ ) . '/jetflow.php' );
99
+ require_once( dirname( __FILE__ ) . '/cerber-news.php' );
100
+ require_once( dirname( __FILE__ ) . '/cerber-scanner.php' );
101
+
102
+ if ( defined( 'WP_ADMIN' ) || defined( 'WP_NETWORK_ADMIN' ) ) {
103
+ // Load dashboard stuff
104
+ require_once( dirname( __FILE__ ) . '/cerber-users.php' );
105
+ require_once( dirname( __FILE__ ) . '/dashboard.php' );
106
+ //require_once( dirname( __FILE__ ) . '/nexus/cerber-nexus.php' );
107
+ }
108
+
109
+ // =============================================================================================
110
+
111
+ class WP_Cerber {
112
+ private $remote_ip;
113
+ private $session_id;
114
+ private $status = null;
115
+ private $options;
116
+ private $locked = null; // IP has been locked out
117
+
118
+ private $recaptcha = null; // Can recaptcha be verified with current request
119
+ private $recaptcha_verified = null; // Is recaptcha successfully verified with current request
120
+ public $recaptcha_here = null; // Is recaptcha widget enabled on the currently displayed page
121
+
122
+ private $uri_prohibited = null;
123
+ private $deny = null;
124
+ private $acl = null;
125
+
126
+ //private $boot_source_file = '';
127
+ //private $boot_target_file = '';
128
+
129
+ public $garbage = false; // Garbage has been deleted
130
+
131
+ final function __construct() {
132
+
133
+ $this->session_id = substr(str_shuffle('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'), 0, 24);
134
+
135
+ // Load settings with filling missing (not-set) array keys
136
+ $this->options = crb_get_settings(); // @since 6.3.3
137
+ $keys = array();
138
+ //$defaults = array();
139
+ foreach ( cerber_get_defaults() as $item ) {
140
+ $keys = array_merge( $keys, array_keys( $item ) );
141
+ //$defaults = array_merge( $defaults, $item );
142
+ }
143
+ foreach ( $keys as $key ) {
144
+ if ( ! isset( $this->options[ $key ] ) ) {
145
+ $this->options[ $key ] = null;
146
+ }
147
+ }
148
+
149
+ if ( defined( 'CERBER_IP_KEY' ) ) {
150
+ $this->remote_ip = filter_var( $_SERVER[ CERBER_IP_KEY ], FILTER_VALIDATE_IP );
151
+ }
152
+ elseif ( $this->options['proxy'] && isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
153
+ $list = explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] );
154
+ foreach ( $list as $maybe_ip ) {
155
+ $this->remote_ip = filter_var( trim( $maybe_ip ), FILTER_VALIDATE_IP );
156
+ if ( $this->remote_ip ) {
157
+ break;
158
+ }
159
+ }
160
+ if ( ! $this->remote_ip && isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
161
+ $this->remote_ip = filter_var( $_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP );
162
+ }
163
+ } else {
164
+ if ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
165
+ $this->remote_ip = $_SERVER['REMOTE_ADDR'];
166
+ } elseif ( isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
167
+ $this->remote_ip = $_SERVER['HTTP_X_REAL_IP'];
168
+ } elseif ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) {
169
+ $this->remote_ip = $_SERVER['HTTP_CLIENT_IP'];
170
+ } elseif ( isset( $_SERVER['SERVER_ADDR'] ) ) {
171
+ $this->remote_ip = $_SERVER['SERVER_ADDR'];
172
+ }
173
+ $this->remote_ip = filter_var( $this->remote_ip, FILTER_VALIDATE_IP );
174
+ }
175
+ // No IP address was found? Roll back to localhost.
176
+ if ( ! $this->remote_ip ) { // including WP-CLI, other way is: if defined('WP_CLI')
177
+ $this->remote_ip = CERBER_NO_REMOTE_IP;
178
+ }
179
+
180
+ $this->remote_ip = cerber_short_ipv6( $this->remote_ip );
181
+
182
+ $this->reCaptchaInit();
183
+
184
+ $this->deleteGarbage();
185
+
186
+ // Condition to check reCAPTCHA
187
+
188
+ add_action( 'login_init', array( $this, 'reCaptchaNow' ) );
189
+
190
+ }
191
+
192
+ /**
193
+ * @since 6.3.3
194
+ */
195
+ final public function isURIProhibited() {
196
+ global $cerber_status;
197
+
198
+ if ( isset( $this->uri_prohibited ) ) {
199
+ return $this->uri_prohibited;
200
+ }
201
+
202
+ if ( crb_acl_is_white() ) {
203
+ $this->uri_prohibited = false;
204
+
205
+ return false;
206
+ }
207
+
208
+ $script = cerber_last_uri();
209
+ if ( substr( $script, - 4 ) != '.php' ) {
210
+ $script .= '.php'; // Apache MultiViews enabled?
211
+ }
212
+
213
+ if ( $script ) {
214
+ if ( $script == WP_LOGIN_SCRIPT
215
+ || $script == WP_SIGNUP_SCRIPT
216
+ || ( $script == WP_REG_URI && ! get_option( 'users_can_register' ) ) ) {
217
+ if ( !empty( $this->options['wplogin'] ) ) {
218
+ $cerber_status = 19;
219
+ cerber_log( 50 );
220
+ cerber_soft_block_add( $this->remote_ip, 702, $script );
221
+ $this->uri_prohibited = true;
222
+ return true;
223
+ }
224
+ if ( ! empty( $this->options['loginnowp'] )
225
+ || $this->isDeny() ) {
226
+ cerber_log( 50 );
227
+ $this->uri_prohibited = true;
228
+ return true;
229
+ }
230
+ }
231
+ elseif ( $script == WP_XMLRPC_SCRIPT || $script == WP_TRACKBACK_SCRIPT ) {
232
+ if ( ! empty( $this->options['xmlrpc'] )
233
+ || $this->isDeny() ) {
234
+ cerber_log( 71 );
235
+ $this->uri_prohibited = true;
236
+ return true;
237
+ }
238
+ if ( !cerber_geo_allowed( 'geo_xmlrpc' ) ) {
239
+ $cerber_status = 16;
240
+ cerber_log( 71 );
241
+ $this->uri_prohibited = true;
242
+ return true;
243
+ }
244
+ }
245
+ }
246
+
247
+ $this->uri_prohibited = false;
248
+
249
+ return $this->uri_prohibited;
250
+ }
251
+
252
+ /**
253
+ * @since 6.3.3
254
+ */
255
+ final public function CheckProhibitedURI(){
256
+ if ($this->isURIProhibited()){
257
+ if ( $this->options['page404'] ) {
258
+ cerber_404_page();
259
+ }
260
+
261
+ return true;
262
+ }
263
+
264
+ return false;
265
+ }
266
+
267
+ /**
268
+ * @since 6.3.3
269
+ */
270
+ final public function InspectRequest() {
271
+ $deny = false;
272
+ $act = 18;
273
+ if ( cerber_is_http_post() ) {
274
+ if ( ! cerber_is_allowed( null, array( 701, 703, 704 ) ) ) {
275
+ $deny = true;
276
+ $act = 18;
277
+ }
278
+ }
279
+ elseif ( cerber_get_non_wp_fields() ) {
280
+ if ( ! cerber_is_allowed() ) {
281
+ $deny = true;
282
+ $act = 100;
283
+ }
284
+ }
285
+ if ( ! $deny && $_FILES ) {
286
+ $file_names = array();
287
+ foreach ( $_FILES as $file ) {
288
+ if ( is_array( $file['name'] ) ) {
289
+ $file_names = array_merge( $file_names, $file['name'] );
290
+ }
291
+ else {
292
+ $file_names[] = $file['name'];
293
+ }
294
+ }
295
+ foreach ( $file_names as $item ) {
296
+ if ( $reason = $this->isProhibitedFilename( $item ) ) {
297
+ $deny = true;
298
+ $act = $reason;
299
+ break;
300
+ }
301
+ }
302
+ }
303
+ if ( $deny ) {
304
+ cerber_log( $act );
305
+ cerber_forbidden_page();
306
+ }
307
+ }
308
+
309
+ /**
310
+ * @since 6.3.3
311
+ */
312
+ final public function isProhibitedFilename( $file_name ) {
313
+ $prohibited = array( '.htaccess' );
314
+ if ( in_array( $file_name, $prohibited ) ) {
315
+ return 57;
316
+ }
317
+ if ( cerber_detect_exec_extension( $file_name, array('js') ) ) {
318
+ return 56;
319
+ }
320
+
321
+ return false;
322
+ }
323
+
324
+ /**
325
+ * @since 6.3.3
326
+ */
327
+ final public function isDeny() {
328
+ if ( isset( $this->deny ) ) {
329
+ return $this->deny;
330
+ }
331
+
332
+ $this->acl = cerber_acl_check();
333
+
334
+ if ( $this->acl == 'B' || ! cerber_is_allowed() ) {
335
+ $this->deny = true;
336
+ }
337
+ else {
338
+ $this->deny = false;
339
+ }
340
+
341
+ return $this->deny;
342
+ }
343
+
344
+ // TODO: replace it with cerber_get_remote_ip()
345
+ final public function getRemoteIp() {
346
+ return $this->remote_ip;
347
+ }
348
+
349
+ final public function getSessionID() {
350
+ return $this->session_id;
351
+ }
352
+
353
+ final public function getStatus() {
354
+ if (isset($this->status)) return $this->status;
355
+
356
+ $this->status = 0; // Default
357
+
358
+ if ( cerber_is_citadel() ) {
359
+ $this->status = 3;
360
+ }
361
+ else {
362
+ //if ( ! cerber_is_allowed( $this->remote_ip ) ) {
363
+ if ( cerber_block_check( $this->remote_ip ) ) {
364
+ $this->status = 2;
365
+ }
366
+ else {
367
+ $tag = cerber_acl_check( $this->remote_ip );
368
+ if ( $tag == 'W' ) {
369
+ //$this->status = 4;
370
+ }
371
+ elseif ( $tag == 'B' || lab_is_blocked($this->remote_ip, false)) {
372
+ $this->status = 1;
373
+ }
374
+ }
375
+ }
376
+
377
+ return $this->status;
378
+ }
379
+
380
+ /*
381
+ Return Error message in context
382
+ */
383
+ final public function getErrorMsg() {
384
+ $status = $this->getStatus();
385
+ switch ( $status ) {
386
+ case 1:
387
+ case 3:
388
+ return apply_filters( 'cerber_msg_blocked', __( 'You are not allowed to log in. Ask your administrator for assistance.', 'wp-cerber' ) , $status);
389
+ case 2:
390
+ $block = cerber_get_block();
391
+ $min = 1 + ( $block->block_until - time() ) / 60;
392
+
393
+ return apply_filters( 'cerber_msg_reached',
394
+ sprintf( __( 'You have exceeded the number of allowed login attempts. Please try again in %d minutes.', 'wp-cerber' ), $min ),
395
+ $min );
396
+ break;
397
+ default:
398
+ return __( 'You are not allowed to log in', 'wp-cerber' );
399
+ }
400
+ }
401
+
402
+ /*
403
+ Return Remain message in context
404
+ */
405
+ final public function getRemainMsg() {
406
+ $acl = !$this->options['limitwhite'];
407
+ $remain = cerber_get_remain_count($this->remote_ip, $acl);
408
+ if ( $remain < $this->options['attempts'] ) {
409
+ if ( $remain == 0 ) {
410
+ $remain = 1; // with some settings or when lockout was manually removed, we need to have 1 attempt.
411
+ }
412
+ return apply_filters( 'cerber_msg_remain',
413
+ sprintf( _n( 'You have only one attempt remaining.', 'You have %d attempts remaining.', $remain, 'wp-cerber' ), $remain ),
414
+ $remain );
415
+ }
416
+
417
+ return false;
418
+ }
419
+
420
+ final public function getSettings( $name = null ) {
421
+ if ( ! empty( $name ) ) {
422
+ if ( isset( $this->options[ $name ] ) ) {
423
+ return $this->options[ $name ];
424
+ } else {
425
+ return false;
426
+ }
427
+ }
428
+
429
+ return $this->options;
430
+ }
431
+
432
+ /*
433
+ final public function isProhibited( $username ) {
434
+ if ( empty( $this->options['prohibited'] ) ) {
435
+ return false;
436
+ }
437
+
438
+ return in_array( $username, (array) $this->options['prohibited'] );
439
+ }*/
440
+
441
+ /**
442
+ * Adding reCAPTCHA widgets
443
+ *
444
+ */
445
+ final public function reCaptchaInit(){
446
+
447
+ if ( $this->status == 4 || empty( $this->options['sitekey'] ) || empty( $this->options['secretkey'] )) return;
448
+
449
+ // Native WP forms
450
+ add_action( 'login_form', function () {
451
+ global $wp_cerber;
452
+ $wp_cerber->reCaptcha( 'widget', 'recaplogin' );
453
+ } );
454
+ add_filter( 'login_form_middle', function ( $value ) {
455
+ global $wp_cerber;
456
+ $value .= $wp_cerber->reCaptcha( 'widget', 'recaplogin', false );
457
+ return $value;
458
+ });
459
+ add_action( 'lostpassword_form', function () {
460
+ global $wp_cerber;
461
+ $wp_cerber->reCaptcha( 'widget', 'recaplost' );
462
+ } );
463
+ add_action( 'register_form', function () {
464
+ global $wp_cerber;
465
+ if ( !did_action( 'woocommerce_register_form_start' ) ) {
466
+ $wp_cerber->reCaptcha( 'widget', 'recapreg' );
467
+ }
468
+ } );
469
+
470
+ // Support for WooCommerce forms: @since 3.8
471
+ add_action( 'woocommerce_login_form', function () {
472
+ global $wp_cerber;
473
+ $wp_cerber->reCaptcha( 'widget', 'recapwoologin' );
474
+ } );
475
+ add_action( 'woocommerce_lostpassword_form', function () {
476
+ global $wp_cerber;
477
+ $wp_cerber->reCaptcha( 'widget', 'recapwoolost' );
478
+ } );
479
+ add_action( 'woocommerce_register_form', function () {
480
+ global $wp_cerber;
481
+ if ( ! did_action( 'woocommerce_register_form_start' ) ) {
482
+ return;
483
+ }
484
+ $wp_cerber->reCaptcha( 'widget', 'recapwooreg' );
485
+ } );
486
+ add_filter( 'woocommerce_process_login_errors', function ( $validation_error ) {
487
+ global $wp_cerber;
488
+ //$wp_cerber->reCaptchaNow();
489
+ if ( ! $wp_cerber->reCaptchaValidate('woologin', true) ) {
490
+
491
+ return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-login'));
492
+ }
493
+ return $validation_error;
494
+ });
495
+ add_filter( 'allow_password_reset', function ( $var ) { // Note: 'allow_password_reset' also is fired in WP itself
496
+ global $wp_cerber;
497
+ if ( isset( $_POST['wc_reset_password'] ) && did_action( 'woocommerce_init' )) {
498
+ //$wp_cerber->reCaptchaNow();
499
+ if ( ! $wp_cerber->reCaptchaValidate( 'woolost' , true) ) {
500
+
501
+ return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-lost'));
502
+ }
503
+ }
504
+ return $var;
505
+ });
506
+ add_filter( 'woocommerce_process_registration_errors', function ( $validation_error ) {
507
+ global $wp_cerber;
508
+ //$wp_cerber->reCaptchaNow();
509
+ if ( ! $wp_cerber->reCaptchaValidate('wooreg' , true) ) {
510
+
511
+ return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-register'));
512
+ }
513
+ return $validation_error;
514
+ });
515
+
516
+ }
517
+
518
+ /**
519
+ * Generates reCAPTCHA HTML
520
+ *
521
+ * @param string $part 'style' or 'widget'
522
+ * @param null $option what plugin setting must be set to show the reCAPTCHA
523
+ * @param bool $echo if false, return the code, otherwise show it
524
+ *
525
+ * @return null|string
526
+ */
527
+ final public function reCaptcha( $part = '', $option = null, $echo = true ) {
528
+ if ( $this->status == 4 || empty( $this->options['sitekey'] ) || empty( $this->options['secretkey'] )
529
+ || ( $option && empty( $this->options[ $option ] ) )
530
+ ) {
531
+ return null;
532
+ }
533
+
534
+ $sitekey = $this->options['sitekey'];
535
+ $ret = '';
536
+
537
+ switch ( $part ) {
538
+ case 'style': // for default login WP form only - fit it in width nicely.
539
+ ?>
540
+ <style type="text/css" media="all">
541
+ #rc-imageselect, .g-recaptcha {
542
+ transform: scale(0.9);
543
+ -webkit-transform: scale(0.9);
544
+ transform-origin: 0 0;
545
+ -webkit-transform-origin: 0 0;
546
+ }
547
+
548
+ .g-recaptcha {
549
+ margin: 16px 0 20px 0;
550
+ }
551
+ </style>
552
+ <?php
553
+ break;
554
+ case 'widget':
555
+ if ( ! empty( $this->options[ $option ] ) ) {
556
+ $this->recaptcha_here = true;
557
+
558
+ //if ($this->options['invirecap']) $ret = '<div data-size="invisible" class="g-recaptcha" data-sitekey="' . $sitekey . '" data-callback="now_submit_the_form" id="cerber-recaptcha" data-badge="bottomright"></div>';
559
+ if ($this->options['invirecap']) {
560
+ $ret = '<span class="cerber-form-marker"></span><div data-size="invisible" class="g-recaptcha" data-sitekey="' . $sitekey . '" data-callback="now_submit_the_form" id="cerber-recaptcha" data-badge="bottomright"></div>';
561
+ }
562
+ else $ret = '<span class="cerber-form-marker"></span><div class="g-recaptcha" data-sitekey="' . $sitekey . '" data-callback="form_button_enabler" id="cerber-recaptcha"></div>';
563
+
564
+ //$ret = '<span class="cerber-form-marker g-recaptcha"></span>';
565
+
566
+ }
567
+ break;
568
+ }
569
+ if ( $echo ) {
570
+ echo $ret;
571
+ $ret = null;
572
+ }
573
+
574
+ return $ret;
575
+ /*
576
+ <script type="text/javascript">
577
+ var onloadCallback = function() {
578
+ //document.getElementById("wp-submit").disabled = true;
579
+ grecaptcha.render("c-recaptcha", {"sitekey" : "<?php echo $sitekey; ?>" });
580
+ //document.getElementById("wp-submit").disabled = false;
581
+ };
582
+ </script>
583
+ <script src = "https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit&hl=<?php echo $lang; ?>" async defer></script>
584
+ */
585
+ }
586
+
587
+ /**
588
+ * Validate reCAPTCHA by calling Google service
589
+ *
590
+ * @param string $form Form ID (slug)
591
+ * @param boolean $force Force validate without pre-checks
592
+ *
593
+ * @return bool true on success false on failure
594
+ */
595
+ final public function reCaptchaValidate($form = null, $force = false) {
596
+ if (!$force) {
597
+ if ( ! $this->recaptcha || $this->status == 4 ) {
598
+ return true;
599
+ }
600
+ }
601
+
602
+ if ($this->recaptcha_verified != null) return $this->recaptcha_verified;
603
+
604
+ if ( $form == 'comment' && $this->options['recapcomauth'] && is_user_logged_in()) return true;
605
+
606
+ if ( ! $form ) {
607
+ $form = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login';
608
+ }
609
+
610
+ $forms = array( // known pairs: form => specific plugin setting
611
+ 'lostpassword' => 'recaplost',
612
+ 'register' => 'recapreg',
613
+ 'login' => 'recaplogin',
614
+ 'comment' => 'recapcom',
615
+ 'woologin' => 'recapwoologin',
616
+ 'woolost' => 'recapwoolost',
617
+ 'wooreg' => 'recapwooreg',
618
+ );
619
+
620
+ if ( isset( $forms[ $form ] ) ) {
621
+ if ( empty( $this->options[ $forms[ $form ] ] ) ) {
622
+ return true; // no validation is required
623
+ }
624
+ }
625
+ else {
626
+ return true; // we don't know this form
627
+ }
628
+
629
+ if ( empty( $_POST['g-recaptcha-response'] ) ) {
630
+ $this->reCaptchaFailed($form);
631
+ return false;
632
+ }
633
+
634
+ $result = $this->reCaptchaRequest($_POST['g-recaptcha-response']);
635
+ if ( ! $result ) {
636
+ cerber_log( 42 );
637
+ return false;
638
+ }
639
+
640
+ $result = json_decode( $result );
641
+ $result = obj_to_arr_deep( $result );
642
+
643
+ if ( ! empty( $result['success'] ) ) {
644
+ $this->recaptcha_verified = true;
645
+ return true;
646
+ }
647
+ $this->recaptcha_verified = false;
648
+
649
+ if ( ! empty( $result['error-codes'] ) ) {
650
+ if ( in_array( 'invalid-input-secret', (array) $result['error-codes'] ) ) {
651
+ cerber_log( 41 );
652
+ }
653
+ }
654
+
655
+ $this->reCaptchaFailed($form);
656
+
657
+ return false;
658
+ }
659
+
660
+ final function reCaptchaFailed($context = '') {
661
+ cerber_log( 40 );
662
+ if ($this->options['recaptcha-period'] && $this->options['recaptcha-number'] && $this->options['recaptcha-within']) {
663
+ $remain = cerber_get_remain_count($this->remote_ip , true, array( 40 ), $this->options['recaptcha-number'], $this->options['recaptcha-within']);
664
+ if ($remain < 1) cerber_block_add( $this->remote_ip, 705 );
665
+ }
666
+ }
667
+
668
+ /**
669
+ * A form with possible reCAPTCHA has been submitted.
670
+ * Allow to process reCAPTCHA by setting a global flag.
671
+ * Must be called before reCaptchaValidate();
672
+ *
673
+ */
674
+ final public function reCaptchaNow() {
675
+ if ( cerber_is_http_post() && $this->options['sitekey'] && $this->options['secretkey'] ) {
676
+ $this->recaptcha = true;
677
+ }
678
+ }
679
+
680
+ /**
681
+ * Make a request to the Google reCaptcha web service
682
+ *
683
+ * @param string $response Google specific field from the submitted form (widget)
684
+ *
685
+ * @return bool|string Response of the Google service or false on failure
686
+ */
687
+ final public function reCaptchaRequest($response = ''){
688
+
689
+ if (!$response) {
690
+ if (!empty($_POST['g-recaptcha-response'])) $response = $_POST['g-recaptcha-response'];
691
+ else return false;
692
+ }
693
+
694
+ $curl = @curl_init(); // @since 4.32
695
+ if (!$curl) {
696
+ cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' Unable to initialize cURL');
697
+ return false;
698
+ }
699
+
700
+ $opt = curl_setopt_array($curl, array(
701
+ CURLOPT_URL => GOO_RECAPTCHA_URL,
702
+ CURLOPT_POST => true,
703
+ CURLOPT_POSTFIELDS => array( 'secret' => $this->options['secretkey'], 'response' => $response ),
704
+ CURLOPT_RETURNTRANSFER => true,
705
+ ));
706
+
707
+ if (!$opt) {
708
+ cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' '. curl_error($curl));
709
+ curl_close($curl);
710
+ return false;
711
+ }
712
+
713
+ $result = @curl_exec($curl);
714
+ if (!$result) {
715
+ cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' '. curl_error($curl));
716
+ $result = false;
717
+ }
718
+ curl_close($curl);
719
+
720
+ return $result;
721
+
722
+ }
723
+
724
+ final public function reCaptchaMsg($context = null){
725
+ return apply_filters( 'cerber_msg_recaptcha', __( 'Human verification failed. Please click the square box in the reCAPTCHA block below.', 'wp-cerber' ), $context);
726
+ }
727
+
728
+ final public function setLocked() {
729
+ if ( ! isset( $this->locked ) ) {
730
+ $this->locked = 1;
731
+ }
732
+ }
733
+
734
+ final public function wasLocked() {
735
+ if ( ! empty( $this->locked ) ) {
736
+ return 1;
737
+ }
738
+ return 0;
739
+ }
740
+
741
+ final public function deleteGarbage() {
742
+ if ( $this->garbage ) {
743
+ return;
744
+ }
745
+ cerber_db_query( 'DELETE FROM ' . CERBER_BLOCKS_TABLE . ' WHERE block_until < ' . time() );
746
+ $this->garbage = true;
747
+ }
748
+ }
749
+
750
+ function cerber_init() {
751
+ static $done = false;
752
+
753
+ if ( $done ) {
754
+ return;
755
+ }
756
+
757
+ cerber_pre_checks();
758
+
759
+ cerber_error_control();
760
+ cerber_request_time();
761
+
762
+ if ( crb_get_settings( 'tiphperr' ) ) {
763
+ set_error_handler( 'cerber_catch_error' );
764
+ }
765
+
766
+ cerber_upgrade_all();
767
+
768
+ global $wp_cerber;
769
+ $wp_cerber = get_wp_cerber();
770
+
771
+ cerber_beast();
772
+
773
+ $antibot = cerber_antibot_gene();
774
+ if ( $antibot && ! empty( $antibot[1] ) ) {
775
+ foreach ( $antibot[1] as $item ) {
776
+ setcookie( $item[0], $item[1], time() + 3600 * 24, cerber_get_cookie_path() );
777
+ }
778
+ }
779
+
780
+ // Redirection control: no default aliases for redirections
781
+ //if ( crb_get_settings( 'noredirect' ) ) {
782
+ if ( cerber_no_redirect() ) {
783
+ remove_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );
784
+ }
785
+
786
+ $hooks = apply_filters( 'cerber_antibot_hooks', array() );
787
+ if ( ! empty( $hooks['login_register'] ) ) {
788
+ foreach ( $hooks['login_register'] as $hook ) {
789
+ add_action( $hook, 'cerber_login_register_stuff', 1000 );
790
+ }
791
+ }
792
+
793
+ $done = true;
794
+ }
795
+
796
+ /**
797
+ * Returns correct WP_Cerber object
798
+ * Protects and sets global $wp_cerber to the proper object
799
+ *
800
+ * @return WP_Cerber
801
+ * @since 6.0
802
+ */
803
+ function get_wp_cerber(){
804
+ global $wp_cerber;
805
+ static $the_wp_cerber = null;
806
+
807
+ if ( ! isset( $the_wp_cerber ) ) {
808
+ $the_wp_cerber = new WP_Cerber();
809
+ }
810
+
811
+ $wp_cerber = $the_wp_cerber;
812
+
813
+ return $the_wp_cerber;
814
+ }
815
+
816
+ /**
817
+ *
818
+ * Initialize Cerber Security
819
+ *
820
+ */
821
+ add_action( 'plugins_loaded', function () {
822
+
823
+ cerber_error_control();
824
+
825
+ get_wp_cerber();
826
+
827
+ cerber_inspect_uploads(); // Uploads in the dashboard
828
+
829
+ $use_eng = false;
830
+ //if ( is_admin() && crb_get_settings( 'admin_lang' ) && cerber_is_admin_page() ) {
831
+ if ( is_admin() && crb_get_settings( 'admin_lang' ) ) {
832
+ $use_eng = true;
833
+ //add_filter( 'locale', function () {
834
+ /*add_filter( 'plugin_locale', function () {
835
+ return 'en_US';
836
+ } );*/
837
+ add_filter( 'override_load_textdomain', function ( $val, $domain, $mofile ) {
838
+ if ($domain == 'wp-cerber'){
839
+ $val = true;
840
+ }
841
+ return $val;
842
+ }, 100, 3 );
843
+ }
844
+ if ( ! $use_eng ) {
845
+ load_plugin_textdomain( 'wp-cerber', false, basename( dirname( __FILE__ ) ) . '/languages' );
846
+ }
847
+
848
+ /* @since 5.8.8
849
+ if ( ! cerber_check_groove() && ! cerber_is_allowed() ) {
850
+ wp_clear_auth_cookie();
851
+ }*/
852
+
853
+ cerber_init_cron();
854
+
855
+ __('> > > Translator of WP Cerber? To get the PRO license for free, drop your contacts here: https://wpcerber.com/contact/','wp-cerber');
856
+
857
+ }, 1000 );
858
+
859
+ /**
860
+ * Some additional tasks...
861
+ *
862
+ */
863
+ function cerber_extra_vision() {
864
+ global $cerber_logged, $cerber_status;
865
+
866
+ // Multiple different malicious activities
867
+ if ( ! empty( $cerber_logged ) ) {
868
+ $ip = cerber_get_remote_ip();
869
+ $black = crb_get_activity_set( 'black' );
870
+ $black_logged = array_intersect( $black, $cerber_logged );
871
+ if ( ! empty( $black_logged ) && cerber_is_allowed() ) {
872
+ $remain = cerber_get_remain_count( $ip, true, $black ); // @since 6.7.5
873
+ if ( $remain < 1 ) {
874
+ cerber_soft_block_add( $ip, 707 );
875
+ $cerber_status = 18;
876
+
877
+ return true;
878
+ }
879
+ }
880
+ }
881
+
882
+ return false;
883
+ }
884
+
885
+ /*
886
+ Display login form if Custom login URL has been requested
887
+
888
+ */
889
+ add_action( 'init', 'cerber_wp_login_page', 20 );
890
+ //add_action( 'setup_theme', 'cerber_wp_login_page' ); // @since 5.05
891
+ function cerber_wp_login_page() {
892
+ if ( $path = crb_get_settings( 'loginpath' ) ) {
893
+ if ( cerber_is_login_request() ) {
894
+ if ( ! defined( 'DONOTCACHEPAGE' ) ) {
895
+ define( 'DONOTCACHEPAGE', true ); // @since 5.7.6
896
+ }
897
+ @ini_set( 'display_startup_errors', 0 );
898
+ @ini_set( 'display_errors', 0 );
899
+ add_action( 'login_init', function () {
900
+ @ini_set( 'display_startup_errors', 0 );
901
+ @ini_set( 'display_errors', 0 );
902
+ } );
903
+ require( ABSPATH . WP_LOGIN_SCRIPT ); // load default wp-login.php form
904
+ exit;
905
+ }
906
+ }
907
+ }
908
+
909
+ /**
910
+ * Check if the current HTTP request is a login/register/lost password page request
911
+ *
912
+ * @return bool
913
+ */
914
+ function cerber_is_login_request() {
915
+ static $ret;
916
+
917
+ if ( isset( $ret ) ) {
918
+ return $ret;
919
+ }
920
+
921
+ $ret = false;
922
+
923
+ if ( $path = crb_get_settings( 'loginpath' ) ) {
924
+ $request = $_SERVER['REQUEST_URI'];
925
+ if ( $pos = strpos( $request, '?' ) ) {
926
+ $request = substr( $request, 0, $pos - 1 );
927
+ }
928
+ $request = explode( '/', rtrim( $request, '/' ) );
929
+ $request = end( $request );
930
+ if ( $path == $request && ! cerber_is_rest_url() ) {
931
+ $ret = true;
932
+ }
933
+ }
934
+ elseif ( CRB_Request::is_script( '/' . WP_LOGIN_SCRIPT ) ) {
935
+ $ret = true;
936
+ }
937
+
938
+ return $ret;
939
+ }
940
+
941
+ /**
942
+ * Does the current location (URL) requires a user to be logged in to view
943
+ *
944
+ * @param $allowed_url string An URL that is allowed to view without authentication
945
+ *
946
+ * @return bool
947
+ */
948
+ function cerber_auth_required( $allowed_url ) {
949
+ if ( $allowed_url && CRB_Request::is_url_equal( $allowed_url ) ) {
950
+ return false;
951
+ }
952
+ if ( cerber_is_login_request() ) {
953
+ return false;
954
+ }
955
+ if ( CRB_Request::is_script( array( '/' . WP_LOGIN_SCRIPT, '/' . WP_SIGNUP_SCRIPT, '/wp-activate.php' ) ) ) {
956
+ return false;
957
+ }
958
+ if ( CRB_Request::is_url_start_with( wp_login_url() ) ) {
959
+ return false;
960
+ }
961
+ if ( class_exists( 'WooCommerce' ) ) {
962
+ if ( CRB_Request::is_url_start_with( get_permalink( get_option( 'woocommerce_myaccount_page_id' ) ) ) ) {
963
+ return false;
964
+ }
965
+ }
966
+
967
+ return true;
968
+ }
969
+
970
+ /*
971
+ Create message to show it above login form for any simply GET
972
+ */
973
+ add_action( 'login_head', 'cerber_login_head' );
974
+ function cerber_login_head() {
975
+ global $error, $wp_cerber;
976
+
977
+ if ( !$allowed = cerber_is_allowed() ) :
978
+ ?>
979
+ <style type="text/css" media="all">
980
+ #loginform {
981
+ display: none;
982
+ }
983
+ </style>
984
+ <?php
985
+ endif;
986
+
987
+ $wp_cerber->reCaptcha( 'style' );
988
+
989
+ if ( !cerber_is_http_get() ) {
990
+ return;
991
+ }
992
+ if ( ! cerber_can_msg() ) {
993
+ return;
994
+ }
995
+
996
+ if ( ! $allowed ) {
997
+ $error = $wp_cerber->getErrorMsg();
998
+ }
999
+ elseif ( $msg = $wp_cerber->getRemainMsg() ) {
1000
+ $error = $msg;
1001
+ }
1002
+ elseif ( crb_get_settings( 'authonly' ) && ( $m = crb_get_settings( 'authonlymsg' ) ) ) {
1003
+ $error = $m;
1004
+ }
1005
+ }
1006
+
1007
+ /**
1008
+ * Control the process of authentication
1009
+ *
1010
+ * @since 2.9
1011
+ *
1012
+ */
1013
+ remove_filter( 'authenticate', 'wp_authenticate_username_password', 20 );
1014
+ remove_filter( 'authenticate', 'wp_authenticate_email_password', 20 );
1015
+ add_filter( 'authenticate', function ( $user, $username, $password ) {
1016
+ return cerber_authenticate( $user, $username, $password );
1017
+ }, 20, 3 );
1018
+ function cerber_authenticate( $user, $username, $password ) {
1019
+ global $wp_cerber;
1020
+
1021
+ if ( ! $wp_cerber->reCaptchaValidate() ) {
1022
+
1023
+ return new WP_Error( 'incorrect_recaptcha',
1024
+ '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1025
+ $wp_cerber->reCaptchaMsg('login'));
1026
+ }
1027
+
1028
+ // Check for prohibited username
1029
+ //if ( $wp_cerber->isProhibited( $username ) ) {
1030
+ if ( $username && cerber_is_prohibited( $username ) ) {
1031
+ cerber_log( 52, $username );
1032
+ cerber_block_add( null, 704, $username );
1033
+
1034
+ // Create with message that is identical default WP
1035
+ return new WP_Error( 'incorrect_password', sprintf(
1036
+ __( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
1037
+ '<strong>' . $username . '</strong>'
1038
+ ) );
1039
+ }
1040
+ /*
1041
+ if ( lab_is_blocked($wp_cerber->getRemoteIp()) ) {
1042
+
1043
+ // Create with message which is identical default WP
1044
+ return new WP_Error( 'incorrect_password', sprintf(
1045
+ __( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
1046
+ '<strong>' . $username . '</strong>'
1047
+ ) );
1048
+ }*/
1049
+
1050
+ $user = wp_authenticate_username_password( $user, $username, $password );
1051
+ $user = wp_authenticate_email_password( $user, $username, $password );
1052
+
1053
+ // @since 4.18 it is replacement for 'wp_login_failed' action hook
1054
+ // see WP function wp_authenticate()
1055
+ $ignore_codes = array( 'empty_username', 'empty_password', 'cerber_denied' );
1056
+ if ( is_wp_error( $user ) && ! in_array( $user->get_error_code(), $ignore_codes ) ) {
1057
+ $user_id = null;
1058
+ if ( ( $data = $user->get_error_data() ) && ! empty( $data['user_id'] ) ) {
1059
+ $user_id = $data['user_id'];
1060
+ }
1061
+ cerber_login_failed( $username, $user_id );
1062
+ }
1063
+
1064
+ return $user;
1065
+ }
1066
+
1067
+ /*
1068
+ Stop the authentication process for an existing user
1069
+ Invoking in:
1070
+ 'wp_authenticate_username_password()'
1071
+ 'wp_authenticate_email_password()'
1072
+ */
1073
+ add_filter( 'wp_authenticate_user', 'cerber_stop_authentication', 9999, 2 );
1074
+ function cerber_stop_authentication( $user, $password ) {
1075
+ global $wp_cerber, $cerber_status;
1076
+
1077
+ $deny = false;
1078
+ $user_msg = '';
1079
+
1080
+ if ( $b = crb_is_user_blocked( $user->ID ) ) {
1081
+ $user_msg = $b['blocked_msg'];
1082
+ $cerber_status = 25;
1083
+ $deny = true;
1084
+ }
1085
+ elseif ( ! cerber_is_allowed() ) {
1086
+ $deny = true;
1087
+ }
1088
+ elseif ( ! cerber_geo_allowed( 'geo_login' ) ) {
1089
+ $cerber_status = 16;
1090
+ $deny = true;
1091
+ }
1092
+ elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
1093
+ $cerber_status = 15;
1094
+ $deny = true;
1095
+ }
1096
+
1097
+ if ( $deny ) {
1098
+ status_header( 403 );
1099
+ $error = new WP_Error();
1100
+ if ( ! $user_msg ) {
1101
+ $user_msg = $wp_cerber->getErrorMsg();
1102
+ }
1103
+ $error->add( 'cerber_wp_error', $user_msg, array( 'user_id' => $user->ID ) );
1104
+
1105
+ return $error;
1106
+ }
1107
+
1108
+ return $user;
1109
+ }
1110
+
1111
+ /**
1112
+ *
1113
+ * Handler for failed login attempts
1114
+ *
1115
+ * @param $user_login
1116
+ * @param int $user_id User ID
1117
+ *
1118
+ */
1119
+ //add_action( 'wp_login_failed', 'cerber_login_failed' ); // @since 4.18
1120
+ function cerber_login_failed( $user_login, $user_id = 0 ) {
1121
+ global $wpdb, $wp_cerber, $cerber_status;
1122
+ static $is_processed = false;
1123
+
1124
+ if ( $is_processed ) return;
1125
+ $is_processed = true;
1126
+
1127
+ $ip = $wp_cerber->getRemoteIp();
1128
+ $acl = cerber_acl_check( $ip );
1129
+ if ( ! cerber_get_user( $user_login ) ) {
1130
+ $no_user = true;
1131
+ }
1132
+ else {
1133
+ $no_user = false;
1134
+ }
1135
+
1136
+ //cerber_failed_work($ip, $acl, $no_user, $user_login);
1137
+
1138
+ //if ( ! $wp_cerber->isProcessed() ) {
1139
+ //if ( ! cerber_get_user( $user_login ) ) {
1140
+ // $no_user = true;
1141
+ //}
1142
+
1143
+ $ac = 7;
1144
+
1145
+ if ( $no_user ) {
1146
+ $ac = 51;
1147
+ }
1148
+ elseif ( ! cerber_is_allowed( $ip ) || $cerber_status == 15 || $cerber_status == 16 || $cerber_status == 25 ) { // TODO should be refactored together with cerber_stop_authentication
1149
+ $ac = 53;
1150
+ }
1151
+ /*
1152
+ elseif ( $acl == 'B' ) {
1153
+ $ac = 14;
1154
+ }
1155
+ elseif ( lab_is_blocked($ip, false) ) {
1156
+ $ac = 53;
1157
+ }
1158
+ else {
1159
+ $ac = 53;
1160
+ }*/
1161
+
1162
+ cerber_log( $ac, $user_login, $user_id );
1163
+
1164
+ //}
1165
+
1166
+
1167
+ // White? Stop further actions.
1168
+ if ( $acl == 'W' && !crb_get_settings( 'limitwhite' )) {
1169
+ return;
1170
+ }
1171
+
1172
+ if ( crb_get_settings( 'usefile' ) ) {
1173
+ cerber_file_log( $user_login, $ip );
1174
+ }
1175
+
1176
+ if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) { // Needs additional researching and, maybe, refactoring
1177
+ status_header( 403 );
1178
+ }
1179
+
1180
+ // Blacklisted? No more actions are needed.
1181
+ if ( $acl == 'B' ) {
1182
+ return;
1183
+ }
1184
+
1185
+ // Must the Citadel mode be activated?
1186
+ if ( $wp_cerber->getSettings( 'ciperiod' ) && ! cerber_is_citadel() ) {
1187
+ $range = time() - $wp_cerber->getSettings( 'ciperiod' ) * 60;
1188
+ //$lockouts = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
1189
+ $lockouts = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
1190
+ if ( $lockouts >= $wp_cerber->getSettings( 'cilimit' ) ) {
1191
+ cerber_enable_citadel();
1192
+ }
1193
+ }
1194
+
1195
+ if ( $no_user && $wp_cerber->getSettings( 'nonusers' ) ) {
1196
+ cerber_block_add( $ip, 703, $user_login); // @since 5.7
1197
+ }
1198
+ elseif ( cerber_get_remain_count($ip, false) < 1 ) { //Limit on the number of login attempts is reached
1199
+ cerber_block_add( $ip, 701, '', null, false);
1200
+ }
1201
+
1202
+ }
1203
+
1204
+ /**
1205
+ * Do the work with failed/blocked attempt
1206
+ *
1207
+ * @param $ip
1208
+ * @param $acl
1209
+ * @param $user_login
1210
+ */
1211
+ function cerber_failed_work($ip, $acl, $no_user, $user_login){
1212
+ global $wpdb, $wp_cerber;
1213
+
1214
+ // White? Stop further actions.
1215
+ if ( $acl == 'W' && !$wp_cerber->getSettings( 'limitwhite' )) {
1216
+ return;
1217
+ }
1218
+
1219
+ if ( $wp_cerber->getSettings( 'usefile' ) ) {
1220
+ cerber_file_log( $user_login, $ip );
1221
+ }
1222
+
1223
+ if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) { // Needs additional researching and, maybe, refactoring
1224
+ status_header( 403 );
1225
+ }
1226
+
1227
+ // Blacklisted? No more actions are needed.
1228
+ if ( $acl == 'B' ) {
1229
+ return;
1230
+ }
1231
+
1232
+ // Must the Citadel mode be activated?
1233
+ if ( $wp_cerber->getSettings( 'ciperiod' ) && ! cerber_is_citadel() ) {
1234
+ $range = time() - $wp_cerber->getSettings( 'ciperiod' ) * 60;
1235
+ //$lockouts = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
1236
+ $lockouts = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
1237
+ if ( $lockouts >= $wp_cerber->getSettings( 'cilimit' ) ) {
1238
+ cerber_enable_citadel();
1239
+ }
1240
+ }
1241
+
1242
+ if ( $no_user && $wp_cerber->getSettings( 'nonusers' ) ) {
1243
+ cerber_block_add( $ip, 703, $user_login );
1244
+ }
1245
+ elseif ( cerber_get_remain_count($ip, false) <= 1 ) { //Limit on the number of login attempts is reached
1246
+ cerber_block_add( $ip, 701, '', null, false);
1247
+ }
1248
+ }
1249
+
1250
+ // Validating the user, we use closure to make this unavoidable
1251
+
1252
+ add_action( 'set_current_user', function () { // the right way
1253
+ cerber_validate_the_user();
1254
+ }, 0 );
1255
+ add_action( 'init', function () { // backup for 'set_current_user'
1256
+ cerber_validate_the_user();
1257
+ }, 0 );
1258
+ function cerber_validate_the_user() {
1259
+ global $current_user, $userdata, $user_ID;
1260
+ $user = ( ! $current_user instanceof WP_User ) ? wp_get_current_user() : $current_user;
1261
+ if ( crb_is_user_blocked( $user->ID ) ) {
1262
+ @wp_logout();
1263
+ $current_user = null;
1264
+ $userdata = null;
1265
+ $user_ID = null;
1266
+ if ( is_admin() ) {
1267
+ wp_redirect( cerber_get_home_url() );
1268
+ }
1269
+ else {
1270
+ wp_safe_redirect( CRB_Request::full_url() );
1271
+ }
1272
+ exit;
1273
+ }
1274
+ }
1275
+
1276
+ // Registration -----------------------------------------------------------------------
1277
+
1278
+ function cerber_is_registration_prohibited( $sanitized_user_login ) {
1279
+ global $wp_cerber, $cerber_status;
1280
+
1281
+ /*
1282
+ if ( crb_acl_is_white() ) {
1283
+ return false;
1284
+ }*/
1285
+
1286
+ $code = null;
1287
+ $msg = null;
1288
+
1289
+ if ( crb_is_reg_limit_reached() ) {
1290
+ $cerber_status = 17;
1291
+ cerber_log( 54 );
1292
+ $code = 'ip_denied';
1293
+ $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1294
+ apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1295
+ }
1296
+ elseif ( cerber_is_bot( 'botsreg' ) ) {
1297
+ cerber_log( 54 ); // TODO should be separate code to detect bot activity?
1298
+ $code = 'bot_detected';
1299
+ $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1300
+ apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1301
+ }
1302
+ elseif ( ! $wp_cerber->reCaptchaValidate() ) {
1303
+ $code = 'incorrect_recaptcha';
1304
+ $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1305
+ $wp_cerber->reCaptchaMsg( 'register' );
1306
+ }
1307
+ elseif ( cerber_is_prohibited( $sanitized_user_login ) ) {
1308
+ $code = 'prohibited_login';
1309
+ $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1310
+ apply_filters( 'cerber_msg_prohibited', __( 'Username is not allowed. Please choose another one.', 'wp-cerber' ), 'register' );
1311
+ }
1312
+ elseif ( ! cerber_is_allowed() || lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
1313
+ cerber_log( 54 );
1314
+ $code = 'ip_denied';
1315
+ $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1316
+ apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1317
+ }
1318
+ elseif ( ! cerber_geo_allowed( 'geo_register' ) ) {
1319
+ $cerber_status = 16; // TODO: refactor cerber_log, include this status as a second parameter
1320
+ cerber_log( 54 ); // TODO should be separate code?
1321
+ $code = 'country_denied';
1322
+ $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1323
+ apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1324
+ }
1325
+
1326
+ if ( $code ) {
1327
+ return array( $code, $msg );
1328
+ }
1329
+
1330
+ return false;
1331
+ }
1332
+
1333
+ /**
1334
+ * Limit on user registrations per IP
1335
+ *
1336
+ * @return bool
1337
+ */
1338
+ function crb_is_reg_limit_reached() {
1339
+
1340
+ if ( ! lab_lab() ) {
1341
+ return false;
1342
+ }
1343
+
1344
+ if ( ! crb_get_settings( 'reglimit_min' ) || ! crb_get_settings( 'reglimit_num' ) ) {
1345
+ return false;
1346
+ }
1347
+
1348
+ if ( crb_acl_is_white() ) {
1349
+ return false;
1350
+ }
1351
+
1352
+ $ip = cerber_get_remote_ip();
1353
+ $stamp = absint( time() - 60 * crb_get_settings( 'reglimit_min' ) );
1354
+ $count = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity = 2 AND stamp > ' . $stamp );
1355
+ if ( $count >= crb_get_settings( 'reglimit_num' ) ) {
1356
+ lab_save_push( $ip, 344, '' );
1357
+
1358
+ return true;
1359
+ }
1360
+
1361
+ return false;
1362
+ }
1363
+
1364
+ // Fires in register_new_user()
1365
+ add_filter( 'registration_errors', 'cerber_pre_new_user', 10, 3 );
1366
+ function cerber_pre_new_user( $errors, $sanitized_user_login, $user_email ) {
1367
+
1368
+ $prohibited = cerber_is_registration_prohibited( $sanitized_user_login );
1369
+
1370
+ if ( $prohibited ) {
1371
+ return new WP_Error( $prohibited[0], $prohibited[1] );
1372
+ }
1373
+
1374
+ return $errors;
1375
+ }
1376
+
1377
+ // @since 5.3
1378
+ // Fires in wp_insert_user()
1379
+ add_filter( 'pre_user_login', function ( $sanitized_user_login ) {
1380
+
1381
+ if ( cerber_is_registration_prohibited( $sanitized_user_login ) ) {
1382
+ return null;
1383
+ }
1384
+
1385
+ return $sanitized_user_login;
1386
+ }, 9999 );
1387
+
1388
+ // @since 7.2.7 for MU and BuddyPress
1389
+ add_filter( 'wpmu_validate_user_signup', function ( $result ) {
1390
+
1391
+ $sanitized_user_login = sanitize_user( $result['user_name'], true );
1392
+
1393
+ if ( $check = cerber_is_registration_prohibited( $sanitized_user_login ) ) {
1394
+ $result['errors'] = new WP_Error( 'user_name', $check[1] );
1395
+ }
1396
+
1397
+ return $result;
1398
+ }, 9999 );
1399
+
1400
+ // Filter out prohibited usernames
1401
+ add_filter( 'illegal_user_logins', function () {
1402
+ return (array) crb_get_settings( 'prohibited' );
1403
+ }, 9999 );
1404
+
1405
+ add_filter( 'option_users_can_register', function ( $value ) {
1406
+ //if ( ! cerber_is_allowed() || !cerber_geo_allowed( 'geo_register' )) {
1407
+ if ( ! cerber_is_allowed() || crb_is_reg_limit_reached() ) {
1408
+ return false;
1409
+ }
1410
+
1411
+ return $value;
1412
+ }, 9999 );
1413
+
1414
+ // Lost password form --------------------------------------------------------------------
1415
+
1416
+ /**
1417
+ * Validate reCAPTCHA for the WordPress lost password form
1418
+ */
1419
+ add_action( 'login_form_' . 'lostpassword', 'cerber_lost_captcha' );
1420
+ function cerber_lost_captcha() {
1421
+ global $wp_cerber, $cerber_lost;
1422
+ if ( ! $wp_cerber->reCaptchaValidate() ) {
1423
+ $_POST['user_login'] = null; // workaround due to lack of any way to control lost password form
1424
+ $cerber_lost = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' . $wp_cerber->reCaptchaMsg('lostpassword');
1425
+ }
1426
+ }
1427
+ /**
1428
+ * Display message on the WordPress lost password form screen
1429
+ */
1430
+ add_action( 'lostpassword_form', 'cerber_lost_show_msg' );
1431
+ function cerber_lost_show_msg() {
1432
+ global $cerber_lost;
1433
+ if ( ! $cerber_lost ) {
1434
+ return;
1435
+ }
1436
+ ?>
1437
+ <script type="text/javascript">
1438
+ //document.getElementById('login_error').style.visibility = "hidden";
1439
+ document.getElementById('login_error').innerHTML = "<?php echo $cerber_lost; ?>";
1440
+ </script>
1441
+ <?php
1442
+ }
1443
+
1444
+
1445
+ // Comments (commenting) section ----------------------------------------------------------
1446
+
1447
+ /**
1448
+ * If a comment must be marked as spam
1449
+ *
1450
+ */
1451
+ add_filter( 'pre_comment_approved', function ( $approved, $commentdata ) {
1452
+ if ( 1 == crb_get_settings( 'spamcomm' ) && ! cerber_is_comment_allowed() ) {
1453
+ $approved = 'spam';
1454
+ }
1455
+
1456
+ return $approved;
1457
+ }, 10, 2 );
1458
+
1459
+ /**
1460
+ * If a comment must be denied
1461
+ *
1462
+ */
1463
+ add_action( 'pre_comment_on_post', function ( $comment_post_ID ) {
1464
+ global $cerber_status;
1465
+
1466
+ $deny = false;
1467
+
1468
+ if ( 1 != crb_get_settings( 'spamcomm' ) && ! cerber_is_comment_allowed() ) {
1469
+ $deny = true;
1470
+ }
1471
+ elseif ( ! cerber_geo_allowed( 'geo_comment' ) ) {
1472
+ $cerber_status = 16;
1473
+ cerber_log(19);
1474
+ $deny = true;
1475
+ }
1476
+
1477
+ if ( $deny ) {
1478
+ setcookie( 'cerber-post-id', $comment_post_ID, time() + 60, '/' );
1479
+ $comments = get_comments( array( 'number' => '1', 'post_id' => $comment_post_ID ) );
1480
+ if ( $comments ) {
1481
+ $loc = get_comment_link( $comments[0]->comment_ID );
1482
+ } else {
1483
+ $loc = get_permalink( $comment_post_ID ) . '#cerber-recaptcha-msg';
1484
+ }
1485
+ wp_safe_redirect( $loc );
1486
+ exit;
1487
+ }
1488
+
1489
+ } );
1490
+
1491
+ /**
1492
+ * If submit comments via REST API is not allowed
1493
+ *
1494
+ */
1495
+ add_filter( 'rest_allow_anonymous_comments', function ( $allowed, $request ) {
1496
+ global $wp_cerber, $cerber_status;
1497
+
1498
+ if ( ! cerber_is_allowed() ) {
1499
+ $allowed = false;
1500
+ }
1501
+ if ( ! cerber_geo_allowed( 'geo_comment' ) ) {
1502
+ ceber_log(19);
1503
+ $cerber_status = 16;
1504
+ $allowed = false;
1505
+ }
1506
+ elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
1507
+ $allowed = false;
1508
+ }
1509
+
1510
+ return $allowed;
1511
+ }, 10, 2 );
1512
+
1513
+ /**
1514
+ * Check if a submitted comment is allowed
1515
+ *
1516
+ * @return bool
1517
+ */
1518
+ function cerber_is_comment_allowed(){
1519
+ global $wp_cerber;
1520
+
1521
+ if (is_admin()) return true;
1522
+
1523
+ $deny = null;
1524
+
1525
+ if ( ! cerber_is_allowed() ) {
1526
+ $deny = 19;
1527
+ }
1528
+ elseif ( cerber_is_bot('botscomm') ) {
1529
+ $remain = cerber_get_remain_count( null, true, array( 16 ), 3, 60 );
1530
+ if ($remain < 1) cerber_block_add( null, 706, '', 60 );
1531
+ $deny = 16;
1532
+ }
1533
+ elseif ( ! $wp_cerber->reCaptchaValidate( 'comment' , true ) ) {
1534
+ $deny = 16;
1535
+ }
1536
+ elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
1537
+ $deny = 19;
1538
+ }
1539
+
1540
+ if ( $deny ) {
1541
+ cerber_log( $deny );
1542
+ $ret = false;
1543
+ }
1544
+ else {
1545
+ $ret = true;
1546
+ }
1547
+
1548
+ return $ret;
1549
+ }
1550
+
1551
+ /**
1552
+ * Showing reCAPTCHA widget.
1553
+ * Displaying error message on the comment form for a human.
1554
+ *
1555
+ */
1556
+ add_filter( 'comment_form_submit_field', function ( $value ) {
1557
+ global $wp_cerber, $post;
1558
+
1559
+ if ( ! empty( $_COOKIE["cerber-post-id"] ) && absint( $_COOKIE["cerber-post-id"] ) == $post->ID ) {
1560
+ //echo '<div id="cerber-recaptcha-msg">' . __( 'ERROR:', 'wp-cerber' ) . ' ' . $wp_cerber->reCaptchaMsg( 'comment' ) . '</div>';
1561
+ echo '<div id="cerber-recaptcha-msg">' . __( 'ERROR:', 'wp-cerber' ) . ' ' . __('Sorry, human verification failed.') . '</div>';
1562
+ echo '<script type="text/javascript">document.cookie = "cerber-post-id=0;path=/";</script>';
1563
+ }
1564
+
1565
+ $au = $wp_cerber->getSettings( 'recapcomauth' );
1566
+ if ( ! $au || ( $au && ! is_user_logged_in() ) ) {
1567
+ $wp_cerber->reCaptcha( 'widget', 'recapcom' );
1568
+ }
1569
+
1570
+ return $value;
1571
+ } );
1572
+
1573
+
1574
+ // Messages ----------------------------------------------------------------------
1575
+
1576
+ /**
1577
+ * Replace ANY system messages or add notify message above login form if IP is not allowed (blocked or locked out)
1578
+ */
1579
+ add_filter( 'login_errors', 'cerber_login_form_msg' ); // hook on POST if credentials was wrong
1580
+ function cerber_login_form_msg( $errors ) {
1581
+ global $error, $wp_cerber;
1582
+ if ( cerber_can_msg() ) {
1583
+ if ( ! cerber_is_allowed() ) {
1584
+ $errors = $wp_cerber->getErrorMsg();
1585
+ }
1586
+ elseif ( ! $error && ( $msg = $wp_cerber->getRemainMsg() ) ) {
1587
+ $errors .= '<p>' . $msg;
1588
+ }
1589
+ }
1590
+
1591
+ return $errors;
1592
+ }
1593
+
1594
+ add_filter( 'shake_error_codes', 'cerber_login_failure_shake' ); // Shake it, baby!
1595
+ function cerber_login_failure_shake( $shake_error_codes ) {
1596
+ $shake_error_codes[] = 'cerber_wp_error';
1597
+
1598
+ return $shake_error_codes;
1599
+ }
1600
+
1601
+ /*
1602
+ Replace default login/logout URL with Custom login page URL
1603
+ */
1604
+ add_filter( 'site_url', 'cerber_login_logout', 9999, 4 );
1605
+ add_filter( 'network_site_url', 'cerber_login_logout', 9999, 3 );
1606
+ function cerber_login_logout( $url, $path, $scheme, $blog_id = 0 ) { // $blog_id only for 'site_url'
1607
+ //global $wp_cerber;
1608
+ //if ( $login_path = $wp_cerber->getSettings( 'loginpath' ) ) {
1609
+ if ( $login_path = crb_get_settings( 'loginpath' ) ) {
1610
+ $url = str_replace( WP_LOGIN_SCRIPT, $login_path . '/', $url );
1611
+ }
1612
+
1613
+ return $url;
1614
+ }
1615
+
1616
+ /*
1617
+ Replace default logout redirect URL with Custom login page URL
1618
+ */
1619
+ add_filter( 'wp_redirect', 'cerber_login_redirect', 9999, 2 );
1620
+ function cerber_login_redirect( $location, $status ) {
1621
+ global $wp_cerber;
1622
+ //if ( ( $path = $wp_cerber->getSettings( 'loginpath' ) ) && ( 0 === strpos( $location, WP_LOGIN_SCRIPT . '?' ) ) ) {
1623
+ if ( ( $path = crb_get_settings( 'loginpath' ) ) && ( 0 === strpos( $location, WP_LOGIN_SCRIPT . '?' ) ) ) {
1624
+ $loc = explode( '?', $location );
1625
+ $location = cerber_get_home_url() . '/' . $path . '/?' . $loc[1];
1626
+ }
1627
+
1628
+ return $location;
1629
+ }
1630
+
1631
+ // Access control ========================================================================================
1632
+
1633
+ add_action( 'init', function () {
1634
+ if ( crb_get_settings( 'adminphp' ) && ! is_user_logged_in() ) {
1635
+ define( 'CONCATENATE_SCRIPTS', false );
1636
+ }
1637
+ if ( ! is_admin()
1638
+ && ! cerber_is_wp_cron() ) {
1639
+ cerber_access_control();
1640
+ cerber_auth_access();
1641
+ }
1642
+ cerber_post_control();
1643
+ }, 0 );
1644
+
1645
+ /**
1646
+ * Restrict access to some vital parts of WP
1647
+ *
1648
+ */
1649
+ function cerber_access_control() {
1650
+ global $wp_cerber, $cerber_status;
1651
+
1652
+ if ( crb_acl_is_white() ) {
1653
+ return;
1654
+ }
1655
+
1656
+ $wp_cerber = get_wp_cerber();
1657
+ if ( $wp_cerber->isURIProhibited() ) {
1658
+ cerber_404_page();
1659
+ }
1660
+
1661
+ $opt = crb_get_settings();
1662
+
1663
+ // REST API
1664
+ if ( $wp_cerber->isDeny() ) {
1665
+ cerber_block_rest_api();
1666
+ }
1667
+ elseif ( cerber_is_rest_url() ) {
1668
+ $rest_allowed = true;
1669
+
1670
+ /*if ( ! empty( $opt['norest'] ) ) {
1671
+ $rest_allowed = false;
1672
+ if ( $opt['restauth'] && is_user_logged_in() ) {
1673
+ $rest_allowed = true;
1674
+ }
1675
+ elseif ( cerber_is_route_allowed() ) {
1676
+ $rest_allowed = true;
1677
+ }
1678
+ }
1679
+ if ( $rest_allowed && cerber_is_route_blocked() ) {
1680
+ $rest_allowed = false;
1681
+ }*/
1682
+
1683
+ if ( ! cerber_is_rest_permitted() ) {
1684
+ $rest_allowed = false;
1685
+ }
1686
+ if ( $rest_allowed && ! cerber_geo_allowed( 'geo_restapi' ) ) {
1687
+ $rest_allowed = false;
1688
+ $cerber_status = 16;
1689
+ }
1690
+ if ( ! $rest_allowed ) {
1691
+ cerber_block_rest_api();
1692
+ }
1693
+ }
1694
+
1695
+ // Some XML-RPC stuff
1696
+ if ( $wp_cerber->isDeny() || ! empty( $opt['xmlrpc'] ) ) {
1697
+ add_filter( 'xmlrpc_enabled', '__return_false' );
1698
+ add_filter( 'pings_open', '__return_false' );
1699
+ add_filter( 'bloginfo_url', 'cerber_pingback_url', 10, 2 );
1700
+ remove_action( 'wp_head', 'rsd_link', 10 );
1701
+ remove_action( 'wp_head', 'wlwmanifest_link', 10 );
1702
+ }
1703
+
1704
+ // Feeds
1705
+ if ( $wp_cerber->isDeny() || ! empty( $opt['nofeeds'] ) ) {
1706
+ remove_action( 'wp_head', 'feed_links', 2 );
1707
+ remove_action( 'wp_head', 'feed_links_extra', 3 );
1708
+
1709
+ remove_action( 'do_feed_rdf', 'do_feed_rdf', 10 );
1710
+ remove_action( 'do_feed_rss', 'do_feed_rss', 10 );
1711
+ remove_action( 'do_feed_rss2', 'do_feed_rss2', 10 );
1712
+ remove_action( 'do_feed_atom', 'do_feed_atom', 10 );
1713
+ remove_action( 'do_pings', 'do_all_pings', 10 );
1714
+
1715
+ add_action( 'do_feed_rdf', 'cerber_404_page', 1 );
1716
+ add_action( 'do_feed_rss', 'cerber_404_page', 1 );
1717
+ add_action( 'do_feed_rss2', 'cerber_404_page', 1 );
1718
+ add_action( 'do_feed_atom', 'cerber_404_page', 1 );
1719
+ add_action( 'do_feed_rss2_comments', 'cerber_404_page', 1 );
1720
+ add_action( 'do_feed_atom_comments', 'cerber_404_page', 1 );
1721
+ }
1722
+
1723
+ }
1724
+
1725
+ function cerber_auth_access() {
1726
+
1727
+ $opt = crb_get_settings();
1728
+
1729
+ if ( $opt['authonlyacl']
1730
+ && crb_acl_is_white() ) {
1731
+ return;
1732
+ }
1733
+
1734
+ if ( $opt['authonly']
1735
+ && ! is_user_logged_in()
1736
+ && cerber_auth_required( $opt['authonlyredir'] ) ) {
1737
+ if ( $opt['authonlyredir'] ) {
1738
+ $redirect = ( strpos( $_SERVER['REQUEST_URI'], '/options.php' ) && wp_get_referer() ) ? wp_get_referer() : set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
1739
+ wp_redirect( add_query_arg( 'redirect_to', $redirect, $opt['authonlyredir'] ) );
1740
+ exit;
1741
+ }
1742
+ auth_redirect();
1743
+ }
1744
+ }
1745
+
1746
+ /**
1747
+ * Antispam & Antibot for forms
1748
+ *
1749
+ */
1750
+ function cerber_post_control() {
1751
+ global $cerber_status;
1752
+
1753
+ if ( ! cerber_is_http_post() || crb_acl_is_white() ) {
1754
+ return;
1755
+ }
1756
+
1757
+ if ( ! cerber_antibot_enabled( 'botsany' ) && ! cerber_geo_rules( 'geo_submit' ) ) {
1758
+ return;
1759
+ }
1760
+
1761
+ // Exceptions -----------------------------------------------------------------------
1762
+
1763
+ if ( cerber_is_antibot_exception() ) {
1764
+ return;
1765
+ }
1766
+
1767
+ // Let's make the checks
1768
+
1769
+ $deny = false;
1770
+
1771
+ if ( ! cerber_is_allowed() ) {
1772
+ $deny = true;
1773
+ cerber_log( 18 );
1774
+ }
1775
+ elseif ( cerber_is_bot( 'botsany' ) ) {
1776
+ $deny = true;
1777
+ cerber_log( 17 );
1778
+ }
1779
+ elseif ( ! cerber_geo_allowed( 'geo_submit' ) ) {
1780
+ $deny = true;
1781
+ $cerber_status = 16; // TODO: refactor cerber_log, include this status as a second parameter
1782
+ cerber_log( 18 );
1783
+ }
1784
+ elseif ( lab_is_blocked( null, true ) ) {
1785
+ $deny = true;
1786
+ $cerber_status = 18;
1787
+ cerber_log( 18 );
1788
+ }
1789
+
1790
+ if ( $deny ) {
1791
+ cerber_forbidden_page();
1792
+ }
1793
+
1794
+ }
1795
+
1796
+ /**
1797
+ * Exception for POST request control
1798
+ *
1799
+ * @return bool
1800
+ */
1801
+ function cerber_is_antibot_exception(){
1802
+
1803
+ if ( cerber_is_wp_cron() ) {
1804
+ return true;
1805
+ }
1806
+
1807
+ // Admin || AJAX requests by unauthorized users
1808
+ if ( is_admin() ) {
1809
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1810
+ if (is_user_logged_in()) {
1811
+ return true;
1812
+ }
1813
+ }
1814
+ else {
1815
+ return true;
1816
+ }
1817
+ }
1818
+
1819
+ // Standard WordPress Comments
1820
+ if ( 0 === strpos( trim( $_SERVER['REQUEST_URI'], '/' ), 'wp-comments-post.php' ) ) {
1821
+ return true;
1822
+ }
1823
+
1824
+ // XML-RPC
1825
+ if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
1826
+ return true;
1827
+ }
1828
+
1829
+ // Trackback
1830
+ if ( is_trackback() ) {
1831
+ return true;
1832
+ }
1833
+
1834
+ // Login page
1835
+ if ( cerber_is_login_request() ) {
1836
+ return true;
1837
+ }
1838
+
1839
+ // Cloud Scanner
1840
+ if ( cerber_is_cloud_request() ) {
1841
+ return true;
1842
+ }
1843
+
1844
+ // REST API (except Contact Form 7 submission)
1845
+ if ( cerber_is_rest_url() ) {
1846
+ if ( false === strpos( $_SERVER['REQUEST_URI'], 'contact-form-7' ) ) {
1847
+ return true;
1848
+ }
1849
+ }
1850
+
1851
+ if ( class_exists( 'WooCommerce' ) ) {
1852
+ if ( cerber_is_permalink_enabled() ) {
1853
+ //if ( 0 === strpos( cerber_get_site_root() . cerber_purify_uri(), get_home_url() . '/wc-api/' ) ) {
1854
+ //if ( 0 === strpos( CRB_Request::full_url(), cerber_get_home_url() . '/wc-api/' ) ) {
1855
+ if ( CRB_Request::is_url_start_with( cerber_get_home_url() . '/wc-api/' ) ) {
1856
+ return true;
1857
+ }
1858
+ }
1859
+ elseif ( ! empty( $_GET['wc-api'] ) ) {
1860
+ if ( cerber_check_remote_domain( array( '*.paypal.com', '*.stripe.com' ) ) ) {
1861
+ return true;
1862
+ }
1863
+ }
1864
+ }
1865
+
1866
+ return false;
1867
+ }
1868
+
1869
+ /**
1870
+ * What antibot mode must be used.
1871
+ *
1872
+ * @return int 1 = Cookies + Fields, 2 = Cookies only
1873
+ */
1874
+ function cerber_antibot_mode() {
1875
+ global $wp;
1876
+ //static $list;
1877
+
1878
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1879
+ if ( crb_get_settings( 'botssafe' ) ) {
1880
+ return 2;
1881
+ }
1882
+ if ( ! empty( $_POST['action'] ) ) {
1883
+ if ( $_POST['action'] == 'heartbeat' ) { // WP heartbeat
1884
+ //$nonce_state = wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' );
1885
+ return 2;
1886
+ }
1887
+ }
1888
+
1889
+ }
1890
+
1891
+ if ( cerber_get_uri_script() ) {
1892
+ return 1;
1893
+ }
1894
+
1895
+ // Check for third party exceptions
1896
+
1897
+ if ( class_exists( 'WooCommerce' ) ) {
1898
+
1899
+ if ( ! empty( $_GET['wc-ajax'] ) &&
1900
+ //$_GET['wc-ajax'] == 'get_refreshed_fragments' &&
1901
+ count( $_GET ) == 1 &&
1902
+ empty( $_POST )
1903
+ ) {
1904
+
1905
+ return 2;
1906
+ }
1907
+
1908
+ if ( cerber_is_permalink_enabled() ) {
1909
+ //if ( function_exists( 'wc_get_page_id' ) && 0 === strpos( cerber_get_site_root() . cerber_purify_uri(), get_permalink( wc_get_page_id( 'checkout' ) ) ) ) {
1910
+ if ( function_exists( 'wc_get_page_id' ) && CRB_Request::is_url_start_with( get_permalink( wc_get_page_id( 'checkout' ) ) ) ) {
1911
+ return 2;
1912
+ }
1913
+ }
1914
+ else {
1915
+ if ( ! empty( $_GET['order-received'] ) && ! empty( $_GET['key'] ) ) {
1916
+ return 2;
1917
+ }
1918
+ }
1919
+ }
1920
+
1921
+ if ( class_exists( 'GFForms' ) ) {
1922
+ if ( count( $_GET ) == 2 &&
1923
+ ! empty( $_GET['gf_page'] ) &&
1924
+ ! empty( $_GET['id'] ) &&
1925
+ is_user_logged_in()
1926
+ ) {
1927
+
1928
+ return 2;
1929
+ }
1930
+ }
1931
+
1932
+ return 1;
1933
+ }
1934
+
1935
+ /*
1936
+ * Disable pingback URL (hide from HEAD)
1937
+ */
1938
+ function cerber_pingback_url( $output, $show ) {
1939
+ if ( $show == 'pingback_url' ) {
1940
+ $output = '';
1941
+ }
1942
+
1943
+ return $output;
1944
+ }
1945
+
1946
+ /**
1947
+ * Disable REST API
1948
+ *
1949
+ */
1950
+ function cerber_block_rest_api() {
1951
+ // OLD WP
1952
+ add_filter( 'json_enabled', '__return_false' );
1953
+ add_filter( 'json_jsonp_enabled', '__return_false' );
1954
+ // WP 4.4, deprecated since 4.7
1955
+ if ( version_compare( cerber_get_wp_version(), '4.7', '<' ) ) {
1956
+ add_filter( 'rest_enabled', '__return_false', 9999 );
1957
+ }
1958
+ // WP 4.7
1959
+ add_filter( 'rest_jsonp_enabled', '__return_false' );
1960
+ // Links
1961
+ remove_action( 'wp_head', 'rest_output_link_wp_head', 10 );
1962
+ remove_action( 'template_redirect', 'rest_output_link_header', 11 );
1963
+ // Default REST API hooks from default-filters.php
1964
+ remove_action( 'init', 'rest_api_init' );
1965
+ remove_action( 'rest_api_init', 'rest_api_default_filters', 10 );
1966
+ remove_action( 'rest_api_init', 'register_initial_settings', 10 );
1967
+ remove_action( 'rest_api_init', 'create_initial_rest_routes', 99 );
1968
+ remove_action( 'parse_request', 'rest_api_loaded' );
1969
+
1970
+ if ( cerber_is_rest_url() ) {
1971
+ cerber_log( 70 );
1972
+ cerber_forbidden_page();
1973
+ }
1974
+ }
1975
+
1976
+ /*
1977
+ * Redirection control: standard admin/login redirections
1978
+ *
1979
+ */
1980
+ add_filter( 'wp_redirect', 'cerber_no_red', 10, 2 );
1981
+ function cerber_no_red( $location, $status ) {
1982
+ global $current_user;
1983
+ if ( ( ! $current_user || $current_user->ID == 0 ) && cerber_no_redirect() ) {
1984
+ $str = urlencode( '/wp-admin/' );
1985
+ $rdr = explode( 'redirect_to=', $location );
1986
+ if ( isset( $rdr[1] ) && strpos( $rdr[1], $str ) ) {
1987
+ cerber_404_page();
1988
+ }
1989
+ }
1990
+
1991
+ return $location;
1992
+ }
1993
+
1994
+ /**
1995
+ * @since 7.0
1996
+ */
1997
+ function cerber_no_redirect() {
1998
+ if ( crb_get_settings( 'noredirect' ) && !cerber_check_groove_x()) {
1999
+ return true;
2000
+ }
2001
+
2002
+ return false;
2003
+ }
2004
+
2005
+ /*
2006
+ * Stop user enumeration
2007
+ *
2008
+ */
2009
+ add_action( 'template_redirect', 'cerber_canonical', 1 );
2010
+ function cerber_canonical() {
2011
+ if ( ! empty( $_GET['author'] ) && ! is_admin() ) {
2012
+ if ( crb_get_settings( 'stopenum' ) ) {
2013
+ cerber_404_page();
2014
+ }
2015
+ }
2016
+ }
2017
+
2018
+ /*
2019
+ if ( $wp_cerber->getSettings( 'hashauthor' ) ) {
2020
+ add_filter( 'request',
2021
+ function ( $vars ) {
2022
+ if (isset($vars['author_name']) && !is_admin()) {
2023
+ $vars['author_name'] = '><';
2024
+ }
2025
+
2026
+ return $vars;
2027
+ } );
2028
+ }
2029
+ */
2030
+
2031
+ /*
2032
+ Can login form message be shown?
2033
+ */
2034
+ function cerber_can_msg() {
2035
+ if ( ! isset( $_REQUEST['action'] ) ) {
2036
+ return true;
2037
+ }
2038
+ if ( $_REQUEST['action'] == 'login' ) {
2039
+ return true;
2040
+ }
2041
+
2042
+ return false;
2043
+ //if ( !in_array( $action, array( 'postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login' );
2044
+ }
2045
+
2046
+
2047
+ // Cookies ---------------------------------------------------------------------------------
2048
+ /*
2049
+ Mark user with Cerber Groove
2050
+ @since 1.3
2051
+ */
2052
+ add_action( 'auth_cookie_valid', 'cerber_cookie_one', 10, 2 );
2053
+ function cerber_cookie_one( $cookie_elements = null, $user = null ) {
2054
+ if ( ! $user ) {
2055
+ $user = wp_get_current_user();
2056
+ }
2057
+ // Mark user with Cerber Groove
2058
+ $expire = time() + apply_filters( 'auth_cookie_expiration', 14 * 24 * 3600, $user->ID, true ) + ( 24 * 3600 );
2059
+ cerber_set_groove( $expire );
2060
+ }
2061
+
2062
+ /*
2063
+ Mark switched user with Cerber Groove
2064
+ @since 1.6
2065
+ */
2066
+ add_action( 'set_logged_in_cookie', 'cerber_cookie2', 10, 5 );
2067
+ function cerber_cookie2( $logged_in_cookie, $expire, $expiration, $user_id, $logged_in ) {
2068
+ cerber_set_groove( $expire );
2069
+ }
2070
+
2071
+ /*
2072
+ Track BAD cookies with non-existence user or bad password (hash)
2073
+ */
2074
+ add_action( 'auth_cookie_bad_username', 'cerber_cookie_bad' );
2075
+ add_action( 'auth_cookie_bad_hash', 'cerber_cookie_bad' );
2076
+ function cerber_cookie_bad( $cookie_elements ) {
2077
+ cerber_login_failed( $cookie_elements['username'] );
2078
+ }
2079
+
2080
+ /**
2081
+ * Is bot detection engine enabled in a given rule_id
2082
+ *
2083
+ * @param $location string|array ID of the location
2084
+ *
2085
+ * @return bool true if enabled
2086
+ */
2087
+ function cerber_antibot_enabled( $location ) {
2088
+
2089
+ if ( crb_get_settings( 'botsnoauth' ) && is_user_logged_in() ) {
2090
+ return false;
2091
+ }
2092
+
2093
+ if ( is_array( $location ) ) {
2094
+ foreach ( $location as $loc ) {
2095
+ if ( crb_get_settings( $loc ) ) {
2096
+ return true;
2097
+ }
2098
+ }
2099
+ }
2100
+ else {
2101
+ if ( crb_get_settings( $location ) ) {
2102
+ return true;
2103
+ }
2104
+ }
2105
+
2106
+ return false;
2107
+ }
2108
+
2109
+ /**
2110
+ * Print out the antibot/antispam jQuery code
2111
+ *
2112
+ * @param $location string|array Location (setting)
2113
+ */
2114
+ function cerber_antibot_code($location) {
2115
+ if ( ! cerber_antibot_enabled( $location ) ) {
2116
+ return;
2117
+ }
2118
+
2119
+ $values = cerber_antibot_gene();
2120
+
2121
+ if ( empty( $values ) || !is_array( $values ) ) {
2122
+ return;
2123
+ }
2124
+
2125
+ ?>
2126
+ <script type="text/javascript">
2127
+ jQuery(document).ready(function ($) {
2128
+ //$( document ).ajaxStart(function() {
2129
+ //});
2130
+
2131
+ <?php // Append form fields directly to the all forms ?>
2132
+
2133
+ for (var i = 0; i < document.forms.length; ++i) {
2134
+ var form = document.forms[i];
2135
+ <?php
2136
+ foreach ( $values[0] as $value ) {
2137
+ echo 'if ($(form).attr("method") != "get") { $(form).append(\'<input type="hidden" name="' . $value[0] . '" value="' . $value[1] . '" />\'); }'."\n";
2138
+ }
2139
+ ?>
2140
+ }
2141
+
2142
+ <?php // Ordinary submit ?>
2143
+
2144
+ $(document).on('submit', 'form', function () {
2145
+ <?php
2146
+ foreach ( $values[0] as $value ) {
2147
+ echo 'if ($(this).attr("method") != "get") { $(this).append(\'<input type="hidden" name="' . $value[0] . '" value="' . $value[1] . '" />\'); }'."\n";
2148
+ }
2149
+ ?>
2150
+ return true;
2151
+ });
2152
+
2153
+ <?php // Pure AJAX submit with two different types of form data (object and string) ?>
2154
+
2155
+ jQuery.ajaxSetup({
2156
+ beforeSend: function (e, data) {
2157
+
2158
+ //console.log(Object.getOwnPropertyNames(data).sort());
2159
+ //console.log(data.type);
2160
+
2161
+ if (data.type !== 'POST') return;
2162
+
2163
+ if (typeof data.data === 'object' && data.data !== null) {
2164
+ <?php
2165
+ foreach ( $values[0] as $value ) {
2166
+ echo 'data.data.append("' . $value[0] . '", "' . $value[1] . '");'."\n";
2167
+ }
2168
+ ?>
2169
+ }
2170
+ else {
2171
+ data.data = data.data + '<?php
2172
+ foreach ( $values[0] as $value ) {
2173
+ echo '&' . $value[0] . '=' . $value[1];
2174
+ }
2175
+ ?>';
2176
+ }
2177
+ }
2178
+ });
2179
+
2180
+ });
2181
+ </script>
2182
+ <?php
2183
+
2184
+ }
2185
+
2186
+ /**
2187
+ * Generates and saves antibot markers
2188
+ *
2189
+ * @return array|bool
2190
+ */
2191
+ function cerber_antibot_gene($recreate = false) {
2192
+
2193
+ if ( !crb_get_settings('botsany') && !crb_get_settings('botscomm') && !crb_get_settings('botsreg') ) {
2194
+ return false;
2195
+ }
2196
+
2197
+ $ret = array();
2198
+
2199
+ if (!$recreate) {
2200
+ $ret = cerber_get_site_option( 'cerber-antibot' );
2201
+ }
2202
+
2203
+ if ( $recreate || !$ret ) {
2204
+
2205
+ $ret = array();
2206
+
2207
+ $max = rand( 2, 4 );
2208
+ for ( $i = 1; $i <= $max; $i ++ ) {
2209
+ $length = rand( 6, 16 );
2210
+ $string1 = str_shuffle( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-' );
2211
+ $string2 = str_shuffle( '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.@*_[]' );
2212
+ $ret[0][] = array( substr( $string1, 0, $length ), substr( $string2, 0, $length ) );
2213
+ }
2214
+
2215
+ $max = rand( 2, 4 );
2216
+ for ( $i = 1; $i <= $max; $i ++ ) {
2217
+ $length = rand( 6, 16 );
2218
+ $string1 = str_shuffle( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-' );
2219
+ $string2 = str_shuffle( '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.@*_[]' );
2220
+ $ret[1][] = array( substr( $string1, 0, $length ), substr( $string2, 0, $length ) );
2221
+ }
2222
+
2223
+ update_site_option( 'cerber-antibot', $ret );
2224
+ }
2225
+
2226
+ return $ret;
2227
+ }
2228
+
2229
+ /**
2230
+ * Is a POST request (a form) submitted by a bot?
2231
+ *
2232
+ * @param $location string identificator of a place where we are check for a bot
2233
+ *
2234
+ * @return bool
2235
+ */
2236
+ function cerber_is_bot( $location = '' ) {
2237
+ global $cerber_status;
2238
+ static $ret = null;
2239
+
2240
+ $remote_ip = cerber_get_remote_ip();
2241
+
2242
+ if ( $remote_ip == '127.0.0.1' || $remote_ip == '::1' ) {
2243
+ return false; // v. 7.8.5
2244
+ }
2245
+
2246
+ if ( isset( $ret ) ) {
2247
+ return $ret;
2248
+ }
2249
+
2250
+ if ( ! $location || ! cerber_is_http_post() || cerber_is_wp_cron() ) {
2251
+ $ret = false;
2252
+
2253
+ return $ret;
2254
+ }
2255
+
2256
+ // Admin || AJAX requests by unauthorized users
2257
+ if ( is_admin() ) {
2258
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
2259
+ if ( is_user_logged_in() ) {
2260
+ $ret = false;
2261
+ }
2262
+ elseif ( ! empty( $_POST['action'] ) ) {
2263
+ if ( $_POST['action'] == 'heartbeat' ) { // WP heartbeat
2264
+ //$nonce_state = wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' );
2265
+ $ret = false;
2266
+ }
2267
+ }
2268
+ }
2269
+ else {
2270
+ $ret = false;
2271
+ }
2272
+ }
2273
+
2274
+ if ($ret !== null) {
2275
+ return $ret;
2276
+ }
2277
+
2278
+ if ( ! cerber_antibot_enabled( $location ) ) {
2279
+ $ret = false;
2280
+
2281
+ return $ret;
2282
+ }
2283
+
2284
+ // Antibot whitelist
2285
+ if ( ( $list = crb_get_settings( 'botswhite' ) ) && is_array( $list ) ) {
2286
+ foreach ( $list as $item ) {
2287
+ if ( substr( $item, 0, 1 ) == '{' && substr( $item, - 1 ) == '}' ) {
2288
+ $pattern = '/' . substr( $item, 1, - 1 ) . '/i';
2289
+ if ( @preg_match( $pattern, '/' . trim( $_SERVER['REQUEST_URI'], '/' ) ) ) {
2290
+ $ret = false;
2291
+ return $ret;
2292
+ }
2293
+ }
2294
+ elseif ( false !== strpos( '/' . trim( $_SERVER['REQUEST_URI'], '/' ), $item ) ) {
2295
+ $ret = false;
2296
+ return $ret;
2297
+ }
2298
+ }
2299
+ }
2300
+
2301
+ $antibot = cerber_antibot_gene();
2302
+
2303
+ $ret = false;
2304
+
2305
+ if ( ! empty( $antibot ) ) {
2306
+
2307
+ $mode = cerber_antibot_mode();
2308
+
2309
+ if ( $mode == 1 ) {
2310
+ foreach ( $antibot[0] as $fields ) {
2311
+ if ( empty( $_POST[ $fields[0] ] ) || $_POST[ $fields[0] ] != $fields[1] ) {
2312
+ $ret = true;
2313
+ break;
2314
+ }
2315
+ }
2316
+ }
2317
+
2318
+ if ( ! $ret ) {
2319
+ foreach ( $antibot[1] as $fields ) {
2320
+ if ( empty( $_COOKIE[ $fields[0] ] ) || $_COOKIE[ $fields[0] ] != $fields[1] ) {
2321
+ $ret = true;
2322
+ break;
2323
+ }
2324
+ }
2325
+ }
2326
+
2327
+ if ( $ret ) {
2328
+ $cerber_status = 11;
2329
+ lab_save_push( $remote_ip, 333, '' );
2330
+ }
2331
+ }
2332
+
2333
+ return $ret;
2334
+ }
2335
+
2336
+ function cerber_geo_allowed( $rule_id = '' ) {
2337
+
2338
+ if ( ! $rule_id || cerber_is_wp_cron() || ! lab_lab() ) {
2339
+ return true;
2340
+ }
2341
+
2342
+ if ( crb_acl_is_white() ) {
2343
+ return true;
2344
+ }
2345
+
2346
+ $rule = cerber_geo_rules( $rule_id );
2347
+ $wp_cerber = get_wp_cerber();
2348
+ if ( $rule && $country = lab_get_country( $wp_cerber->getRemoteIp(), false ) ) {
2349
+ if ( in_array( $country, $rule['list'] ) ) {
2350
+ if ( $rule['type'] == 'W' ) {
2351
+ return true;
2352
+ }
2353
+
2354
+ return false;
2355
+ }
2356
+ if ( $rule['type'] == 'W' ) {
2357
+ return false;
2358
+ }
2359
+
2360
+ return true;
2361
+ }
2362
+
2363
+ return true;
2364
+ }
2365
+
2366
+ /**
2367
+ * Retrieve and return GEO rule(s) from the DB
2368
+ *
2369
+ * @param string $rule_id Slug of a rule
2370
+ *
2371
+ * @return bool|array If a rule exists return array of countries
2372
+ */
2373
+ function cerber_geo_rules( $rule_id = '' ) {
2374
+ global $wpdb;
2375
+
2376
+ if (is_multisite()) {
2377
+ //$geo = $wpdb->get_var( 'SELECT meta_value FROM ' . $wpdb->sitemeta . ' WHERE meta_key = "geo_rule_set"' );
2378
+ $geo = cerber_db_get_var( 'SELECT meta_value FROM ' . $wpdb->sitemeta . ' WHERE meta_key = "geo_rule_set"' );
2379
+ }
2380
+ else {
2381
+ //$geo = $wpdb->get_var( 'SELECT option_value FROM ' . $wpdb->options . ' WHERE option_name = "geo_rule_set"' );
2382
+ $geo = cerber_db_get_var( 'SELECT option_value FROM ' . $wpdb->options . ' WHERE option_name = "geo_rule_set"' );
2383
+ }
2384
+
2385
+ if ( $geo ) {
2386
+ $rules = unserialize( $geo );
2387
+ if ( $rule_id ) {
2388
+ if ( ! empty( $rules[ $rule_id ] ) ) {
2389
+ $ret = $rules[ $rule_id ];
2390
+ }
2391
+ else {
2392
+ $ret = false;
2393
+ }
2394
+ }
2395
+ else {
2396
+ $ret = $rules;
2397
+ }
2398
+ }
2399
+ else {
2400
+ $ret = false;
2401
+ }
2402
+
2403
+ return $ret;
2404
+ }
2405
+
2406
+ /**
2407
+ * Set user session expiration
2408
+ *
2409
+ */
2410
+ add_filter( 'auth_cookie_expiration', function ( $expire ) {
2411
+ $time = crb_get_settings( 'auth_expire' );
2412
+ if ( $time ) {
2413
+ $expire = 60 * $time;
2414
+ }
2415
+
2416
+ return $expire;
2417
+ } );
2418
+
2419
+ // Track various activity -------------------------------------------------------------------------
2420
+
2421
+ add_action( 'wp_login', function ( $login, $user ) {
2422
+ global $wp_cerber_user_id;
2423
+ if ( ! empty( $_POST['log'] ) ) { // default WP form
2424
+ $user_login = htmlspecialchars( $_POST['log'] );
2425
+ }
2426
+ else {
2427
+ $user_login = $login;
2428
+ }
2429
+ $wp_cerber_user_id = $user->ID;
2430
+ cerber_log( 5, $user_login, $user->ID );
2431
+ }, 10, 2 );
2432
+
2433
+ /**
2434
+ * Catching some cases of authentication without using login form or not a default user login process
2435
+ */
2436
+ add_action( 'set_auth_cookie', function () {
2437
+ add_action( 'shutdown', function () { // deferred to allow the possible 'wp_login' action be logged first
2438
+ if ($user_id = get_current_user_id()) {
2439
+ cerber_log( 5, '', $user_id );
2440
+ }
2441
+ } );
2442
+ } );
2443
+
2444
+ /*add_action( 'wp_logout', function() {
2445
+ global $user_ID;
2446
+ if ( ! $user_ID ) {
2447
+ $user = wp_get_current_user();
2448
+ $user_ID = $user->ID;
2449
+ }
2450
+ cerber_log( 6, '', $user_ID );
2451
+ });*/
2452
+
2453
+ add_action( 'clear_auth_cookie', function () {
2454
+ $uid = get_current_user_id();
2455
+ if ( $uid ) {
2456
+ cerber_log( 6, '', $uid );
2457
+ }
2458
+ } );
2459
+
2460
+ //add_action( 'lostpassword_post', 'cerber_password_post' );
2461
+ add_action( 'retrieve_password', function ( $user_login ) {
2462
+ cerber_log( 21, $user_login );
2463
+ } );
2464
+
2465
+ add_action( 'password_reset', 'crb_pass_reset' );
2466
+ add_action( 'crb_after_reset', 'crb_pass_reset', 10, 2);
2467
+
2468
+ function crb_pass_reset( $user, $user_id = null) {
2469
+ if ( ! $user && $user_id ) {
2470
+ $user = get_user_by( 'id', $user_id );
2471
+ }
2472
+ if ( ! $user ) {
2473
+ return;
2474
+ }
2475
+ cerber_log( 20, $user->user_login, $user->ID );
2476
+ }
2477
+
2478
+ // Fires in wp_insert_user()
2479
+ add_action( 'user_register', function ( $user_id ) { // @since 5.6
2480
+ $cid = get_current_user_id();
2481
+ if ($user = get_user_by( 'ID', $user_id )) {
2482
+ if ( $cid && $cid != $user_id ) {
2483
+ $ac = 1;
2484
+ }
2485
+ else {
2486
+ $ac = 2;
2487
+ }
2488
+ cerber_log( $ac, $user->user_login, $user_id );
2489
+ crb_log_user_ip( $user_id, $cid );
2490
+ }
2491
+ });
2492
+
2493
+ // Fires after a new user has been created in WP dashboard.
2494
+ add_action( 'edit_user_created_user', function ( $user_id, $notify = null ) {
2495
+ if ( $user_id && $user = get_user_by( 'ID', $user_id ) ) {
2496
+ cerber_log( 1, $user->user_login, $user_id );
2497
+ crb_log_user_ip( $user_id );
2498
+ }
2499
+ }, 10, 2 );
2500
+
2501
+ // Log IP address of user registration independently
2502
+ function crb_log_user_ip( $user_id, $by_user = null ) {
2503
+ global $wp_cerber;
2504
+ if ( ! $user_id ) {
2505
+ return;
2506
+ }
2507
+ if ( ! $by_user ) {
2508
+ $by_user = get_current_user_id();
2509
+ }
2510
+ add_user_meta( $user_id, '_crb_reg_', array( 'IP' => $wp_cerber->getRemoteIp(), 'user' => $by_user ) );
2511
+ }
2512
+
2513
+ // Lockouts routines ---------------------------------------------------------------------
2514
+
2515
+ /**
2516
+ * Lock out IP address if it is an alien IP only (browser does not have valid Cerber groove)
2517
+ *
2518
+ * @param $ip string IP address to block
2519
+ * @param integer $reason_id ID of reason of blocking
2520
+ * @param string $details Reason of blocking
2521
+ * @param null $duration Duration of blocking
2522
+ *
2523
+ * @return bool|false|int
2524
+ */
2525
+ function cerber_soft_block_add( $ip, $reason_id, $details = '', $duration = null ) {
2526
+ if ( cerber_check_groove() ) {
2527
+ return false;
2528
+ }
2529
+
2530
+ return cerber_block_add( $ip, $reason_id, $details, $duration );
2531
+ }
2532
+
2533
+ /**
2534
+ * Lock out IP address
2535
+ *
2536
+ * @param $ip string IP address to block
2537
+ * @param integer $reason_id ID of reason of blocking
2538
+ * @param string $details Reason of blocking
2539
+ * @param int $duration Duration of blocking
2540
+ *
2541
+ * @return bool|false|int
2542
+ */
2543
+ function cerber_block_add( $ip = '', $reason_id = 1, $details = '', $duration = null ) {
2544
+ global $cerber_blocked;
2545
+
2546
+ if ( cerber_is_cloud_request() ) {
2547
+ return false;
2548
+ }
2549
+
2550
+ $wp_cerber = get_wp_cerber();
2551
+
2552
+ //$wp_cerber->setProcessed();
2553
+
2554
+ if ( empty( $ip ) || ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2555
+ $ip = $wp_cerber->getRemoteIp();
2556
+ }
2557
+
2558
+ if ( cerber_get_block( $ip ) ) {
2559
+ return false;
2560
+ }
2561
+
2562
+ if ( cerber_acl_check( $ip ) ) {
2563
+ return false;
2564
+ }
2565
+
2566
+ $ip_address = $ip;
2567
+
2568
+ lab_save_push( $ip, $reason_id, $details );
2569
+
2570
+ if ( $wp_cerber->getSettings( 'subnet' ) ) {
2571
+ $ip = cerber_get_subnet( $ip );
2572
+ $activity = 11;
2573
+ }
2574
+ else {
2575
+ $activity = 10;
2576
+ }
2577
+
2578
+ /*if ( $wpdb->get_var( $wpdb->prepare( 'SELECT count(ip) FROM ' . CERBER_BLOCKS_TABLE . ' WHERE ip = %s', $ip ) ) ) {
2579
+ return false;
2580
+ }*/
2581
+
2582
+ $reason = cerber_get_reason( $reason_id );
2583
+ if ( $details ) {
2584
+ $reason .= ': <b>' . $details . '</b>';
2585
+ }
2586
+
2587
+ if ( ! $duration ) {
2588
+ $duration = cerber_calc_duration( $ip );
2589
+ }
2590
+ $until = time() + $duration;
2591
+
2592
+ //$result = $wpdb->query($wpdb->prepare('INSERT INTO '. CERBER_BLOCKS_TABLE . ' (ip,block_until,reason) VALUES (%s,%d,%s)',$ip,$until,$reason));
2593
+ /*
2594
+ $result = $wpdb->insert( CERBER_BLOCKS_TABLE, array(
2595
+ 'ip' => $ip,
2596
+ 'block_until' => $until,
2597
+ 'reason' => $reason,
2598
+ 'reason_id' => absint( $reason_id )
2599
+ ), array( '%s', '%d', '%s' ) );*/
2600
+
2601
+ $reason = cerber_real_escape( $reason );
2602
+ $result = cerber_db_query( 'INSERT INTO ' . CERBER_BLOCKS_TABLE . ' (ip,block_until,reason,reason_id) VALUES ("' . $ip . '",' . $until . ',"' . $reason . '",' . absint( $reason_id ) . ')' );
2603
+
2604
+ if ( $result ) {
2605
+ $cerber_blocked = $reason_id;
2606
+ cerber_log( $activity, null, null, $ip_address );
2607
+ $wp_cerber->setLocked();
2608
+ do_action( 'cerber_ip_locked', array( 'IP' => $ip_address, 'reason' => $reason ) );
2609
+ $result = true;
2610
+ }
2611
+ else {
2612
+ cerber_db_error_log();
2613
+ $result = false;
2614
+ }
2615
+
2616
+ if ( $wp_cerber->getSettings( 'notify' ) ) {
2617
+ $count = cerber_blocked_num();
2618
+ if ( $count > $wp_cerber->getSettings( 'above' ) ) {
2619
+ cerber_send_email( 'lockout', '', $ip_address );
2620
+ }
2621
+ }
2622
+
2623
+ return $result;
2624
+ }
2625
+
2626
+ /**
2627
+ *
2628
+ * Check if an IP address is currently blocked. With C subnet also.
2629
+ *
2630
+ * @param string $ip an IP address
2631
+ *
2632
+ * @return bool true if IP is locked out
2633
+ */
2634
+ function cerber_block_check( $ip = '' ) {
2635
+
2636
+ // @since 4.8
2637
+ if ( cerber_get_block( $ip ) ) {
2638
+ return true;
2639
+ }
2640
+
2641
+ return false;
2642
+ }
2643
+
2644
+ /**
2645
+ *
2646
+ * Return the lockout row for an IP if it is blocked. With C subnet also.
2647
+ *
2648
+ * @param string $ip an IP address
2649
+ *
2650
+ * @return object|bool object if IP is locked out, false otherwise
2651
+ */
2652
+ function cerber_get_block( $ip = '' ) {
2653
+ global $wp_cerber;
2654
+
2655
+ if ( ! $ip ) {
2656
+ $wp_cerber = get_wp_cerber();
2657
+ $ip = $wp_cerber->getRemoteIp();
2658
+ }
2659
+
2660
+ if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2661
+ return false;
2662
+ }
2663
+
2664
+ $where = ' WHERE ip = "' . $ip . '"';
2665
+ if ( cerber_is_ipv4( $ip ) ) {
2666
+ $subnet = cerber_get_subnet( $ip );
2667
+ $where .= ' OR ip = "' . $subnet . '"';
2668
+ }
2669
+ /*if ( $ret = $wpdb->get_row( 'SELECT * FROM ' . CERBER_BLOCKS_TABLE . $where ) ) {
2670
+ return $ret;
2671
+ }*/
2672
+ if ( $ret = cerber_db_get_row( 'SELECT * FROM ' . CERBER_BLOCKS_TABLE . $where, MYSQL_FETCH_OBJECT ) ) {
2673
+ return $ret;
2674
+ }
2675
+ return false;
2676
+ }
2677
+
2678
+ /**
2679
+ * Return the number of currently locked out IPs
2680
+ *
2681
+ * @return int the number of currently locked out IPs
2682
+ * @since 3.0
2683
+ */
2684
+ function cerber_blocked_num() {
2685
+ return absint( cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_BLOCKS_TABLE ) );
2686
+ }
2687
+
2688
+ /**
2689
+ * Calculate duration for a lockout of an IP address based on settings
2690
+ *
2691
+ * @param string $ip
2692
+ *
2693
+ * @return integer Duration in seconds
2694
+ */
2695
+ function cerber_calc_duration( $ip ) {
2696
+ $range = time() - crb_get_settings( 'aglast' ) * 3600;
2697
+ //$lockouts = $wpdb->get_var( $wpdb->prepare( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = %s AND activity IN (10,11) AND stamp > %d', $ip, $range ) );
2698
+ //$lockouts = $wpdb->get_var( 'SELECT COUNT(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity IN (10,11) AND stamp > ' . $range );
2699
+ $lockouts = cerber_db_get_var( 'SELECT COUNT(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity IN (10,11) AND stamp > ' . $range );
2700
+ if ( $lockouts >= crb_get_settings( 'aglocks' ) ) {
2701
+ $ret = crb_get_settings( 'agperiod' ) * 3600;
2702
+ }
2703
+ else {
2704
+ $ret = crb_get_settings( 'lockout' ) * 60;
2705
+ }
2706
+ $ret = absint( $ret );
2707
+ if ( $ret < 60 ) {
2708
+ $ret = 60;
2709
+ }
2710
+
2711
+ return $ret;
2712
+ }
2713
+
2714
+ /**
2715
+ * Calculation of remaining attempts
2716
+ *
2717
+ * @param $ip string an IP address
2718
+ * @param $check_acl bool if true will check the White IP ACL first
2719
+ * @param $activity array List of activity IDs to calculate for
2720
+ * @param $allowed int Allowed attempts within $period
2721
+ * @param $period int Period for count attempts
2722
+ *
2723
+ * @return int Allowed attempts for present moment
2724
+ */
2725
+ function cerber_get_remain_count( $ip = '', $check_acl = true, $activity = array( '7,51,52' ), $allowed = null, $period = null ) {
2726
+ global $wpdb, $wp_cerber;
2727
+ if ( ! $ip ) {
2728
+ $ip = $wp_cerber->getRemoteIp();
2729
+ }
2730
+ else {
2731
+ if ( ! $ip = filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2732
+ return 0;
2733
+ }
2734
+ }
2735
+
2736
+ if ( ! $allowed ) {
2737
+ $allowed = absint( crb_get_settings( 'attempts' ) );
2738
+ }
2739
+
2740
+ if ( $check_acl && crb_acl_is_white( $ip ) ) {
2741
+ return $allowed; // whitelist = infinity attempts
2742
+ }
2743
+
2744
+ if ( ! $period ) {
2745
+ $period = absint( crb_get_settings( 'period' ) );
2746
+ }
2747
+
2748
+ $range = time() - $period * 60;
2749
+ $in = implode( ',', array_filter( array_map( 'absint', $activity ) ) );
2750
+ $attempts = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity IN (' . $in . ') AND stamp > ' . $range );
2751
+
2752
+ if ( ! $attempts ) {
2753
+ return $allowed;
2754
+ }
2755
+ else {
2756
+ $ret = $allowed - $attempts;
2757
+ }
2758
+ $ret = $ret < 0 ? 0 : $ret;
2759
+
2760
+ return $ret;
2761
+ }
2762
+
2763
+ /**
2764
+ * Is a given IP is allowed to do restricted things?
2765
+ * Here Cerber makes its decision.
2766
+ *
2767
+ * @param string $ip IP address
2768
+ * @param array $allowed a list of reason ids @since 7.5.2
2769
+ *
2770
+ * @return bool
2771
+ */
2772
+ function cerber_is_allowed( $ip = '', $allowed = array() ) {
2773
+
2774
+ if ( ! $ip ) {
2775
+ $wp_cerber = get_wp_cerber();
2776
+ $ip = $wp_cerber->getRemoteIp();
2777
+ }
2778
+ elseif ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2779
+ return false;
2780
+ }
2781
+
2782
+ // @since 7.5.2
2783
+ $tag = cerber_acl_check( $ip );
2784
+ if ( $tag == 'W' ) {
2785
+ return true;
2786
+ }
2787
+ if ( $tag == 'B' ) {
2788
+ return false;
2789
+ }
2790
+
2791
+ // @since 4.7.9
2792
+ if ( $b = cerber_get_block( $ip ) ) {
2793
+ if ( empty( $allowed ) ) {
2794
+ return false;
2795
+ }
2796
+ elseif ( ! in_array( $b->reason_id, $allowed ) ) {
2797
+ return false;
2798
+ }
2799
+ }
2800
+
2801
+ /* @since 4.7.9
2802
+ if ( cerber_block_check( $ip ) ) {
2803
+ return false;
2804
+ }*/
2805
+
2806
+ if ( cerber_is_citadel() ) {
2807
+ return false;
2808
+ }
2809
+
2810
+ if ( lab_is_blocked( $ip, false ) ) {
2811
+ return false;
2812
+ }
2813
+
2814
+ return true;
2815
+ }
2816
+
2817
+ /**
2818
+ * Check if a given username is not permitted to login or register
2819
+ *
2820
+ * @param $username string
2821
+ *
2822
+ * @return bool true if username is prohibited
2823
+ */
2824
+ function cerber_is_prohibited( $username ) {
2825
+ if ( ! $username ) {
2826
+ return false;
2827
+ }
2828
+
2829
+ if ( $list = (array) crb_get_settings( 'prohibited' ) ) {
2830
+ foreach ( $list as $item ) {
2831
+ if ( mb_substr( $item, 0, 1 ) == '/' && mb_substr( $item, - 1 ) == '/' ) {
2832
+ $pattern = trim( $item, '/' );
2833
+ if ( @mb_ereg_match( $pattern, $username, 'i' ) ) {
2834
+ return true;
2835
+ }
2836
+ }
2837
+ elseif ($username === $item){
2838
+ return true;
2839
+ }
2840
+ }
2841
+ }
2842
+
2843
+ return false;
2844
+ }
2845
+
2846
+ // TODO: Merge with $wp_cerber->getStatus();
2847
+ function cerber_get_status( $ip ) {
2848
+ global $cerber_status;
2849
+
2850
+ if ( ! empty( $cerber_status ) ) {
2851
+ return absint($cerber_status);
2852
+ }
2853
+
2854
+ if ( cerber_block_check( $ip ) ) {
2855
+ return 13;
2856
+ }
2857
+
2858
+ $tag = cerber_acl_check( $ip );
2859
+ if ( $tag == 'W' ) {
2860
+ return 0;
2861
+ }
2862
+ if ( $tag == 'B' ) {
2863
+ return 14;
2864
+ }
2865
+
2866
+ if ( cerber_is_citadel() ) {
2867
+ return 12;
2868
+ }
2869
+
2870
+ if ( lab_is_blocked( $ip, false ) ) {
2871
+ return 15;
2872
+ }
2873
+
2874
+
2875
+ return 0;
2876
+ }
2877
+
2878
+ // Access lists (ACL) routines --------------------------------------------------------------------------------
2879
+
2880
+ // TODO: move to dashboard.php
2881
+ /**
2882
+ * Add IP to specified access list
2883
+ *
2884
+ * @param $ip string|array single IP address, string with IP network, range or associative range array
2885
+ * @param $tag string 'B'|'W'
2886
+ *
2887
+ * @return bool|int|object Result of operation
2888
+ */
2889
+ function cerber_acl_add( $ip, $tag, $comment = '') {
2890
+ global $wpdb;
2891
+ if ( is_string( $ip ) ) {
2892
+ if ( ! cerber_is_ipv4( $ip ) ) {
2893
+ $ip = cerber_short_ipv6( $ip );
2894
+ }
2895
+ if ( cerber_db_get_var( $wpdb->prepare( 'SELECT COUNT(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s', $ip ) ) ) {
2896
+ return false; //__( 'Element is already in list', 'wp-cerber' );
2897
+ }
2898
+ $range = cerber_any2range( $ip );
2899
+ if ( is_array( $range ) ) {
2900
+ $begin = $range['begin'];
2901
+ $end = $range['end'];
2902
+ }
2903
+ else {
2904
+ if (cerber_is_ipv4($ip)) {
2905
+ $begin = ip2long( $ip );
2906
+ $end = ip2long( $ip );
2907
+ }
2908
+ else{
2909
+ $begin = 0;
2910
+ $end = 0;
2911
+ }
2912
+ }
2913
+
2914
+ $result = $wpdb->insert( CERBER_ACL_TABLE, array( 'ip' => $ip,
2915
+ 'ip_long_begin' => $begin,
2916
+ 'ip_long_end' => $end,
2917
+ 'tag' => $tag,
2918
+ 'comments' => $comment
2919
+ ), array( '%s', '%d', '%d', '%s', '%s' ) );
2920
+ return $result;
2921
+ }
2922
+ elseif ( is_array( $ip ) ) {
2923
+ $range = $ip['range'];
2924
+ $begin = $ip['begin'];
2925
+ $end = $ip['end'];
2926
+ if ( cerber_db_get_var( $wpdb->prepare( 'SELECT COUNT(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = %d AND ip_long_end = %d', $begin, $end ) ) ) {
2927
+ return false;
2928
+ }
2929
+
2930
+ $result = $wpdb->insert( CERBER_ACL_TABLE, array( 'ip' => $range,
2931
+ 'ip_long_begin' => $begin,
2932
+ 'ip_long_end' => $end,
2933
+ 'tag' => $tag,
2934
+ 'comments' => $comment
2935
+ ), array( '%s', '%d', '%d', '%s', '%s' ) );
2936
+
2937
+ return $result;
2938
+
2939
+ //return $wpdb->query( $wpdb->prepare( 'INSERT INTO ' . CERBER_ACL_TABLE . ' (ip, ip_long_begin, ip_long_end, tag) VALUES (%s,%d,%d,%s)', $range, $begin, $end, $tag ) );
2940
+ }
2941
+
2942
+ return false;
2943
+ }
2944
+ // TODO: move to dashboard.php
2945
+ function cerber_add_white( $ip, $comment = '' ) {
2946
+ return cerber_acl_add( $ip, 'W', $comment );
2947
+ }
2948
+ // TODO: move to dashboard.php
2949
+ function cerber_add_black( $ip, $comment = '') {
2950
+ return cerber_acl_add( $ip, 'B', $comment );
2951
+ }
2952
+ // TODO: move to dashboard.php
2953
+ function cerber_acl_remove( $ip ) {
2954
+ global $wpdb;
2955
+ if ( is_string( $ip ) ) {
2956
+ return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s ', $ip ) );
2957
+ } elseif ( is_array( $ip ) ) {
2958
+ return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = %d AND ip_long_end = %d', $ip['begin'], $ip['end'] ) );
2959
+ }
2960
+
2961
+ return false;
2962
+ }
2963
+
2964
+ // TODO: move to dashboard.php
2965
+ /**
2966
+ * Can a given IP (user input) be added to the blacklist
2967
+ *
2968
+ * @param $ip
2969
+ * @param string $list
2970
+ *
2971
+ * @return bool
2972
+ */
2973
+ function cerber_can_be_listed( $ip, $list = 'B' ) {
2974
+ global $wp_cerber;
2975
+ if ( $list == 'B' ) {
2976
+ if ( crb_acl_is_white( $wp_cerber->getRemoteIp() ) ) {
2977
+ return true;
2978
+ }
2979
+ if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2980
+ if ( cerber_is_myip( $ip ) ) {
2981
+ return false;
2982
+ }
2983
+ }
2984
+ $range = cerber_any2range( $ip );
2985
+ if ( cerber_is_ip_in_range( $range ) ) {
2986
+ return false;
2987
+ }
2988
+
2989
+ return true;
2990
+ }
2991
+
2992
+ return true;
2993
+ }
2994
+
2995
+ /**
2996
+ * Is an IP whitelisted?
2997
+ *
2998
+ * @param $ip string
2999
+ *
3000
+ * @return bool
3001
+ */
3002
+ function crb_acl_is_white( $ip = null ){
3003
+
3004
+ if ( cerber_acl_check( $ip, 'W' ) ) {
3005
+ return true;
3006
+ }
3007
+
3008
+ return false;
3009
+ }
3010
+
3011
+ /**
3012
+ * Is an IP blacklisted?
3013
+ *
3014
+ * @param $ip string
3015
+ *
3016
+ * @return bool
3017
+ */
3018
+ function crb_acl_is_black( $ip = '' ) {
3019
+ $tag = cerber_acl_check( $ip );
3020
+ if ( $tag === 'W' ) {
3021
+ return false;
3022
+ }
3023
+ elseif ( $tag === 'B' ) {
3024
+ return true;
3025
+ }
3026
+
3027
+ return false;
3028
+ }
3029
+
3030
+ /**
3031
+ * Check ACLs for given IP. Some extra lines for performance reason.
3032
+ *
3033
+ * @param string $ip
3034
+ * @param string $tag
3035
+ *
3036
+ * @return bool|string
3037
+ */
3038
+ function cerber_acl_check( $ip = null, $tag = '' ) {
3039
+ global $wp_cerber;
3040
+ static $cache;
3041
+
3042
+ if ( ! $ip ) {
3043
+ $wp_cerber = get_wp_cerber();
3044
+ $ip = $wp_cerber->getRemoteIp();
3045
+ //$ip = cerber_get_remote_ip();
3046
+ }
3047
+
3048
+ $key = cerber_get_id_ip( $ip ) . (string)$tag;
3049
+
3050
+ if ( isset( $cache[ $key ] ) ) {
3051
+ return $cache[ $key ];
3052
+ }
3053
+
3054
+ if ( ! cerber_is_ipv4( $ip ) ) {
3055
+ $ret = cerber_acl_checkV6( $ip, $tag );
3056
+ $cache[ $key ] = $ret;
3057
+ return $ret;
3058
+ }
3059
+
3060
+ $long = ip2long( $ip );
3061
+
3062
+ if ( $tag ) {
3063
+ if ( $tag !== 'W' && $tag !== 'B' ) {
3064
+ $ret = false;
3065
+ }
3066
+ elseif ( cerber_db_get_var( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= '.$long.' AND '.$long.' <= ip_long_end AND tag = "'.$tag.'" LIMIT 1' ) ) {
3067
+ $ret = true;
3068
+ }
3069
+ else {
3070
+ $ret = false;
3071
+ }
3072
+
3073
+ $cache[ $key ] = $ret;
3074
+ return $ret;
3075
+ }
3076
+ else {
3077
+ // We use two queries because of possible overlapping an IP and its network
3078
+ if ( $ret = cerber_db_get_var( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= ' . $long . ' AND ' . $long . ' <= ip_long_end AND tag = "W" LIMIT 1' ) ) {
3079
+ $cache[ $key ] = $ret;
3080
+ return $ret;
3081
+ }
3082
+ if ( $ret = cerber_db_get_var( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= ' . $long . ' AND ' . $long . ' <= ip_long_end AND tag = "B" LIMIT 1' ) ) {
3083
+ $cache[ $key ] = $ret;
3084
+ return $ret;
3085
+ }
3086
+
3087
+ $cache[ $key ] = false;
3088
+ return false;
3089
+ }
3090
+ }
3091
+
3092
+ /**
3093
+ * IPv6 version of cerber_acl_check() without subnets and ranges
3094
+ *
3095
+ * @param null $ip
3096
+ * @param string $tag
3097
+ *
3098
+ * @return bool|null|string
3099
+ */
3100
+ function cerber_acl_checkV6( $ip = null, $tag = '' ) {
3101
+ global $wp_cerber;
3102
+
3103
+ if ( ! $ip ) {
3104
+ //$ip = $wp_cerber->getRemoteIp();
3105
+ $ip = cerber_get_remote_ip();
3106
+ }
3107
+ elseif ( ! cerber_is_ip( $ip ) ) {
3108
+ return false;
3109
+ }
3110
+
3111
+ if ( $tag ) {
3112
+ if ( $tag != 'W' && $tag != 'B' ) {
3113
+ return false;
3114
+ }
3115
+ if ( cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip = "' . $ip . '" AND tag = "' . $tag . '"' ) ) {
3116
+ return true;
3117
+ }
3118
+
3119
+ return false;
3120
+ }
3121
+ else {
3122
+ if ( $ret = cerber_db_get_var( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip = "' . $ip . '"' ) ) {
3123
+ return $ret;
3124
+ }
3125
+
3126
+ return false;
3127
+ }
3128
+ }
3129
+
3130
+ /*
3131
+ * Logging directly to the file
3132
+ *
3133
+ * CERBER_FAIL_LOG optional, full path including filename to the log file
3134
+ * CERBER_LOG_FACILITY optional, use to specify what type of program is logging the messages
3135
+ *
3136
+ * */
3137
+ function cerber_file_log( $user_login, $ip ) {
3138
+ if ( defined( 'CERBER_FAIL_LOG' ) ) {
3139
+ if ( $log = @fopen( CERBER_FAIL_LOG, 'a' ) ) {
3140
+ $pid = absint( @posix_getpid() );
3141
+ @fwrite( $log, date( 'M j H:i:s ' ) . $_SERVER['SERVER_NAME'] . ' Cerber(' . $_SERVER['HTTP_HOST'] . ')[' . $pid . ']: Authentication failure for ' . $user_login . ' from ' . $ip . "\n" );
3142
+ @fclose( $log );
3143
+ }
3144
+ } else {
3145
+ @openlog( 'Cerber(' . $_SERVER['HTTP_HOST'] . ')', LOG_NDELAY | LOG_PID, defined( 'CERBER_LOG_FACILITY' ) ? CERBER_LOG_FACILITY : LOG_AUTH );
3146
+ @syslog( LOG_NOTICE, 'Authentication failure for ' . $user_login . ' from ' . $ip );
3147
+ @closelog();
3148
+ }
3149
+ }
3150
+
3151
+ /*
3152
+ Return wildcard - string like subnet Class C
3153
+ */
3154
+ function cerber_get_subnet( $ip ) {
3155
+ return preg_replace( '/\.\d{1,3}$/', '.*', $ip );
3156
+ }
3157
+
3158
+ /*
3159
+ Check if given IP address or wildcard or CIDR is valid
3160
+ */
3161
+ function cerber_is_ip_or_net( $ip ) {
3162
+ if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
3163
+ return true;
3164
+ }
3165
+ // WILDCARD: 192.168.1.*
3166
+ $ip = str_replace( '*', '0', $ip );
3167
+ //if ( @inet_pton( $ip ) ) {
3168
+ if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
3169
+ return true;
3170
+ }
3171
+ // CIDR: 192.168.1/24
3172
+ if ( strpos( $ip, '/' ) ) {
3173
+ $cidr = explode( '/', $ip );
3174
+ $net = $cidr[0];
3175
+ $mask = absint( $cidr[1] );
3176
+ $dots = substr_count( $net, '.' );
3177
+ if ( $dots < 3 ) {
3178
+ if ( $dots == 1 ) {
3179
+ $net .= '.0.0';
3180
+ } elseif ( $dots == 2 ) {
3181
+ $net .= '.0';
3182
+ }
3183
+ }
3184
+ if ( ! cerber_is_ipv4( $net ) ) {
3185
+ return false;
3186
+ }
3187
+ if ( ! is_numeric( $mask ) ) {
3188
+ return false;
3189
+ }
3190
+
3191
+ return true;
3192
+ }
3193
+
3194
+ return false;
3195
+ }
3196
+
3197
+ /**
3198
+ * Tries to recognize single IP address or IP v4 range (with dash) in a given string.
3199
+ *
3200
+ * @param string $string String to recognize IP address in
3201
+ *
3202
+ * @return array|bool|string Return single IP address or wildcard or CIDR as a string, and IP range as an array.
3203
+ */
3204
+ function cerber_parse_ip( $string = '' ) {
3205
+ $string = trim( $string );
3206
+ if ( cerber_is_ip_or_net( $string ) ) {
3207
+ return $string;
3208
+ }
3209
+ $explode = explode( '-', $string );
3210
+ if ( ! is_array( $explode ) || ! $explode ) {
3211
+ return false;
3212
+ }
3213
+ $range = array();
3214
+ $count = 0;
3215
+ foreach ( $explode as $ip ) {
3216
+ $ip = trim( $ip );
3217
+ if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
3218
+ $range[] = $ip;
3219
+ $count ++;
3220
+ if ( $count >= 2 ) {
3221
+ break;
3222
+ }
3223
+ }
3224
+ }
3225
+ if ( count( $range ) < 2 ) {
3226
+ return false;
3227
+ }
3228
+ if ( ip2long( $range[1] ) <= ip2long( $range[0] ) ) {
3229
+ return false;
3230
+ }
3231
+
3232
+ return array(
3233
+ 'range' => $range[0] . ' - ' . $range[1],
3234
+ 'begin_ip' => $range[0],
3235
+ 'end_ip' => $range[1],
3236
+ 'begin' => ip2long( $range[0] ),
3237
+ 'end' => ip2long( $range[1] ),
3238
+ );
3239
+ }
3240
+
3241
+ /**
3242
+ * Convert a network wildcard string like x.x.x.* to an IP v4 range
3243
+ *
3244
+ * @param $wildcard string
3245
+ *
3246
+ * @return array|bool|string False if no wildcard found, otherwise result of cerber_parse_ip()
3247
+ */
3248
+ function cerber_wildcard2range( $wildcard = '' ) {
3249
+ $begin = str_replace( '*', '0', $wildcard );
3250
+ $end = str_replace( '*', '255', $wildcard );
3251
+ if ( ! cerber_is_ipv4( $begin ) ) {
3252
+ return false;
3253
+ }
3254
+ if ( ! cerber_is_ipv4( $end ) ) {
3255
+ return false;
3256
+ }
3257
+
3258
+ return cerber_parse_ip( $begin . ' - ' . $end );
3259
+ }
3260
+
3261
+ /**
3262
+ * Convert a CIDR to an IP v4 range
3263
+ *
3264
+ * @param $cidr string
3265
+ *
3266
+ * @return array|bool|string
3267
+ */
3268
+ function cerber_cidr2range( $cidr = '' ) {
3269
+ if ( ! strpos( $cidr, '/' ) ) {
3270
+ return false;
3271
+ }
3272
+ $cidr = explode( '/', $cidr );
3273
+ $net = $cidr[0];
3274
+ $mask = absint( $cidr[1] );
3275
+ $dots = substr_count( $net, '.' );
3276
+ if ( $dots < 3 ) { // not completed CIDR
3277
+ if ( $dots == 1 ) {
3278
+ $net .= '.0.0';
3279
+ } elseif ( $dots == 2 ) {
3280
+ $net .= '.0';
3281
+ }
3282
+ }
3283
+ if ( ! cerber_is_ipv4( $net ) ) {
3284
+ return false;
3285
+ }
3286
+ if ( ! is_numeric( $mask ) ) {
3287
+ return false;
3288
+ }
3289
+ $begin = long2ip( ( ip2long( $net ) ) & ( ( - 1 << ( 32 - (int) $mask ) ) ) );
3290
+ $end = long2ip( ( ip2long( $net ) ) + pow( 2, ( 32 - (int) $mask ) ) - 1 );
3291
+
3292
+ return cerber_parse_ip( $begin . ' - ' . $end );
3293
+ }
3294
+
3295
+ /**
3296
+ * Try to recognize an IP range or a single IP in a string.
3297
+ *
3298
+ * @param $string string Network wildcard, CIDR or IP range.
3299
+ *
3300
+ * @return array|bool|string
3301
+ */
3302
+ function cerber_any2range( $string = '' ) {
3303
+ // Do not change the order!
3304
+ $ret = cerber_wildcard2range( $string );
3305
+ if ( ! $ret ) {
3306
+ $ret = cerber_cidr2range( $string );
3307
+ }
3308
+ if ( ! $ret ) {
3309
+ $ret = cerber_parse_ip( $string ); // must be last due to checking for cidr and wildcard
3310
+ }
3311
+
3312
+ return $ret;
3313
+ }
3314
+
3315
+ /*
3316
+ Check for given IP address or subnet belong to this session.
3317
+ */
3318
+ function cerber_is_myip( $ip ) {
3319
+ global $wp_cerber;
3320
+ if ( ! is_string( $ip ) ) {
3321
+ return false;
3322
+ }
3323
+ $remote_ip = $wp_cerber->getRemoteIp();
3324
+ if ( $ip == $remote_ip ) {
3325
+ return true;
3326
+ }
3327
+ if ( $ip == cerber_get_subnet( $remote_ip ) ) {
3328
+ return true;
3329
+ }
3330
+
3331
+ return false;
3332
+ }
3333
+
3334
+ function cerber_is_ip_in_range( $range, $ip = null ) {
3335
+ global $wp_cerber;
3336
+ if ( ! is_array( $range ) ) {
3337
+ return false;
3338
+ }
3339
+ if ( ! $ip ) {
3340
+ $ip = $wp_cerber->getRemoteIp();
3341
+ }
3342
+ $long = ip2long( $ip );
3343
+ if ( $range['begin'] <= $long && $long <= $range['end'] ) {
3344
+ return true;
3345
+ }
3346
+
3347
+ return false;
3348
+ }
3349
+
3350
+ /**
3351
+ * Display 404 page to bump bots and bad guys
3352
+ *
3353
+ * @param bool $simple If true force displaying basic 404 page
3354
+ */
3355
+ function cerber_404_page($simple = false) {
3356
+ global $wp_query;
3357
+
3358
+ if ( !$simple ) {
3359
+ if ( function_exists( 'status_header' ) ) {
3360
+ status_header( '404' );
3361
+ }
3362
+ if ( isset( $wp_query ) && is_object( $wp_query ) ) {
3363
+ $wp_query->set_404();
3364
+ }
3365
+ if ( 0 == crb_get_settings( 'page404' ) ) {
3366
+ $template = null;
3367
+ if ( function_exists( 'get_404_template' ) ) {
3368
+ $template = get_404_template();
3369
+ }
3370
+ if ( function_exists( 'apply_filters' ) ) {
3371
+ $template = apply_filters( 'cerber_404_template', $template );
3372
+ }
3373
+ if ( $template && @file_exists( $template ) ) {
3374
+ include( $template );
3375
+ exit;
3376
+ }
3377
+ }
3378
+ }
3379
+
3380
+ header( 'HTTP/1.0 404 Not Found', true, 404 );
3381
+ echo '<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL ' . esc_url( $_SERVER['REQUEST_URI'] ) . ' was not found on this server.</p></body></html>';
3382
+ cerber_traffic_log(); // do not remove!
3383
+ exit;
3384
+ }
3385
+ /*
3386
+ Display Forbidden page
3387
+ */
3388
+ function cerber_forbidden_page() {
3389
+ status_header( '403' );
3390
+ header( 'HTTP/1.0 403 Access Forbidden', true, 403 );
3391
+ ?>
3392
+ <!DOCTYPE html>
3393
+ <html style="height: 100%;">
3394
+ <meta charset="UTF-8">
3395
+ <head><title>403 Access Forbidden</title></head>
3396
+ <body style="height: 100%;">
3397
+ <div style="display: flex; align-items: center; justify-content: center; height: 70%;">
3398
+ <div style="background-color: #eee; width: 70%; border: solid 3px #ddd; padding: 1.5em 3em 3em 3em; font-family: Arial, Helvetica, sans-serif;">
3399
+ <div style="display: table-row;">
3400
+ <div style="display: table-cell; font-size: 150px; color: red; vertical-align: middle; padding-right: 50px;">
3401
+ &#9995;
3402
+ </div>
3403
+ <div style="display: table-cell; vertical-align: middle;">
3404
+ <h1><?php _e("We're sorry, you are not allowed to proceed", 'wp-cerber'); ?></h1>
3405
+ <p>Our server stopped processing your request. Your request looks suspicious or similar to automated
3406
+ requests from spam posting software.</p>
3407
+ <p>If you believe you should be able to perform this request, please let us know.</p>
3408
+ </div>
3409
+ </div>
3410
+ </div>
3411
+ </div>
3412
+ </body>
3413
+ </html>
3414
+ <?php
3415
+ cerber_traffic_log(); // do not remove!
3416
+ exit;
3417
+ }
3418
+
3419
+ // Citadel mode -------------------------------------------------------------------------------------
3420
+
3421
+ function cerber_enable_citadel() {
3422
+ global $wp_cerber;
3423
+ if ( get_transient( 'cerber_citadel' ) ) {
3424
+ return;
3425
+ }
3426
+ set_transient( 'cerber_citadel', true, crb_get_settings( 'ciduration' ) * 60 );
3427
+ cerber_log( 12 );
3428
+
3429
+ // Notify admin
3430
+ if ( $wp_cerber->getSettings( 'cinotify' ) ) {
3431
+ cerber_send_email( 'citadel' );
3432
+ }
3433
+ }
3434
+
3435
+ function cerber_disable_citadel() {
3436
+ delete_transient( 'cerber_citadel' );
3437
+ }
3438
+
3439
+ function cerber_is_citadel() {
3440
+ if ( get_transient( 'cerber_citadel' ) ) {
3441
+ return true;
3442
+ }
3443
+
3444
+ return false;
3445
+ }
3446
+
3447
+ // Hardening -------------------------------------------------------------------------------------
3448
+
3449
+ //if (!cerber_acl_check(cerber_get_ip(),'W') && false) {
3450
+
3451
+ /*
3452
+ if ($hardening['ping']) {
3453
+ add_filter( 'xmlrpc_methods', 'remove_xmlrpc_pingback' );
3454
+ function remove_xmlrpc_pingback( $methods ) {
3455
+ unset($methods['pingback.ping']);
3456
+ unset($methods['pingback.extensions.getPingbacks']);
3457
+ return $methods;
3458
+ }
3459
+ add_filter( 'wp_headers', 'remove_pingback_header' );
3460
+ function remove_pingback_header( $headers ) {
3461
+ unset( $headers['X-Pingback'] );
3462
+ return $headers;
3463
+ }
3464
+ }
3465
+ */
3466
+ //pingback_ping();
3467
+
3468
+
3469
+ /*
3470
+ // Remove shortlink from HEAD <link rel='shortlink' href='http://адрес-сайта/?p=45' />
3471
+ remove_action('wp_head', 'wp_shortlink_wp_head', 10, 0 );
3472
+ */
3473
+
3474
+ /**
3475
+ *
3476
+ * Send notification letter
3477
+ *
3478
+ * @param string $type Notification type
3479
+ * @param string|array $msg Additional message
3480
+ * @param string $ip Remote IP address, if applicable
3481
+ *
3482
+ * @return bool
3483
+ */
3484
+ function cerber_send_email( $type = '', $msg = '', $ip = '' ) {
3485
+ global $wp_cerber;
3486
+ if ( ! $type ) {
3487
+ return false;
3488
+ }
3489
+
3490
+ /*
3491
+ $super = false;
3492
+ if ( function_exists( 'is_super_admin' ) ) {
3493
+ $super = is_super_admin();
3494
+ }
3495
+ if ( $type == 'lockout' && !$usper()) {
3496
+ */
3497
+
3498
+ if ( $type == 'lockout' && ! is_admin() ) {
3499
+ $rate = absint( $wp_cerber->getSettings( 'emailrate' ) );
3500
+ if ( $rate ) {
3501
+ $last_em = cerber_get_set( '_cerber_last', 1, false );
3502
+ $period = 60 * 60; // per hour
3503
+ if ( $last_em ) {
3504
+ if ( $last_em > ( time() - $period / $rate ) ) {
3505
+ return false;
3506
+ }
3507
+ }
3508
+ cerber_update_set( '_cerber_last', time(), 1, false, time() + $period );
3509
+ }
3510
+ }
3511
+
3512
+ $html_mode = false;
3513
+
3514
+ $subj = '[' . get_option( 'blogname' ) . '] ' . __( 'WP Cerber notify', 'wp-cerber' ) . ': ';
3515
+ $body = '';
3516
+
3517
+ if ( is_array( $msg ) ) {
3518
+ $msg = implode( "\n\n", $msg );
3519
+ }
3520
+
3521
+ $last = null;
3522
+
3523
+ switch ( $type ) {
3524
+ case 'citadel':
3525
+ $max = cerber_db_get_var( 'SELECT MAX(stamp) FROM ' . CERBER_LOG_TABLE . ' WHERE activity = 7' );
3526
+ if ( $max ) {
3527
+ $last_date = cerber_date( $max );
3528
+ //$last = $wpdb->get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE stamp = ' . $max . ' AND activity = 7' );
3529
+ $last = cerber_db_get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE stamp = ' . $max . ' AND activity = 7', MYSQL_FETCH_OBJECT );
3530
+ }
3531
+
3532
+ if ( ! $last ) { // workaround for the empty log table
3533
+ $last = new stdClass();
3534
+ $last->ip = CERBER_NO_REMOTE_IP;
3535
+ $last->user_login = 'test';
3536
+ }
3537
+
3538
+ $subj .= __( 'Citadel mode is activated', 'wp-cerber' );
3539
+
3540
+ $body = sprintf( __( 'Citadel mode is activated after %d failed login attempts in %d minutes.', 'wp-cerber' ), $wp_cerber->getSettings( 'cilimit' ), $wp_cerber->getSettings( 'ciperiod' ) ) . "\n\n";
3541
+ $body .= sprintf( __( 'Last failed attempt was at %s from IP %s with user login: %s.', 'wp-cerber' ), $last_date, $last->ip, $last->user_login ) . "\n\n";
3542
+ $body .= __( 'View activity in dashboard', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . "\n\n";
3543
+ //$body .= __('Change notification settings','wp-cerber').': '.cerber_admin_link();
3544
+ break;
3545
+ case 'lockout':
3546
+ $max = cerber_db_get_var( 'SELECT MAX(stamp) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (10,11)' );
3547
+ if ( $max ) {
3548
+ $last_date = cerber_date( $max );
3549
+ $last = cerber_db_get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE stamp = ' . $max . ' AND activity IN (10,11)', MYSQL_FETCH_OBJECT );
3550
+ }
3551
+
3552
+ if ( ! $last ) { // workaround for the empty log table
3553
+ $last = new stdClass();
3554
+ $last->ip = CERBER_NO_REMOTE_IP;
3555
+ $last->user_login = 'test';
3556
+ }
3557
+
3558
+ if ( ! $active = cerber_blocked_num() ) {
3559
+ $active = 0;
3560
+ }
3561
+
3562
+ if ( $last->ip && ( $block = cerber_get_block( $last->ip ) ) ) {
3563
+ $reason = $block->reason;
3564
+ }
3565
+ else {
3566
+ $reason = __( 'unspecified', 'wp-cerber' );
3567
+ }
3568
+
3569
+ $subj .= __( 'Number of lockouts is increasing', 'wp-cerber' ) . ' (' . $active . ')';
3570
+
3571
+ $body = __( 'Number of active lockouts', 'wp-cerber' ) . ': ' . $active . "\n\n";
3572
+ $body .= sprintf( __( 'Last lockout was added: %s for IP %s', 'wp-cerber' ), $last_date, $last->ip . ' (' . @gethostbyaddr( $last->ip ) . ')' ) . "\n\n";
3573
+ $body .= __( 'Reason', 'wp-cerber' ) . ': ' . strip_tags($reason) . "\n\n";
3574
+ $body .= __( 'View activity for this IP', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . '&filter_ip=' . $last->ip . "\n\n";
3575
+ $body .= __( 'View lockouts in dashboard', 'wp-cerber' ) . ': ' . cerber_admin_link( 'lockouts' ) . "\n\n";
3576
+ break;
3577
+ case 'new_version':
3578
+ $subj = __( 'A new version of WP Cerber is available to install', 'wp-cerber' );
3579
+ $body = __( 'Hi!', 'wp-cerber' ) . "\n\n";
3580
+ $body .= __( 'A new version of WP Cerber is available to install', 'wp-cerber' ) . "\n\n";
3581
+ $body .= $msg . "\n\n";
3582
+ $body .= __( 'Website', 'wp-cerber' ) . ': ' . crb_get_bloginfo( 'name' );
3583
+ break;
3584
+ case 'shutdown':
3585
+ $subj = '[' . get_option( 'blogname' ) . '] ' . __( 'The WP Cerber security plugin has been deactivated', 'wp-cerber' );
3586
+ $body .= __( 'The WP Cerber security plugin has been deactivated', 'wp-cerber' ) . "\n\n";
3587
+ if ( ! is_user_logged_in() ) {
3588
+ $u = __( 'Not logged in', 'wp-cerber' );
3589
+ } else {
3590
+ $user = wp_get_current_user();
3591
+ $u = $user->display_name;
3592
+ }
3593
+ $body .= __( 'Website', 'wp-cerber' ) . ': ' . crb_get_bloginfo( 'name' ) . "\n";
3594
+ $body .= __( 'By user', 'wp-cerber' ) . ': ' . $u . "\n";
3595
+ $body .= __( 'From IP address', 'wp-cerber' ) . ': ' . $wp_cerber->getRemoteIp() . "\n";
3596
+ $whois = cerber_ip_whois_info( $wp_cerber->getRemoteIp() );
3597
+ if ( ! empty( $whois['data']['country'] ) ) {
3598
+ $body .= __( 'From country', 'wp-cerber' ) . ': ' . cerber_country_name( $whois['data']['country'] );
3599
+ }
3600
+ break;
3601
+ case 'activated':
3602
+ $subj = '[' . get_option( 'blogname' ) . '] ' . __( 'The WP Cerber security plugin is now active', 'wp-cerber' );
3603
+ $body .= __( 'WP Cerber is now active and has started protecting your site', 'wp-cerber' ) . "\n\n";
3604
+ //$body .= __( 'Change notification settings', 'wp-cerber' ) . ': ' . cerber_admin_link('notifications') . "\n\n";
3605
+ $body .= __( 'Getting Started Guide', 'wp-cerber' ) . "\n\n";
3606
+ $body .= 'https://wpcerber.com/getting-started/' . "\n\n";
3607
+ $body .= 'Be in touch with the developer. Subscribe to Cerber\'s newsletter: http://wpcerber.com/subscribe-newsletter/';
3608
+ break;
3609
+ case 'newlurl':
3610
+ $subj .= __( 'New Custom login URL', 'wp-cerber' );
3611
+ $body .= $msg;
3612
+ break;
3613
+ case 'subs':
3614
+ $subj .= __( 'A new activity has been recorded', 'wp-cerber' );
3615
+ $body = __( 'A new activity has been recorded', 'wp-cerber' ) . "\n\n";
3616
+ $body .= $msg;
3617
+ break;
3618
+ case 'report':
3619
+ $html_mode = true;
3620
+ $subj = '[' . get_option( 'blogname' ) . '] WP Cerber Security: ' . __( 'Weekly report', 'wp-cerber' );
3621
+ $body = cerber_generate_report();
3622
+ $link = cerber_admin_link( 'notifications' );
3623
+ $body .= '<br/>' . __( 'To change reporting settings visit', 'wp-cerber' ) . ' <a href="' . $link . '">' . $link . '</a>';
3624
+ if ($msg) {
3625
+ $body .= nl2br($msg);
3626
+ }
3627
+ break;
3628
+ case 'scan':
3629
+ $html_mode = true;
3630
+ $subj = '[' . get_option( 'blogname' ) . '] WP Cerber Security: ' . __( 'Scanner Report', 'wp-cerber' );
3631
+ $body = $msg;
3632
+ $link = cerber_admin_link( 'scan_schedule' );
3633
+ $body .= '<br/>' . __( 'To change reporting settings visit', 'wp-cerber' ) . ' <a href="' . $link . '">' . $link . '</a>';
3634
+ break;
3635
+ }
3636
+
3637
+ $to_list = cerber_get_email( $type, true );
3638
+ $to = implode( ', ', $to_list );
3639
+
3640
+ $body_filtered = apply_filters( 'cerber_notify_body', $body, array( 'type' => $type,
3641
+ 'IP' => $ip,
3642
+ 'to' => $to,
3643
+ 'subject' => $subj
3644
+ ) );
3645
+ if ( $body_filtered && is_string( $body_filtered ) ) {
3646
+ $body = $body_filtered;
3647
+ }
3648
+
3649
+ $footer = '';
3650
+
3651
+ if ( $lolink = cerber_get_login_url() ) {
3652
+ $lourl = urldecode( $lolink );
3653
+ if ( $html_mode ) {
3654
+ $lourl = '<a href="' . $lolink . '">' . $lourl . '</a>';
3655
+ }
3656
+ $footer .= "\n\n" . __( 'Your login page:', 'wp-cerber' ) . ' ' . $lourl;
3657
+ }
3658
+
3659
+ if ( $type == 'report' && $date = lab_lab(true) ) {
3660
+ $footer .= "\n\n" . __( 'Your license is valid until', 'wp-cerber' ) . ' ' . $date;
3661
+ }
3662
+
3663
+ $footer .= "\n\n\n" . __( 'This message was sent by', 'wp-cerber' ) . ' WP Cerber Security ' . CERBER_VER . "\n";
3664
+ $footer .= 'https://wpcerber.com';
3665
+
3666
+ if ( $html_mode ) {
3667
+ add_filter( 'wp_mail_content_type', 'cerber_enable_html' );
3668
+ $footer = str_replace( "\n", '<br/>', $footer );
3669
+ }
3670
+
3671
+ // Everything is prepared, let's send it out
3672
+
3673
+ $result = null;
3674
+ if ( $to && $subj && $body ) {
3675
+ if ( ! $html_mode ) {
3676
+ cerber_pb_send( $subj, $body.$footer );
3677
+ }
3678
+
3679
+ if ( $type == 'report') {
3680
+ $result = true;
3681
+ foreach ( $to_list as $email ) {
3682
+ $lastus = '';
3683
+ if ( $rec = cerber_get_last_login( null, $email ) ) {
3684
+ $lastus = sprintf( __( 'Your last sign-in was %s from %s', 'wp-cerber' ), cerber_date( $rec->stamp ), $rec->ip . ' (' . cerber_country_name( $rec->country ) . ')' );
3685
+ if ( $html_mode ) {
3686
+ $lastus = '<br/><br/>' . $lastus;
3687
+ }
3688
+ else {
3689
+ $lastus = "\n\n" . $lastus;
3690
+ }
3691
+ }
3692
+
3693
+ if ( ! wp_mail( $email, $subj, '<html>' . $body . $lastus . $footer . '</html>' ) ) {
3694
+ $result = false;
3695
+ }
3696
+ }
3697
+ }
3698
+ else {
3699
+ if ( function_exists( 'wp_mail' ) ) {
3700
+ $body = $body . $footer;
3701
+ if ( $html_mode ) {
3702
+ $body = '<html>' . $body . '</html>';
3703
+ }
3704
+ $result = wp_mail( $to, $subj, $body );
3705
+ }
3706
+ }
3707
+ }
3708
+
3709
+ remove_filter('wp_mail_content_type', 'cerber_enable_html');
3710
+
3711
+ $params = array( 'type' => $type, 'IP' => $ip, 'to' => $to, 'subject' => $subj );
3712
+ if ( $result ) {
3713
+ do_action( 'cerber_notify_sent', $body, $params );
3714
+ }
3715
+ else {
3716
+ do_action( 'cerber_notify_fail', $body, $params );
3717
+ }
3718
+
3719
+ return $result;
3720
+ }
3721
+
3722
+ function cerber_enable_html() {
3723
+ return 'text/html';
3724
+ }
3725
+
3726
+ /**
3727
+ * Generates a performance report
3728
+ *
3729
+ * @param int $period Days to look back
3730
+ *
3731
+ * @return string
3732
+ */
3733
+ function cerber_generate_report($period = 7){
3734
+ global $wpdb;
3735
+
3736
+ $period = absint( $period );
3737
+
3738
+ if ( ! $period ) {
3739
+ $period = 7;
3740
+ }
3741
+
3742
+ $ret = '';
3743
+ $rows = array();
3744
+ $stamp = time() - $period * 24 * 3600;
3745
+ //$in = implode( ',', crb_get_activity_set( 'malicious' ) );
3746
+ //$link_base = '<a href="' . cerber_activity_link( array( 2 ) ) . '">';
3747
+ $base_url = cerber_admin_link( 'activity' );
3748
+ $css_table = 'width: 95%; max-width: 1000px; margin:0 auto; margin-bottom: 10px; background-color: #f5f5f5; text-align: center; font-family: Arial, Helvetica, sans-serif;';
3749
+ $css_td = 'padding: 0.5em 0.5em 0.5em 1em; text-align: left;';
3750
+ $css_border = 'border-bottom: solid 2px #f9f9f9;';
3751
+
3752
+ $site_name = ( is_multisite() ) ? get_site_option( 'site_name' ) : get_option( 'blogname' );
3753
+
3754
+ $ret .= '<div style="' . $css_table . '"><div style="margin:0 auto; text-align: center;"><p style="font-size: 130%; padding-top: 0.5em;">' . $site_name .'</p><p style="padding-bottom: 1em;">'. __('Weekly Report','wp-cerber'). '</p></div></div>';
3755
+
3756
+ $kpi_list = cerber_calculate_kpi( $period );
3757
+
3758
+ foreach ($kpi_list as $kpi){
3759
+ $rows[] = '<td style="'.$css_td.' text-align: right;">'.$kpi[1].'</td><td style="padding: 0.5em; text-align: left;">'.$kpi[0].'</td>';
3760
+ }
3761
+
3762
+ $ret .= '<div style="text-align: center; '.$css_table.'"><table style="font-size: 130%; margin:0 auto;"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table></div>';
3763
+
3764
+ // Activities counters
3765
+ $rows = array();
3766
+ $rows[] = '<td style="'.$css_td.$css_border.'" colspan="2"><p style="line-height: 1.5em; font-weight: bold;">'.__('Activity details','wp-cerber').'</p></td>';
3767
+ $activites = $wpdb->get_results( 'SELECT activity, COUNT(activity) cnt FROM ' . CERBER_LOG_TABLE . ' WHERE stamp > ' . $stamp . ' GROUP by activity ORDER BY cnt DESC' );
3768
+ if ( $activites ) {
3769
+ $lables = cerber_get_labels();
3770
+ foreach ( $activites as $a ) {
3771
+ $rows[] = '<td style="'.$css_border.$css_td.'">' . $lables[ $a->activity ] . '</td><td style="padding: 0.5em; text-align: center; width:10%;'.$css_border.'"><a href="'.$base_url.'&filter_activity='.$a->activity.'">' . $a->cnt . '</a></td>';
3772
+ }
3773
+ }
3774
+ $ret .= '<table style="border-collapse: collapse; '.$css_table.'"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table>';
3775
+
3776
+ // Activities counters
3777
+ $activites = $wpdb->get_results( 'SELECT user_login, COUNT(user_login) cnt FROM ' . CERBER_LOG_TABLE . ' WHERE activity = 51 AND stamp > ' . $stamp . ' GROUP by user_login ORDER BY cnt DESC LIMIT 10' );
3778
+ if ( $activites ) {
3779
+ $rows = array();
3780
+ $rows[] = '<td style="'.$css_td.$css_border.'" colspan="2"><p style="line-height: 1.5em; font-weight: bold;">'.__('Attempts to log in with non-existent username','wp-cerber').'</p></td>';
3781
+ foreach ( $activites as $a ) {
3782
+ $rows[] = '<td style="'.$css_border.$css_td.'">' . htmlspecialchars($a->user_login) . '</td><td style="padding: 0.5em; text-align: center; width:10%;'.$css_border.'"><a href="'.$base_url.'&filter_login='.$a->user_login.'">' . $a->cnt . '</a></td>';
3783
+ }
3784
+ $ret .= '<table style="border-collapse: collapse; '.$css_table.'"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table>';
3785
+ }
3786
+
3787
+ $ret = '<div style="width:100%; padding: 1em; text-align: center; background-color: #f9f9f9;">' . $ret . '</div>';
3788
+
3789
+ return $ret;
3790
+ }
3791
+
3792
+
3793
+ // Maintenance routines ----------------------------------------------------------------
3794
+
3795
+ function cerber_init_cron(){
3796
+ $next_hour = intval( floor( ( time() + 3600 ) / 3600 ) * 3600 );
3797
+
3798
+ if ( ! wp_next_scheduled( 'cerber_hourly_1' ) ) {
3799
+ wp_schedule_event( $next_hour, 'hourly', 'cerber_hourly_1' );
3800
+ }
3801
+
3802
+ if ( ! wp_next_scheduled( 'cerber_hourly_2' ) ) {
3803
+ wp_schedule_event( $next_hour + 600 , 'hourly', 'cerber_hourly_2' );
3804
+ }
3805
+
3806
+ if ( ! wp_next_scheduled( 'cerber_daily' ) ) {
3807
+ wp_schedule_event( $next_hour + 1200, 'daily', 'cerber_daily' );
3808
+ }
3809
+ }
3810
+
3811
+ add_action( 'cerber_hourly_1', 'cerber_do_hourly' );
3812
+ function cerber_do_hourly( $force = false ) {
3813
+ global $wpdb, $wp_cerber;
3814
+
3815
+ $t = 'cerber_hourly_1';
3816
+ $start = time();
3817
+
3818
+ // Avoid multiple executions on a weird hosting
3819
+ if ( ( $last = get_site_transient( $t ) ) && date( 'G', $last[0] ) == date( 'G' ) ) {
3820
+ return;
3821
+ }
3822
+
3823
+ set_site_transient( $t, array( $start ), 2 * 3600 );
3824
+
3825
+ if ( is_multisite() ) {
3826
+ if ( ! $force && get_site_transient( 'cerber_multisite' ) ) {
3827
+ return;
3828
+ }
3829
+ set_site_transient( 'cerber_multisite', 'executed', 3600 );
3830
+ }
3831
+
3832
+ $time = time();
3833
+ $days = absint( crb_get_settings( 'keeplog' ) );
3834
+ if ( $days > 0 ) {
3835
+ $wpdb->query( 'DELETE FROM ' . CERBER_LOG_TABLE . ' WHERE stamp < ' . ( $time - $days * 24 * 3600 ) );
3836
+ }
3837
+ $days = absint( crb_get_settings( 'tikeeprec' ) );
3838
+ if ( $days > 0 ) {
3839
+ $wpdb->query( 'DELETE FROM ' . CERBER_TRAF_TABLE . ' WHERE stamp < ' . ( $time - $days * 24 * 3600 ) );
3840
+ }
3841
+
3842
+ $wpdb->query( 'DELETE FROM ' . CERBER_LAB_IP_TABLE . ' WHERE expires < ' . $time );
3843
+
3844
+ if ( $wp_cerber->getSettings( 'trashafter-enabled') && absint($wp_cerber->getSettings('trashafter'))) {
3845
+ $list = get_comments( array( 'status' => 'spam' ) );
3846
+ if ( $list ) {
3847
+ $time = time() - DAY_IN_SECONDS * absint($wp_cerber->getSettings( 'trashafter' ));
3848
+ foreach ( $list as $item ) {
3849
+ if ( $time > strtotime( $item->comment_date_gmt ) ) {
3850
+ wp_trash_comment( $item->comment_ID );
3851
+ }
3852
+ }
3853
+ }
3854
+ }
3855
+
3856
+ cerber_up_data();
3857
+
3858
+ // Keep the size of the log file small
3859
+ cerber_truncate_log();
3860
+
3861
+ set_site_transient( $t, array( $start, time() ), 2 * 3600 );
3862
+ }
3863
+
3864
+ add_action( 'cerber_hourly_2', function () {
3865
+ $t = 'cerber_hourly_2';
3866
+ $start = time();
3867
+ if ( ( $last = get_site_transient( $t ) ) && date( 'G', $last[0] ) == date( 'G' ) ) {
3868
+ return;
3869
+ }
3870
+ set_site_transient( $t, array( $start ), 2 * 3600 );
3871
+
3872
+ $gmt_offset = get_option( 'gmt_offset' ) * 3600;
3873
+
3874
+ if ( crb_get_settings( 'enable-report' )
3875
+ && date( 'w', time() + $gmt_offset ) == crb_get_settings( 'wreports-day' )
3876
+ && date( 'G', time() + $gmt_offset ) == crb_get_settings( 'wreports-time' )
3877
+ //&& ! get_site_transient( 'cerber_wreport' )
3878
+ ) {
3879
+ $result = cerber_send_email( 'report' );
3880
+ //set_site_transient( 'cerber_wreport', 'sent', 7200 );
3881
+ update_site_option( '_cerber_report', array( time(), $result ) );
3882
+ }
3883
+
3884
+ cerber_watchdog( true );
3885
+
3886
+ cerber_delete_expired_set();
3887
+
3888
+ // Cleanup the quarantine folder
3889
+ if ( $dirs = glob( cerber_get_the_folder() . 'quarantine' . '/*', GLOB_ONLYDIR ) ) {
3890
+ foreach ( $dirs as $dir ) {
3891
+ $d = basename( $dir );
3892
+ if ( is_numeric( $d ) ) {
3893
+ if ( $d < ( time() - DAY_IN_SECONDS * crb_get_settings( 'scan_qcleanup' ) ) ) {
3894
+ $fs = cerber_init_wp_filesystem();
3895
+ if ( ! is_wp_error( $fs ) ) {
3896
+ $fs->delete( $dir, true );
3897
+ }
3898
+ }
3899
+ }
3900
+ }
3901
+ }
3902
+
3903
+ if ( crb_get_settings( 'cerberlab' ) || lab_lab() ) {
3904
+ lab_check_nodes( true, true );
3905
+ }
3906
+
3907
+ cerber_push_lab();
3908
+
3909
+ cerber_cloud_sync();
3910
+
3911
+ // Simply keep folder locked
3912
+ cerber_get_the_folder();
3913
+
3914
+ cerber_db_query( 'DELETE FROM ' . CERBER_QMEM_TABLE . ' WHERE stamp < ' . ( time() - 30 * 60 ) );
3915
+
3916
+ set_site_transient( $t, array( $start, time() ), 2 * 3600 );
3917
+ });
3918
+
3919
+ add_action( 'cerber_daily', 'cerber_do_daily' );
3920
+ function cerber_do_daily() {
3921
+ $t = 'cerber_daily_1';
3922
+ $start = time();
3923
+ if ( ( $last = get_site_transient( $t ) ) && date( 'j', $last[0] ) == date( 'j' ) ) {
3924
+ return;
3925
+ }
3926
+ set_site_transient( $t, array( $start ), 48 * 3600 );
3927
+
3928
+ cerber_do_hourly( true );
3929
+
3930
+ $time = time();
3931
+
3932
+ lab_validate_lic();
3933
+
3934
+ cerber_db_query( 'DELETE FROM ' . CERBER_LAB_NET_TABLE . ' WHERE expires < ' . $time );
3935
+ cerber_db_query( 'DELETE FROM ' . CERBER_LAB_TABLE . ' WHERE stamp < ' . ( $time - 3600 ) ); // workaround for weird/misconfigured hostings
3936
+
3937
+ cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_LOG_TABLE );
3938
+ cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_QMEM_TABLE );
3939
+ cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_TRAF_TABLE );
3940
+ cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_ACL_TABLE );
3941
+ cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_BLOCKS_TABLE );
3942
+ cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_LAB_TABLE );
3943
+ cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_LAB_IP_TABLE );
3944
+ cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_LAB_NET_TABLE );
3945
+ cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_SCAN_TABLE );
3946
+ cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_SETS_TABLE );
3947
+
3948
+ if ( $new = cerber_check_version() ) {
3949
+ $history = get_site_option( '_cerber_notify_new' );
3950
+ if ( ! $history || ! is_array( $history ) ) {
3951
+ $history = array();
3952
+ }
3953
+ if ( ! in_array( $new['ver'], $history ) ) {
3954
+ if ( crb_get_settings( 'notify-new-ver' ) ) {
3955
+ cerber_send_email( 'new_version', 'Read more: https://wpcerber.com/?plugin_version=' . $new['ver'] );
3956
+ }
3957
+ $history[] = $new['ver'];
3958
+ update_site_option( '_cerber_notify_new', $history );
3959
+ }
3960
+ }
3961
+
3962
+ // TODO: implement holding previous values for a while
3963
+ // cerber_antibot_gene();
3964
+
3965
+ set_site_transient( $t, array( $start, time() ), 48 * 3600 );
3966
+ }
3967
+
3968
+ /**
3969
+ * Log activity
3970
+ *
3971
+ * @param int $activity Activity ID
3972
+ * @param string $login Login used or any additional information
3973
+ * @param int $user_id User ID
3974
+ * @param null $ip IP Address
3975
+ *
3976
+ * @return false|int
3977
+ * @since 3.0
3978
+ */
3979
+ function cerber_log( $activity, $login = '', $user_id = 0, $ip = null ) {
3980
+ global $user_ID, $cerber_logged, $cerber_blocked;
3981
+ static $logged = array();
3982
+
3983
+ $wp_cerber = get_wp_cerber();
3984
+
3985
+ $activity = absint( $activity );
3986
+
3987
+ if ( isset( $logged[ $activity ] ) ) {
3988
+ return false;
3989
+ }
3990
+ else {
3991
+ $logged[ $activity ] = true;
3992
+ }
3993
+
3994
+ $cerber_logged[ $activity ] = $activity;
3995
+
3996
+ //$wp_cerber->setProcessed();
3997
+
3998
+ if ( empty( $ip ) ) {
3999
+ $ip = $wp_cerber->getRemoteIp();
4000
+ }
4001
+ elseif ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
4002
+ return false;
4003
+ }
4004
+
4005
+ if ( cerber_is_ipv4( $ip ) ) {
4006
+ $ip_long = ip2long( $ip );
4007
+ }
4008
+ else {
4009
+ $ip_long = 1;
4010
+ }
4011
+
4012
+ if ( empty( $user_id ) ) {
4013
+ $user_id = ( $user_ID ) ? $user_ID : 0;
4014
+ }
4015
+
4016
+ $user_id = absint( $user_id );
4017
+
4018
+ $stamp = microtime( true );
4019
+
4020
+ $pos = strpos($_SERVER['REQUEST_URI'],'?');
4021
+ if ($pos) {
4022
+ $path = substr( $_SERVER['REQUEST_URI'], 0, $pos );
4023
+ }
4024
+ else {
4025
+ $path = $_SERVER['REQUEST_URI'];
4026
+ }
4027
+ $url = strip_tags($_SERVER['HTTP_HOST'] . $path);
4028
+
4029
+ $status = 0;
4030
+ if ( $activity != 10 && $activity != 11 ) {
4031
+ $status = cerber_get_status( $ip );
4032
+ }
4033
+ elseif ( $cerber_blocked ) {
4034
+ $status = $cerber_blocked;
4035
+ }
4036
+
4037
+ $details = $status .'|0|0|0|'. $url;
4038
+
4039
+ $country = lab_get_country( $ip );
4040
+
4041
+ $login = cerber_real_escape( $login );
4042
+ $details = cerber_real_escape( $details );
4043
+ $ret = cerber_db_query( 'INSERT INTO ' . CERBER_LOG_TABLE . ' (ip, ip_long, user_login, user_id, stamp, activity, session_id, country, details)
4044
+ VALUES ("' . $ip . '",' . $ip_long . ',"' . $login . '",' . $user_id . ',"' . $stamp . '",' . $activity . ',"' . $wp_cerber->getSessionID() . '","' . $country . '","' . $details . '")' );
4045
+
4046
+ if ( ! $ret ) {
4047
+ cerber_watchdog();
4048
+ }
4049
+
4050
+ // Subscriptions - notifications for admin ---------------------------------------------------
4051
+
4052
+ $subs = cerber_get_site_option( '_cerber_subs' );
4053
+
4054
+ if (!empty($subs)) {
4055
+ foreach ( $subs as $hash => $sub ) {
4056
+
4057
+ // Loop through subscription parameters
4058
+ if ( ! empty( $sub[0] )) {
4059
+ if ( ! in_array( $activity, $sub[0] ) ) {
4060
+ continue;
4061
+ }
4062
+ }
4063
+ if ( ! empty( $sub[1] ) && $sub[1] != $user_id ) {
4064
+ continue;
4065
+ }
4066
+ if ( ! empty( $sub[3] ) && ( $ip_long < $sub[2] || $sub[3] < $ip_long ) ) {
4067
+ continue;
4068
+ }
4069
+ if ( ! empty( $sub[4] ) && $sub[4] != $ip ) {
4070
+ continue;
4071
+ }
4072
+ if ( ! empty( $sub[5] ) && $sub[5] != $login ) {
4073
+ continue;
4074
+ }
4075
+ if ( ! empty( $sub[6] ) ) {
4076
+ $none = true;
4077
+ if ( false !== strpos( $ip, $sub[6] ) ) {
4078
+ $none = false;
4079
+ }
4080
+ elseif ( false !== mb_stripos( $login, $sub[6] ) ) {
4081
+ $none = false;
4082
+ }
4083
+ elseif ( $user_id ) {
4084
+ if ( ! $user = wp_get_current_user() ) {
4085
+ $user = get_userdata( $user_id );
4086
+ }
4087
+ if ( false !== mb_stripos( $user->user_firstname, $sub[6] )
4088
+ || false !== mb_stripos( $user->user_lastname, $sub[6] )
4089
+ || false !== mb_stripos( $user->nickname, $sub[6] )) {
4090
+ $none = false;
4091
+ }
4092
+ }
4093
+ /*elseif ( $user_id && in_array( $user_id, $sub[8] ) ) {
4094
+ $none = false;
4095
+ }*/
4096
+ if ( $none ) {
4097
+ continue;
4098
+ }
4099
+ }
4100
+
4101
+ // Some parameter(s) matched, prepare and send notification
4102
+
4103
+ $labels = cerber_get_labels( 'activity' );
4104
+
4105
+ $msg = __( 'Activity', 'wp-cerber' ) . ': ' . $labels[$activity] . "\n\n";
4106
+
4107
+ if ( $country ) {
4108
+ $coname = ' ('.cerber_country_name( $country ).')';
4109
+ }
4110
+ else {
4111
+ $coname = '';
4112
+ }
4113
+
4114
+ $msg .= __( 'IP', 'wp-cerber' ) . ': ' . $ip . $coname. "\n\n";
4115
+
4116
+ if ( $user_id && function_exists('get_userdata')) {
4117
+ $u = get_userdata( $user_id );
4118
+ $msg .= __( 'User', 'wp-cerber' ) . ': ' . $u->display_name . "\n\n";
4119
+ }
4120
+
4121
+ if ( $login ) {
4122
+ $msg .= __( 'Username used', 'wp-cerber' ) . ': ' . $login . "\n\n";
4123
+ }
4124
+
4125
+ if ( ! empty( $sub['6'] ) ) {
4126
+ $msg .= __( 'Search string', 'wp-cerber' ) . ': ' . $sub['6'] . "\n\n";
4127
+ }
4128
+
4129
+ // Link to the Activity admin page
4130
+ $args = cerber_subscribe_params();
4131
+ $i = 0;
4132
+ $link_params = '';
4133
+ foreach ($args as $arg => $val){
4134
+ if (is_array($sub[$i])){
4135
+ foreach ( $sub[ $i ] as $item ) {
4136
+ $link_params .= '&' . $arg . '[]=' . $item;
4137
+ }
4138
+ }
4139
+ else {
4140
+ $link_params .= '&' . $arg . '=' . $sub[ $i ];
4141
+ }
4142
+ $i++;
4143
+ }
4144
+ $link = cerber_admin_link( 'activity' ) . $link_params;
4145
+
4146
+ $msg .= __( 'View activity in dashboard', 'wp-cerber' ) . ': ' . $link;
4147
+ $msg .= "\n\n" . __( 'To unsubscribe click here', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . '&unsubscribeme=' . $hash;
4148
+
4149
+ cerber_send_email( 'subs', $msg, $ip );
4150
+
4151
+ break; // Just one notification letter per event
4152
+ }
4153
+ }
4154
+
4155
+ if ( in_array( $activity, array( 16, 17, 40, 56, 100 ) ) ) {
4156
+ lab_save_push( $ip, $activity, '' );
4157
+ }
4158
+
4159
+ return $ret;
4160
+ }
4161
+
4162
+ /**
4163
+ * Get records from the log
4164
+ *
4165
+ * @param array $activity
4166
+ * @param array $user
4167
+ * @param array $order
4168
+ * @param string $limit
4169
+ *
4170
+ * @return array|null
4171
+ */
4172
+ function cerber_get_log($activity = array(), $user = array(), $order = array(), $limit = ''){
4173
+ global $wpdb;
4174
+
4175
+ $where = array();
4176
+ if ( $activity ) {
4177
+ $activity = array_map( 'absint', $activity );
4178
+ $where[] = 'activity IN (' . implode( ', ', $activity ) . ')';
4179
+ }
4180
+
4181
+ if ( ! empty( $user['email'] ) ) {
4182
+ $user = get_user_by( 'email', $user['email'] );
4183
+ $where[] = 'user_id = ' . absint( $user->ID );
4184
+ }
4185
+ elseif ( ! empty( $user['id'] ) ) {
4186
+ $where[] = 'user_id = ' . absint( $user['id'] );
4187
+ }
4188
+
4189
+ $where_sql = '';
4190
+ if ( $where ) {
4191
+ $where_sql = ' WHERE ' . implode( ' AND ', $where );
4192
+ }
4193
+
4194
+ $order_sql = '';
4195
+ if ( $order ) {
4196
+ if ( ! empty( $order['DESC'] ) ) {
4197
+ $order_sql = ' ORDER BY ' . preg_replace( '/[^\w]/', '', $order['DESC'] ) . ' DESC ';
4198
+ }
4199
+ elseif ( ! empty( $order['ASC'] ) ) {
4200
+ $order_sql = ' ORDER BY ' . preg_replace( '/[^\w]/', '', $order['ASC'] ) . ' ASC ';
4201
+ }
4202
+ }
4203
+
4204
+ $limit_sql = '';
4205
+ if ( $limit ) {
4206
+ $limit_sql = ' LIMIT ' . preg_replace( '/[^0-9\.]/', '', $limit );
4207
+ }
4208
+
4209
+ // $row = $wpdb->get_row('SELECT * FROM '.CERBER_LOG_TABLE.' WHERE activity = 5 AND user_id = '.absint($user_id) . ' ORDER BY stamp DESC LIMIT 1');
4210
+ return $wpdb->get_results( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' ' . $where_sql . $order_sql . $limit_sql );
4211
+
4212
+ }
4213
+
4214
+ /**
4215
+ * Return the last login record for a given user
4216
+ *
4217
+ * @param $user_id int|null
4218
+ * @param $user_email string
4219
+ *
4220
+ * @return array|null|object|string
4221
+ */
4222
+ function cerber_get_last_login( $user_id, $user_email = '' ) {
4223
+ if ( $user_id ) {
4224
+ $u = array( 'id' => $user_id );
4225
+ }
4226
+ elseif ( $user_email ) {
4227
+ $u = array( 'email' => $user_email );
4228
+ }
4229
+
4230
+ if ( ! $u ) {
4231
+ return false;
4232
+ }
4233
+
4234
+ if ( $recs = cerber_get_log( array( 5 ), $u, array( 'DESC' => 'stamp' ), 1 ) ) {
4235
+ return $recs[0];
4236
+ }
4237
+
4238
+ return false;
4239
+ }
4240
+
4241
+ function cerber_count_log($activity = array(), $period = 1) {
4242
+
4243
+ $period = absint( $period );
4244
+ if ( ! $period ) {
4245
+ $period = 1;
4246
+ }
4247
+
4248
+ $stamp = time() - $period * 24 * 3600;
4249
+
4250
+ // TODO: replace with SELECT COUNT(DISTINCT session_id)
4251
+ $ret = cerber_db_get_var('SELECT COUNT(ip) FROM '. CERBER_LOG_TABLE .' WHERE activity IN ('.implode(',',$activity).') AND stamp > '. $stamp);
4252
+ if (!$ret) $ret = 0;
4253
+
4254
+ return $ret;
4255
+ }
4256
+
4257
+ /**
4258
+ * Create a set of parameters for using it in Subscriptions
4259
+ * The keys are used to built an URL. Values to calculate a hash.
4260
+ *
4261
+ * @return array The set of parameters
4262
+ */
4263
+ function cerber_subscribe_params() {
4264
+ // Mandatory parameters in a particular order.
4265
+ $params = array( 'filter_activity' => 0, 'filter_user' => 0, 'begin' => 0, 'end' => 0, 'filter_ip' => 0, 'filter_login' => 0, 'search_activity' => 0, 'filter_role' => 0, 'user_ids' => 0 );
4266
+
4267
+ $begin = 0;
4268
+ $end = 0;
4269
+ $ip = 0;
4270
+ if ( ! empty( $_GET['filter_ip'] ) ) {
4271
+ $ip = cerber_any2range( $_GET['filter_ip'] );
4272
+ if ( is_array( $ip ) ) {
4273
+ $begin = $ip['begin'];
4274
+ $end = $ip['end'];
4275
+ $ip = 0;
4276
+ } elseif ( ! $ip ) {
4277
+ $ip = 0;
4278
+ }
4279
+ }
4280
+ $params['begin'] = $begin;
4281
+ $params['end'] = $end;
4282
+ $params['filter_ip'] = $ip;
4283
+
4284
+ $get_list = array( 'filter_activity', 'filter_user', 'filter_login', 'search_activity', 'filter_role', 'filter_set' );
4285
+ foreach ( $get_list as $item ) {
4286
+ if ( ! empty( $_GET[ $item ] ) ) {
4287
+ if ( is_array( $_GET[ $item ] ) ) {
4288
+ $params[ $item ] = array_map( 'trim', $_GET[ $item ] );
4289
+ }
4290
+ else {
4291
+ $params[ $item ] = trim( $_GET[ $item ] );
4292
+ }
4293
+ }
4294
+ else {
4295
+ $params[ $item ] = 0;
4296
+ }
4297
+ //$params[ $item ] = ( empty( $_GET[ $item ] ) ) ? 0 : trim( $_GET[ $item ] );
4298
+ }
4299
+
4300
+ if ( ! is_array( $params['filter_activity'] ) ) {
4301
+ $params['filter_activity'] = array( $params['filter_activity'] );
4302
+ }
4303
+ $params['filter_activity'] = array_filter( $params['filter_activity'] );
4304
+
4305
+ // 'begin' and 'end' array keys are not used, added for compatibility
4306
+ //return array( 'filter_activity' => $filter_activity, 'filter_user' => $filter_user, 'begin' => $begin, 'end' => $end, 'filter_ip' => $ip, 'filter_login' => $filter_login, 'search_activity' => $search_activity, 'filter_role' => $filter_role );
4307
+ return $params;
4308
+ }
4309
+
4310
+ /**
4311
+ * Loads must have settings
4312
+ * @since 7.8.3
4313
+ *
4314
+ */
4315
+ function cerber_pre_checks() {
4316
+ // Load must have settings before the rest of the stuff during the plugin activation
4317
+
4318
+ // The only way to get it done earlier
4319
+ if ( cerber_get_get( 'action' ) === 'activate'
4320
+ && cerber_get_get( 'plugin' ) === 'wp-cerber/wp-cerber.php' ) {
4321
+ // The plugin is activated in wp-admin
4322
+ if ( ! crb_get_settings() ) {
4323
+ define('CRB_JUST_MARRIED', 1);
4324
+ cerber_load_defaults();
4325
+ }
4326
+ }
4327
+
4328
+ // A backup way
4329
+ add_action( 'activated_plugin', function ( $plugin ) {
4330
+ if ( $plugin !== 'wp-cerber/wp-cerber.php' ) {
4331
+ return;
4332
+ }
4333
+ if ( ! crb_get_settings() ) {
4334
+ if ( ! defined( 'CRB_JUST_MARRIED' ) ) {
4335
+ define( 'CRB_JUST_MARRIED', 1 );
4336
+ }
4337
+ cerber_load_defaults();
4338
+ }
4339
+ } );
4340
+ }
4341
+
4342
+ /**
4343
+ * Post plugin activation stuff
4344
+ *
4345
+ */
4346
+ register_activation_hook( cerber_plugin_file(), function () {
4347
+
4348
+ $assets_url = cerber_plugin_dir_url() . 'assets';
4349
+
4350
+ load_plugin_textdomain( 'wp-cerber', false, basename( dirname( __FILE__ ) ) . '/languages' );
4351
+
4352
+ if ( version_compare( CERBER_REQ_PHP, phpversion(), '>' ) ) {
4353
+ cerber_stop_activating( '<h3>' . sprintf( __( 'The WP Cerber requires PHP %s or higher. You are running', 'wp-cerber' ), CERBER_REQ_PHP ) . ' ' . phpversion() . '</h3>' );
4354
+ }
4355
+
4356
+ if ( version_compare( CERBER_REQ_WP, cerber_get_wp_version(), '>' ) ) {
4357
+ cerber_stop_activating( '<h3>' . sprintf( __( 'The WP Cerber requires WordPress %s or higher. You are running', 'wp-cerber' ), CERBER_REQ_WP ) . ' ' . cerber_get_wp_version() . '</h3>' );
4358
+ }
4359
+
4360
+ $db_errors = cerber_create_db();
4361
+ if ( $db_errors ) {
4362
+ $e = '';
4363
+ foreach ( $db_errors as $db_error ) {
4364
+ $e .= '<p>' . implode( '</p><p>', $db_error ) . '</p>';
4365
+ }
4366
+ cerber_stop_activating( '<h3>' . __( "Can't activate WP Cerber due to a database error.", 'wp-cerber' ) . '</h3>'.$e);
4367
+ }
4368
+
4369
+ lab_get_key( true );
4370
+
4371
+ cerber_upgrade_all();
4372
+
4373
+ cerber_cookie_one();
4374
+ cerber_disable_citadel();
4375
+
4376
+ $wp_cerber = get_wp_cerber();
4377
+
4378
+ cerber_add_white( cerber_get_subnet( $wp_cerber->getRemoteIp() ) , 'My subnet' ); // Protection for non-experienced user
4379
+
4380
+ cerber_htaccess_sync( 'main' );
4381
+ cerber_htaccess_sync( 'media' );
4382
+
4383
+ cerber_set_boot_mode();
4384
+
4385
+ cerber_admin_message(
4386
+ '<img style="float:left; margin-left:-10px;" src="' . $assets_url . '/icon-128x128.png">' .
4387
+ '<p style="font-size:120%;">' . __( 'WP Cerber is now active and has started protecting your site', 'wp-cerber' ) . '</p>' .
4388
+ ' <p>' . __( 'Your IP address is added to the', 'wp-cerber' ) . ' ' . __( 'White IP Access List', 'wp-cerber' ) .
4389
+
4390
+ ' <p style="font-size:130%;"><a href="http://wpcerber.com/getting-started/" target="_blank">' . __( 'Getting Started Guide', 'wp-cerber' ) . '</a></p>' .
4391
+
4392
+ //' <p><b>' . __( "It's important to check security settings.", 'wp-cerber' ) . '</b> &nbsp;<a href="http://wpcerber.com/" target="_blank">Read Cerber\'s blog</a> ' .
4393
+ //'&nbsp; <a href="http://wpcerber.com/subscribe-newsletter/" target="_blank">Subscribe to Cerber\'s newsletter</a></p>' .
4394
+
4395
+ ' <p>
4396
+ </p>
4397
+ <p id="crb-activation-msg">
4398
+ <i class="crb-icon crb-icon-bx-slider"></i> <a href="' . cerber_admin_link( 'main' ) . '">' . __( 'Main Settings', 'wp-cerber' ) . '</a>' .
4399
+ ' <i class="crb-icon crb-icon-bx-radar"></i> <a href="' . cerber_admin_link( 'scanner' ) . '">' . __( 'Security Scanner', 'wp-cerber' ) . '</a>' .
4400
+ ' <i class="crb-icon crb-icon-bx-lock"></i> <a href="' . cerber_admin_link( 'acl' ) . '">' . __( 'Access Lists', 'wp-cerber' ) . '</a>' .
4401
+ ' <i class="crb-icon crb-icon-bxs-shield"></i> <a href="' . cerber_admin_link( 'antispam' ) . '">' . __( 'Antispam', 'wp-cerber' ) . '</a>' .
4402
+ ' <i class="crb-icon crb-icon-bx-shield-alt"></i> <a href="' . cerber_admin_link( 'hardening' ) . '">' . __( 'Hardening', 'wp-cerber' ) . '</a>' .
4403
+ ' <i class="crb-icon crb-icon-bx-bell"></i> <a href="' . cerber_admin_link( 'notifications' ) . '">' . __( 'Notifications', 'wp-cerber' ) . '</a>' .
4404
+ ' <i class="crb-icon crb-icon-bx-layer"></i> <a href="' . cerber_admin_link( 'imex' ) . '">' . __( 'Import settings', 'wp-cerber' ) . '</a>' .
4405
+ '</p>' );
4406
+
4407
+
4408
+ if ( ! defined( 'CRB_JUST_MARRIED' ) || ! CRB_JUST_MARRIED ) {
4409
+ return;
4410
+ }
4411
+
4412
+ cerber_send_email( 'activated' );
4413
+
4414
+ $p = get_file_data( cerber_plugin_file(), array( 'Version' => 'Version' ), 'plugin' );
4415
+ $p['time'] = time();
4416
+ $p['user'] = get_current_user_id();
4417
+ cerber_update_set( '_activated', $p );
4418
+
4419
+ });
4420
+
4421
+ /*
4422
+ Abort activating plugin!
4423
+ */
4424
+ function cerber_stop_activating( $msg ) {
4425
+ //deactivate_plugins( plugin_basename( __FILE__ ) );
4426
+ deactivate_plugins( cerber_plug_in() );
4427
+ wp_die( $msg );
4428
+ }
4429
+
4430
+ /**
4431
+ * Upgrade database tables, data and plugin settings
4432
+ *
4433
+ * @since 3.0
4434
+ *
4435
+ */
4436
+ function cerber_upgrade_all() {
4437
+ global $cerber_doing_upgrade;
4438
+ $ver = cerber_get_site_option( '_cerber_up' );
4439
+ if ( ! $ver || $ver['v'] != CERBER_VER ) {
4440
+ $d = @ini_get( 'display_errors');
4441
+ @ini_set( 'display_errors', 0 );
4442
+ $cerber_doing_upgrade = true;
4443
+ define( 'CRB_DOING_UPGRADE', 1 );
4444
+ crb_clear_admin_msg();
4445
+ cerber_create_db();
4446
+ cerber_upgrade_db();
4447
+ cerber_acl_fixer( true );
4448
+ cerber_antibot_gene( true );
4449
+ cerber_upgrade_settings();
4450
+ wp_clear_scheduled_hook( 'cerber_hourly' ); // @since 5.8
4451
+ update_site_option( '_cerber_up', array( 'v' => CERBER_VER, 't' => time() ) );
4452
+ cerber_push_the_news( CERBER_VER );
4453
+ cerber_delete_expired_set( true );
4454
+ lab_get_key( true );
4455
+ $cerber_doing_upgrade = false;
4456
+ @ini_set( 'display_errors', $d );
4457
+ }
4458
+ }
4459
+
4460
+ /**
4461
+ * Creates DB tables if they don't exist
4462
+ *
4463
+ * @param bool $recreate If true, recreate some tables completely (with data lost)
4464
+ *
4465
+ * @return array Errors
4466
+ */
4467
+ function cerber_create_db($recreate = true) {
4468
+ global $wpdb;
4469
+
4470
+ $wpdb->hide_errors();
4471
+ $db_errors = array();
4472
+ $sql = array();
4473
+
4474
+ if (!cerber_is_table(CERBER_LOG_TABLE)){
4475
+ $sql[] = "
4476
+ CREATE TABLE IF NOT EXISTS " . CERBER_LOG_TABLE . " (
4477
+ ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
4478
+ user_login varchar(60) NOT NULL COMMENT 'Username from HTTP request',
4479
+ user_id bigint(20) unsigned NOT NULL DEFAULT '0',
4480
+ stamp bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
4481
+ activity int(10) unsigned NOT NULL DEFAULT '0',
4482
+ KEY ip (ip)
4483
+ ) DEFAULT CHARSET=utf8 COMMENT='Cerber activity log';
4484
+ ";
4485
+ }
4486
+
4487
+ if (!cerber_is_table(CERBER_ACL_TABLE)){
4488
+ $sql[] = "
4489
+ CREATE TABLE IF NOT EXISTS " . CERBER_ACL_TABLE . " (
4490
+ ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'IP',
4491
+ tag char(1) NOT NULL COMMENT 'Type: B or W',
4492
+ comments varchar(250) NOT NULL,
4493
+ UNIQUE KEY ip (ip)
4494
+ ) DEFAULT CHARSET=utf8 COMMENT='Cerber IP Access Lists';
4495
+ ";
4496
+ }
4497
+
4498
+ if (!cerber_is_table(CERBER_BLOCKS_TABLE)){
4499
+ $sql[] = "
4500
+ CREATE TABLE IF NOT EXISTS " . CERBER_BLOCKS_TABLE . " (
4501
+ ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
4502
+ block_until bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
4503
+ reason varchar(250) NOT NULL COMMENT 'Why IP was blocked',
4504
+ reason_id int(11) unsigned NOT NULL DEFAULT '0',
4505
+ UNIQUE KEY ip (ip)
4506
+ ) DEFAULT CHARSET=utf8 COMMENT='Cerber list of currently blocked IPs';
4507
+ ";
4508
+ }
4509
+
4510
+ if (!cerber_is_table(CERBER_LAB_TABLE)){
4511
+ $sql[] = "
4512
+ CREATE TABLE IF NOT EXISTS " . CERBER_LAB_TABLE . " (
4513
+ ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
4514
+ reason_id int(11) unsigned NOT NULL DEFAULT '0',
4515
+ stamp bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
4516
+ details text NOT NULL
4517
+ ) DEFAULT CHARSET=utf8 COMMENT='Cerber lab cache';
4518
+ ";
4519
+ }
4520
+
4521
+
4522
+ if ($recreate || !cerber_is_table(CERBER_LAB_IP_TABLE)){
4523
+ if ( $recreate && cerber_is_table( CERBER_LAB_IP_TABLE ) ) {
4524
+ $sql[] = 'DROP TABLE IF EXISTS ' . CERBER_LAB_IP_TABLE;
4525
+ }
4526
+ $sql[] = "
4527
+ CREATE TABLE IF NOT EXISTS " . CERBER_LAB_IP_TABLE . " (
4528
+ ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'IP',
4529
+ reputation INT(11) UNSIGNED NOT NULL COMMENT 'Reputation of IP',
4530
+ expires INT(11) UNSIGNED NOT NULL COMMENT 'Unix timestamp',
4531
+ PRIMARY KEY (ip)
4532
+ ) DEFAULT CHARSET=utf8 COMMENT='Cerber lab IP cache';
4533
+ ";
4534
+ }
4535
+
4536
+ if ( $recreate || ! cerber_is_table( CERBER_LAB_NET_TABLE ) ) {
4537
+ if ( $recreate && cerber_is_table( CERBER_LAB_NET_TABLE ) ) {
4538
+ $sql[] = 'DROP TABLE IF EXISTS ' . CERBER_LAB_NET_TABLE;
4539
+ }
4540
+ $sql[] = '
4541
+ CREATE TABLE IF NOT EXISTS ' . CERBER_LAB_NET_TABLE . ' (
4542
+ ip varchar(39) CHARACTER SET ascii NOT NULL DEFAULT "" COMMENT "IP address",
4543
+ ip_long_begin BIGINT UNSIGNED NOT NULL DEFAULT "0",
4544
+ ip_long_end BIGINT UNSIGNED NOT NULL DEFAULT "0",
4545
+ country CHAR(3) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Country code",
4546
+ expires INT(11) UNSIGNED NOT NULL DEFAULT "0",
4547
+ PRIMARY KEY (ip),
4548
+ UNIQUE KEY begin_end (ip_long_begin, ip_long_end)
4549
+ ) DEFAULT CHARSET=utf8 COMMENT="Cerber lab network cache";
4550
+ ';
4551
+ }
4552
+
4553
+ if (!cerber_is_table(CERBER_GEO_TABLE)){
4554
+ $sql[] = '
4555
+ CREATE TABLE IF NOT EXISTS ' . CERBER_GEO_TABLE . ' (
4556
+ country CHAR(3) NOT NULL DEFAULT "" COMMENT "Country code",
4557
+ locale CHAR(10) NOT NULL DEFAULT "" COMMENT "Locale i18n",
4558
+ country_name VARCHAR(250) NOT NULL DEFAULT "" COMMENT "Country name",
4559
+ PRIMARY KEY (country, locale)
4560
+ ) DEFAULT CHARSET=utf8;
4561
+ ';
4562
+ }
4563
+
4564
+ if (!cerber_is_table(CERBER_TRAF_TABLE)){
4565
+ $sql[] = '
4566
+ CREATE TABLE IF NOT EXISTS ' . CERBER_TRAF_TABLE . ' (
4567
+ ip varchar(39) CHARACTER SET ascii NOT NULL,
4568
+ ip_long BIGINT UNSIGNED NOT NULL DEFAULT "0",
4569
+ hostname varchar(250) NOT NULL DEFAULT "",
4570
+ uri text NOT NULL,
4571
+ request_fields MEDIUMTEXT NOT NULL,
4572
+ request_details MEDIUMTEXT NOT NULL,
4573
+ session_id char(32) CHARACTER SET ascii NOT NULL,
4574
+ user_id bigint(20) UNSIGNED NOT NULL DEFAULT 0,
4575
+ stamp decimal(14,4) NOT NULL,
4576
+ processing int(10) NOT NULL DEFAULT 0,
4577
+ country char(3) CHARACTER SET ascii NOT NULL DEFAULT "",
4578
+ request_method char(8) CHARACTER SET ascii NOT NULL,
4579
+ http_code int(10) UNSIGNED NOT NULL,
4580
+ wp_id bigint(20) UNSIGNED NOT NULL DEFAULT 0,
4581
+ wp_type int(10) UNSIGNED NOT NULL DEFAULT 0,
4582
+ is_bot int(10) UNSIGNED NOT NULL DEFAULT 0,
4583
+ blog_id int(10) UNSIGNED NOT NULL DEFAULT 0,
4584
+ KEY stamp (stamp)
4585
+ ) DEFAULT CHARSET=utf8;
4586
+ ';
4587
+ }
4588
+
4589
+ if ( ! cerber_is_table( cerber_get_db_prefix() . CERBER_SCAN_TABLE ) ) {
4590
+ $sql[] = '
4591
+ CREATE TABLE IF NOT EXISTS ' . cerber_get_db_prefix(). CERBER_SCAN_TABLE . ' (
4592
+ scan_id INT(10) UNSIGNED NOT NULL,
4593
+ scan_type INT(10) UNSIGNED NOT NULL DEFAULT 1,
4594
+ scan_mode INT(10) UNSIGNED NOT NULL DEFAULT 0,
4595
+ scan_status INT(10) UNSIGNED NOT NULL DEFAULT 0,
4596
+ file_name_hash VARCHAR(255) CHARACTER SET ascii NOT NULL DEFAULT "",
4597
+ file_name TEXT NOT NULL,
4598
+ file_type INT(10) UNSIGNED NOT NULL DEFAULT 0,
4599
+ file_hash VARCHAR(255) CHARACTER SET ascii NOT NULL DEFAULT "",
4600
+ file_md5 VARCHAR(255) CHARACTER SET ascii NOT NULL DEFAULT "",
4601
+ file_hash_repo VARCHAR(255) CHARACTER SET ascii NOT NULL DEFAULT "",
4602
+ hash_match INT(10) UNSIGNED NOT NULL DEFAULT 0,
4603
+ file_size BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
4604
+ file_perms INT(11) NOT NULL DEFAULT 0,
4605
+ file_writable INT(10) UNSIGNED NOT NULL DEFAULT 0,
4606
+ file_mtime INT(10) UNSIGNED NOT NULL DEFAULT 0,
4607
+ extra TEXT NOT NULL,
4608
+ PRIMARY KEY (scan_id, file_name_hash)
4609
+ ) DEFAULT CHARSET=utf8;
4610
+ ';
4611
+ }
4612
+
4613
+ if ( ! cerber_is_table( cerber_get_db_prefix() . CERBER_SETS_TABLE ) ) {
4614
+ $sql[] = '
4615
+ CREATE TABLE IF NOT EXISTS ' . cerber_get_db_prefix() . CERBER_SETS_TABLE . ' (
4616
+ the_key VARCHAR(255) CHARACTER SET ascii NOT NULL,
4617
+ the_id BIGINT(20) NOT NULL DEFAULT 0,
4618
+ the_value LONGTEXT NOT NULL,
4619
+ expires BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
4620
+ PRIMARY KEY (the_key, the_id)
4621
+ ) DEFAULT CHARSET=utf8;
4622
+ ';
4623
+ }
4624
+
4625
+ if ( ! cerber_is_table( CERBER_QMEM_TABLE ) ) {
4626
+ $sql[] = '
4627
+ CREATE TABLE IF NOT EXISTS ' . CERBER_QMEM_TABLE . ' (
4628
+ ip varchar(39) CHARACTER SET ascii NOT NULL,
4629
+ http_code int(10) UNSIGNED NOT NULL,
4630
+ stamp int(10) UNSIGNED NOT NULL,
4631
+ KEY ip_stamp (ip, stamp)
4632
+ ) DEFAULT CHARSET=utf8;
4633
+ ';
4634
+ }
4635
+
4636
+ foreach ( $sql as $query ) {
4637
+ if ( ! $wpdb->query( $query ) && $wpdb->last_error ) {
4638
+ $db_errors[] = array( $wpdb->last_error, $wpdb->last_query );
4639
+ }
4640
+ }
4641
+
4642
+ return $db_errors;
4643
+ }
4644
+
4645
+ /**
4646
+ * Upgrade structure of existing DB tables
4647
+ *
4648
+ * @return array Errors during upgrading
4649
+ * @since 3.0
4650
+ */
4651
+ function cerber_upgrade_db( $force = false ) {
4652
+ global $wpdb;
4653
+ $wpdb->hide_errors();
4654
+ if ( $force ) {
4655
+ $wpdb->suppress_errors();
4656
+ }
4657
+ $db_errors = array();
4658
+ $sql = array();
4659
+
4660
+ // @since 3.0
4661
+ $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' CHANGE stamp stamp DECIMAL(14,4) NOT NULL';
4662
+
4663
+ // @since 3.1
4664
+ if ( $force || ! cerber_is_column( CERBER_LOG_TABLE, 'ip_long' ) ) {
4665
+ $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' ADD ip_long BIGINT UNSIGNED NOT NULL DEFAULT "0" COMMENT "IPv4 long" AFTER ip, ADD INDEX (ip_long)';
4666
+ }
4667
+ if ( $force || ! cerber_is_column( CERBER_ACL_TABLE, 'ip_long_begin' ) ) {
4668
+ $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . " ADD ip_long_begin BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT 'IPv4 range begin' AFTER ip, ADD ip_long_end BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT 'IPv4 range end' AFTER ip_long_begin";
4669
+ }
4670
+ if ( $force || !cerber_is_index( CERBER_ACL_TABLE, 'ip_begin_end' ) ) {
4671
+ $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' ADD UNIQUE ip_begin_end (ip, ip_long_begin, ip_long_end)';
4672
+ }
4673
+ if ( $force || cerber_is_index( CERBER_ACL_TABLE, 'ip' ) ) {
4674
+ $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' DROP INDEX ip';
4675
+ }
4676
+
4677
+ // @since 4.8.2
4678
+ if ( $force || cerber_is_index( CERBER_ACL_TABLE, 'begin_end' ) ) {
4679
+ $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' DROP INDEX begin_end';
4680
+ }
4681
+ if ( $force || !cerber_is_index( CERBER_ACL_TABLE, 'begin_end_tag' ) ) {
4682
+ $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' ADD INDEX begin_end_tag (ip_long_begin, ip_long_end, tag)';
4683
+ }
4684
+
4685
+ // @since 4.9
4686
+ if ( $force || ! cerber_is_column( CERBER_LOG_TABLE, 'session_id' ) ) {
4687
+ $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . '
4688
+ ADD session_id CHAR(32) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "",
4689
+ ADD country CHAR(3) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Country code",
4690
+ ADD details VARCHAR(250) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Details about HTTP request";
4691
+ ';
4692
+ }
4693
+
4694
+ // @since 6.1
4695
+ if ( $force || ! cerber_is_index( CERBER_LOG_TABLE, 'session_index' ) ) {
4696
+ $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' ADD INDEX session_index (session_id)';
4697
+ }
4698
+
4699
+ // @since 7.0.3
4700
+ $sql[] = 'DROP TABLE IF EXISTS ' . CERBER_SCAN_TABLE;
4701
+
4702
+ // @since 7.1
4703
+ if ( $force || ! cerber_is_column( cerber_get_db_prefix() . CERBER_SCAN_TABLE, 'file_status' ) ) {
4704
+ $sql[] = 'ALTER TABLE ' . cerber_get_db_prefix() . CERBER_SCAN_TABLE . " ADD file_status INT UNSIGNED NOT NULL DEFAULT '0' AFTER scan_status";
4705
+ }
4706
+
4707
+ // @since 7.5.2
4708
+ if ( $force || ! cerber_is_column( CERBER_BLOCKS_TABLE, 'reason_id' ) ) {
4709
+ $sql[] = 'ALTER TABLE ' . CERBER_BLOCKS_TABLE . ' ADD reason_id int(11) unsigned NOT NULL DEFAULT "0"';
4710
+ }
4711
+
4712
+ // @since 7.8.6
4713
+ if ( $force || ! cerber_is_column( CERBER_TRAF_TABLE, 'php_errors' ) ) {
4714
+ $sql[] = 'ALTER TABLE ' . CERBER_TRAF_TABLE . ' ADD php_errors TEXT NOT NULL AFTER blog_id';
4715
+ }
4716
+
4717
+ if (!empty($sql)) {
4718
+ foreach ( $sql as $query ) {
4719
+ if ( !$wpdb->query( $query ) && $wpdb->last_error ) {
4720
+ $db_errors[] = array( $wpdb->last_error, $wpdb->last_query );
4721
+ }
4722
+ }
4723
+ }
4724
+
4725
+ // Convert existing data into the new format
4726
+
4727
+ cerber_acl_fixer();
4728
+
4729
+ if ( $db_errors ) {
4730
+ update_site_option( '_cerber_db_errors', $db_errors );
4731
+ }
4732
+ else {
4733
+ update_site_option( '_cerber_db_errors', '' );
4734
+ }
4735
+
4736
+ return $db_errors;
4737
+ }
4738
+
4739
+ /**
4740
+ * Updating old activity log records to the new row format (has been introduced in v 3.1)
4741
+ *
4742
+ * @since 4.0
4743
+ *
4744
+ */
4745
+ function cerber_up_data() {
4746
+ $ips = cerber_db_get_col( 'SELECT DISTINCT ip FROM ' . CERBER_LOG_TABLE . ' WHERE ip_long = 0 LIMIT 50' );
4747
+ if ( ! $ips ) {
4748
+ return;
4749
+ }
4750
+ foreach ( $ips as $ip ) {
4751
+ if ( cerber_is_ipv4( $ip ) ) {
4752
+ $ip_long = ip2long( $ip );
4753
+ } else {
4754
+ $ip_long = 1;
4755
+ }
4756
+ cerber_db_query( 'UPDATE ' . CERBER_LOG_TABLE . ' SET ip_long = ' . $ip_long . ' WHERE ip = "' . $ip .'" AND ip_long = 0');
4757
+ }
4758
+ }
4759
+
4760
+ /**
4761
+ * Upgrade corrupted / outdated rows in ACL
4762
+ *
4763
+ * @param bool $ipv6 if true Process IPv6 addresses
4764
+ *
4765
+ */
4766
+ function cerber_acl_fixer( $ipv6 = false ) {
4767
+ global $wpdb;
4768
+
4769
+ // Repair/update IPs without long values
4770
+ $ips = cerber_db_get_col( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = 0 OR ip_long_end = 0' );
4771
+ if ( ! $ips ) {
4772
+ return;
4773
+ }
4774
+ foreach ( $ips as $ip ) {
4775
+ if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
4776
+ continue;
4777
+ }
4778
+ $range = cerber_any2range( $ip );
4779
+ if ( is_array( $range ) ) {
4780
+ $begin = $range['begin'];
4781
+ $end = $range['end'];
4782
+ }
4783
+ else {
4784
+ $begin = ip2long( $ip );
4785
+ $end = ip2long( $ip );
4786
+ }
4787
+
4788
+ cerber_db_query( 'UPDATE ' . CERBER_ACL_TABLE . ' SET ip_long_begin = ' . $begin . ', ip_long_end = ' . $end . ' WHERE ip = "' . $ip . '"' );
4789
+ }
4790
+
4791
+ // Convert old IPv6 to all shortened
4792
+ if ( $ipv6 ) {
4793
+ $ips = cerber_db_get_col( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = 0' );
4794
+ if ( $ips ) {
4795
+ foreach ( $ips as $ip ) {
4796
+ if ( ! filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
4797
+ continue;
4798
+ }
4799
+ $short_ip = cerber_short_ipv6( $ip );
4800
+ if ( $short_ip != $ip ) {
4801
+ cerber_db_query( 'UPDATE ' . CERBER_ACL_TABLE . ' SET ip = "' . $short_ip . '" WHERE ip = "' . $ip . '"' );
4802
+ }
4803
+ }
4804
+ }
4805
+ }
4806
+ }
4807
+
4808
+ add_action( 'deac' . 'tivate_' . cerber_plug_in(), 'cerber_clean' );
4809
+ function cerber_clean( $ip ) {
4810
+ wp_clear_scheduled_hook( 'cerber_hourly_1' );
4811
+ wp_clear_scheduled_hook( 'cerber_hourly_2' );
4812
+ wp_clear_scheduled_hook( 'cerber_daily' );
4813
+
4814
+ cerber_htaccess_clean_up();
4815
+ cerber_set_boot_mode( 0 );
4816
+ cerber_delete_expired_set( true );
4817
+
4818
+ $pi = get_file_data( cerber_plugin_file(), array( 'Version' => 'Version' ), 'plugin' );
4819
+ $pi ['v'] = time();
4820
+ $pi ['u'] = get_current_user_id();
4821
+ update_site_option( '_cerber_o' . 'ff', $pi );
4822
+ $f = 'cerb' . 'er_se' . 'nd_em' . 'ail';
4823
+ $f( 'sh' . 'utd' . 'own' );
4824
+ }
4825
+
4826
+ /*
4827
+ Fix an issue with the empty user_id field in the comments table.
4828
+ */
4829
+ add_filter( 'preprocess_comment', 'cerber_add_uid' );
4830
+ function cerber_add_uid( $commentdata ) {
4831
+ $current_user = wp_get_current_user();
4832
+ $commentdata['user_ID'] = $current_user->ID;
4833
+
4834
+ return $commentdata;
4835
+ }
4836
+
4837
+ /**
4838
+ * Load jQuery on the page
4839
+ *
4840
+ */
4841
+ add_action( 'login_enqueue_scripts', 'cerber_login_scripts' );
4842
+ function cerber_login_scripts() {
4843
+ if ( cerber_antibot_enabled( array('botsreg', 'botsany') ) ) {
4844
+ wp_enqueue_script( 'jquery' );
4845
+ }
4846
+ }
4847
+ add_action( 'wp_enqueue_scripts', 'cerber_scripts' );
4848
+ function cerber_scripts() {
4849
+ global $wp_cerber;
4850
+ if ( ( is_singular() && cerber_antibot_enabled( array( 'botscomm', 'botsany' ) ) )
4851
+ || ( $wp_cerber->getSettings( 'sitekey' ) && $wp_cerber->getSettings( 'secretkey' ) )
4852
+ ) {
4853
+ wp_enqueue_script( 'jquery' );
4854
+ }
4855
+ }
4856
+
4857
+ /**
4858
+ * Footer stuff like JS code
4859
+ * Explicit rendering reCAPTCHA
4860
+ *
4861
+ */
4862
+ add_action( 'login_footer', 'cerber_login_register_stuff', 1000 );
4863
+ function cerber_login_register_stuff() {
4864
+ global $wp_cerber;
4865
+
4866
+ cerber_antibot_code(array( 'botsreg', 'botsany' ));
4867
+
4868
+ // Universal JS
4869
+ if (!$wp_cerber->recaptcha_here) return;
4870
+
4871
+ $sitekey = $wp_cerber->getSettings('sitekey');
4872
+
4873
+ if (!$wp_cerber->getSettings('invirecap')){
4874
+ // Classic version (visible reCAPTCHA)
4875
+ echo '<script src = https://www.google.com/recaptcha/api.js?hl='.cerber_recaptcha_lang().' async defer></script>';
4876
+ }
4877
+ else {
4878
+ // Pure JS version with explicit rendering
4879
+ ?>
4880
+ <script src="https://www.google.com/recaptcha/api.js?onload=init_recaptcha_widgets&render=explicit&hl=<?php echo cerber_recaptcha_lang(); ?>" async defer></script>
4881
+ <script type='text/javascript'>
4882
+
4883
+ document.getElementById("cerber-recaptcha").remove();
4884
+
4885
+ var init_recaptcha_widgets = function () {
4886
+ for (var i = 0; i < document.forms.length; ++i) {
4887
+ var form = document.forms[i];
4888
+ var place = form.querySelector('.cerber-form-marker');
4889
+ if (null !== place) render_recaptcha_widget(form, place);
4890
+ }
4891
+ };
4892
+
4893
+ function render_recaptcha_widget(form, place) {
4894
+ var place_id = grecaptcha.render(place, {
4895
+ 'callback': function (g_recaptcha_response) {
4896
+ HTMLFormElement.prototype.submit.call(form);
4897
+ },
4898
+ 'sitekey': '<?php echo $sitekey; ?>',
4899
+ 'size': 'invisible',
4900
+ 'badge': 'bottomright'
4901
+ });
4902
+
4903
+ form.onsubmit = function (event) {
4904
+ event.preventDefault();
4905
+ grecaptcha.execute(place_id);
4906
+ };
4907
+
4908
+ }
4909
+ </script>
4910
+ <?php
4911
+ }
4912
+ }
4913
+
4914
+ /**
4915
+ * Inline reCAPTCHA widget
4916
+ *
4917
+ */
4918
+ add_action( 'wp_footer', 'cerber_foo', 1000 );
4919
+ function cerber_foo() {
4920
+ global $wp_cerber;
4921
+
4922
+ if (is_singular()) cerber_antibot_code( array( 'botscomm', 'botsany' ) );
4923
+
4924
+ if (!$wp_cerber->recaptcha_here) return;
4925
+
4926
+ // jQuery version with support visible and invisible reCAPTCHA
4927
+ // TODO: convert it into pure JS
4928
+ ?>
4929
+ <script type="text/javascript">
4930
+
4931
+ jQuery(document).ready(function ($) {
4932
+
4933
+ var recaptcha_ok = false;
4934
+ var the_recaptcha_widget = $("#cerber-recaptcha");
4935
+ var is_recaptcha_visible = ($(the_recaptcha_widget).data('size') !== 'invisible');
4936
+
4937
+ var the_form = $(the_recaptcha_widget).closest("form");
4938
+ var the_button = $(the_form).find('input[type="submit"]');
4939
+ if (!the_button.length) {
4940
+ the_button = $(the_form).find(':button');
4941
+ }
4942
+
4943
+ // visible
4944
+ if (the_button.length && is_recaptcha_visible) {
4945
+ the_button.prop("disabled", true);
4946
+ the_button.css("opacity", 0.5);
4947
+ }
4948
+
4949
+ window.form_button_enabler = function () {
4950
+ if (!the_button.length) return;
4951
+ the_button.prop("disabled", false);
4952
+ the_button.css( "opacity", 1 );
4953
+ };
4954
+
4955
+ // invisible
4956
+ if (!is_recaptcha_visible) {
4957
+ $(the_button).click(function (event) {
4958
+ if (recaptcha_ok) return;
4959
+ event.preventDefault();
4960
+ grecaptcha.execute();
4961
+ });
4962
+ }
4963
+
4964
+ window.now_submit_the_form = function () {
4965
+ recaptcha_ok = true;
4966
+ $(the_button).click(); // this is only way to submit a form that contains "submit" inputs
4967
+ };
4968
+ });
4969
+ </script>
4970
+ <script src = "https://www.google.com/recaptcha/api.js?hl=<?php echo cerber_recaptcha_lang(); ?>" async defer></script>
4971
+ <?php
4972
+ }
4973
+
4974
+ register_shutdown_function( function () {
4975
+
4976
+ cerber_extra_vision();
4977
+
4978
+ // Error monitoring
4979
+ if ( 400 <= http_response_code()
4980
+ && ! cerber_is_wp_cron()
4981
+ && ( $mode = crb_get_settings( 'tierrmon' ) ) ) {
4982
+ cerber_error_shield( $mode );
4983
+ }
4984
+
4985
+ cerber_push_lab();
4986
+ cerber_traffic_log();
4987
+ } );
4988
+
4989
+ function cerber_error_shield( $mode = 1 ) {
4990
+ global $cerber_status, $cerber_blocked;
4991
+
4992
+ if ( ! $mode || ( crb_get_settings( 'tierrnoauth' ) && is_user_logged_in() ) ) {
4993
+ return;
4994
+ }
4995
+
4996
+ $time = 900;
4997
+ $limit = 3; // allowed within $time
4998
+ $codes = array();
4999
+ if ( $mode == 1 ) { // safe mode
5000
+ $time = 300;
5001
+ $limit = 7;
5002
+ $codes = array( 404, 500 );
5003
+ }
5004
+
5005
+ $code = http_response_code();
5006
+ if ( $code < 400 || ( $codes && ! in_array( $code, $codes ) ) ) {
5007
+ return;
5008
+ }
5009
+
5010
+ $go = false;
5011
+ if ( cerber_is_http_post() ) {
5012
+ $go = true;
5013
+ }
5014
+
5015
+ if ( ! $go && cerber_get_uri_script() ) {
5016
+ $go = true;
5017
+ }
5018
+
5019
+ if ( ! $go ) {
5020
+ if ( $mode == 1 ) {
5021
+ if ( cerber_get_non_wp_fields() ) {
5022
+ $go = true;
5023
+ }
5024
+ }
5025
+ else {
5026
+ if ( ! empty( $_GET ) ) {
5027
+ $go = true;
5028
+ }
5029
+ }
5030
+ }
5031
+
5032
+ if ( ! $go && cerber_is_rest_url() ) {
5033
+ $go = true;
5034
+ }
5035
+
5036
+ if ( ! $go ) {
5037
+ return;
5038
+ }
5039
+
5040
+ $ip = cerber_get_remote_ip();
5041
+ cerber_db_query( 'INSERT INTO ' . CERBER_QMEM_TABLE . ' (ip, http_code, stamp)
5042
+ VALUES ("' . $ip . '",' . intval( http_response_code() ) . ',' . time() . ')' );
5043
+
5044
+ if ( ! $cerber_blocked ) {
5045
+ $t = time() - $time;
5046
+ $c = cerber_db_get_var( 'SELECT COUNT(ip) FROM ' . CERBER_QMEM_TABLE . ' WHERE ip = "' . $ip . '" AND stamp > ' . $t );
5047
+ if ( $c >= $limit ) {
5048
+ cerber_soft_block_add( $ip, 711 );
5049
+ $cerber_status = 18;
5050
+ }
5051
+ }
5052
+
5053
+ }
5054
+
5055
+ function cerber_catch_error( $errno, $errstr = null, $errfile = null, $errline = null ) {
5056
+ global $cerber_php_errors;
5057
+ if ( ! $errno ) {
5058
+ return false;
5059
+ }
5060
+ if ( ! isset( $cerber_php_errors ) || ! is_array( $cerber_php_errors ) ) {
5061
+ $cerber_php_errors = array();
5062
+ }
5063
+ $cerber_php_errors[] = array( $errno, $errstr, $errfile, $errline );
5064
+
5065
+ return false;
5066
+
5067
+ }
5068
+
5069
+ function cerber_traffic_log(){
5070
+ global $cerber_php_errors, $cerber_db_errors, $wp_query, $wp_cerber_user_id, $wp_cerber_start_stamp, $blog_id;
5071
+ static $logged = false;
5072
+
5073
+ if ( $logged || cerber_is_cloud_request() ) {
5074
+ return;
5075
+ }
5076
+
5077
+ $wp_cerber = get_wp_cerber();
5078
+
5079
+ $wp_type = 700;
5080
+
5081
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
5082
+ /*
5083
+ if ( isset( $_POST['action'] ) && $_POST['action'] == 'heartbeat' ) {
5084
+ return;
5085
+ }*/
5086
+ $wp_type = 500;
5087
+ }
5088
+ elseif ( is_admin() ) {
5089
+ $wp_type = 501;
5090
+ }
5091
+ elseif ( cerber_is_wp_cron() ) {
5092
+ $wp_type = 502;
5093
+ }
5094
+ elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
5095
+ $wp_type = 515;
5096
+ }
5097
+ elseif ( cerber_is_rest_url() ) {
5098
+ $wp_type = 520;
5099
+ }
5100
+ // Public part starts with 600
5101
+ elseif ( $wp_query && is_object( $wp_query ) ) {
5102
+ $wp_type = 600;
5103
+ if ( $wp_query->is_singular ) {
5104
+ $wp_type = 601;
5105
+ }
5106
+ elseif ( $wp_query->is_tag ) {
5107
+ $wp_type = 603;
5108
+ }
5109
+ elseif ( $wp_query->is_category ) {
5110
+ $wp_type = 604;
5111
+ }
5112
+ elseif ( $wp_query->is_search ) {
5113
+ $wp_type = 605;
5114
+ }
5115
+ }
5116
+
5117
+ if ( function_exists( 'http_response_code' ) ) { // PHP >= 5.4.0, PHP 7
5118
+ $http_code = http_response_code();
5119
+ }
5120
+ else {
5121
+ $http_code = 200;
5122
+ if ( $wp_type > 600 ) {
5123
+ if ( $wp_query->is_404 ) {
5124
+ $http_code = 404;
5125
+ }
5126
+ }
5127
+ }
5128
+
5129
+ $user_id = 0;
5130
+ if ( function_exists( 'get_current_user_id' ) ) {
5131
+ $user_id = get_current_user_id();
5132
+ }
5133
+ if ( ! $user_id && $wp_cerber_user_id ) {
5134
+ $user_id = absint( $wp_cerber_user_id );
5135
+ }
5136
+
5137
+ if ( ! cerber_to_log( $wp_type, $http_code, $user_id ) ) {
5138
+ return;
5139
+ }
5140
+
5141
+ $logged = true;
5142
+
5143
+ $ua = '';
5144
+ if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
5145
+ $ua = substr ($_SERVER['HTTP_USER_AGENT'], 0, 1000);
5146
+ }
5147
+
5148
+ $bot = cerber_is_crawler( $ua );
5149
+ if ( $bot && crb_get_settings( 'tinocrabs' ) ) {
5150
+ return;
5151
+ }
5152
+
5153
+ $ip = $wp_cerber->getRemoteIp();
5154
+ $ip_long = 0;
5155
+ if ( cerber_is_ipv4( $ip ) ) {
5156
+ $ip_long = ip2long( $ip );
5157
+ }
5158
+
5159
+ $wp_id = 0;
5160
+ if ( $wp_query && is_object( $wp_query ) ) {
5161
+ $wp_id = absint( $wp_query->get_queried_object_id() );
5162
+ }
5163
+
5164
+ $session_id = $wp_cerber->getSessionID();
5165
+ if ( is_ssl() ) {
5166
+ $scheme = 'https';
5167
+ }
5168
+ else {
5169
+ $scheme = 'http';
5170
+ }
5171
+ $uri = $scheme . '://'. $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
5172
+ $method = preg_replace( '/[^\w]/', '', $_SERVER['REQUEST_METHOD'] );
5173
+
5174
+ // Request fields
5175
+
5176
+ $fields = '';
5177
+ if ( crb_get_settings( 'tifields' ) ) {
5178
+ $fields = array();
5179
+ if ( ! empty( $_POST ) ) {
5180
+ $fields[1] = cerber_prepare_fields( cerber_mask_fields( (array) $_POST ) );
5181
+ }
5182
+ if ( ! empty( $_GET ) ) {
5183
+ $fields[2] = cerber_prepare_fields( (array) $_GET );
5184
+ }
5185
+ if ( ! empty( $_FILES ) ) {
5186
+ $fields[3] = $_FILES;
5187
+ }
5188
+ if ( ! empty( $fields ) ) {
5189
+ $fields = serialize( $fields );
5190
+ }
5191
+ else {
5192
+ $fields = '';
5193
+ }
5194
+ }
5195
+
5196
+ // Extra request details
5197
+
5198
+ $details = array();
5199
+ $details[1] = $ua;
5200
+
5201
+ if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
5202
+ //$ref = mb_substr( $_SERVER['HTTP_REFERER'], 0, 1048576 ); // 1 Mb for ASCII
5203
+ $details[2] = filter_var( $_SERVER['HTTP_REFERER'], FILTER_SANITIZE_URL );
5204
+ }
5205
+ /*
5206
+ if ( ! empty( $_FILES ) ) {
5207
+ $details[3] = $_FILES;
5208
+ }*/
5209
+ if ( $wp_type == 605 && ! empty( $_GET['s'] ) ) {
5210
+ $details[4] = $_GET['s'];
5211
+ }
5212
+ if ( $wp_type == 515 ) {
5213
+ // TODO: add a setting to enable it because there is a user/password in the php://input
5214
+ //$details[5] = file_get_contents('php://input');
5215
+ }
5216
+ if ( crb_get_settings( 'tihdrs' ) ) {
5217
+ $hds = getallheaders();
5218
+ unset( $hds['Cookie'] );
5219
+ $details[6] = $hds;
5220
+ }
5221
+ if ( crb_get_settings( 'tisenv' ) ) {
5222
+ $srv = $_SERVER;
5223
+ unset( $srv['HTTP_COOKIE'] );
5224
+ $details[7] = $srv;
5225
+ }
5226
+ if ( crb_get_settings( 'ticandy' ) && ! empty( $_COOKIE ) ) {
5227
+ $details[8] = $_COOKIE;
5228
+ }
5229
+ if ( !empty( $details ) ) {
5230
+ $details = cerber_prepare_fields( $details );
5231
+ $details = serialize($details);
5232
+ }
5233
+ else {
5234
+ $details = '';
5235
+ }
5236
+
5237
+ // Software errors
5238
+ $php_err = '';
5239
+ if ( crb_get_settings( 'tiphperr' ) ) {
5240
+ if ( $cerber_php_errors && is_array( $cerber_php_errors ) ) {
5241
+ //$err_not = array( E_NOTICE, E_WARNING );
5242
+ $i = 0;
5243
+ foreach ( $cerber_php_errors as $key => $e ) {
5244
+ if ( $e[0] == E_NOTICE ) {
5245
+ //unset( $cerber_php_errors[ $key ] );
5246
+ }
5247
+ else {
5248
+ $i ++;
5249
+ }
5250
+ if ( $i > 25 ) { // Save no more errors
5251
+ break;
5252
+ }
5253
+ }
5254
+ if ( $cerber_php_errors ) {
5255
+ $cerber_php_errors = array_values( $cerber_php_errors );
5256
+ $cerber_php_errors = array_slice( $cerber_php_errors, 0, 25 );
5257
+ $php_err = serialize( $cerber_php_errors );
5258
+ }
5259
+ }
5260
+ }
5261
+
5262
+ // Timestamps
5263
+ if ( ! empty( $wp_cerber_start_stamp ) && is_numeric( $wp_cerber_start_stamp ) ) {
5264
+ $start = (float) $wp_cerber_start_stamp; // define this variable: $wp_cerber_start_stamp = microtime( true ); in wp-config.php
5265
+ }
5266
+ else {
5267
+ $start = cerber_request_time();
5268
+ }
5269
+
5270
+ $processing = (int) ( 1000 * ( microtime( true ) - $start ) );
5271
+
5272
+ $uri = cerber_real_escape( $uri );
5273
+ $fields = cerber_real_escape( $fields );
5274
+ $details = cerber_real_escape( $details );
5275
+ $php_err = cerber_real_escape( $php_err );
5276
+
5277
+ $query = 'INSERT INTO ' . CERBER_TRAF_TABLE . '
5278
+ (ip, ip_long, uri, request_fields , request_details, session_id, user_id, stamp, processing, request_method, http_code, wp_id, wp_type, is_bot, blog_id, php_errors )
5279
+ VALUES ("' . $ip . '", ' . $ip_long . ',"' . $uri . '","' . $fields . '","' . $details . '", "' . $session_id . '", ' . $user_id . ', ' . $start . ',' . $processing . ', "' . $method . '", ' . $http_code . ',' . $wp_id . ', ' . $wp_type . ', ' . $bot . ', ' . absint( $blog_id ) . ',"' . $php_err . '")';
5280
+
5281
+ $ret = cerber_db_query( $query );
5282
+
5283
+ if ( ! $ret ) {
5284
+ //cerber_diag_log( print_r( $cerber_db_errors, 1 ) );
5285
+
5286
+ // mysqli_error($wpdb->dbh);
5287
+
5288
+ // TODO: Daily software error report
5289
+ /*
5290
+ echo mysqli_sqlstate($wpdb->dbh);
5291
+ echo $wpdb->last_error;
5292
+ echo "<p>\n";
5293
+ echo $uri;
5294
+ echo "<p>\n";
5295
+ echo '<p>ERR '.$query.$wpdb->last_error;
5296
+ echo '<p>'.$wpdb->_real_escape( $uri );
5297
+ */
5298
+ }
5299
+
5300
+ }
5301
+
5302
+ /**
5303
+ * To log or not to log current request?
5304
+ *
5305
+ * @param $wp_type integer
5306
+ * @param $http_code integer
5307
+ * @param $user_id integer
5308
+ *
5309
+ * @return bool
5310
+ * @since 6.0
5311
+ */
5312
+ function cerber_to_log( $wp_type, $http_code, $user_id ) {
5313
+ global $cerber_logged, $cerber_blocked, $wp_cerber;
5314
+
5315
+ $mode = crb_get_settings( 'timode' );
5316
+
5317
+ if ( $mode == 0 ) {
5318
+ return false;
5319
+ }
5320
+ if ( $mode == 2 ) {
5321
+ if ( $wp_type < 515 ) { // Pure admin requests
5322
+ if ( $wp_type < 502 && ! $user_id ) { // @since 6.3
5323
+ return true;
5324
+ }
5325
+ //if ( $wp_type == 500 && 'admin-ajax.php' != cerber_get_uri_script() ) { // @since 7.8
5326
+ if ( $wp_type == 500 && ! CRB_Request::is_script( '/wp-admin/admin-ajax.php' ) ) { // @since 7.9.1
5327
+ return true;
5328
+ }
5329
+
5330
+ return false;
5331
+ }
5332
+
5333
+ return true;
5334
+ }
5335
+
5336
+ // Smart mode ---------------------------------------------------------
5337
+
5338
+ if ( ! empty( $cerber_logged ) ) {
5339
+ $tmp = $cerber_logged;
5340
+ unset( $tmp[7] );
5341
+ unset( $tmp[51] );
5342
+ if ( ! empty( $tmp ) ) {
5343
+ return true;
5344
+ }
5345
+ }
5346
+
5347
+ if ( $cerber_blocked ) {
5348
+ return true;
5349
+ }
5350
+
5351
+ if ( $wp_type < 515 ) {
5352
+ if ( $wp_type < 502 && ! $user_id ) { // @since 6.3
5353
+ if ( ! empty( $_GET ) || ! empty( $_POST ) || ! empty( $_FILES ) ) {
5354
+ return true;
5355
+ }
5356
+ }
5357
+ if ( $wp_type == 500 && ! CRB_Request::is_script( '/wp-admin/admin-ajax.php' ) ) { // @since 7.8
5358
+ return true;
5359
+ }
5360
+
5361
+ return false;
5362
+ }
5363
+
5364
+ if ( $http_code >= 400 ||
5365
+ $wp_type < 600 ||
5366
+ $user_id ||
5367
+ ! empty( $_POST ) ||
5368
+ ! empty( $_FILES ) ||
5369
+ isset( $_GET['s'] )
5370
+ || cerber_get_non_wp_fields() ) {
5371
+ return true;
5372
+ }
5373
+
5374
+ if ( cerber_is_http_post()
5375
+ || cerber_get_uri_script() ) {
5376
+ return true;
5377
+ }
5378
+
5379
+ return false;
5380
+ }
5381
+
5382
+ /**
5383
+ * Mask sensitive request fields before saving in DB (avoid information leaks)
5384
+ *
5385
+ * @param $fields array
5386
+ *
5387
+ * @return array
5388
+ * @since 6.0
5389
+ */
5390
+ function cerber_mask_fields( $fields ) {
5391
+ $to_mask = array( 'pwd', 'pass', 'password', 'password_1', 'password_2', 'cerber-cloud-key' );
5392
+ if ( $list = (array) crb_get_settings( 'timask' ) ) {
5393
+ $to_mask = array_merge( $to_mask, $list );
5394
+ }
5395
+ foreach ( $to_mask as $mask_field ) {
5396
+ if ( ! empty( $fields[ $mask_field ] ) ) {
5397
+ $fields[ $mask_field ] = str_pad( '', mb_strlen( $fields[ $mask_field ] ), '*' );
5398
+ }
5399
+ }
5400
+
5401
+ return $fields;
5402
+ }
5403
+
5404
+ /**
5405
+ * Recursive prepare values in array for inserting into DB
5406
+ *
5407
+ * @param $list
5408
+ *
5409
+ * @return mixed
5410
+ * @since 6.0
5411
+ */
5412
+ function cerber_prepare_fields( $list ) {
5413
+ foreach ( $list as &$field ) {
5414
+ if ( is_array( $field ) ) {
5415
+ $field = cerber_prepare_fields( $field );
5416
+ }
5417
+ else {
5418
+ if ( ! $field ) {
5419
+ $field = '';
5420
+ }
5421
+ else {
5422
+ $field = mb_substr( $field, 0, 1048576 ); // 1 Mb for ASCII
5423
+ }
5424
+ }
5425
+ }
5426
+
5427
+ $list = stripslashes_deep( $list );
5428
+
5429
+ return $list;
5430
+ }
5431
+
5432
+ /**
5433
+ * Request time
5434
+ *
5435
+ * @return mixed
5436
+ * @since 6.0
5437
+ */
5438
+ function cerber_request_time() {
5439
+ static $stamp = null;
5440
+
5441
+ if ( ! isset( $stamp ) ) {
5442
+
5443
+ if ( ! empty( $_SERVER['REQUEST_TIME_FLOAT'] ) ) { // PHP >= 5.4
5444
+ $stamp = filter_var( $_SERVER['REQUEST_TIME_FLOAT'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
5445
+ }
5446
+ $mt = microtime( true );
5447
+ if ( ! $stamp || $stamp > ( $mt + 300 ) ) { // Some platforms may have wrong value in 'REQUEST_TIME_FLOAT'
5448
+ $stamp = $mt;
5449
+ }
5450
+ }
5451
+
5452
+ return $stamp;
5453
+ }
5454
+
5455
+ /**
5456
+ * Return non WordPress public query $_GET fields (parameters)
5457
+ *
5458
+ * @param array $fields An associative array field => value to check
5459
+ *
5460
+ * @return array
5461
+ * @since 6.0
5462
+ */
5463
+ function cerber_get_non_wp_fields( $fields = array() ) {
5464
+ global $wp_query;
5465
+ static $result;
5466
+
5467
+ if ( isset( $result ) ) {
5468
+ return $result;
5469
+ }
5470
+
5471
+ if ( empty( $fields ) ) {
5472
+ $get_keys = array_keys( $_GET );
5473
+ }
5474
+ else {
5475
+ $get_keys = array_keys( $fields );
5476
+ }
5477
+
5478
+ if ( empty( $get_keys ) ) {
5479
+ $result = array();
5480
+ }
5481
+
5482
+ if ( is_object( $wp_query ) ) {
5483
+ $keys = $wp_query->fill_query_vars( array() );
5484
+ }
5485
+ elseif ( class_exists( 'WP_Query' ) ) {
5486
+ $tmp = new WP_Query();
5487
+ $keys = $tmp->fill_query_vars( array() );
5488
+ }
5489
+ else {
5490
+ $keys = array();
5491
+ }
5492
+
5493
+ $wp_keys = array_keys( $keys ); // WordPress GET fields for frontend
5494
+
5495
+ // Some well-known fields
5496
+ $wp_keys[] = 'redirect_to';
5497
+ $wp_keys[] = 'reauth';
5498
+ $wp_keys[] = 'action';
5499
+ $wp_keys[] = '_wpnonce';
5500
+ $wp_keys[] = 'loggedout';
5501
+ $wp_keys[] = 'doing_wp_cron';
5502
+
5503
+ // WP Customizer fields
5504
+ $wp_keys = array_merge( $wp_keys, array(
5505
+ 'nonce',
5506
+ '_method',
5507
+ 'wp_customize',
5508
+ 'changeset_uuid',
5509
+ 'customize_changeset_uuid',
5510
+ 'customize_theme',
5511
+ 'theme',
5512
+ 'customize_messenger_channel',
5513
+ 'customize_autosaved'
5514
+ ) );
5515
+
5516
+ $result = array_diff( $get_keys, $wp_keys );
5517
+
5518
+ if ( ! $result ) {
5519
+ $result = array();
5520
+ }
5521
+
5522
+ return $result;
5523
+
5524
+ }
5525
+
5526
+
5527
+ /**
5528
+ *
5529
+ * @since 6.0
5530
+ */
5531
+ function cerber_beast() {
5532
+ global $cerber_status;
5533
+
5534
+ if ( is_admin()
5535
+ || cerber_is_wp_cron()
5536
+ || ( defined( 'WP_CLI' ) && WP_CLI )
5537
+ ) {
5538
+ return;
5539
+ }
5540
+
5541
+ $wp_cerber = get_wp_cerber();
5542
+
5543
+ $wp_cerber->CheckProhibitedURI();
5544
+
5545
+ // TI --------------------------------------------------------------------
5546
+
5547
+ if ( ! $ti_mode = crb_get_settings( 'tienabled' ) ) {
5548
+ return;
5549
+ }
5550
+
5551
+ // White list by IP
5552
+ if ( crb_get_settings( 'tiipwhite' ) && crb_acl_is_white() ) {
5553
+ return; // @since 7.9
5554
+ }
5555
+
5556
+ // White list by URI
5557
+ //$uri = cerber_purify_uri();
5558
+ $uri = CRB_Request::URI();
5559
+ if ( $tiwhite = crb_get_settings( 'tiwhite' ) ) {
5560
+ foreach ( (array) $tiwhite as $item ) {
5561
+ if ( substr( $item, 0, 1 ) == '{' && substr( $item, - 1 ) == '}' ) {
5562
+ $pattern = '/' . substr( $item, 1, - 1 ) . '/i';
5563
+ if ( @preg_match( $pattern, $uri ) ) {
5564
+ return;
5565
+ }
5566
+ }
5567
+ elseif ( $item == $uri ) {
5568
+ return;
5569
+ }
5570
+ }
5571
+ }
5572
+
5573
+ // Step one
5574
+ $wp_cerber->InspectRequest();
5575
+
5576
+ // Step two
5577
+ //$uri_script = cerber_get_uri_script();
5578
+ $uri_script = CRB_Request::script();
5579
+
5580
+ if ( $uri_script && $script_filename = cerber_script_filename() ) {
5581
+ // Scanning for executable scripts?
5582
+ if ( ! cerber_script_exists( $uri ) && ! cerber_is_login_request() ) {
5583
+ $cerber_status = 19;
5584
+ cerber_log( 55 );
5585
+ if ( $ti_mode > 1 ) {
5586
+ cerber_soft_block_add( null, 708 );
5587
+ }
5588
+ cerber_forbidden_page();
5589
+ }
5590
+ // Direct access to a PHP script
5591
+ $deny = false;
5592
+ if ( crb_acl_is_black() ) {
5593
+ $deny = true;
5594
+ $cerber_status = 14;
5595
+ }
5596
+ //elseif ( ! in_array( $uri_script, cerber_get_wp_scripts() ) ) {
5597
+ elseif ( ! CRB_Request::is_script( cerber_get_wp_scripts() ) ) {
5598
+ if ( ! cerber_is_allowed() ) {
5599
+ $deny = true;
5600
+ $cerber_status = 13;
5601
+ }
5602
+ elseif ( lab_is_blocked( null, true ) ) {
5603
+ $deny = true;
5604
+ $cerber_status = 15;
5605
+ }
5606
+ }
5607
+ if ( $deny ) {
5608
+ cerber_log( 50 );
5609
+ cerber_forbidden_page();
5610
+ }
5611
+ }
5612
+
5613
+ // Step three
5614
+ cerber_screen_request_fields();
5615
+
5616
+ // Step four
5617
+ cerber_inspect_uploads();
5618
+ }
5619
+
5620
+ /**
5621
+ * Inspects POST & GET fields
5622
+ *
5623
+ */
5624
+ function cerber_screen_request_fields(){
5625
+ global $cerber_in_context;
5626
+
5627
+ $white = array();
5628
+ $found = false;
5629
+
5630
+ if ( ! empty( $_GET ) ) {
5631
+ $cerber_in_context = 1;
5632
+ $found = cerber_inspect_array( $_GET, array( 's' ) );
5633
+ }
5634
+
5635
+ if ( ! empty( $_POST ) && ! $found ) {
5636
+ if ( CRB_Request::is_script( '/' . WP_COMMENT_SCRIPT ) ) {
5637
+ $white = array( 'comment' );
5638
+ }
5639
+ $cerber_in_context = 2;
5640
+ $found = cerber_inspect_array( $_POST, $white );
5641
+ }
5642
+
5643
+ if ( $found ) {
5644
+ cerber_log( $found );
5645
+ cerber_soft_block_add( null, 709);
5646
+ cerber_forbidden_page();
5647
+ }
5648
+ }
5649
+
5650
+ /**
5651
+ * Recursively inspects values in a given multi-dimensional array
5652
+ *
5653
+ * @param array $array
5654
+ * @param array $white A list of elements to skip
5655
+ *
5656
+ * @return bool|int
5657
+ */
5658
+ function cerber_inspect_array( &$array, $white = array() ) {
5659
+ global $cerber_status;
5660
+ static $rec_limit = null;
5661
+
5662
+ if ( ! $array ) {
5663
+ return false;
5664
+ }
5665
+
5666
+ if ( $rec_limit === null ) {
5667
+ $rec_limit = CERBER_CIREC_LIMIT;
5668
+ }
5669
+ else {
5670
+ $rec_limit --;
5671
+ if ( $rec_limit <= 0 ) {
5672
+ $rec_limit = null;
5673
+ $cerber_status = 20;
5674
+
5675
+ return 100;
5676
+ }
5677
+ }
5678
+
5679
+ foreach ( $array as $key => $value ) {
5680
+ if ( in_array( $key, $white ) ) {
5681
+ continue;
5682
+ }
5683
+ if ( is_array( $value ) ) {
5684
+ $found = cerber_inspect_array( $value );
5685
+ }
5686
+ else {
5687
+ $found = cerber_inspect_value( $value, true );
5688
+ }
5689
+ if ( $found ) {
5690
+ return $found;
5691
+ }
5692
+ }
5693
+
5694
+ $rec_limit ++;
5695
+
5696
+ return false;
5697
+ }
5698
+
5699
+ function cerber_inspect_value( &$value = '', $reset = false ) {
5700
+ global $cerber_status, $crb_x64;
5701
+ static $rec_limit = null; // Real recursion limit
5702
+
5703
+ if ( ! $value || is_numeric( $value ) ) {
5704
+ return false;
5705
+ }
5706
+
5707
+ if ( $reset ) {
5708
+ $rec_limit = null;
5709
+ }
5710
+
5711
+ if ( $rec_limit === null ) {
5712
+ $rec_limit = CERBER_CIREC_LIMIT;
5713
+ }
5714
+ else {
5715
+ $rec_limit --;
5716
+ if ( $rec_limit <= 0 ) {
5717
+ $rec_limit = null;
5718
+ $cerber_status = 21;
5719
+
5720
+ return 100;
5721
+ }
5722
+ }
5723
+
5724
+ $found = false;
5725
+
5726
+ if ( $varbyref = cerber_is_base64_encoded( $value ) ) {
5727
+ $found = cerber_inspect_value( $varbyref );
5728
+ }
5729
+ else {
5730
+ $parsed = cerber_detect_php_code( $value );
5731
+ if ( ! empty( $parsed[0] ) ) {
5732
+ $cerber_status = 22;
5733
+ $found = 100;
5734
+ }
5735
+ elseif ( ! empty( $parsed[1] ) ) {
5736
+ foreach ( $parsed[1] as $string ) {
5737
+ $found = cerber_inspect_value( $string );
5738
+ if ( $found ) {
5739
+ break;
5740
+ }
5741
+ }
5742
+ }
5743
+ if ( ! $found && cerber_detect_other_code( $value ) ) {
5744
+ $cerber_status = 23;
5745
+ $found = 100;
5746
+ }
5747
+ if ( ! $found && cerber_detect_js_code( $value ) ) {
5748
+ $cerber_status = 24;
5749
+ $found = 100;
5750
+ }
5751
+ }
5752
+
5753
+ $rec_limit ++;
5754
+
5755
+ return $found;
5756
+ }
5757
+
5758
+ /**
5759
+ * @param $value string
5760
+ *
5761
+ * @return array A list of suspicious code patterns
5762
+ */
5763
+ function cerber_detect_php_code( &$value ) {
5764
+ static $list;
5765
+ if ( ! $list ) {
5766
+ $list = cerber_get_php_unsafe();
5767
+ }
5768
+ $ret = array( array(), array() );
5769
+ $code_tokens = array( T_STRING, T_EVAL );
5770
+
5771
+ $clean = preg_replace( "/[\r\n\s]+/", '', cerber_remove_comments( $value ) );
5772
+
5773
+ if ( $tokens = @token_get_all( '<?php ' . $clean ) ) {
5774
+ foreach ( $tokens as $token ) {
5775
+ if ( ! is_array( $token ) ) {
5776
+ continue;
5777
+ }
5778
+ if ( in_array( $token[0], $code_tokens ) && isset( $list[ $token[1] ] ) ) {
5779
+ if ( preg_match( '/' . $token[1] . '\((?!\)).+\)/i', $clean ) ) {
5780
+ $ret[0] = array( $token[0], $list[ $token[1] ] );
5781
+ break;
5782
+ }
5783
+ }
5784
+ elseif ( $token[0] == T_CONSTANT_ENCAPSED_STRING ) {
5785
+ $string = trim( $token[1], '\'"' );
5786
+ if ( ! $string || is_numeric( $string ) ) {
5787
+ continue;
5788
+ }
5789
+ $ret[1][] = $string;
5790
+ }
5791
+ }
5792
+ }
5793
+
5794
+ return $ret;
5795
+ }
5796
+
5797
+ function cerber_detect_other_code( &$value ) {
5798
+ global $cerber_in_context;
5799
+ //static $sql = array( 'information_schema.', 'xp_cmdshell', 'FROM_BASE64', '@@' );
5800
+ $co = ( isset( $cerber_in_context ) ) ? $cerber_in_context : 0;
5801
+ $score = 0;
5802
+ $str = $value;
5803
+ if ( $co > 0 ) {
5804
+ $str = preg_replace( '#/\*(?:[^*]*(?:\*(?!/))*)*\*/#', '', $str ); // Remove comments
5805
+ if ( $co == 1 ) {
5806
+ if ( strlen( $value ) != strlen( $str ) ) {
5807
+ $score ++;
5808
+ }
5809
+ }
5810
+ }
5811
+ if ( preg_match( '/\b(?:SELECT|INSERT|UPDATE|DELETE)\b/i', $str ) ) { // SQL?
5812
+ $score ++;
5813
+ $p = stripos( $str, 'UNION' );
5814
+ if ( $p !== false ) {
5815
+ $score ++;
5816
+ if ( $co == 1 ) {
5817
+ return true;
5818
+ }
5819
+ }
5820
+ if ( preg_match( '/\b(?:information_schema|FROM_BASE64|wp_users|xp_cmdshell|LOAD_FILE)\b/i', $value ) ) {
5821
+ return true;
5822
+ }
5823
+ if ( $co < 1 ) {
5824
+ return false;
5825
+ }
5826
+ // $_GET & $_POST
5827
+ if ( preg_match( '/\b(?:name_const|unhex)\b/i', $value ) ) {
5828
+ $score ++;
5829
+ }
5830
+ if ( $score > 3 ) {
5831
+ return true;
5832
+ }
5833
+ $char = substr_count( strtoupper( $value ), 'CHAR' );
5834
+ if ( $char > 1 ) {
5835
+ return true;
5836
+ }
5837
+ $score += $char;
5838
+ if ( $score > 3 ) {
5839
+ return true;
5840
+ }
5841
+ }
5842
+
5843
+ return false;
5844
+ }
5845
+
5846
+ /**
5847
+ * Detects ob/fus/cated JS
5848
+ *
5849
+ * @param $val
5850
+ *
5851
+ * @return bool
5852
+ */
5853
+ function cerber_detect_js_code( $val ) {
5854
+ $val = trim( $val );
5855
+ if ( empty( $val ) || is_numeric( $val ) ) {
5856
+ return false;
5857
+ }
5858
+ $val = preg_replace( "/[\s]+/", '', $val );
5859
+ if ( strlen( $val ) < 32 ) {
5860
+ return false;
5861
+ }
5862
+ // HEX
5863
+ if ( preg_match_all( '/(["\'])(\\\\x[0-9a-fA-F]{2})+?\1/m', $val, $matches ) ) {
5864
+ $found = array_map( function ( $v ) {
5865
+ return trim( $v, '\'"' );
5866
+ }, $matches[0] );
5867
+ $found = str_replace( '\x', '', $found );
5868
+
5869
+ // -- V2
5870
+ /*
5871
+ $pieces = array();
5872
+ foreach ( $found as $str) {
5873
+ echo $str.'-';
5874
+ $hexs = str_split( $str, 2 );
5875
+ $pieces[] = implode( '', array_map( function ( $v ) {
5876
+ return chr( hexdec( $v ) );
5877
+ }, $hexs ) );
5878
+ }*/
5879
+
5880
+ // V1
5881
+ $hexs = str_split( implode( '', $found ), 2 );
5882
+ $decoded = implode( '', array_map( function ( $hex ) {
5883
+ return chr( hexdec( $hex ) );
5884
+ }, $hexs ) );
5885
+
5886
+ if ( preg_match( '/(fromCharCode|createElement|appendChild|script|eval|unescape|getElement|querySelector|XMLHttpRequest|FileSystemObject)/i', $decoded ) ) {
5887
+ return true;
5888
+ }
5889
+
5890
+ }
5891
+
5892
+ if ( preg_match_all( '/((?:\d|0x)[\da-fA-F]{1,4})\s*(?:,|\))/m', $val, $matches ) ) {
5893
+ $decoded = cerber_fromcharcode( implode( ',', $matches[1] ) );
5894
+ $p = cerber_get_js_patterns();
5895
+ list ($xdata, $severity) = cerber_process_patterns( $decoded, $p );
5896
+ if ( $xdata ) {
5897
+ return true;
5898
+ }
5899
+ }
5900
+
5901
+ return false;
5902
+ }
5903
+
5904
+ function cerber_process_patterns( $str, $patterns ) {
5905
+ $xdata = array();
5906
+ $severity = array();
5907
+
5908
+ foreach ( $patterns as $pa ) {
5909
+ if ($pa[1] == 2) { // 2 = REGEX
5910
+ $matches = array();
5911
+ if ( preg_match_all( '/' . $pa[2] . '/i', $str, $matches, PREG_OFFSET_CAPTURE ) ) {
5912
+
5913
+ if ( ! empty( $pa['not_func'] ) && function_exists( $pa['not_func'] ) ) {
5914
+ foreach ( $matches[0] as $key => $match ) {
5915
+ if ( call_user_func( $pa['not_func'], $match[0] ) ) {
5916
+ unset( $matches[0][ $key ] );
5917
+ }
5918
+ }
5919
+ }
5920
+
5921
+ if ( ! empty( $pa['func'] ) && function_exists( $pa['func'] ) ) {
5922
+ foreach ( $matches[0] as $key => $match ) {
5923
+ if ( ! call_user_func( $pa['func'], $match[0] ) ) {
5924
+ unset( $matches[0][ $key ] );
5925
+ }
5926
+ }
5927
+ }
5928
+
5929
+ if ( ! empty( $matches[0] ) ) {
5930
+ $xdata[] = array( 2, $pa[0], array_values( $matches[0] ) );
5931
+ $severity[] = $pa[3];
5932
+ }
5933
+ }
5934
+ }
5935
+ else {
5936
+ if ( false !== stripos( $str, $pa[2] ) ) {
5937
+ $xdata[] = array( 2, $pa[0], array( array( $pa[2] ) ) );
5938
+ $severity[] = $pa[3];
5939
+ }
5940
+ }
5941
+ }
5942
+
5943
+ return array( $xdata, $severity );
5944
+ }
5945
+
5946
+ function cerber_inspect_uploads() {
5947
+ static $found = null;
5948
+
5949
+ if ( $found !== null ) {
5950
+ return $found; // avoid double inspection
5951
+ }
5952
+
5953
+ if ( empty( $_FILES ) ) {
5954
+ return $found;
5955
+ }
5956
+
5957
+ $files = array();
5958
+
5959
+ foreach ( $_FILES as $file ) {
5960
+ if ( is_array( $file['tmp_name'] ) ) {
5961
+ $files[] = array_merge( $files, $file['tmp_name'] );
5962
+ }
5963
+ else {
5964
+ $files[] = $file['tmp_name'];
5965
+ }
5966
+ }
5967
+
5968
+ $found = false;
5969
+
5970
+ foreach ( $files as $file_name ) {
5971
+ if ( $f = @fopen( $file_name, 'r' ) ) {
5972
+ $str = @fread( $f, 100000 );
5973
+ @fclose( $f );
5974
+ if ( cerber_inspect_value( $str ) ) {
5975
+ $found = 56;
5976
+ if ( ! @unlink( $file_name ) ) {
5977
+ // if a system doesn't permit us to delete the file in the tmp uploads folder
5978
+ $target = cerber_get_the_folder() . 'must_be_deleted.tmp';
5979
+ @move_uploaded_file( $file_name, $target );
5980
+ @unlink( $target );
5981
+ }
5982
+ }
5983
+ }
5984
+ }
5985
+
5986
+ if ( $found ) {
5987
+ cerber_log( $found );
5988
+ cerber_soft_block_add( null, 710);
5989
+ }
5990
+
5991
+ return $found;
5992
+ }
5993
+
5994
+ function cerber_error_control() {
5995
+ if ( crb_get_settings( 'nophperr' ) ) {
5996
+ @ini_set( 'display_startup_errors', 0 );
5997
+ @ini_set( 'display_errors', 0 );
5998
+ }
5999
+ }
6000
+
6001
+ // Menu routines ---------------------------------------------------------------
6002
+
6003
+ // Hide/show menu items in public
6004
+ add_filter( 'wp_get_nav_menu_items', function ( $items, $menu, $args ) {
6005
+ if ( is_admin() ) {
6006
+ return $items;
6007
+ }
6008
+ $logged = is_user_logged_in();
6009
+ foreach ( $items as $key => $item ) {
6010
+ // For *MENU*CERBER* See cerber_nav_menu_box() !!!
6011
+ if ( 0 === strpos( $item->attr_title, '*MENU*CERBER*' ) ) {
6012
+ $menu_id = explode( '|', $item->attr_title );
6013
+ switch ( $menu_id[1] ) {
6014
+ case 'wp-cerber-login-url':
6015
+ if ( $logged ) {
6016
+ unset( $items[ $key ] );
6017
+ }
6018
+ break;
6019
+ case 'wp-cerber-logout-url':
6020
+ if ( ! $logged ) {
6021
+ unset( $items[ $key ] );
6022
+ }
6023
+ break;
6024
+ case 'wp-cerber-reg-url':
6025
+ if ( $logged ) {
6026
+ unset( $items[ $key ] );
6027
+ }
6028
+ break;
6029
+ case 'wp-cerber-wc-login-url':
6030
+ if ( $logged ) {
6031
+ unset( $items[ $key ] );
6032
+ }
6033
+ break;
6034
+ case 'wp-cerber-wc-logout-url':
6035
+ if ( ! $logged ) {
6036
+ unset( $items[ $key ] );
6037
+ }
6038
+ break;
6039
+ }
6040
+ }
6041
+ }
6042
+
6043
+ return $items;
6044
+ }, 10, 3 );
6045
+
6046
+ // Set actual URL for a menu item based on a special value in title attribute
6047
+ add_filter( 'nav_menu_link_attributes', function ( $atts ) {
6048
+
6049
+ // For *MENU*CERBER* See cerber_nav_menu_box() !!!
6050
+ if ( 0 === strpos( $atts['title'], '*MENU*CERBER*' ) ) {
6051
+ $title = explode( '|', $atts['title'] );
6052
+ $atts['title'] = '';
6053
+
6054
+ $url = '#';
6055
+ // See cerber_nav_menu_items() !!!
6056
+ switch ( $title[1] ) {
6057
+ case 'wp-cerber-login-url':
6058
+ $url = wp_login_url();
6059
+ break;
6060
+ case 'wp-cerber-logout-url':
6061
+ $url = wp_logout_url();
6062
+ break;
6063
+ case 'wp-cerber-reg-url':
6064
+ if ( get_option( 'users_can_register' ) ) {
6065
+ $url = wp_registration_url();
6066
+ }
6067
+ break;
6068
+ case 'wp-cerber-wc-login-url':
6069
+ if ( class_exists( 'WooCommerce' ) ) {
6070
+ $url = get_permalink( get_option( 'woocommerce_myaccount_page_id' ) );
6071
+ }
6072
+ break;
6073
+ case 'wp-cerber-wc-logout-url':
6074
+ if ( class_exists( 'WooCommerce' ) ) {
6075
+ $url = wc_logout_url();
6076
+ }
6077
+ break;
6078
+ }
6079
+
6080
+ $atts['href'] = $url;
6081
+ }
6082
+
6083
+ return $atts;
6084
  }, 1 );
cerber-news.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
4
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
@@ -118,6 +118,14 @@ function cerber_push_the_news( $version ) {
118
  $news['7.9.3'][] = 'Bug fixed: The malware scanner wrongly prevents PHP files with few specific names in one particular location from being deleted after a manual scan or during the automatic malware removal.';
119
  $news['7.9.3'][] = 'Bug fixed: The number of email notifications might be incorrectly limited to one email per hour.';
120
 
 
 
 
 
 
 
 
 
121
  if ( ! empty( $news[ $version ] ) ) {
122
  //$text = '<h3>What\'s new in WP Cerber '.$version.'</h3>';
123
 
1
  <?php
2
  /*
3
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
4
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
118
  $news['7.9.3'][] = 'Bug fixed: The malware scanner wrongly prevents PHP files with few specific names in one particular location from being deleted after a manual scan or during the automatic malware removal.';
119
  $news['7.9.3'][] = 'Bug fixed: The number of email notifications might be incorrectly limited to one email per hour.';
120
 
121
+ $news['7.9.7'][] = 'New: Authorized users only mode';
122
+ $news['7.9.7'][] = 'New: An ability to block a user account with a custom message';
123
+ $news['7.9.7'][] = 'New: Role-based access to WordPress REST API';
124
+ $news['7.9.7'][] = 'Added ability to search and filter a user on the Activity page';
125
+ $news['7.9.7'][] = 'Improved handling scheduled maintenance tasks on a multi-site WordPress installation';
126
+ $news['7.9.7'][] = 'A new Changelog section on the Tools page';
127
+
128
+
129
  if ( ! empty( $news[ $version ] ) ) {
130
  //$text = '<h3>What\'s new in WP Cerber '.$version.'</h3>';
131
 
cerber-pluggable.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
4
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
1
  <?php
2
  /*
3
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
4
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
cerber-request.php CHANGED
@@ -2,10 +2,10 @@
2
 
3
  final class CRB_Request {
4
  private static $remote_ip = null;
5
- private static $clean_uri = null; // No junk and GET parameters
6
  private static $uri_script = null; // With path and the starting slash (if script)
7
- private static $site_root = null; // without trailing slash and path
8
- private static $sub_folder = null; // without trailing slash and site domain
9
 
10
  static function URI() {
11
  if ( isset( self::$clean_uri ) ) {
@@ -40,28 +40,78 @@ final class CRB_Request {
40
  return;
41
  }
42
 
43
- $home_url = cerber_get_home_url();
44
- $p1 = strpos( $home_url, '//' );
45
- $p2 = strpos( $home_url, '/', $p1 + 2 );
46
  if ( $p2 !== false ) {
47
- self::$site_root = substr( $home_url, 0, $p2 );
48
- self::$sub_folder = substr( $home_url, $p2 );
49
  }
50
  else {
51
- self::$site_root = $home_url;
52
  self::$sub_folder = '';
53
  }
54
 
55
  }
56
 
 
 
 
 
 
57
  static function full_url() {
58
 
59
  self::parse_site_url();
60
 
 
 
 
 
 
 
 
 
61
  return self::$site_root . self::URI();
62
 
63
  }
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  static function script() {
66
 
67
  if ( isset( self::$uri_script ) ) {
2
 
3
  final class CRB_Request {
4
  private static $remote_ip = null;
5
+ private static $clean_uri = null; // No trailing slash, GET parameters and other junk symbols
6
  private static $uri_script = null; // With path and the starting slash (if script)
7
+ private static $site_root = null; // Without trailing slash and path (site domain or IP address)
8
+ private static $sub_folder = null; // Without trailing slash and site domain
9
 
10
  static function URI() {
11
  if ( isset( self::$clean_uri ) ) {
40
  return;
41
  }
42
 
43
+ $site_url = cerber_get_site_url(); // Including the path to WP files and stuff
44
+ $p1 = strpos( $site_url, '//' );
45
+ $p2 = strpos( $site_url, '/', $p1 + 2 );
46
  if ( $p2 !== false ) {
47
+ self::$site_root = substr( $site_url, 0, $p2 );
48
+ self::$sub_folder = substr( $site_url, $p2 );
49
  }
50
  else {
51
+ self::$site_root = $site_url;
52
  self::$sub_folder = '';
53
  }
54
 
55
  }
56
 
57
+ /**
58
+ * Requested URL as is
59
+ *
60
+ * @return string
61
+ */
62
  static function full_url() {
63
 
64
  self::parse_site_url();
65
 
66
+ return self::$site_root . $_SERVER['REQUEST_URI'];
67
+
68
+ }
69
+
70
+ static function full_url_clean() {
71
+
72
+ self::parse_site_url();
73
+
74
  return self::$site_root . self::URI();
75
 
76
  }
77
 
78
+ /**
79
+ * Does requested URL start with a given string
80
+ *
81
+ * @return string
82
+ */
83
+ static function is_url_start_with( $str ) {
84
+
85
+ if ( substr( $str, - 1, 1 ) == '/' ) {
86
+ $url = rtrim( self::full_url_clean(), '/' ) . '/';
87
+ }
88
+ else {
89
+ $url = self::full_url_clean();
90
+ }
91
+
92
+ if ( 0 === strpos( $url, $str ) ) {
93
+ return true;
94
+ }
95
+
96
+ return false;
97
+ }
98
+
99
+ static function is_url_equal( $str ) {
100
+
101
+ if ( substr( $str, - 1, 1 ) == '/' ) {
102
+ $url = rtrim( self::full_url_clean(), '/' ) . '/';
103
+ }
104
+ else {
105
+ $url = self::full_url_clean();
106
+ }
107
+
108
+ if ($url == $str ) {
109
+ return true;
110
+ }
111
+
112
+ return false;
113
+ }
114
+
115
  static function script() {
116
 
117
  if ( isset( self::$uri_script ) ) {
cerber-scanner.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
4
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
@@ -84,7 +84,7 @@ function cerber_integrity_page() {
84
  $tab = cerber_get_active_tab( $tabs );
85
 
86
  ?>
87
- <div class="wrap crb-admin">
88
 
89
  <h1><?php _e( 'Site Integrity', 'wp-cerber' ) ?></h1>
90
 
@@ -1556,6 +1556,8 @@ function cerber_verify_plugins() {
1556
  $plugin_folder = dirname( $plugin );
1557
  }
1558
 
 
 
1559
  $plugin_hash = cerber_get_plugin_hash( $plugin_folder, $plugins[ $plugin ]['Version'] );
1560
 
1561
  if ( $plugin_hash && ! is_wp_error( $plugin_hash ) ) {
@@ -1715,12 +1717,11 @@ function cerber_verify_plugin( $plugin_folder, $plugin_data ) {
1715
  //$ret = new WP_Error( 'net_issue', $msg );
1716
  cerber_log_scan_error( $msg );
1717
  }
1718
-
1719
  }
1720
  }
1721
 
1722
  if ( $hash ) {
1723
- //$local_prefix = cerber_get_plugins_dir() . DIRECTORY_SEPARATOR . $plugin_folder . DIRECTORY_SEPARATOR;
1724
  $local_prefix = cerber_get_plugins_dir() . DIRECTORY_SEPARATOR;
1725
  if ( ! strpos( $plugin_folder, '.' ) ) { // Not a single file plugin
1726
  $local_prefix .= $plugin_folder . DIRECTORY_SEPARATOR;
@@ -1741,23 +1742,19 @@ function cerber_verify_plugin( $plugin_folder, $plugin_data ) {
1741
  * @return int
1742
  */
1743
  function cerber_verify_wp() {
1744
- $wp_version = cerber_get_wp_version();
1745
 
1746
- $data = null;
1747
- $ret = 0;
1748
- $verified = 0;
1749
- $wp_hash = cerber_get_wp_hash();
1750
 
1751
- if ( ! is_wp_error( $wp_hash ) && ! empty( $wp_hash->checksums ) ) {
1752
- $data = get_object_vars( $wp_hash->checksums );
1753
- }
1754
 
1755
- if ( $data ) {
1756
- // In case the default name 'plugins' of the plugins folder has been changed
1757
  $wp_plugins_dir = basename( cerber_get_plugins_dir() );
1758
  if ( $wp_plugins_dir != 'plugins' ) {
1759
  $new_data = array();
1760
- foreach ( $data as $key => $item ) {
1761
  if ( 0 === strpos( $key, 'wp-content/plugins/' ) ) {
1762
  $new_data[ 'wp-content/' . $wp_plugins_dir . '/' . substr( $key, 19 ) ] = $item;
1763
  }
@@ -1765,15 +1762,14 @@ function cerber_verify_wp() {
1765
  $new_data[ $key ] = $item;
1766
  }
1767
  }
1768
- $data = $new_data;
1769
  }
1770
 
1771
  // In case the default name 'wp-content' of the CONTENT folder has been changed
1772
-
1773
  $wp_content_dir = basename( cerber_get_content_dir() );
1774
  if ( $wp_content_dir != 'wp-content' ) {
1775
  $new_data = array();
1776
- foreach ( $data as $key => $item ) {
1777
  if ( 0 === strpos( $key, 'wp-content/' ) ) {
1778
  $new_data[ $wp_content_dir . '/' . substr( $key, 11 ) ] = $item;
1779
  }
@@ -1781,10 +1777,10 @@ function cerber_verify_wp() {
1781
  $new_data[ $key ] = $item;
1782
  }
1783
  }
1784
- $data = $new_data;
1785
  }
1786
 
1787
- list( $issues, $errors ) = cerber_verify_files( $data, 'file_md5', ABSPATH, array(CERBER_FT_PLUGIN, CERBER_FT_THEME), CERBER_FT_WP, '_crb_not_existing' );
1788
  if ( ! $errors ) {
1789
  $verified = 1;
1790
  $status = CERBER_FOK;
@@ -2444,8 +2440,9 @@ function cerber_get_php_unsafe(){
2444
  'getenv' => array(1, ''),
2445
  'phpinfo' => array(1, ''),
2446
  'header' => array(1, ''),
2447
- 'add_filter' => array(1, ''),
2448
  'add_action' => array(1, ''),
 
2449
 
2450
  );
2451
  }
@@ -2614,7 +2611,7 @@ function _is_unsafe_redirect_rule( $found, $line ) {
2614
  }
2615
 
2616
  if ( ! $allowed ) {
2617
- $allowed = array( home_url(), 'https://%{HTTP_HOST}', 'http://%{HTTP_HOST}' );
2618
  }
2619
 
2620
  if ( 0 !== crb_stripos_multi( $found, $allowed ) ) {
@@ -2798,7 +2795,6 @@ function cerber_get_plugin_hash( $plugin, $ver, $nocache = false ) {
2798
  $msg = 'Unknown network error';
2799
  }
2800
  $ret = new WP_Error( 'net_issue', $msg );
2801
- cerber_log_scan_error( $msg );
2802
  }
2803
 
2804
 
@@ -2898,21 +2894,31 @@ function cerber_get_wp_hash( $nocache = false ) {
2898
 
2899
  if ( ! $response['error'] ) {
2900
  $ret = $response['server_data'];
 
 
 
 
 
 
 
 
 
2901
  }
2902
  else {
2903
  if ( ! empty( $response['curl_error'] ) ) {
2904
- $msg = 'CURL ' . $response['curl_error'];
2905
  }
2906
  elseif ( ! empty( $response['json_error'] ) ) {
2907
- $msg = 'JSON ' . $response['json_error'];
2908
  }
2909
  else {
2910
- $msg = 'Unknown network error';
2911
  }
2912
- $ret = new WP_Error( 'net_issue', $msg );
2913
- cerber_log_scan_error( $msg );
2914
  }
2915
 
 
 
 
2916
  return $ret;
2917
 
2918
  }
@@ -2934,6 +2940,7 @@ function cerber_obtain_hash( $url, $nocache = false ) {
2934
  }
2935
 
2936
  $ret = array( 'error' => 1 );
 
2937
 
2938
  $curl = @curl_init();
2939
  if ( ! $curl ) {
@@ -2954,6 +2961,7 @@ function cerber_obtain_hash( $url, $nocache = false ) {
2954
  CURLOPT_CAINFO => ABSPATH . WPINC . '/certificates/ca-bundle.crt',
2955
  ) );
2956
 
 
2957
  $result = curl_exec( $curl );
2958
 
2959
  $ret['curl_status'] = curl_getinfo( $curl );
@@ -2962,11 +2970,13 @@ function cerber_obtain_hash( $url, $nocache = false ) {
2962
 
2963
  if ( $result ) {
2964
  if ( 200 === $http_code ) {
 
 
2965
  $ret['server_data'] = json_decode( $result );
2966
  if ( JSON_ERROR_NONE != json_last_error() ) {
2967
  $ret['server_data'] = '';
2968
- $ret['json_error'] = json_last_error();
2969
- $ret['error'] = json_last_error();
2970
  }
2971
  else {
2972
  $ret['error'] = 0;
@@ -2974,13 +2984,14 @@ function cerber_obtain_hash( $url, $nocache = false ) {
2974
  }
2975
  }
2976
  elseif ( 404 === $http_code ) {
2977
- $ret['curl_error'] = 'Remote server return 404 URL not found';
2978
- $ret['error'] = $ret['curl_error'];
 
2979
  // There is no information about the plugin or this version of the plugin
2980
  }
2981
  else {
2982
  if ( ! $err = curl_error( $curl ) ) {
2983
- $err = 'Unknown CURL (network) error with code ' . $http_code;
2984
  }
2985
  $ret['curl_error'] = $err;
2986
  $ret['error'] = $err;
@@ -2988,19 +2999,23 @@ function cerber_obtain_hash( $url, $nocache = false ) {
2988
  }
2989
  else {
2990
  if ( ! $err = curl_error( $curl ) ) {
2991
- $err = 'Unknown CURL (network) error with code ' . $http_code;
2992
  }
2993
  $ret['curl_error'] = $err;
2994
  $ret['error'] = $err;
2995
- //curl_errno($curl);
2996
  }
2997
 
2998
  if ( ! empty( $ret['curl_error'] ) ) {
2999
- $ret['curl_error'] = 'ERROR# ' . curl_errno( $curl ) . ' ' . $ret['curl_error'] . ' for URL: ' . $url;
 
3000
  }
3001
 
3002
  curl_close( $curl );
3003
 
 
 
 
 
3004
  return $ret;
3005
  }
3006
 
@@ -3486,7 +3501,7 @@ function _crb_save_file_names( $list ) {
3486
  $status = 0;
3487
  if ( isset( $ignore[ $file_name_hash ] ) ) {
3488
  $status = 1;
3489
- crb_scan_debug( 'The file in the ignore list: ' . $filename );
3490
  }
3491
 
3492
  $filename = cerber_real_escape( $filename );
1
  <?php
2
  /*
3
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
4
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
84
  $tab = cerber_get_active_tab( $tabs );
85
 
86
  ?>
87
+ <div id="crb-admin" class="wrap">
88
 
89
  <h1><?php _e( 'Site Integrity', 'wp-cerber' ) ?></h1>
90
 
1556
  $plugin_folder = dirname( $plugin );
1557
  }
1558
 
1559
+ crb_scan_debug( 'Verifying ' . $plugins[ $plugin ]['Name'] . ' ' . $plugins[ $plugin ]['Version'] );
1560
+
1561
  $plugin_hash = cerber_get_plugin_hash( $plugin_folder, $plugins[ $plugin ]['Version'] );
1562
 
1563
  if ( $plugin_hash && ! is_wp_error( $plugin_hash ) ) {
1717
  //$ret = new WP_Error( 'net_issue', $msg );
1718
  cerber_log_scan_error( $msg );
1719
  }
 
1720
  }
1721
  }
1722
 
1723
  if ( $hash ) {
1724
+ crb_scan_debug( 'Using local hash...' );
1725
  $local_prefix = cerber_get_plugins_dir() . DIRECTORY_SEPARATOR;
1726
  if ( ! strpos( $plugin_folder, '.' ) ) { // Not a single file plugin
1727
  $local_prefix .= $plugin_folder . DIRECTORY_SEPARATOR;
1742
  * @return int
1743
  */
1744
  function cerber_verify_wp() {
 
1745
 
1746
+ $wp_version = cerber_get_wp_version();
1747
+ $ret = 0;
1748
+ $verified = 0;
1749
+ $wp_hash = cerber_get_wp_hash();
1750
 
1751
+ if ( ! is_wp_error( $wp_hash ) ) {
 
 
1752
 
1753
+ // In case the default name 'plugins' of the plugins folder has been changed
 
1754
  $wp_plugins_dir = basename( cerber_get_plugins_dir() );
1755
  if ( $wp_plugins_dir != 'plugins' ) {
1756
  $new_data = array();
1757
+ foreach ( $wp_hash as $key => $item ) {
1758
  if ( 0 === strpos( $key, 'wp-content/plugins/' ) ) {
1759
  $new_data[ 'wp-content/' . $wp_plugins_dir . '/' . substr( $key, 19 ) ] = $item;
1760
  }
1762
  $new_data[ $key ] = $item;
1763
  }
1764
  }
1765
+ $wp_hash = $new_data;
1766
  }
1767
 
1768
  // In case the default name 'wp-content' of the CONTENT folder has been changed
 
1769
  $wp_content_dir = basename( cerber_get_content_dir() );
1770
  if ( $wp_content_dir != 'wp-content' ) {
1771
  $new_data = array();
1772
+ foreach ( $wp_hash as $key => $item ) {
1773
  if ( 0 === strpos( $key, 'wp-content/' ) ) {
1774
  $new_data[ $wp_content_dir . '/' . substr( $key, 11 ) ] = $item;
1775
  }
1777
  $new_data[ $key ] = $item;
1778
  }
1779
  }
1780
+ $wp_hash = $new_data;
1781
  }
1782
 
1783
+ list( $issues, $errors ) = cerber_verify_files( $wp_hash, 'file_md5', ABSPATH, array(CERBER_FT_PLUGIN, CERBER_FT_THEME), CERBER_FT_WP, '_crb_not_existing' );
1784
  if ( ! $errors ) {
1785
  $verified = 1;
1786
  $status = CERBER_FOK;
2440
  'getenv' => array(1, ''),
2441
  'phpinfo' => array(1, ''),
2442
  'header' => array(1, ''),
2443
+ 'add_filter' => array(1, 'Can alter any website data or website settings'),
2444
  'add_action' => array(1, ''),
2445
+ 'unserialize' => array(1, 'Can pose a serious security threat if it processes unfiltered user input'),
2446
 
2447
  );
2448
  }
2611
  }
2612
 
2613
  if ( ! $allowed ) {
2614
+ $allowed = array( cerber_get_home_url(), 'https://%{HTTP_HOST}', 'http://%{HTTP_HOST}' );
2615
  }
2616
 
2617
  if ( 0 !== crb_stripos_multi( $found, $allowed ) ) {
2795
  $msg = 'Unknown network error';
2796
  }
2797
  $ret = new WP_Error( 'net_issue', $msg );
 
2798
  }
2799
 
2800
 
2894
 
2895
  if ( ! $response['error'] ) {
2896
  $ret = $response['server_data'];
2897
+ if ( ! empty( $ret->checksums ) ) {
2898
+ return get_object_vars( $ret->checksums );
2899
+ }
2900
+ elseif ( isset( $ret->checksums ) ) {
2901
+ $err = 'WordPress integrity data not found. Version: ' . $wp_version . ', locale: ' . $locale;
2902
+ }
2903
+ else {
2904
+ $err = 'WordPress integrity data has invalid format. Version: ' . $wp_version . ', locale: ' . $locale;
2905
+ }
2906
  }
2907
  else {
2908
  if ( ! empty( $response['curl_error'] ) ) {
2909
+ $err = 'CURL ' . $response['curl_error'];
2910
  }
2911
  elseif ( ! empty( $response['json_error'] ) ) {
2912
+ $err = 'JSON ' . $response['json_error'];
2913
  }
2914
  else {
2915
+ $err = 'Unknown network error';
2916
  }
 
 
2917
  }
2918
 
2919
+ $ret = new WP_Error( 'net_issue', $err );
2920
+ cerber_log_scan_error( $err );
2921
+
2922
  return $ret;
2923
 
2924
  }
2940
  }
2941
 
2942
  $ret = array( 'error' => 1 );
2943
+ $err = null;
2944
 
2945
  $curl = @curl_init();
2946
  if ( ! $curl ) {
2961
  CURLOPT_CAINFO => ABSPATH . WPINC . '/certificates/ca-bundle.crt',
2962
  ) );
2963
 
2964
+ crb_scan_debug( 'Launching CURL to download integrity data from: ' . $url );
2965
  $result = curl_exec( $curl );
2966
 
2967
  $ret['curl_status'] = curl_getinfo( $curl );
2970
 
2971
  if ( $result ) {
2972
  if ( 200 === $http_code ) {
2973
+ crb_scan_debug( 'Integrity data is downloaded from: ' . $url );
2974
+ crb_scan_debug( 'SIZE: ' . strlen( $result ) );
2975
  $ret['server_data'] = json_decode( $result );
2976
  if ( JSON_ERROR_NONE != json_last_error() ) {
2977
  $ret['server_data'] = '';
2978
+ $ret['json_error'] = json_last_error();
2979
+ $ret['error'] = json_last_error();
2980
  }
2981
  else {
2982
  $ret['error'] = 0;
2984
  }
2985
  }
2986
  elseif ( 404 === $http_code ) {
2987
+ $err = 'Remote server return 404 URL not found';
2988
+ $ret['curl_error'] = $err;
2989
+ $ret['error'] = $err;
2990
  // There is no information about the plugin or this version of the plugin
2991
  }
2992
  else {
2993
  if ( ! $err = curl_error( $curl ) ) {
2994
+ $err = 'Unknown CURL (network) error. Code ' . $http_code;
2995
  }
2996
  $ret['curl_error'] = $err;
2997
  $ret['error'] = $err;
2999
  }
3000
  else {
3001
  if ( ! $err = curl_error( $curl ) ) {
3002
+ $err = 'Unknown CURL (network) error. Code ' . $http_code;
3003
  }
3004
  $ret['curl_error'] = $err;
3005
  $ret['error'] = $err;
 
3006
  }
3007
 
3008
  if ( ! empty( $ret['curl_error'] ) ) {
3009
+ $err = '#' . curl_errno( $curl ) . ' ' . $ret['curl_error'] . ' for URL: ' . $url;
3010
+ $ret['curl_error'] = $err;
3011
  }
3012
 
3013
  curl_close( $curl );
3014
 
3015
+ if ( $err ) {
3016
+ cerber_log_scan_error( $err );
3017
+ }
3018
+
3019
  return $ret;
3020
  }
3021
 
3501
  $status = 0;
3502
  if ( isset( $ignore[ $file_name_hash ] ) ) {
3503
  $status = 1;
3504
+ crb_scan_debug( 'The file is in the ignore list: ' . $filename );
3505
  }
3506
 
3507
  $filename = cerber_real_escape( $filename );
cerber-tools.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
4
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL
7
 
@@ -39,14 +39,15 @@ function cerber_tools_page() {
39
  $tabs = array(
40
  'imex' => array( 'bx-layer', __( 'Export & Import', 'wp-cerber' ) ),
41
  'diagnostic' => array( 'bx-wrench', __( 'Diagnostic', 'wp-cerber' ) ),
 
 
42
  'license' => array( 'bx-key', __( 'License', 'wp-cerber' ) ),
43
- 'diag-log' => array( 'bx-bug', __( 'Log', 'wp-cerber' ) ),
44
  );
45
 
46
  $tab = cerber_get_active_tab( $tabs );
47
 
48
  ?>
49
- <div class="wrap crb-admin">
50
 
51
  <h1><?php _e( 'Tools', 'wp-cerber' ) ?></h1>
52
 
@@ -68,6 +69,9 @@ function cerber_tools_page() {
68
  case 'diag-log':
69
  cerber_show_diag_log();
70
  break;
 
 
 
71
  case 'help':
72
  cerber_show_help();
73
  break;
@@ -114,7 +118,7 @@ function cerber_export(){
114
  wp_die( 'Error!' );
115
  }
116
  $p = cerber_plugin_data();
117
- $data = array('cerber_version' => $p['Version'],'home'=> get_home_url(),'date'=>date('d M Y H:i:s'));
118
  if (!empty($_GET['exportset'])) {
119
  $data ['options'] = crb_get_settings();
120
  $data ['geo-rules'] = cerber_geo_rules();
@@ -160,11 +164,11 @@ function cerber_import() {
160
 
161
  if ( $_POST['importset'] && $data['options'] && ! empty( $data['options'] ) && is_array( $data['options'] ) ) {
162
  $data['options']['loginpath'] = urldecode( $data['options']['loginpath'] ); // needed for filter cerber_sanitize_m()
163
- if ( $data['home'] != get_home_url() ) {
164
  $data['options']['sitekey'] = $wp_cerber->getSettings( 'sitekey' );
165
  $data['options']['secretkey'] = $wp_cerber->getSettings( 'secretkey' );
166
  }
167
- cerber_save_options( $data['options'] ); // @since 2.0
168
  if ( isset( $data['geo-rules'] ) ) {
169
  update_site_option( 'geo_rule_set', $data['geo-rules'] );
170
  }
@@ -189,7 +193,7 @@ function cerber_import() {
189
  }
190
  }
191
 
192
- cerber_upgrade_options(); // In case it was settings from an older version
193
 
194
  cerber_admin_message( __( 'Settings has imported successfully from', 'wp-cerber' ) . ' ' . $_FILES['ifile']['name'] );
195
  }
@@ -304,10 +308,12 @@ function cerber_show_lic() {
304
  if ( ! empty( $key[2] ) ) {
305
  $lic = $key[2];
306
  if ( $expires = lab_validate_lic( $lic ) ) {
307
- $valid = '<span style="color: green;">This key is valid until '.$expires.'</span>';
 
 
308
  }
309
  else {
310
- $valid = '<span style="color: red;">This license key is invalid or expired</span>';
311
  }
312
  }
313
  else {
@@ -321,7 +327,7 @@ function cerber_show_lic() {
321
  <th scope="row">License key for PRO version</th>
322
  <td>
323
  <input name="cerber_license" style="font-family: Menlo, Consolas, Monaco, monospace;" value="<?php echo $lic; ?>" size="<?php echo LAB_KEY_LENGTH; ?>" maxlength="<?php echo LAB_KEY_LENGTH; ?>" type="text">
324
- <?php echo '<p>'.$valid.'</p>'; ?>
325
  </td>
326
  </tr>
327
  <tr>
@@ -357,6 +363,7 @@ function cerber_show_wp_diag(){
357
  array( 'PHP version ', phpversion() ),
358
  array( 'Server API ', php_sapi_name() ),
359
  array( 'WordPress version', cerber_get_wp_version() ),
 
360
  array( 'Options DB table', $wpdb->prefix . 'options' ),
361
  array( 'Server platform', PHP_OS ),
362
  array( 'Memory limit', @ini_get( 'memory_limit' ) ),
@@ -438,9 +445,9 @@ function cerber_show_wp_diag(){
438
  $pls[] = array($data['Name'], $data['Version']);
439
  }
440
 
441
- $ret[] = 'Active plugins<br>'.cerber_make_plain_table( $pls );
442
 
443
- echo implode("<br>",$ret);
444
  }
445
 
446
  function cerber_make_plain_table( $data ) {
@@ -493,7 +500,7 @@ function cerber_db_diag(){
493
  update_site_option( '_cerber_db_errors', '' );
494
  }
495
 
496
- return $err.implode('<br>',$ret);
497
  }
498
 
499
  /**
@@ -516,7 +523,7 @@ function cerber_table_info( $table ) {
516
  $field = array_shift( $column );
517
  $type = array_shift( $column );
518
  $collation = array_shift( $column );
519
- $columns .= '<tr><td><b>' . $field . '<b></td><td>' . $type . '</td><td>' . $collation . '</td></tr>';
520
  }
521
  $columns .= '</table>';
522
 
@@ -525,7 +532,7 @@ function cerber_table_info( $table ) {
525
  $sts = $wpdb->get_row( 'SHOW TABLE STATUS WHERE NAME = "' . $table .'"');
526
  $status = '<table>';
527
  foreach ( $sts as $key => $value ) {
528
- $status .= '<tr><td><b>' . $key . '<b></td><td>' . $value . '</td></tr>';
529
  }
530
  $status .= '</table>';
531
 
@@ -540,8 +547,8 @@ function cerber_table_info( $table ) {
540
 
541
  function cerber_environment_diag() {
542
  $issues = array();
543
- if ( version_compare( '5.6', phpversion(), '>' ) ) {
544
- $issues[] = 'Your site run on the outdated version of PHP ' . phpversion() . '. We strongly encourage you to upgrade it to a newer version of PHP.';
545
  }
546
  if ( ! function_exists( 'http_response_code' ) ) {
547
  $issues[] = 'The PHP function http_response_code() is not found or disabled.';
@@ -558,7 +565,7 @@ function cerber_environment_diag() {
558
  if ( $issues ) {
559
  $issues = '<p>' . implode( '</p><p>', $issues ) . '</p>';
560
  $ret = array(
561
- '<h3><span style="color: red;" class="dashicons dashicons-warning"></span> Some issues detected. They can affect plugin functionality.</h3>',
562
  $issues
563
  );
564
  }
@@ -696,3 +703,32 @@ function cerber_manage_diag_log( $v ) {
696
  exit;
697
  }
698
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
  /*
3
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
4
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL
7
 
39
  $tabs = array(
40
  'imex' => array( 'bx-layer', __( 'Export & Import', 'wp-cerber' ) ),
41
  'diagnostic' => array( 'bx-wrench', __( 'Diagnostic', 'wp-cerber' ) ),
42
+ 'diag-log' => array( 'bx-bug', __( 'Log', 'wp-cerber' ) ),
43
+ 'change-log' => array( 'bx-collection', __( 'Changelog', 'wp-cerber' ) ),
44
  'license' => array( 'bx-key', __( 'License', 'wp-cerber' ) ),
 
45
  );
46
 
47
  $tab = cerber_get_active_tab( $tabs );
48
 
49
  ?>
50
+ <div id="crb-admin" class="wrap">
51
 
52
  <h1><?php _e( 'Tools', 'wp-cerber' ) ?></h1>
53
 
69
  case 'diag-log':
70
  cerber_show_diag_log();
71
  break;
72
+ case 'change-log':
73
+ cerber_show_change_log();
74
+ break;
75
  case 'help':
76
  cerber_show_help();
77
  break;
118
  wp_die( 'Error!' );
119
  }
120
  $p = cerber_plugin_data();
121
+ $data = array('cerber_version' => $p['Version'],'home'=> cerber_get_home_url(),'date'=>date('d M Y H:i:s'));
122
  if (!empty($_GET['exportset'])) {
123
  $data ['options'] = crb_get_settings();
124
  $data ['geo-rules'] = cerber_geo_rules();
164
 
165
  if ( $_POST['importset'] && $data['options'] && ! empty( $data['options'] ) && is_array( $data['options'] ) ) {
166
  $data['options']['loginpath'] = urldecode( $data['options']['loginpath'] ); // needed for filter cerber_sanitize_m()
167
+ if ( $data['home'] != cerber_get_home_url() ) {
168
  $data['options']['sitekey'] = $wp_cerber->getSettings( 'sitekey' );
169
  $data['options']['secretkey'] = $wp_cerber->getSettings( 'secretkey' );
170
  }
171
+ cerber_save_settings( $data['options'] ); // @since 2.0
172
  if ( isset( $data['geo-rules'] ) ) {
173
  update_site_option( 'geo_rule_set', $data['geo-rules'] );
174
  }
193
  }
194
  }
195
 
196
+ cerber_upgrade_settings(); // In case it was settings from an older version
197
 
198
  cerber_admin_message( __( 'Settings has imported successfully from', 'wp-cerber' ) . ' ' . $_FILES['ifile']['name'] );
199
  }
308
  if ( ! empty( $key[2] ) ) {
309
  $lic = $key[2];
310
  if ( $expires = lab_validate_lic( $lic ) ) {
311
+ $valid = '
312
+ <p><span style="color: green;">This key is valid until '.$expires.'</span></p>
313
+ <p>To move the key to another website please follow these steps: <a href="https://my.wpcerber.com/how-to-move-license-key/">https://my.wpcerber.com/how-to-move-license-key/</a></p>';
314
  }
315
  else {
316
+ $valid = '<p><span style="color: red;">This license key is invalid or expired</span></p>';
317
  }
318
  }
319
  else {
327
  <th scope="row">License key for PRO version</th>
328
  <td>
329
  <input name="cerber_license" style="font-family: Menlo, Consolas, Monaco, monospace;" value="<?php echo $lic; ?>" size="<?php echo LAB_KEY_LENGTH; ?>" maxlength="<?php echo LAB_KEY_LENGTH; ?>" type="text">
330
+ <?php echo $valid; ?>
331
  </td>
332
  </tr>
333
  <tr>
363
  array( 'PHP version ', phpversion() ),
364
  array( 'Server API ', php_sapi_name() ),
365
  array( 'WordPress version', cerber_get_wp_version() ),
366
+ array( 'WordPress locale', get_locale() ),
367
  array( 'Options DB table', $wpdb->prefix . 'options' ),
368
  array( 'Server platform', PHP_OS ),
369
  array( 'Memory limit', @ini_get( 'memory_limit' ) ),
445
  $pls[] = array($data['Name'], $data['Version']);
446
  }
447
 
448
+ $ret[] = 'Active plugins<br />'.cerber_make_plain_table( $pls );
449
 
450
+ echo implode("<br />",$ret);
451
  }
452
 
453
  function cerber_make_plain_table( $data ) {
500
  update_site_option( '_cerber_db_errors', '' );
501
  }
502
 
503
+ return $err.implode('<br />',$ret);
504
  }
505
 
506
  /**
523
  $field = array_shift( $column );
524
  $type = array_shift( $column );
525
  $collation = array_shift( $column );
526
+ $columns .= '<tr><td><b>' . $field . '</b></td><td>' . $type . '</td><td>' . $collation . '</td></tr>';
527
  }
528
  $columns .= '</table>';
529
 
532
  $sts = $wpdb->get_row( 'SHOW TABLE STATUS WHERE NAME = "' . $table .'"');
533
  $status = '<table>';
534
  foreach ( $sts as $key => $value ) {
535
+ $status .= '<tr><td><b>' . $key . '</b></td><td>' . $value . '</td></tr>';
536
  }
537
  $status .= '</table>';
538
 
547
 
548
  function cerber_environment_diag() {
549
  $issues = array();
550
+ if ( version_compare( '7.0', phpversion(), '>' ) ) {
551
+ $issues[] = 'Your site run on the outdated (unsupported) version of PHP ' . phpversion() . '. We strongly encourage you to upgrade it to a newer version of PHP. See more at: <a target="_blank" href="http://php.net/supported-versions.php">http://php.net/supported-versions.php</a>';
552
  }
553
  if ( ! function_exists( 'http_response_code' ) ) {
554
  $issues[] = 'The PHP function http_response_code() is not found or disabled.';
565
  if ( $issues ) {
566
  $issues = '<p>' . implode( '</p><p>', $issues ) . '</p>';
567
  $ret = array(
568
+ '<h3><span style="color: red;" class="dashicons dashicons-warning"></span> Some issues detected. They might affect plugin functionality.</h3>',
569
  $issues
570
  );
571
  }
703
  exit;
704
  }
705
  }
706
+
707
+ function cerber_show_change_log() {
708
+ if ( ! $text = file( cerber_get_plugins_dir() . '/wp-cerber/changelog.txt' ) ) {
709
+ echo 'File changelog.txt not found';
710
+
711
+ return;
712
+ }
713
+
714
+ echo '<div id="crb-change-log-view">';
715
+ foreach ( $text as $line ) {
716
+ $line = htmlspecialchars( $line );
717
+ if ( preg_match_all( '/(\[.+?\])(\(.+?\))/', $line, $m ) ) {
718
+ $anchors = $m[1];
719
+ $links = $m[2];
720
+ $replace = array();
721
+ foreach ( $anchors as $i => $anchor ) {
722
+ $replace[] = '<a href="' . trim( $links[ $i ], '()' ) . '" target="_blank">' . trim( $anchor, '[]' ) . '</a>';
723
+ }
724
+ $line = str_replace( $anchors, $replace, $line );
725
+ $line = str_replace( $links, '', $line );
726
+ }
727
+ if ( preg_match( '/=([\d\.\s]+?)=/', $line, $m ) ) {
728
+ $line = str_replace( $m[0], '<span class="crb-version">' . $m[1] . '</span>', $line );
729
+ }
730
+
731
+ echo $line . '<br/>';
732
+ }
733
+ echo '</div>';
734
+ }
cerber-users.php ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ add_action( 'personal_options', function ( $profileuser ) {
4
+ if ( defined( 'IS_PROFILE_PAGE' ) && IS_PROFILE_PAGE ) {
5
+ return;
6
+ }
7
+ $b = crb_is_user_blocked( $profileuser->ID );
8
+ $b_msg = ( ! empty( $b['blocked_msg'] ) ) ? $b['blocked_msg'] : '';
9
+ $dsp = ( ! $b ) ? 'display:none;' : '';
10
+ ?>
11
+ <tr>
12
+ <th scope="row"><?php _e( 'Block User', 'wp-cerber' ); ?></th>
13
+ <td>
14
+ <fieldset>
15
+ <legend class="screen-reader-text">
16
+ <span><?php _e( 'User is not permitted to log into the website', 'wp-cerber' ) ?></span>
17
+ </legend>
18
+ <label for="crb_user_blocked">
19
+ <input name="crb_user_blocked" type="checkbox" id="crb_user_blocked"
20
+ value="1" <?php
21
+ checked( ( $b ) ? true : false ); ?> />
22
+ <?php _e( 'User is not permitted to log into the website', 'wp-cerber' );
23
+ if ( ! empty( $b['blocked_by'] ) ) {
24
+ if ( $b['blocked_by'] == get_current_user_id() ) {
25
+ $who = __( 'You', 'wp-cerber' );
26
+ }
27
+ else {
28
+ $user = get_userdata( $b['blocked_by'] );
29
+ $who = $user->display_name;
30
+ }
31
+ $who = sprintf( _x( 'blocked by %s at %s', 'e.g. by John at 11:00', 'wp-cerber' ), $who, cerber_date( $b['blocked_time'] ) );
32
+ echo ' - <i>' . $who . '</i>';
33
+ }
34
+ ?>
35
+ </label>
36
+ </fieldset>
37
+
38
+ </td>
39
+ </tr>
40
+ <tr id="crb_blocked_msg_row" style="<?php echo $dsp; ?>">
41
+ <th scope="row"><?php _e( 'User Message', 'wp-cerber' ); ?></th>
42
+ <td>
43
+ <textarea placeholder="<?php _e( 'An optional message for this user', 'wp-cerber' ); ?>"
44
+ id="crb_blocked_msg" name="crb_blocked_msg"><?php echo htmlspecialchars( $b_msg ); ?></textarea>
45
+ </td>
46
+ </tr>
47
+ <?php
48
+
49
+ }, 1000 );
50
+
51
+ add_action( 'edit_user_profile_update', function ( $user_id ) {
52
+ if ( $user_id == get_current_user_id() ) {
53
+ return;
54
+ }
55
+ $b = absint( $_POST['crb_user_blocked'] );
56
+ if ( ! $b ) {
57
+ delete_user_meta( $user_id, CERBER_BUKEY );
58
+
59
+ return;
60
+ }
61
+ $m = get_user_meta( $user_id, CERBER_BUKEY, 1 );
62
+ if ( ! $m ) {
63
+ $m = array();
64
+ $m['blocked'] = 0;
65
+ }
66
+ if ( $m['blocked'] != $b ) {
67
+ $m['blocked'] = $b;
68
+ $m[ 'u' . $user_id ] = $user_id;
69
+ $m['blocked_by'] = get_current_user_id();
70
+ $m['blocked_time'] = time();
71
+ $m['blocked_ip'] = cerber_get_remote_ip();
72
+ }
73
+ $m['blocked_msg'] = strip_tags( stripslashes( $_POST['crb_blocked_msg'] ) );
74
+ update_user_meta( $user_id, CERBER_BUKEY, $m );
75
+ } );
76
+
77
+ add_filter( 'user_row_actions', 'crb_collect_uids', 10, 2 );
78
+ add_filter( 'ms_user_row_actions', 'crb_collect_uids', 10, 2 );
79
+ function crb_collect_uids( $actions, $user_object ) {
80
+ crb_user_id_list( $user_object->ID );
81
+
82
+ return $actions;
83
+ }
84
+
85
+ function crb_user_id_list( $uid = 0 ) {
86
+ static $list = array();
87
+ if ( $uid ) {
88
+ $list[ $uid ] = $uid;
89
+ }
90
+ else {
91
+ return $list;
92
+ }
93
+ }
94
+
95
+ add_filter( 'views_users', function ( $views ) {
96
+ global $wpdb;
97
+ $c = cerber_db_get_var( 'SELECT COUNT(meta_key) FROM ' . $wpdb->usermeta . ' WHERE meta_key = "' . CERBER_BUKEY . '"' );
98
+ $t = __( 'Blocked Users', 'wp-cerber' );
99
+ if ( $c ) {
100
+ $t = '<a href="users.php?crb_filter_users=blocked">' . $t . '</a>';
101
+ }
102
+ $views['cerber_blocked'] = $t . ' (' . $c . ')';
103
+
104
+ return $views;
105
+ } );
106
+
107
+ add_filter( 'users_list_table_query_args', function ( $args ) {
108
+ if ( isset( $_REQUEST['crb_filter_users'] ) ) {
109
+ $args['meta_key'] = CERBER_BUKEY;
110
+ $args['meta_compare'] = 'EXISTS';
111
+ }
112
+
113
+ return $args;
114
+ } );
115
+
116
+ function crb_format_user_name( $data ) {
117
+ if ( $data->first_name ) {
118
+ $ret = $data->first_name . ' ' . $data->last_name;
119
+ }
120
+ else {
121
+ $ret = $data->display_name;
122
+ }
123
+
124
+ return $ret . ' (' . $data->user_login . ')';
125
+ }
changelog.txt CHANGED
@@ -1,3 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
1
  = 7.9.3 =
2
  * New: New settings for the Traffic Inspector firewall allow you to fine-tune its behavior. You can enable less or more restrictive firewall rules.
3
  * Update: Troubleshooting of possible issues with scheduled maintenance tasks has been improved.
@@ -19,7 +30,7 @@
19
  * [Read more](https://wpcerber.com/wp-cerber-security-7-9/)
20
 
21
  = 7.8.5 =
22
- * New: A new set of heuristics algorithms for detecting obfuscated malware JavaScript code.
23
  * New: A new file filter on the Quarantine page lets to filter out quarantined files by the date of the scan.
24
  * New: The performance of the malware scanner has been improved. Now the scanner deletes all files in the website session and temporary folders permanently before the scan.
25
  * Update: If the plugin is unable to detect the remote IP address, it uses 0.0.0.0 as an IP.
1
+ = 7.9.7 =
2
+ * New: [Authorized users only mode](https://wpcerber.com/only-logged-in-wordpress-users/).
3
+ * New: [An ability to block a user account](https://wpcerber.com/how-to-block-wordpress-user/).
4
+ * New: [Role-based access to WordPress REST API](https://wpcerber.com/restrict-access-to-wordpress-rest-api/).
5
+ * Update: Added ability to search and filter a user on the Activity page.
6
+ * Update: A new, separate setting for preventing user enumeration and user data leaks via WordPress REST API.
7
+ * Update: A new Changelog section on the Tools page.
8
+ * Update: Improved handling scheduled maintenance tasks on a multi-site WordPress installation.
9
+ * Fixed: Several HTML markup errors on plugin admin pages.
10
+ * [Read more](https://wpcerber.com/wp-cerber-security-7-9-7/)
11
+
12
  = 7.9.3 =
13
  * New: New settings for the Traffic Inspector firewall allow you to fine-tune its behavior. You can enable less or more restrictive firewall rules.
14
  * Update: Troubleshooting of possible issues with scheduled maintenance tasks has been improved.
30
  * [Read more](https://wpcerber.com/wp-cerber-security-7-9/)
31
 
32
  = 7.8.5 =
33
+ * New: A new set of heuristics algorithms for detecting obfuscated malicious JavaScript code.
34
  * New: A new file filter on the Quarantine page lets to filter out quarantined files by the date of the scan.
35
  * New: The performance of the malware scanner has been improved. Now the scanner deletes all files in the website session and temporary folders permanently before the scan.
36
  * Update: If the plugin is unable to detect the remote IP address, it uses 0.0.0.0 as an IP.
common.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
4
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
@@ -66,7 +66,7 @@ function cerber_admin_link($tab = '', $args = array()){
66
  $page = 'cerber-recaptcha';
67
  //$tab = null;
68
  }
69
- elseif ( in_array( $tab, array( 'imex', 'diagnostic', 'license', 'diag-log' ) ) ) {
70
  $page = 'cerber-tools';
71
  }
72
  elseif ( in_array( $tab, array( 'traffic', 'ti_settings' ) ) ) {
@@ -127,12 +127,38 @@ function cerber_get_login_url(){
127
  $ret = '';
128
 
129
  if ($path = crb_get_settings( 'loginpath' )) {
130
- $ret = get_home_url() . '/' . $path . '/';
131
  }
132
 
133
  return $ret;
134
  }
135
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  function cerber_get_home_url() {
137
  static $url;
138
 
@@ -299,9 +325,9 @@ function cerber_check_environment(){
299
  curl_close( $curl );
300
  }
301
 
302
- if ( ! in_array( 'mbstring', $ex_list ) ) {
303
  cerber_admin_notice( __( 'ERROR:', 'wp-cerber' ) . ' A PHP extension <b>mbstring</b> is not enabled on this website. Some plugin features will not work properly.
304
- You need to enable the PHP mbstring extension in your hosting control panel.' );
305
  }
306
 
307
  if ( cerber_get_mode() != crb_get_settings( 'boot-mode' ) ) {
@@ -542,6 +568,10 @@ function crb_array_column( $arr = array(), $column = '' ) {
542
  return $ret;
543
  }
544
 
 
 
 
 
545
  /**
546
  * Return true if a REST API URL has been requested
547
  *
@@ -572,7 +602,7 @@ function cerber_is_rest_url(){
572
  $uri = '/' . trim( $_SERVER['REQUEST_URI'], '/' ) . '/';
573
 
574
  if ( 0 === strpos( $uri, '/' . rest_get_url_prefix() . '/' ) ) {
575
- if ( 0 === strpos( get_home_url() . urldecode( $uri ), get_rest_url() ) ) {
576
  $ret = true;
577
  }
578
  }
@@ -667,7 +697,7 @@ function cerber_is_route_allowed() {
667
  * @return bool
668
  */
669
  function cerber_is_route_blocked() {
670
- if ( crb_get_settings( 'stopenum' ) ) {
671
  $path = explode( '/', crb_get_rest_path() );
672
  if ( $path && count( $path ) > 2 && $path[0] == 'wp' && $path[2] == 'users' ) {
673
  return true;
@@ -676,24 +706,89 @@ function cerber_is_route_blocked() {
676
  return false;
677
  }
678
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
679
  function crb_get_rest_path() {
680
  static $ret;
681
  if ( isset( $ret ) ) {
682
  return $ret;
683
  }
684
 
685
- if (isset($_REQUEST['rest_route'])){
686
  $ret = ltrim( $_REQUEST['rest_route'], '/' );
687
  }
688
  elseif ( cerber_is_permalink_enabled() ) {
689
  $pos = strlen( get_rest_url() );
690
- $ret = substr( get_home_url() . urldecode( $_SERVER['REQUEST_URI'] ), $pos );
691
  $ret = trim( $ret, '/' );
692
  }
693
 
694
  return $ret;
695
  }
696
 
 
 
 
 
 
 
 
 
 
 
697
  /**
698
  * Return the last element in the path of the requested URI.
699
  *
@@ -798,53 +893,6 @@ function cerber_detect_exec_extension( $line, $extra = array() ) {
798
  return false;
799
  }
800
 
801
- /**
802
- * Return home with subfolders removed
803
- *
804
- * @return string
805
- */
806
- function cerber_get_site_root(){
807
- static $home_url;
808
-
809
- if ( isset( $home_url ) ) {
810
- return $home_url;
811
- }
812
-
813
- $home_url = get_home_url();
814
- $p1 = strpos( $home_url, '//' );
815
- $p2 = strpos( $home_url, '/', $p1 + 2 );
816
- if ( $p2 !== false ) {
817
- $home_url = substr( $home_url, 0, $p2 );
818
- }
819
-
820
- return $home_url;
821
- }
822
-
823
- /**
824
- * Clean up the requested URI from parameters and extra slashes
825
- *
826
- * @return bool|mixed|string
827
- */
828
- /*
829
- function cerber_purify_uri() {
830
- static $ret;
831
-
832
- if ( isset( $ret ) ) {
833
- return $ret;
834
- }
835
-
836
- $ret = $_SERVER['REQUEST_URI'];
837
-
838
- if ( $pos = strpos( $ret, '?' ) ) {
839
- $ret = substr( $ret, 0, $pos );
840
- }
841
-
842
- $ret = rtrim( $ret, '/' );
843
- $ret = preg_replace( '/\/+/', '/', $ret );
844
-
845
- return $ret;
846
- }*/
847
-
848
  /**
849
  * Remove extra slashes \ / from a script file name
850
  *
@@ -951,21 +999,22 @@ function cerber_get_labels( $type = 'activity', $all = true ) {
951
  $labels[22] = __( 'Malicious code detected', 'wp-cerber' );
952
  $labels[23] = __( 'Suspicious SQL code detected', 'wp-cerber' );
953
  $labels[24] = __( 'Suspicious JavaScript code detected', 'wp-cerber' );
 
954
  }
955
 
956
  return $labels;
957
  }
958
 
959
- function crb_get_activity_set($slice = 'malicious') {
960
  switch ( $slice ) {
961
  case 'malicious':
962
  return array( 10, 11, 16, 17, 40, 50, 51, 52, 53, 54, 55, 56, 100 );
963
  case 'suspicious':
964
- return array( 10, 11, 16, 17, 20, 40, 50, 51, 52, 53, 54, 55, 56, 100, 70, 71);
965
  case 'black':
966
  return array( 16, 17, 40, 50, 51, 52, 55, 56, 100 );
967
  case 'dashboard':
968
- return array( 1, 2, 5, 10, 11, 12, 16, 17, 18, 19, 40, 41, 42, 50, 51, 52, 53, 54, 55, 56, 100);
969
  }
970
 
971
  return array();
@@ -1524,12 +1573,12 @@ function cerber_db_get_results( $query, $type = MYSQLI_ASSOC ) {
1524
 
1525
  if ( $result = cerber_db_query( $query ) ) {
1526
  if ( cerber_db_use_mysqli() ) {
1527
- //$ret = $result->fetch_all( $type );
1528
  switch ( $type ) {
1529
  case MYSQLI_ASSOC:
1530
  while ( $row = mysqli_fetch_assoc( $result ) ) {
1531
  $ret[] = $row;
1532
  }
 
1533
  break;
1534
  case MYSQL_FETCH_OBJECT:
1535
  while ( $row = mysqli_fetch_object( $result ) ) {
@@ -1851,12 +1900,12 @@ function cerber_delete_set( $key, $id = null) {
1851
  */
1852
  function cerber_delete_expired_set( $all = false ) {
1853
  if ( ! $all ) {
1854
- $where = 'AND expires < ' . time();
1855
  }
1856
  else {
1857
- $where = '';
1858
  }
1859
- if ( cerber_db_query( 'DELETE FROM ' . cerber_get_db_prefix() . CERBER_SETS_TABLE . ' WHERE expires > 0 ' . $where ) ) {
1860
  return true;
1861
  }
1862
  else {
@@ -2207,15 +2256,12 @@ function cerber_get_mode() {
2207
 
2208
  function cerber_is_permalink_enabled() {
2209
  static $ret;
 
2210
  if ( isset( $ret ) ) {
2211
  return $ret;
2212
  }
2213
- if ( get_option( 'permalink_structure' ) ) {
2214
- $ret = true;
2215
- }
2216
- else {
2217
- $ret = false;
2218
- }
2219
 
2220
  return $ret;
2221
  }
@@ -2434,3 +2480,13 @@ function cerber_empty_dir( $dir ) {
2434
 
2435
  return $count;
2436
  }
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
  /*
3
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
4
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
66
  $page = 'cerber-recaptcha';
67
  //$tab = null;
68
  }
69
+ elseif ( in_array( $tab, array( 'imex', 'diagnostic', 'license', 'diag-log', 'change-log' ) ) ) {
70
  $page = 'cerber-tools';
71
  }
72
  elseif ( in_array( $tab, array( 'traffic', 'ti_settings' ) ) ) {
127
  $ret = '';
128
 
129
  if ($path = crb_get_settings( 'loginpath' )) {
130
+ $ret = cerber_get_home_url() . '/' . $path . '/';
131
  }
132
 
133
  return $ret;
134
  }
135
 
136
+ /**
137
+ * Always includes the path to the current WP installation
138
+ *
139
+ * @since 7.9.4
140
+ *
141
+ * @return string
142
+ */
143
+ function cerber_get_site_url() {
144
+ static $url;
145
+
146
+ if ( isset( $url ) ) {
147
+ return $url;
148
+ }
149
+
150
+ $url = trim( get_site_url(), '/' );
151
+
152
+ return $url;
153
+ }
154
+ /**
155
+ * Might NOT include the path to the current WP installation in some cases
156
+ * See: https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory
157
+ *
158
+ * @since 7.9.4
159
+ *
160
+ * @return string
161
+ */
162
  function cerber_get_home_url() {
163
  static $url;
164
 
325
  curl_close( $curl );
326
  }
327
 
328
+ if ( ! in_array( 'mbstring', $ex_list ) || ! function_exists( 'mb_convert_encoding' ) ) {
329
  cerber_admin_notice( __( 'ERROR:', 'wp-cerber' ) . ' A PHP extension <b>mbstring</b> is not enabled on this website. Some plugin features will not work properly.
330
+ You need to enable the PHP mbstring extension (multibyte string support) in your hosting control panel.' );
331
  }
332
 
333
  if ( cerber_get_mode() != crb_get_settings( 'boot-mode' ) ) {
568
  return $ret;
569
  }
570
 
571
+ function crb_array_get( &$arr, $key, $default = false ) {
572
+ return ( isset( $arr[ $key ] ) ) ? $arr[ $key ] : $default;
573
+ }
574
+
575
  /**
576
  * Return true if a REST API URL has been requested
577
  *
602
  $uri = '/' . trim( $_SERVER['REQUEST_URI'], '/' ) . '/';
603
 
604
  if ( 0 === strpos( $uri, '/' . rest_get_url_prefix() . '/' ) ) {
605
+ if ( 0 === strpos( cerber_get_home_url() . urldecode( $uri ), get_rest_url() ) ) {
606
  $ret = true;
607
  }
608
  }
697
  * @return bool
698
  */
699
  function cerber_is_route_blocked() {
700
+ if ( crb_get_settings( 'norestuser' ) ) {
701
  $path = explode( '/', crb_get_rest_path() );
702
  if ( $path && count( $path ) > 2 && $path[0] == 'wp' && $path[2] == 'users' ) {
703
  return true;
706
  return false;
707
  }
708
 
709
+ function cerber_is_rest_permitted() {
710
+ $opt = crb_get_settings();
711
+
712
+ if ( ! empty( $opt['norestuser'] ) ) {
713
+ $path = explode( '/', crb_get_rest_path() );
714
+ if ( $path && count( $path ) > 2 && $path[0] == 'wp' && $path[2] == 'users' ) {
715
+ return false;
716
+ }
717
+ }
718
+
719
+ if ( empty( $opt['norest'] ) ) {
720
+ return true;
721
+ }
722
+
723
+ if ( $opt['restauth'] && is_user_logged_in() ) {
724
+ return true;
725
+ }
726
+
727
+ if ( ! empty( $opt['restwhite'] ) || is_array( $opt['restwhite'] ) ) {
728
+ $rest_path = crb_get_rest_path();
729
+ $namespace = substr( $rest_path, 0, strpos( $rest_path, '/' ) );
730
+ foreach ( $opt['restwhite'] as $exception ) {
731
+ if ( $exception == $namespace ) {
732
+ return true;
733
+ }
734
+ }
735
+
736
+ }
737
+
738
+ if ( ! empty( $opt['restroles'] ) || is_array( $opt['restroles'] ) ) {
739
+ if ( cerber_user_has_role( $opt['restroles'] ) ) {
740
+ return true;
741
+ }
742
+ }
743
+
744
+ return false;
745
+ }
746
+
747
+ function cerber_user_has_role( $roles = array(), $user_id = null ) {
748
+ if ( ! $user_id ) {
749
+ $user = wp_get_current_user();
750
+ }
751
+ else {
752
+ $user = get_userdata( $user_id );
753
+ }
754
+ if ( ! $user || empty( $user->roles ) ) {
755
+ return false;
756
+ }
757
+ if ( array_intersect( $user->roles, $roles ) ) {
758
+ return true;
759
+ }
760
+
761
+ return false;
762
+ }
763
+
764
  function crb_get_rest_path() {
765
  static $ret;
766
  if ( isset( $ret ) ) {
767
  return $ret;
768
  }
769
 
770
+ if ( isset( $_REQUEST['rest_route'] ) ) {
771
  $ret = ltrim( $_REQUEST['rest_route'], '/' );
772
  }
773
  elseif ( cerber_is_permalink_enabled() ) {
774
  $pos = strlen( get_rest_url() );
775
+ $ret = substr( cerber_get_home_url() . urldecode( $_SERVER['REQUEST_URI'] ), $pos );
776
  $ret = trim( $ret, '/' );
777
  }
778
 
779
  return $ret;
780
  }
781
 
782
+ function crb_is_user_blocked( $uid ) {
783
+ if ( ( $m = get_user_meta( $uid, CERBER_BUKEY, 1 ) )
784
+ && ! empty( $m['blocked'] )
785
+ && $m[ 'u' . $uid ] == $uid ) {
786
+ return $m;
787
+ }
788
+
789
+ return false;
790
+ }
791
+
792
  /**
793
  * Return the last element in the path of the requested URI.
794
  *
893
  return false;
894
  }
895
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
896
  /**
897
  * Remove extra slashes \ / from a script file name
898
  *
999
  $labels[22] = __( 'Malicious code detected', 'wp-cerber' );
1000
  $labels[23] = __( 'Suspicious SQL code detected', 'wp-cerber' );
1001
  $labels[24] = __( 'Suspicious JavaScript code detected', 'wp-cerber' );
1002
+ $labels[25] = __( 'Blocked by administrator', 'wp-cerber' );
1003
  }
1004
 
1005
  return $labels;
1006
  }
1007
 
1008
+ function crb_get_activity_set( $slice = 'malicious' ) {
1009
  switch ( $slice ) {
1010
  case 'malicious':
1011
  return array( 10, 11, 16, 17, 40, 50, 51, 52, 53, 54, 55, 56, 100 );
1012
  case 'suspicious':
1013
+ return array( 10, 11, 16, 17, 20, 40, 50, 51, 52, 53, 54, 55, 56, 100, 70, 71 );
1014
  case 'black':
1015
  return array( 16, 17, 40, 50, 51, 52, 55, 56, 100 );
1016
  case 'dashboard':
1017
+ return array( 1, 2, 5, 10, 11, 12, 16, 17, 18, 19, 40, 41, 42, 50, 51, 52, 53, 54, 55, 56, 100 );
1018
  }
1019
 
1020
  return array();
1573
 
1574
  if ( $result = cerber_db_query( $query ) ) {
1575
  if ( cerber_db_use_mysqli() ) {
 
1576
  switch ( $type ) {
1577
  case MYSQLI_ASSOC:
1578
  while ( $row = mysqli_fetch_assoc( $result ) ) {
1579
  $ret[] = $row;
1580
  }
1581
+ //$ret = mysqli_fetch_all( $result, $type ); // Requires mysqlnd driver
1582
  break;
1583
  case MYSQL_FETCH_OBJECT:
1584
  while ( $row = mysqli_fetch_object( $result ) ) {
1900
  */
1901
  function cerber_delete_expired_set( $all = false ) {
1902
  if ( ! $all ) {
1903
+ $where = 'expires > 0 AND expires < ' . time();
1904
  }
1905
  else {
1906
+ $where = 'expires > 0';
1907
  }
1908
+ if ( cerber_db_query( 'DELETE FROM ' . cerber_get_db_prefix() . CERBER_SETS_TABLE . ' WHERE ' . $where ) ) {
1909
  return true;
1910
  }
1911
  else {
2256
 
2257
  function cerber_is_permalink_enabled() {
2258
  static $ret;
2259
+
2260
  if ( isset( $ret ) ) {
2261
  return $ret;
2262
  }
2263
+
2264
+ $ret = ( get_option( 'permalink_structure' ) ) ? true : false;
 
 
 
 
2265
 
2266
  return $ret;
2267
  }
2480
 
2481
  return $count;
2482
  }
2483
+
2484
+ /**
2485
+ * Tries to raise PHP limits
2486
+ *
2487
+ */
2488
+ function crb_raise_limits() {
2489
+ @set_time_limit( 180 );
2490
+ @ini_set( 'max_execution_time', 180 );
2491
+ @ini_set( 'memory_limit', 512 );
2492
+ }
dashboard.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
4
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
@@ -376,6 +376,20 @@ function cerber_admin_ajax() {
376
  update_site_option( 'cerber_admin_info', '' );
377
  }
378
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
 
380
  echo json_encode( $response );
381
  wp_die();
@@ -540,13 +554,12 @@ function cerber_safe_redirect( $remove_args ) {
540
 
541
  function cerber_export_activity() {
542
 
543
- if ( function_exists( 'wp_raise_memory_limit' ) ) {
544
- wp_raise_memory_limit( 'admin' );
545
- }
546
 
547
  list( $query, $per_page, $falist, $ip, $filter_login, $user_id, $search ) = cerber_activity_query( array( 'per_page' => 0 ) );
548
 
549
  if ( ! $rows = cerber_db_get_results( $query, MYSQL_FETCH_OBJECT ) ) {
 
550
  wp_die( 'Nothing to export' );
551
  }
552
  $total = cerber_db_get_var( "SELECT FOUND_ROWS()" );
@@ -588,13 +601,14 @@ function cerber_export_activity() {
588
 
589
 
590
  foreach ( $rows as $row ) {
 
 
591
  if ( ! empty( $row->details ) ) {
592
  $details = explode( '|', $row->details );
593
  }
594
  else {
595
  $details = array( '', '', '', '', '' );
596
  }
597
- $values = array();
598
  $values[] = $row->ip;
599
  $values[] = cerber_date( $row->stamp );
600
  $values[] = $labels[ $row->activity ];
@@ -662,12 +676,14 @@ function cerber_show_activity($args = array(), $echo = true){
662
 
663
  list( $query, $per_page, $falist, $filter_ip, $filter_login, $user_id, $search ) = cerber_activity_query( $args );
664
 
 
665
  $info = '';
666
- if ($filter_ip){
667
- $info .= cerber_ip_extra_view( $filter_ip );
668
  }
669
- if ($user_id){
670
- $info .= cerber_user_extra_view( $user_id );
 
671
  }
672
 
673
  $user_cache = array();
@@ -693,7 +709,7 @@ function cerber_show_activity($args = array(), $echo = true){
693
 
694
  if ( empty( $args['no_details'] ) && $row->details ) {
695
  $details = explode( '|', $row->details );
696
- if ( ! empty( $details[0] ) ) {
697
  $activity .= ' <span class = "act-details">' . $status_labels[ $details[0] ] . '</span>';
698
  }
699
  //elseif ($row->activity == 50 && $details[4]) $activity .= ' '.$details[4];
@@ -824,11 +840,12 @@ function cerber_show_activity($args = array(), $echo = true){
824
 
825
  $filters = '<form action="">'
826
  . cerber_select( 'filter_activity', $labels, $selected )
827
- . '<input type="text" value="' . $search . '" name="search_activity" placeholder="' . __( 'Search for IP or username', 'wp-cerber' ) . '"><input type="submit" value="' . __( 'Filter', 'wp-cerber' ) . '" class="button">'
 
 
828
  . '
829
  <!-- Preserve values -->
830
  <input type="hidden" name="filter_ip" value="' . htmlspecialchars( $filter_ip ) . '" >
831
- <input type="hidden" name="filter_user" value="' . $user_id . '" >
832
  <input type="hidden" name="filter_login" value="' . $filter_login . '" >
833
 
834
  <input type="hidden" name="page" value="cerber-security" >
@@ -903,9 +920,9 @@ function cerber_activity_query($args = array()){
903
  $where[] = $wpdb->prepare( 'log.user_login = %s', $_GET['filter_login'] );
904
  $ret[4] = htmlspecialchars( $_GET['filter_login'] );
905
  }
906
- if ( ! empty( $_GET['filter_user'] ) ) {
907
- $user_id = absint( $_GET['filter_user'] );
908
- $ret[5] = $user_id;
909
  $where[] = 'log.user_id = ' . $user_id;
910
  }
911
  if ( ! empty( $_GET['search_activity'] ) ) {
@@ -915,9 +932,10 @@ function cerber_activity_query($args = array()){
915
 
916
  $escaped = cerber_real_escape( $search );
917
  $w = array();
 
918
  if ( $uids = cerber_db_get_col( 'SELECT user_id FROM ' . $wpdb->usermeta . ' WHERE (meta_key = "first_name" OR meta_key = "last_name" OR meta_key = "nickname") AND meta_value LIKE "' . cerber_real_escape( $search ) . '"' ) ) {
919
  $w[] = 'log.user_id IN (' . implode( ',', $uids ) . ')';
920
- }
921
  $w[] = 'log.user_login LIKE "'.$escaped.'"';
922
  $w[] = 'log.ip LIKE "'.$escaped.'"';
923
 
@@ -1064,6 +1082,8 @@ function cerber_user_extra_view( $user_id, $context = 'activity' ) {
1064
  global $wp_roles, $wpdb;
1065
 
1066
  $ret = '';
 
 
1067
  if ( $u = get_userdata( $user_id ) ) {
1068
  if ( ! is_multisite() && $u->roles ) {
1069
  $roles = array();
@@ -1077,7 +1097,7 @@ function cerber_user_extra_view( $user_id, $context = 'activity' ) {
1077
  }
1078
 
1079
  $edit = get_edit_user_link( $user_id );
1080
- $name = '<b><a href="' . $edit . '">' . $u->display_name . '</a></b><p>' . $roles . '</p>';
1081
 
1082
  if ( $avatar = get_avatar( $user_id, 96 ) ) {
1083
  $ret .= '<div>' . $avatar . '</div>';
@@ -1138,10 +1158,17 @@ function cerber_user_extra_view( $user_id, $context = 'activity' ) {
1138
  else {
1139
  $link = ' <a class="crb-button-tiny" href="' . cerber_admin_link( 'activity', array( 'filter_user' => $user_id ) ) . '">' . __( 'Check for activities', 'wp-cerber' ) . '</a>';
1140
  }
 
 
 
 
1141
  }
1142
 
1143
  if ( $ret ) {
1144
- return '<div class="crb-extra-info" id="user-extra-info">' . $ret . $link . '</div>';
 
 
 
1145
  }
1146
 
1147
  return '';
@@ -1201,7 +1228,7 @@ add_filter( 'manage_users_custom_column' , function ($value, $column, $user_id)
1201
  if ($row) {
1202
  $act_link = cerber_admin_link('activity');
1203
  if ( $country = crb_country_html( $row->country, $row->ip ) ) {
1204
- $country = '<br>' . $country;
1205
  } else {
1206
  $country = '';
1207
  }
@@ -1233,9 +1260,9 @@ add_filter( 'manage_users_custom_column' , function ($value, $column, $user_id)
1233
  if ($rm = get_user_meta($user_id, '_crb_reg_', true)){
1234
  if ($rm['IP']) {
1235
  $act_link = cerber_admin_link( 'activity', array( 'filter_ip' => $rm['IP'] ) );
1236
- $ret .= '<br><a href="'.$act_link.'">'.$rm['IP'].'</a>';
1237
  if ( $country = crb_country_html( null, $rm['IP'] ) ) {
1238
- $ret .= '<br>' . $country;
1239
  }
1240
  }
1241
  $uid = absint( $rm['user'] );
@@ -1248,7 +1275,7 @@ add_filter( 'manage_users_custom_column' , function ($value, $column, $user_id)
1248
  if ($user_ID == $uid){
1249
  $name .= ' (' . __( 'You', 'wp-cerber' ) . ')';
1250
  }
1251
- $ret .= '<br>' . $name;
1252
  }
1253
  }
1254
  break;
@@ -1936,7 +1963,8 @@ function cerber_show_aside($page){
1936
  <div class="crb-box-inner">
1937
  <!-- <h3><span class="dashicons-before dashicons-lightbulb"></span> Read Cerber\'s blog</h3> -->
1938
  <h3>Documentation & How to</h3>
1939
-
 
1940
  <p><a href="https://wpcerber.com/automatic-malware-removal-wordpress/" target="_blank">Automatic cleanup of malware and suspicious files</a>
1941
  <p><a href="https://wpcerber.com/wordpress-security-scanner-scan-malware-detect/" target="_blank">What Cerber Security Scanner scans and detects</a>
1942
  <p><a href="https://wpcerber.com/automated-recurring-malware-scans/" target="_blank">Automated recurring scans and email reporting</a>
@@ -1955,8 +1983,6 @@ function cerber_show_aside($page){
1955
  </div>';
1956
 
1957
  if ( ! lab_lab() ) {
1958
- //$a = get_site_option( '_cerber_activated', null );
1959
- //$a = maybe_unserialize($a);
1960
  $a = cerber_get_set( '_activated' );
1961
  if ( ! $a || ( ! empty( $a['time'] ) && $a['time'] < ( time() - WEEK_IN_SECONDS ) ) ) {
1962
  $aside[] = '<a href="https://wordpress.org/support/plugin/wp-cerber/reviews/#new-post" target="_blank"><img style="width: 290px;" src="' . $crb_assets_url . 'rateit2.png" /></a>';
@@ -2216,6 +2242,11 @@ function cerber_admin_assets() {
2216
  wp_enqueue_style( 'crb_tpicker_css' );
2217
  wp_enqueue_script( 'crb_tpicker', $crb_assets_url . 'tpicker/jquery.timepicker.min.js', array(), CERBER_VER );
2218
 
 
 
 
 
 
2219
  add_thickbox();
2220
  }
2221
 
@@ -2232,11 +2263,6 @@ function cerber_admin_assets() {
2232
  wp_register_style( 'cerber_css', $crb_assets_url . 'admin.css', null, CERBER_VER );
2233
  wp_enqueue_style( 'cerber_css' );
2234
 
2235
- // Select2
2236
- //wp_register_style( 'select2css', $crb_assets_url . 'select2/dist/css/select2.min.css' );
2237
- //wp_enqueue_style( 'select2css' );
2238
- //wp_enqueue_script( 'select2js', $crb_assets_url . 'select2/dist/js/select2.min.js', null, null, true );
2239
-
2240
  }
2241
 
2242
  /*
@@ -2391,7 +2417,6 @@ function cerber_admin_footer() {
2391
  crb_load_wp_js();
2392
 
2393
  // Add a button on a user profile page
2394
-
2395
  $uid = 0;
2396
  if ( defined( 'IS_PROFILE_PAGE' ) && IS_PROFILE_PAGE ) {
2397
  $uid = get_current_user_id();
@@ -2403,13 +2428,45 @@ function cerber_admin_footer() {
2403
  $user_link = '<a href="' . cerber_admin_link( 'activity', array( 'filter_user' => $uid ) ) . '" class="page-title-action">' . __( 'View Activity', 'wp-cerber' ) . '</a>';
2404
  ?>
2405
  <script>
2406
- jQuery(document).ready(function ($) {
2407
- $("#profile-page").find(".wp-heading-inline").after('<?php echo $user_link; ?>');
2408
- });
2409
  </script>
2410
  <?php
 
2411
 
 
 
 
 
 
 
 
 
2412
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2413
 
2414
  // ------------------------------------------------------
2415
 
@@ -2472,7 +2529,7 @@ function cerber_footer_text1($text){
2472
  if ( ! cerber_is_admin_page() ) {
2473
  return $text;
2474
  }
2475
- return 'If you like how <strong>WP Cerber</strong> protects your website, please <a target="_blank" href="https://wordpress.org/support/plugin/wp-cerber/reviews/#new-post">leave it a &#9733; &#9733; &#9733; &#9733; &#9733; rating</a>. Thanks!';
2476
  }
2477
  add_filter( 'update_footer','cerber_footer_text2', 1000);
2478
  function cerber_footer_text2($text){
@@ -2582,7 +2639,7 @@ function cerber_rules_page(){
2582
  $tab = cerber_get_active_tab( $tabs );
2583
 
2584
  ?>
2585
- <div class="wrap crb-admin">
2586
 
2587
  <h1><?php _e( 'Security Rules', 'wp-cerber' ) ?></h1>
2588
 
@@ -2680,7 +2737,7 @@ function cerber_show_geo_rules(){
2680
  if ($note) $note = '<p><span class="dashicons-before dashicons-warning"></span> Warning: '.$note.'</p>';
2681
 
2682
  //$tablinks .= '<button class="tablinks '.$b_class.'" data-rule-id="'.$rule_id.'">'.$rule['name'].'</button>';
2683
- $tablinks .= '<div class="tablinks '.$b_class.'" data-rule-id="'.$rule_id.'">'.$rule['name'].'<br><span>'.$info.'</span></div>';
2684
 
2685
  $tabs .= '<div id="tab-' . $rule_id . '" class="vtabcontent" '.$t_style.'>'.$note.$selector.'</div>';
2686
 
@@ -2920,7 +2977,7 @@ function cerber_traffic_page(){
2920
  $tab = cerber_get_active_tab( $tabs );
2921
 
2922
  ?>
2923
- <div class="wrap crb-admin">
2924
 
2925
  <h1><?php _e( 'Traffic Inspector', 'wp-cerber' ) ?></h1>
2926
 
@@ -2955,17 +3012,16 @@ function cerber_traffic_page(){
2955
 
2956
  function cerber_export_traffic() {
2957
 
2958
- if ( function_exists( 'wp_raise_memory_limit' ) ) {
2959
- wp_raise_memory_limit( 'admin' );
2960
- }
2961
 
2962
  $args = array(
2963
  'per_page' => 0,
2964
- 'columns' => array( 'ip', 'uri', 'stamp', 'session_id', 'user_id', 'processing', 'request_method', 'http_code', 'wp_type', 'blog_id' )
2965
  );
2966
  list( $query, $found ) = cerber_traffic_query( $args );
2967
 
2968
- if ( ! $rows = cerber_db_get_results( $query, MYSQL_FETCH_OBJECT ) ) {
 
2969
  wp_die( 'Nothing to export' );
2970
  }
2971
  $total = cerber_db_get_var( $found );
@@ -2993,6 +3049,8 @@ function cerber_export_traffic() {
2993
 
2994
  foreach ( $rows as $row ) {
2995
  $values = array();
 
 
2996
  $values[] = $row->ip;
2997
  $values[] = cerber_date( $row->stamp );
2998
  $values[] = $row->request_method;
@@ -3003,16 +3061,19 @@ function cerber_export_traffic() {
3003
  $values[] = $row->processing;
3004
  $values[] = $row->blog_id;
3005
  $values[] = $row->wp_type;
3006
- $values[] = $row->stamp;
3007
-
3008
- /*$values[] = $labels[ $row->activity ];
3009
- $values[] = $row->display_name;
3010
- $values[] = $row->ulogin;
3011
- $values[] = $row->user_id;
3012
- $values[] = $row->user_login;
3013
- $values[] = $row->stamp;
3014
- $values[] = $row->session_id;
3015
- $values[] = $status[ $details[0] ];*/
 
 
 
3016
 
3017
  cerber_send_csv_line( $values );
3018
  }
@@ -3100,7 +3161,8 @@ function cerber_show_traffic( $args = array(), $echo = true ) {
3100
  $info .= cerber_ip_extra_view( $filter_ip, 'traffic' );
3101
  }
3102
  if ($user_id){
3103
- $info .= cerber_user_extra_view( $user_id, 'traffic' );
 
3104
  }
3105
 
3106
  if ( $rows ) {
@@ -3114,7 +3176,7 @@ function cerber_show_traffic( $args = array(), $echo = true ) {
3114
  $ip_id = cerber_get_id_ip($row->ip);
3115
 
3116
  if ( $row->user_id ) {
3117
- $name = '<a href="' . $base_url . '&filter_user=' . $row->user_id . '"><b>' . $users[ $row->user_id ]['name'] . '</b></a><br>' . $users[ $row->user_id ]['roles'];
3118
  }
3119
  else {
3120
  $name = '';
@@ -3761,7 +3823,7 @@ function cerber_recaptcha_page() {
3761
  $tab = cerber_get_active_tab( $tabs );
3762
 
3763
  ?>
3764
- <div class="wrap crb-admin">
3765
 
3766
  <h2><?php _e( 'Antispam and bot detection settings', 'wp-cerber' ) ?></h2>
3767
 
@@ -3804,9 +3866,10 @@ function cerber_recaptcha_page() {
3804
  */
3805
  function cerber_get_active_tab( $tabs = array() ) {
3806
 
3807
- $tabs['help'] = 1; // always should be
3808
 
3809
- $tab = isset( $_GET['tab'] ) ? $_GET['tab'] : false;
 
3810
 
3811
  if ( ! $tab || ! isset( $tabs[ $tab ] ) ) {
3812
  $tab = key( $tabs );
1
  <?php
2
  /*
3
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
4
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
376
  update_site_option( 'cerber_admin_info', '' );
377
  }
378
  }
379
+ elseif ( $admin && ( $usearch = crb_array_get( $_REQUEST, 'user_search' ) ) ) {
380
+ check_ajax_referer( 'crb-ajax-admin', 'ajax_nonce' );
381
+ $users = get_users( array( 'search' => '*' . esc_attr( $usearch ) . '*', ) );
382
+ $response = array();
383
+ if ( $users ) {
384
+ foreach ( $users as $user ) {
385
+ $data = get_userdata( $user->ID );
386
+ $response[] = array(
387
+ 'id' => $user->ID,
388
+ 'text' => crb_format_user_name( $data )
389
+ );
390
+ }
391
+ }
392
+ }
393
 
394
  echo json_encode( $response );
395
  wp_die();
554
 
555
  function cerber_export_activity() {
556
 
557
+ crb_raise_limits();
 
 
558
 
559
  list( $query, $per_page, $falist, $ip, $filter_login, $user_id, $search ) = cerber_activity_query( array( 'per_page' => 0 ) );
560
 
561
  if ( ! $rows = cerber_db_get_results( $query, MYSQL_FETCH_OBJECT ) ) {
562
+ //if ( ! $rows = cerber_db_get_results( $query, 0 ) ) {
563
  wp_die( 'Nothing to export' );
564
  }
565
  $total = cerber_db_get_var( "SELECT FOUND_ROWS()" );
601
 
602
 
603
  foreach ( $rows as $row ) {
604
+ $values = array();
605
+
606
  if ( ! empty( $row->details ) ) {
607
  $details = explode( '|', $row->details );
608
  }
609
  else {
610
  $details = array( '', '', '', '', '' );
611
  }
 
612
  $values[] = $row->ip;
613
  $values[] = cerber_date( $row->stamp );
614
  $values[] = $labels[ $row->activity ];
676
 
677
  list( $query, $per_page, $falist, $filter_ip, $filter_login, $user_id, $search ) = cerber_activity_query( $args );
678
 
679
+ $sname = '';
680
  $info = '';
681
+ if ( $filter_ip ) {
682
+ $info .= cerber_ip_extra_view( $filter_ip );
683
  }
684
+ if ( $user_id ) {
685
+ list( $sname, $tmp ) = cerber_user_extra_view( $user_id );
686
+ $info .= $tmp;
687
  }
688
 
689
  $user_cache = array();
709
 
710
  if ( empty( $args['no_details'] ) && $row->details ) {
711
  $details = explode( '|', $row->details );
712
+ if ( ! empty( $details[0] ) && isset( $status_labels[ $details[0] ] ) ) {
713
  $activity .= ' <span class = "act-details">' . $status_labels[ $details[0] ] . '</span>';
714
  }
715
  //elseif ($row->activity == 50 && $details[4]) $activity .= ' '.$details[4];
840
 
841
  $filters = '<form action="">'
842
  . cerber_select( 'filter_activity', $labels, $selected )
843
+ . cerber_select( 'filter_user', ( $user_id ) ? array( $user_id => $sname ) : array(), $user_id, 'crb-select2-ajax', false, esc_html__( 'Filter by registered user', 'wp-cerber' ), array( 'min_symbols' => 3 ) )
844
+ . '<input type="text" value="' . $search . '" name="search_activity" placeholder="' . esc_html__( 'Search for IP or username', 'wp-cerber' ) . '">
845
+ <input type="submit" value="' . __( 'Filter', 'wp-cerber' ) . '" class="button button-secondary">'
846
  . '
847
  <!-- Preserve values -->
848
  <input type="hidden" name="filter_ip" value="' . htmlspecialchars( $filter_ip ) . '" >
 
849
  <input type="hidden" name="filter_login" value="' . $filter_login . '" >
850
 
851
  <input type="hidden" name="page" value="cerber-security" >
920
  $where[] = $wpdb->prepare( 'log.user_login = %s', $_GET['filter_login'] );
921
  $ret[4] = htmlspecialchars( $_GET['filter_login'] );
922
  }
923
+ $user_id = absint( crb_array_get( $_GET, 'filter_user', 0 ) );
924
+ $ret[5] = $user_id;
925
+ if ( $user_id ) {
926
  $where[] = 'log.user_id = ' . $user_id;
927
  }
928
  if ( ! empty( $_GET['search_activity'] ) ) {
932
 
933
  $escaped = cerber_real_escape( $search );
934
  $w = array();
935
+ /*
936
  if ( $uids = cerber_db_get_col( 'SELECT user_id FROM ' . $wpdb->usermeta . ' WHERE (meta_key = "first_name" OR meta_key = "last_name" OR meta_key = "nickname") AND meta_value LIKE "' . cerber_real_escape( $search ) . '"' ) ) {
937
  $w[] = 'log.user_id IN (' . implode( ',', $uids ) . ')';
938
+ }*/
939
  $w[] = 'log.user_login LIKE "'.$escaped.'"';
940
  $w[] = 'log.ip LIKE "'.$escaped.'"';
941
 
1082
  global $wp_roles, $wpdb;
1083
 
1084
  $ret = '';
1085
+ $class = '';
1086
+
1087
  if ( $u = get_userdata( $user_id ) ) {
1088
  if ( ! is_multisite() && $u->roles ) {
1089
  $roles = array();
1097
  }
1098
 
1099
  $edit = get_edit_user_link( $user_id );
1100
+ $name = '<span class="crb-user-name"><b><a href="' . $edit . '">' . $u->display_name . '</a></b></span><p>' . $roles . '</p>';
1101
 
1102
  if ( $avatar = get_avatar( $user_id, 96 ) ) {
1103
  $ret .= '<div>' . $avatar . '</div>';
1158
  else {
1159
  $link = ' <a class="crb-button-tiny" href="' . cerber_admin_link( 'activity', array( 'filter_user' => $user_id ) ) . '">' . __( 'Check for activities', 'wp-cerber' ) . '</a>';
1160
  }
1161
+
1162
+ if ( crb_is_user_blocked( $user_id ) ) {
1163
+ $class = 'crb-user-blocked';
1164
+ }
1165
  }
1166
 
1167
  if ( $ret ) {
1168
+ return array(
1169
+ crb_format_user_name( $u ),
1170
+ '<div class="crb-extra-info ' . $class . '" id="user-extra-info">' . $ret . $link . '</div>'
1171
+ );
1172
  }
1173
 
1174
  return '';
1228
  if ($row) {
1229
  $act_link = cerber_admin_link('activity');
1230
  if ( $country = crb_country_html( $row->country, $row->ip ) ) {
1231
+ $country = '<br />' . $country;
1232
  } else {
1233
  $country = '';
1234
  }
1260
  if ($rm = get_user_meta($user_id, '_crb_reg_', true)){
1261
  if ($rm['IP']) {
1262
  $act_link = cerber_admin_link( 'activity', array( 'filter_ip' => $rm['IP'] ) );
1263
+ $ret .= '<br /><a href="'.$act_link.'">'.$rm['IP'].'</a>';
1264
  if ( $country = crb_country_html( null, $rm['IP'] ) ) {
1265
+ $ret .= '<br />' . $country;
1266
  }
1267
  }
1268
  $uid = absint( $rm['user'] );
1275
  if ($user_ID == $uid){
1276
  $name .= ' (' . __( 'You', 'wp-cerber' ) . ')';
1277
  }
1278
+ $ret .= '<br />' . $name;
1279
  }
1280
  }
1281
  break;
1963
  <div class="crb-box-inner">
1964
  <!-- <h3><span class="dashicons-before dashicons-lightbulb"></span> Read Cerber\'s blog</h3> -->
1965
  <h3>Documentation & How to</h3>
1966
+
1967
+ <p><a href="https://wpcerber.com/how-to-block-wordpress-user/" target="_blank">How to block a user account</a>
1968
  <p><a href="https://wpcerber.com/automatic-malware-removal-wordpress/" target="_blank">Automatic cleanup of malware and suspicious files</a>
1969
  <p><a href="https://wpcerber.com/wordpress-security-scanner-scan-malware-detect/" target="_blank">What Cerber Security Scanner scans and detects</a>
1970
  <p><a href="https://wpcerber.com/automated-recurring-malware-scans/" target="_blank">Automated recurring scans and email reporting</a>
1983
  </div>';
1984
 
1985
  if ( ! lab_lab() ) {
 
 
1986
  $a = cerber_get_set( '_activated' );
1987
  if ( ! $a || ( ! empty( $a['time'] ) && $a['time'] < ( time() - WEEK_IN_SECONDS ) ) ) {
1988
  $aside[] = '<a href="https://wordpress.org/support/plugin/wp-cerber/reviews/#new-post" target="_blank"><img style="width: 290px;" src="' . $crb_assets_url . 'rateit2.png" /></a>';
2242
  wp_enqueue_style( 'crb_tpicker_css' );
2243
  wp_enqueue_script( 'crb_tpicker', $crb_assets_url . 'tpicker/jquery.timepicker.min.js', array(), CERBER_VER );
2244
 
2245
+ // Select2
2246
+ wp_register_style( 'select2css', $crb_assets_url . 'select2/dist/css/select2.min.css', null, null );
2247
+ wp_enqueue_style( 'select2css' );
2248
+ wp_enqueue_script( 'select2js', $crb_assets_url . 'select2/dist/js/select2.min.js', null, null, true );
2249
+
2250
  add_thickbox();
2251
  }
2252
 
2263
  wp_register_style( 'cerber_css', $crb_assets_url . 'admin.css', null, CERBER_VER );
2264
  wp_enqueue_style( 'cerber_css' );
2265
 
 
 
 
 
 
2266
  }
2267
 
2268
  /*
2417
  crb_load_wp_js();
2418
 
2419
  // Add a button on a user profile page
 
2420
  $uid = 0;
2421
  if ( defined( 'IS_PROFILE_PAGE' ) && IS_PROFILE_PAGE ) {
2422
  $uid = get_current_user_id();
2428
  $user_link = '<a href="' . cerber_admin_link( 'activity', array( 'filter_user' => $uid ) ) . '" class="page-title-action">' . __( 'View Activity', 'wp-cerber' ) . '</a>';
2429
  ?>
2430
  <script>
2431
+ document.querySelector('#profile-page .wp-heading-inline').insertAdjacentHTML('afterend','<?php echo $user_link; ?>');
 
 
2432
  </script>
2433
  <?php
2434
+ }
2435
 
2436
+ // User blocking admin JS
2437
+ $blocked = array();
2438
+ if ( $uids = crb_user_id_list() ) {
2439
+ foreach ( $uids as $uid ) {
2440
+ if ( crb_is_user_blocked( $uid ) ) {
2441
+ $blocked[] = $uid;
2442
+ }
2443
+ }
2444
  }
2445
+ ?>
2446
+ <script>
2447
+ // Blocked users
2448
+ var crb_blocked_users = <?php echo '[' . implode( ',', $blocked ) . ']'; ?>;
2449
+ if (crb_blocked_users.length) {
2450
+ crb_blocked_users.forEach(function (uid) {
2451
+ var element = document.getElementById('user-' + uid);
2452
+ element.classList.add("crb-user-blocked");
2453
+ });
2454
+ }
2455
+ // Switching textarea
2456
+ jQuery(document).ready(function ($) {
2457
+ var mrow = $('#profile-page #crb_blocked_msg_row');
2458
+ $("#crb_user_blocked").change(function () {
2459
+ if ($(this).is(':checked')) {
2460
+ mrow.show();
2461
+ }
2462
+ else {
2463
+ mrow.hide();
2464
+ }
2465
+ });
2466
+ });
2467
+ </script>
2468
+ <?php
2469
+
2470
 
2471
  // ------------------------------------------------------
2472
 
2529
  if ( ! cerber_is_admin_page() ) {
2530
  return $text;
2531
  }
2532
+ return 'If you like <strong>WP Cerber</strong>, <a target="_blank" href="https://wordpress.org/support/plugin/wp-cerber/reviews/#new-post">please give it a &#9733; &#9733; &#9733; &#9733; &#9733; review</a>. Thanks!';
2533
  }
2534
  add_filter( 'update_footer','cerber_footer_text2', 1000);
2535
  function cerber_footer_text2($text){
2639
  $tab = cerber_get_active_tab( $tabs );
2640
 
2641
  ?>
2642
+ <div id="crb-admin" class="wrap">
2643
 
2644
  <h1><?php _e( 'Security Rules', 'wp-cerber' ) ?></h1>
2645
 
2737
  if ($note) $note = '<p><span class="dashicons-before dashicons-warning"></span> Warning: '.$note.'</p>';
2738
 
2739
  //$tablinks .= '<button class="tablinks '.$b_class.'" data-rule-id="'.$rule_id.'">'.$rule['name'].'</button>';
2740
+ $tablinks .= '<div class="tablinks '.$b_class.'" data-rule-id="'.$rule_id.'">'.$rule['name'].'<br/><span>'.$info.'</span></div>';
2741
 
2742
  $tabs .= '<div id="tab-' . $rule_id . '" class="vtabcontent" '.$t_style.'>'.$note.$selector.'</div>';
2743
 
2977
  $tab = cerber_get_active_tab( $tabs );
2978
 
2979
  ?>
2980
+ <div id="crb-admin" class="wrap">
2981
 
2982
  <h1><?php _e( 'Traffic Inspector', 'wp-cerber' ) ?></h1>
2983
 
3012
 
3013
  function cerber_export_traffic() {
3014
 
3015
+ crb_raise_limits();
 
 
3016
 
3017
  $args = array(
3018
  'per_page' => 0,
3019
+ 'columns' => array( 'ip', 'stamp', 'uri', 'session_id', 'user_id', 'processing', 'request_method', 'http_code', 'wp_type', 'blog_id' )
3020
  );
3021
  list( $query, $found ) = cerber_traffic_query( $args );
3022
 
3023
+ //if ( ! $rows = cerber_db_get_results( $query, MYSQL_FETCH_OBJECT ) ) {
3024
+ if ( ! $rows = cerber_db_get_results( $query, MYSQLI_ASSOC ) ) {
3025
  wp_die( 'Nothing to export' );
3026
  }
3027
  $total = cerber_db_get_var( $found );
3049
 
3050
  foreach ( $rows as $row ) {
3051
  $values = array();
3052
+
3053
+ /*
3054
  $values[] = $row->ip;
3055
  $values[] = cerber_date( $row->stamp );
3056
  $values[] = $row->request_method;
3061
  $values[] = $row->processing;
3062
  $values[] = $row->blog_id;
3063
  $values[] = $row->wp_type;
3064
+ $values[] = $row->stamp;*/
3065
+
3066
+ $values[] = $row['ip'];
3067
+ $values[] = cerber_date( $row['stamp'] );
3068
+ $values[] = $row['request_method'];
3069
+ $values[] = $row['uri'];
3070
+ $values[] = $row['http_code'];
3071
+ $values[] = $row['session_id'];
3072
+ $values[] = $row['user_id'];
3073
+ $values[] = $row['processing'];
3074
+ $values[] = $row['blog_id'];
3075
+ $values[] = $row['wp_type'];
3076
+ $values[] = $row['stamp'];
3077
 
3078
  cerber_send_csv_line( $values );
3079
  }
3161
  $info .= cerber_ip_extra_view( $filter_ip, 'traffic' );
3162
  }
3163
  if ($user_id){
3164
+ list( $sname, $tmp ) = cerber_user_extra_view( $user_id, 'traffic' );
3165
+ $info .= $tmp;
3166
  }
3167
 
3168
  if ( $rows ) {
3176
  $ip_id = cerber_get_id_ip($row->ip);
3177
 
3178
  if ( $row->user_id ) {
3179
+ $name = '<a href="' . $base_url . '&filter_user=' . $row->user_id . '"><b>' . $users[ $row->user_id ]['name'] . '</b></a><br/>' . $users[ $row->user_id ]['roles'];
3180
  }
3181
  else {
3182
  $name = '';
3823
  $tab = cerber_get_active_tab( $tabs );
3824
 
3825
  ?>
3826
+ <div id="crb-admin" class="wrap">
3827
 
3828
  <h2><?php _e( 'Antispam and bot detection settings', 'wp-cerber' ) ?></h2>
3829
 
3866
  */
3867
  function cerber_get_active_tab( $tabs = array() ) {
3868
 
3869
+ $tabs['help'] = 1; // always should be in the array
3870
 
3871
+ //$tab = isset( $_GET['tab'] ) ? $_GET['tab'] : false;
3872
+ $tab = crb_array_get( $_GET, 'tab' );
3873
 
3874
  if ( ! $tab || ! isset( $tabs[ $tab ] ) ) {
3875
  $tab = key( $tabs );
jetflow.php CHANGED
@@ -4,8 +4,8 @@
4
  Integration with the jetFlow.io automation and customization plugin, http://jetflow.io
5
  Actions and triggers definitions.
6
 
7
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
8
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
9
 
10
  Licenced under the GNU GPL.
11
 
4
  Integration with the jetFlow.io automation and customization plugin, http://jetflow.io
5
  Actions and triggers definitions.
6
 
7
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
8
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
9
 
10
  Licenced under the GNU GPL.
11
 
languages/wp-cerber.pot CHANGED
@@ -5,7 +5,7 @@ msgstr ""
5
  "Project-Id-Version: WP Cerber\n"
6
  "Report-Msgid-Bugs-To: \n"
7
  "POT-Creation-Date: Tue Sep 08 2015 21:38:11 GMT+0300\n"
8
- "POT-Revision-Date: Thu Dec 06 2018 22:13:20 GMT+0300 (Moscow Standard Time)\n"
9
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
10
  "Last-Translator: \n"
11
  "Language-Team: \n"
@@ -28,8 +28,8 @@ msgstr ""
28
  msgid "Cerber Dashboard"
29
  msgstr ""
30
 
31
- #: ../dashboard.php:55 ../dashboard.php:1349 ../dashboard.php:2166 ../settings.
32
- #: php:654
33
  msgid "Dashboard"
34
  msgstr ""
35
 
@@ -37,7 +37,7 @@ msgstr ""
37
  msgid "Cerber Traffic Inspector"
38
  msgstr ""
39
 
40
- #: ../dashboard.php:57 ../dashboard.php:1319 ../dashboard.php:2925
41
  msgid "Traffic Inspector"
42
  msgstr ""
43
 
@@ -45,7 +45,7 @@ msgstr ""
45
  msgid "Cerber Security Rules"
46
  msgstr ""
47
 
48
- #: ../dashboard.php:61 ../dashboard.php:2587
49
  msgid "Security Rules"
50
  msgstr ""
51
 
@@ -57,7 +57,7 @@ msgstr ""
57
  msgid "Cerber antispam settings"
58
  msgstr ""
59
 
60
- #: ../dashboard.php:69 ../cerber-load.php:4294 ../settings.php:212
61
  msgid "Antispam"
62
  msgstr ""
63
 
@@ -65,7 +65,7 @@ msgstr ""
65
  msgid "Cerber tools"
66
  msgstr ""
67
 
68
- #: ../dashboard.php:70 ../cerber-tools.php:51
69
  msgid "Tools"
70
  msgstr ""
71
 
@@ -73,16 +73,16 @@ msgstr ""
73
  msgid "Remove"
74
  msgstr ""
75
 
76
- #: ../dashboard.php:135 ../dashboard.php:781 ../dashboard.php:3328 ../cerber-load.
77
- #: php:4007
78
  msgid "IP"
79
  msgstr ""
80
 
81
- #: ../dashboard.php:136 ../dashboard.php:782
82
  msgid "Hostname"
83
  msgstr ""
84
 
85
- #: ../dashboard.php:137 ../dashboard.php:783
86
  msgid "Country"
87
  msgstr ""
88
 
@@ -90,11 +90,11 @@ msgstr ""
90
  msgid "Expires"
91
  msgstr ""
92
 
93
- #: ../dashboard.php:139 ../cerber-load.php:3465
94
  msgid "Reason"
95
  msgstr ""
96
 
97
- #: ../dashboard.php:140 ../cerber-scanner.php:5413 ../cerber-scanner.php:5544
98
  msgid "Action"
99
  msgstr ""
100
 
@@ -115,8 +115,8 @@ msgstr ""
115
  msgid "No lockouts at the moment. The sky is clear."
116
  msgstr ""
117
 
118
- #: ../dashboard.php:180 ../dashboard.php:756 ../dashboard.php:983 ../dashboard.
119
- #: php:1314 ../dashboard.php:3140 ../cerber-load.php:4281 ../settings.php:624
120
  msgid "White IP Access List"
121
  msgstr ""
122
 
@@ -124,8 +124,8 @@ msgstr ""
124
  msgid "These IPs will never be locked out"
125
  msgstr ""
126
 
127
- #: ../dashboard.php:182 ../dashboard.php:757 ../dashboard.php:986 ../dashboard.
128
- #: php:1315 ../dashboard.php:3141
129
  msgid "Black IP Access List"
130
  msgstr ""
131
 
@@ -137,8 +137,8 @@ msgstr ""
137
  msgid "Your IP"
138
  msgstr ""
139
 
140
- #: ../dashboard.php:207 ../dashboard.php:996 ../dashboard.php:1027 ../dashboard.
141
- #: php:1139
142
  msgid "Check for activities"
143
  msgstr ""
144
 
@@ -176,520 +176,524 @@ msgstr ""
176
  msgid "Address %s was added to Black IP Access List"
177
  msgstr ""
178
 
179
- #: ../dashboard.php:362 ../dashboard.php:3070 ../whois.php:225 ../whois.php:256 ..
180
- #: /common.php:995 ../common.php:1410
181
  msgid "Unknown"
182
  msgstr ""
183
 
184
- #: ../dashboard.php:401
185
  msgid "unknown"
186
  msgstr ""
187
 
188
- #: ../dashboard.php:432
189
  msgid "Email has been sent to"
190
  msgstr ""
191
 
192
- #: ../dashboard.php:435
193
  msgid "Unable to send email to"
194
  msgstr ""
195
 
196
- #: ../dashboard.php:441
197
  #, php-format
198
  msgid "Lockout for %s was removed"
199
  msgstr ""
200
 
201
- #: ../dashboard.php:460 ../dashboard.php:1997
202
  msgid "Settings saved"
203
  msgstr ""
204
 
205
- #: ../dashboard.php:571 ../dashboard.php:2976
206
  msgid "IP address"
207
  msgstr ""
208
 
209
- #: ../dashboard.php:572 ../dashboard.php:784 ../dashboard.php:2977 ../dashboard.
210
- #: php:3326
211
  msgid "Date"
212
  msgstr ""
213
 
214
- #: ../dashboard.php:573 ../dashboard.php:785
215
  msgid "Event"
216
  msgstr ""
217
 
218
- #: ../dashboard.php:574
219
  msgid "Additional Details"
220
  msgstr ""
221
 
222
- #: ../dashboard.php:575 ../dashboard.php:786 ../dashboard.php:3331
223
  msgid "Local User"
224
  msgstr ""
225
 
226
- #: ../dashboard.php:576
227
  msgid "User login"
228
  msgstr ""
229
 
230
- #: ../dashboard.php:577 ../dashboard.php:2982
231
  msgid "User ID"
232
  msgstr ""
233
 
234
- #: ../dashboard.php:578 ../dashboard.php:787 ../cerber-load.php:4015
235
  msgid "Username used"
236
  msgstr ""
237
 
238
- #: ../dashboard.php:761 ../dashboard.php:989 ../dashboard.php:3145 ../common.php:
239
- #: 940
240
  msgid "Locked out"
241
  msgstr ""
242
 
243
- #: ../dashboard.php:805 ../dashboard.php:3385
244
  msgid "Export"
245
  msgstr ""
246
 
247
- #: ../dashboard.php:809
248
  msgid "No activity has been logged."
249
  msgstr ""
250
 
251
- #: ../dashboard.php:816
252
  msgid "All events"
253
  msgstr ""
254
 
255
- #: ../dashboard.php:827
 
 
 
 
256
  msgid "Search for IP or username"
257
  msgstr ""
258
 
259
- #: ../dashboard.php:827
260
  msgid "Filter"
261
  msgstr ""
262
 
263
- #: ../dashboard.php:1023
264
  msgid "Abuse email:"
265
  msgstr ""
266
 
267
- #: ../dashboard.php:1027
268
  msgid "Network:"
269
  msgstr ""
270
 
271
- #: ../dashboard.php:1041
272
  msgid "Add network to the Black List"
273
  msgstr ""
274
 
275
- #: ../dashboard.php:1046
276
  msgid "Add IP to the Black List"
277
  msgstr ""
278
 
279
- #: ../dashboard.php:1102
280
  msgid "Activated"
281
  msgstr ""
282
 
283
- #: ../dashboard.php:1123
284
  msgid "Last seen"
285
  msgstr ""
286
 
287
- #: ../dashboard.php:1133 ../dashboard.php:1179
288
  msgid "Registered"
289
  msgstr ""
290
 
291
- #: ../dashboard.php:1176
292
  msgid "Comments"
293
  msgstr ""
294
 
295
- #: ../dashboard.php:1177
296
  msgid "Last login"
297
  msgstr ""
298
 
299
- #: ../dashboard.php:1178
300
  msgid "Failed login attempts"
301
  msgstr ""
302
 
303
- #: ../dashboard.php:1210 ../dashboard.php:1297 ../common.php:1136
304
  msgid "Never"
305
  msgstr ""
306
 
307
- #: ../dashboard.php:1249
308
  msgid "You"
309
  msgstr ""
310
 
311
- #: ../dashboard.php:1267
312
  msgid "Cerber Quick View"
313
  msgstr ""
314
 
315
- #: ../dashboard.php:1301 ../dashboard.php:1323
316
  msgid "active"
317
  msgstr ""
318
 
319
- #: ../dashboard.php:1301
320
  msgid "deactivate"
321
  msgstr ""
322
 
323
- #: ../dashboard.php:1303
324
  msgid "not active"
325
  msgstr ""
326
 
327
- #: ../dashboard.php:1304 ../dashboard.php:1318
328
  msgid "disabled"
329
  msgstr ""
330
 
331
- #: ../dashboard.php:1309
332
  msgid "failed attempts"
333
  msgstr ""
334
 
335
- #: ../dashboard.php:1309 ../dashboard.php:1310
336
  msgid "in 24 hours"
337
  msgstr ""
338
 
339
- #: ../dashboard.php:1309 ../dashboard.php:1310
340
  msgid "view all"
341
  msgstr ""
342
 
343
- #: ../dashboard.php:1310
344
  msgid "lockouts"
345
  msgstr ""
346
 
347
- #: ../dashboard.php:1312
348
  msgid "Lockouts at the moment"
349
  msgstr ""
350
 
351
- #: ../dashboard.php:1313
352
  msgid "Last lockout"
353
  msgstr ""
354
 
355
- #: ../dashboard.php:1314 ../dashboard.php:1315 ../dashboard.php:2144
356
  msgid "entry"
357
  msgid_plural "entries"
358
  msgstr[0] ""
359
  msgstr[1] ""
360
 
361
- #: ../dashboard.php:1316 ../settings.php:104
362
  msgid "Citadel mode"
363
  msgstr ""
364
 
365
- #: ../dashboard.php:1318
366
  msgid "enabled"
367
  msgstr ""
368
 
369
- #: ../dashboard.php:1323
370
  msgid "no connection"
371
  msgstr ""
372
 
373
- #: ../dashboard.php:1333
374
  msgctxt "Example: Last malware scan: 23 Jan 2018"
375
  msgid "Last malware scan"
376
  msgstr ""
377
 
378
- #: ../dashboard.php:1336 ../dashboard.php:1338 ../settings.php:290 ../settings.
379
- #: php:316 ../cerber-scanner.php:1466
380
  msgid "Disabled"
381
  msgstr ""
382
 
383
- #: ../dashboard.php:1337 ../cerber-scanner.php:915
384
  msgid "Quick Scan"
385
  msgstr ""
386
 
387
- #: ../dashboard.php:1339 ../cerber-scanner.php:915
388
  msgid "Full Scan"
389
  msgstr ""
390
 
391
- #: ../dashboard.php:1350 ../dashboard.php:1825 ../cerber-load.php:3998 ..
392
- #: /settings.php:109 ../settings.php:655
393
  msgid "Activity"
394
  msgstr ""
395
 
396
- #: ../dashboard.php:1351
397
  msgid "Traffic"
398
  msgstr ""
399
 
400
- #: ../dashboard.php:1352
401
  msgid "Integrity"
402
  msgstr ""
403
 
404
- #: ../dashboard.php:1628 ../settings.php:84
405
  msgid "My site is behind a reverse proxy"
406
  msgstr ""
407
 
408
- #: ../dashboard.php:1804
409
  msgid "in the last 24 hours"
410
  msgstr ""
411
 
412
- #: ../dashboard.php:1810 ../dashboard.php:1836
413
  msgid "View all"
414
  msgstr ""
415
 
416
- #: ../dashboard.php:1818 ../common.php:885
417
  msgid "User registered"
418
  msgstr ""
419
 
420
- #: ../dashboard.php:1819
421
  msgid "All suspicious activity"
422
  msgstr ""
423
 
424
- #: ../dashboard.php:1837
425
  msgid "Recently locked out IP addresses"
426
  msgstr ""
427
 
428
- #: ../dashboard.php:1861
429
  msgid "Confused about some settings?"
430
  msgstr ""
431
 
432
- #: ../dashboard.php:1862
433
  msgid "You can easily load default recommended settings using button below"
434
  msgstr ""
435
 
436
- #: ../dashboard.php:1864
437
  msgid "Load default settings"
438
  msgstr ""
439
 
440
- #: ../dashboard.php:1866 ../cerber-tools.php:649 ../cerber-scanner.php:5389 ..
441
- #: /cerber-scanner.php:5531
442
  msgid "Are you sure?"
443
  msgstr ""
444
 
445
- #: ../dashboard.php:1872
446
  msgid "doesn't affect Custom login URL and Access Lists"
447
  msgstr ""
448
 
449
- #: ../dashboard.php:1873 ../cerber-load.php:3497 ../cerber-load.php:4283
450
  msgid "Getting Started Guide"
451
  msgstr ""
452
 
453
- #: ../dashboard.php:1980
454
  msgid "Attention! Citadel mode is now active. Nobody is able to log in."
455
  msgstr ""
456
 
457
- #: ../dashboard.php:1981
458
  msgid "Deactivate"
459
  msgstr ""
460
 
461
- #: ../dashboard.php:1982 ../dashboard.php:2403
462
  msgid "View Activity"
463
  msgstr ""
464
 
465
- #: ../dashboard.php:2064
466
  msgid "Subscribe"
467
  msgstr ""
468
 
469
- #: ../dashboard.php:2065 ../cerber-tools.php:282
470
  msgid "Unsubscribe"
471
  msgstr ""
472
 
473
- #: ../dashboard.php:2093
474
  msgid "You've subscribed"
475
  msgstr ""
476
 
477
- #: ../dashboard.php:2096
478
  msgid "You've unsubscribed"
479
  msgstr ""
480
 
481
- #: ../dashboard.php:2167
482
  msgid "Main settings"
483
  msgstr ""
484
 
485
- #: ../dashboard.php:2271
486
  msgid "Are you sure you want to delete selected files?"
487
  msgstr ""
488
 
489
- #: ../dashboard.php:2272
490
  msgid "These files have been moved to the quarantine"
491
  msgstr ""
492
 
493
- #: ../dashboard.php:2275
494
  msgid "Do you want to add selected files to the ignore list?"
495
  msgstr ""
496
 
497
- #: ../dashboard.php:2276
498
  msgid "These files have been added to the ignore list"
499
  msgstr ""
500
 
501
- #: ../dashboard.php:2278
502
  msgid "Some errors occurred"
503
  msgstr ""
504
 
505
- #: ../dashboard.php:2279
506
  msgid "All files have been processed"
507
  msgstr ""
508
 
509
- #: ../dashboard.php:2447
510
  msgid "These features are available in a professional version of the plugin."
511
  msgstr ""
512
 
513
- #: ../dashboard.php:2448
514
  msgid "Know more about all advantages at"
515
  msgstr ""
516
 
517
- #: ../dashboard.php:2579
518
  msgid "Countries"
519
  msgstr ""
520
 
521
- #: ../dashboard.php:2648
522
  #, php-format
523
  msgid "Permitted for one country"
524
  msgid_plural "Permitted for %d countries"
525
  msgstr[0] ""
526
  msgstr[1] ""
527
 
528
- #: ../dashboard.php:2651
529
  #, php-format
530
  msgid "Not permitted for one country"
531
  msgid_plural "Not permitted for %d countries"
532
  msgstr[0] ""
533
  msgstr[1] ""
534
 
535
- #: ../dashboard.php:2659
536
  msgid "No rule"
537
  msgstr ""
538
 
539
- #: ../dashboard.php:2715
540
  msgid "Start typing here to find a country"
541
  msgstr ""
542
 
543
- #: ../dashboard.php:2798
544
  msgid "Click on a country name to add it to the list of selected countries"
545
  msgstr ""
546
 
547
- #: ../dashboard.php:2802
548
  #, php-format
549
  msgctxt "to is a marker of infinitive, e.g. \"to use it\""
550
  msgid "Selected countries are permitted to %s, other countries are not permitted to"
551
  msgstr ""
552
 
553
- #: ../dashboard.php:2805
554
  #, php-format
555
  msgctxt "to is a marker of infinitive, e.g. \"to use it\""
556
  msgid "Selected countries are not permitted to %s, other countries are permitted to"
557
  msgstr ""
558
 
559
- #: ../dashboard.php:2822
560
  msgid "Submit forms"
561
  msgstr ""
562
 
563
- #: ../dashboard.php:2823
564
  msgid "Post comments"
565
  msgstr ""
566
 
567
- #: ../dashboard.php:2824
568
  msgid "Log in to the website"
569
  msgstr ""
570
 
571
- #: ../dashboard.php:2825
572
  msgid "Register on the website"
573
  msgstr ""
574
 
575
- #: ../dashboard.php:2826
576
  msgid "Use XML-RPC"
577
  msgstr ""
578
 
579
- #: ../dashboard.php:2827
580
  msgid "Use REST API"
581
  msgstr ""
582
 
583
- #: ../dashboard.php:2871
584
  msgid "Security rules have been updated"
585
  msgstr ""
586
 
587
- #: ../dashboard.php:2916
588
  msgid "Live Traffic"
589
  msgstr ""
590
 
591
- #: ../dashboard.php:2917 ../cerber-tools.php:91 ../cerber-tools.php:100 ../cerber-
592
  #: scanner.php:76
593
  msgid "Settings"
594
  msgstr ""
595
 
596
- #: ../dashboard.php:2983
597
  msgid "Page generation time"
598
  msgstr ""
599
 
600
- #: ../dashboard.php:3327
601
  msgid "Request"
602
  msgstr ""
603
 
604
- #: ../dashboard.php:3329
605
  msgid "Host Info"
606
  msgstr ""
607
 
608
- #: ../dashboard.php:3330
609
  msgid "User Agent"
610
  msgstr ""
611
 
612
- #: ../dashboard.php:3347
613
  msgid "No requests have been logged."
614
  msgstr ""
615
 
616
- #: ../dashboard.php:3355
617
  msgid "All requests"
618
  msgstr ""
619
 
620
- #: ../dashboard.php:3357
621
  msgid "Suspicious activity"
622
  msgstr ""
623
 
624
- #: ../dashboard.php:3358
625
  msgid "Errors"
626
  msgstr ""
627
 
628
- #: ../dashboard.php:3359 ../settings.php:180
629
  msgid "Logged in users"
630
  msgstr ""
631
 
632
- #: ../dashboard.php:3360
633
  msgid "Not logged in visitors"
634
  msgstr ""
635
 
636
- #: ../dashboard.php:3363
637
  msgid "Form submissions"
638
  msgstr ""
639
 
640
- #: ../dashboard.php:3365
641
  msgid "Page Not Found"
642
  msgstr ""
643
 
644
- #: ../dashboard.php:3374
645
  msgid "Longer than"
646
  msgstr ""
647
 
648
- #: ../dashboard.php:3390
649
  msgid "Refresh"
650
  msgstr ""
651
 
652
- #: ../dashboard.php:3655
653
  msgid "Any"
654
  msgstr ""
655
 
656
- #: ../dashboard.php:3698
657
  msgid "Advanced search"
658
  msgstr ""
659
 
660
- #: ../dashboard.php:3757
661
  msgid "Antispam engine"
662
  msgstr ""
663
 
664
- #: ../dashboard.php:3766
665
  msgid "Antispam and bot detection settings"
666
  msgstr ""
667
 
668
- #: ../dashboard.php:3824
669
  msgid "Help"
670
  msgstr ""
671
 
672
- #: ../dashboard.php:3846
673
  msgid "Log In"
674
  msgstr ""
675
 
676
- #: ../dashboard.php:3847
677
  msgid "Log Out"
678
  msgstr ""
679
 
680
- #: ../dashboard.php:3848
681
  msgid "Register"
682
  msgstr ""
683
 
684
- #: ../dashboard.php:3851
685
  msgid "WooCommerce Log In"
686
  msgstr ""
687
 
688
- #: ../dashboard.php:3852
689
  msgid "WooCommerce Log Out"
690
  msgstr ""
691
 
692
- #: ../dashboard.php:3891 ../dashboard.php:3892
693
  msgid "Add to menu"
694
  msgstr ""
695
 
@@ -718,288 +722,292 @@ msgstr ""
718
  msgid "Check for requests"
719
  msgstr ""
720
 
721
- #: ../common.php:166
722
  msgid "Malicious activities mitigated"
723
  msgstr ""
724
 
725
- #: ../common.php:169
726
  msgid "Spam comments denied"
727
  msgstr ""
728
 
729
- #: ../common.php:170
730
  msgid "Spam form submissions denied"
731
  msgstr ""
732
 
733
- #: ../common.php:171
734
  msgid "Malicious IP addresses detected"
735
  msgstr ""
736
 
737
- #: ../common.php:172
738
  msgid "Lockouts occurred"
739
  msgstr ""
740
 
741
- #: ../common.php:226 ../common.php:292 ../common.php:297 ../common.php:303 ..
742
- #: /common.php:308 ../cerber-load.php:694 ../cerber-load.php:706 ../cerber-load.
743
- #: php:713 ../cerber-load.php:988 ../cerber-load.php:1215 ../cerber-load.php:1221
744
- #: ../cerber-load.php:1226 ../cerber-load.php:1231 ../cerber-load.php:1237 ..
745
- #: /cerber-load.php:1244 ../cerber-load.php:1346 ../cerber-load.php:1483 ..
746
- #: /settings.php:1061 ../settings.php:1144
747
  msgid "ERROR:"
748
  msgstr ""
749
 
750
- #: ../common.php:884
751
  msgid "User created"
752
  msgstr ""
753
 
754
- #: ../common.php:886
755
  msgid "Logged in"
756
  msgstr ""
757
 
758
- #: ../common.php:887
759
  msgid "Logged out"
760
  msgstr ""
761
 
762
- #: ../common.php:888
763
  msgid "Login failed"
764
  msgstr ""
765
 
766
- #: ../common.php:891
767
  msgid "IP blocked"
768
  msgstr ""
769
 
770
- #: ../common.php:892
771
  msgid "Subnet blocked"
772
  msgstr ""
773
 
774
- #: ../common.php:894
775
  msgid "Citadel activated!"
776
  msgstr ""
777
 
778
- #: ../common.php:895
779
  msgid "Spam comment denied"
780
  msgstr ""
781
 
782
- #: ../common.php:896
783
  msgid "Spam form submission denied"
784
  msgstr ""
785
 
786
- #: ../common.php:897
787
  msgid "Form submission denied"
788
  msgstr ""
789
 
790
- #: ../common.php:898
791
  msgid "Comment denied"
792
  msgstr ""
793
 
794
- #: ../common.php:909
795
  msgid "Password changed"
796
  msgstr ""
797
 
798
- #: ../common.php:910
799
  msgid "Password reset requested"
800
  msgstr ""
801
 
802
- #: ../common.php:912
803
  msgid "reCAPTCHA verification failed"
804
  msgstr ""
805
 
806
- #: ../common.php:913
807
  msgid "reCAPTCHA settings are incorrect"
808
  msgstr ""
809
 
810
- #: ../common.php:914
811
  msgid "Request to the Google reCAPTCHA service failed"
812
  msgstr ""
813
 
814
- #: ../common.php:916 ../common.php:999
815
  msgid "Attempt to access prohibited URL"
816
  msgstr ""
817
 
818
- #: ../common.php:917 ../common.php:979
819
  msgid "Attempt to log in with non-existent username"
820
  msgstr ""
821
 
822
- #: ../common.php:918 ../common.php:980
823
  msgid "Attempt to log in with prohibited username"
824
  msgstr ""
825
 
826
- #: ../common.php:920
827
  msgid "Attempt to log in denied"
828
  msgstr ""
829
 
830
- #: ../common.php:921
831
  msgid "Attempt to register denied"
832
  msgstr ""
833
 
834
- #: ../common.php:922 ../common.php:984
835
  msgid "Probing for vulnerable PHP code"
836
  msgstr ""
837
 
838
- #: ../common.php:923
839
  msgid "Attempt to upload malicious file denied"
840
  msgstr ""
841
 
842
- #: ../common.php:924
843
  msgid "File upload denied"
844
  msgstr ""
845
 
846
- #: ../common.php:926
847
  msgid "Request to REST API denied"
848
  msgstr ""
849
 
850
- #: ../common.php:927
851
  msgid "XML-RPC request denied"
852
  msgstr ""
853
 
854
- #: ../common.php:929
855
  msgid "Malicious request denied"
856
  msgstr ""
857
 
858
- #: ../common.php:933
859
  msgid "User activated"
860
  msgstr ""
861
 
862
- #: ../common.php:938
863
  msgid "Bot detected"
864
  msgstr ""
865
 
866
- #: ../common.php:939
867
  msgid "Citadel mode is active"
868
  msgstr ""
869
 
870
- #: ../common.php:941
871
  msgid "IP address is locked out"
872
  msgstr ""
873
 
874
- #: ../common.php:942
875
  msgid "IP blacklisted"
876
  msgstr ""
877
 
878
- #: ../common.php:944
879
  msgid "Malicious activity detected"
880
  msgstr ""
881
 
882
- #: ../common.php:945
883
  msgid "Blocked by country rule"
884
  msgstr ""
885
 
886
- #: ../common.php:946
887
  msgid "Limit reached"
888
  msgstr ""
889
 
890
- #: ../common.php:947
891
  msgid "Multiple suspicious activities"
892
  msgstr ""
893
 
894
- #: ../common.php:948
895
  msgid "Denied"
896
  msgstr ""
897
 
898
- #: ../common.php:949
899
  msgid "Suspicious number of fields"
900
  msgstr ""
901
 
902
- #: ../common.php:950
903
  msgid "Suspicious number of nested values"
904
  msgstr ""
905
 
906
- #: ../common.php:951 ../common.php:985
907
  msgid "Malicious code detected"
908
  msgstr ""
909
 
910
- #: ../common.php:952
911
  msgid "Suspicious SQL code detected"
912
  msgstr ""
913
 
914
- #: ../common.php:953
915
  msgid "Suspicious JavaScript code detected"
916
  msgstr ""
917
 
918
- #: ../common.php:977
 
 
 
 
919
  msgid "Limit on login attempts is reached"
920
  msgstr ""
921
 
922
- #: ../common.php:978
923
  msgid "Attempt to access"
924
  msgstr ""
925
 
926
- #: ../common.php:981
927
  msgid "Limit on failed reCAPTCHA verifications is reached"
928
  msgstr ""
929
 
930
- #: ../common.php:982
931
  msgid "Bot activity is detected"
932
  msgstr ""
933
 
934
- #: ../common.php:983
935
  msgid "Multiple suspicious activities were detected"
936
  msgstr ""
937
 
938
- #: ../common.php:986
939
  msgid "Attempt to upload a file with malicious code"
940
  msgstr ""
941
 
942
- #: ../common.php:988
943
  msgid "Multiple suspicious requests"
944
  msgstr ""
945
 
946
- #: ../common.php:1131
947
  #, php-format
948
  msgid "%s ago"
949
  msgstr ""
950
 
951
- #: ../common.php:1131
952
  #, php-format
953
  msgctxt "preposition of a period of time like: in 6 hours"
954
  msgid "in %s"
955
  msgstr ""
956
 
957
- #: ../common.php:1217
958
  msgid "Bytes"
959
  msgstr ""
960
 
961
- #: ../common.php:1315 ../settings.php:237
962
  msgid "New version is available"
963
  msgstr ""
964
 
965
- #: ../common.php:1322
966
  #, php-format
967
  msgid "Update to version %s of WP Cerber"
968
  msgstr ""
969
 
970
- #: ../common.php:1341
971
  msgid "Not specified"
972
  msgstr ""
973
 
974
- #: ../common.php:2167
975
  msgid "Unable to create the directory"
976
  msgstr ""
977
 
978
- #: ../common.php:2172
979
  msgid "Destination folder access denied"
980
  msgstr ""
981
 
982
- #: ../common.php:2175
983
  msgid "File not found"
984
  msgstr ""
985
 
986
- #: ../common.php:2178
987
  msgid "Unable to copy the file"
988
  msgstr ""
989
 
990
- #: ../common.php:2184
991
  msgid "Unable to delete the file"
992
  msgstr ""
993
 
994
- #: ../cerber-news.php:139
995
  msgid "Awesome!"
996
  msgstr ""
997
 
998
- #: ../cerber-lab.php:762
999
  msgid "Want to make WP Cerber even more powerful?"
1000
  msgstr ""
1001
 
1002
- #: ../cerber-lab.php:763
1003
  msgid ""
1004
  "Allow WP Cerber to send locked out malicious IP addresses to Cerber Lab. "
1005
  "This helps the plugin team to develop new algorithms for WP Cerber that will "
@@ -1007,1148 +1015,1218 @@ msgid ""
1007
  "everyday. You can disable the sending in the plugin settings at any time."
1008
  msgstr ""
1009
 
1010
- #: ../cerber-lab.php:764
1011
  msgid "OK, nail them all"
1012
  msgstr ""
1013
 
1014
- #: ../cerber-lab.php:765
1015
  msgid "NO, maybe later"
1016
  msgstr ""
1017
 
1018
- #: ../cerber-lab.php:766 ../settings.php:628 ../settings.php:631
1019
  msgid "Know more"
1020
  msgstr ""
1021
 
1022
- #: ../cerber-load.php:385
1023
  msgid "You are not allowed to log in. Ask your administrator for assistance."
1024
  msgstr ""
1025
 
1026
- #: ../cerber-load.php:392
1027
  #, php-format
1028
  msgid ""
1029
  "You have exceeded the number of allowed login attempts. Please try again in "
1030
  "%d minutes."
1031
  msgstr ""
1032
 
1033
- #: ../cerber-load.php:411
 
 
 
 
1034
  #, php-format
1035
  msgid "You have only one attempt remaining."
1036
  msgid_plural "You have %d attempts remaining."
1037
  msgstr[0] ""
1038
  msgstr[1] ""
1039
 
1040
- #: ../cerber-load.php:723
1041
  msgid ""
1042
  "Human verification failed. Please click the square box in the reCAPTCHA "
1043
  "block below."
1044
  msgstr ""
1045
 
1046
- #: ../cerber-load.php:853
1047
  msgid ""
1048
  "> > > Translator of WP Cerber? To get the PRO license for free, drop your "
1049
  "contacts here: https://wpcerber.com/contact/"
1050
  msgstr ""
1051
 
1052
- #: ../cerber-load.php:1000
1053
  #, php-format
1054
  msgid ""
1055
  "<strong>ERROR</strong>: The password you entered for the username %s is "
1056
  "incorrect."
1057
  msgstr ""
1058
 
1059
- #: ../cerber-load.php:1216 ../cerber-load.php:1222 ../cerber-load.php:1238 ..
1060
- #: /cerber-load.php:1245
1061
  msgid "You are not allowed to register."
1062
  msgstr ""
1063
 
1064
- #: ../cerber-load.php:1232
1065
  msgid "Username is not allowed. Please choose another one."
1066
  msgstr ""
1067
 
1068
- #: ../cerber-load.php:1483
1069
  msgid "Sorry, human verification failed."
1070
  msgstr ""
1071
 
1072
- #: ../cerber-load.php:3296
1073
  msgid "We're sorry, you are not allowed to proceed"
1074
  msgstr ""
1075
 
1076
- #: ../cerber-load.php:3406
1077
  msgid "WP Cerber notify"
1078
  msgstr ""
1079
 
1080
- #: ../cerber-load.php:3430
1081
  msgid "Citadel mode is activated"
1082
  msgstr ""
1083
 
1084
- #: ../cerber-load.php:3432
1085
  #, php-format
1086
  msgid "Citadel mode is activated after %d failed login attempts in %d minutes."
1087
  msgstr ""
1088
 
1089
- #: ../cerber-load.php:3433
1090
  #, php-format
1091
  msgid "Last failed attempt was at %s from IP %s with user login: %s."
1092
  msgstr ""
1093
 
1094
- #: ../cerber-load.php:3434 ../cerber-load.php:4039
1095
  msgid "View activity in dashboard"
1096
  msgstr ""
1097
 
1098
- #: ../cerber-load.php:3458
1099
  msgid "unspecified"
1100
  msgstr ""
1101
 
1102
- #: ../cerber-load.php:3461
1103
  msgid "Number of lockouts is increasing"
1104
  msgstr ""
1105
 
1106
- #: ../cerber-load.php:3463
1107
  msgid "Number of active lockouts"
1108
  msgstr ""
1109
 
1110
- #: ../cerber-load.php:3464
1111
  #, php-format
1112
  msgid "Last lockout was added: %s for IP %s"
1113
  msgstr ""
1114
 
1115
- #: ../cerber-load.php:3466
1116
  msgid "View activity for this IP"
1117
  msgstr ""
1118
 
1119
- #: ../cerber-load.php:3467
1120
  msgid "View lockouts in dashboard"
1121
  msgstr ""
1122
 
1123
- #: ../cerber-load.php:3470 ../cerber-load.php:3472
1124
  msgid "A new version of WP Cerber is available to install"
1125
  msgstr ""
1126
 
1127
- #: ../cerber-load.php:3471
1128
  msgid "Hi!"
1129
  msgstr ""
1130
 
1131
- #: ../cerber-load.php:3474 ../cerber-load.php:3485
1132
  msgid "Website"
1133
  msgstr ""
1134
 
1135
- #: ../cerber-load.php:3477 ../cerber-load.php:3478
1136
  msgid "The WP Cerber security plugin has been deactivated"
1137
  msgstr ""
1138
 
1139
- #: ../cerber-load.php:3480
1140
  msgid "Not logged in"
1141
  msgstr ""
1142
 
1143
- #: ../cerber-load.php:3486
1144
  msgid "By user"
1145
  msgstr ""
1146
 
1147
- #: ../cerber-load.php:3487
1148
  msgid "From IP address"
1149
  msgstr ""
1150
 
1151
- #: ../cerber-load.php:3490
1152
  msgid "From country"
1153
  msgstr ""
1154
 
1155
- #: ../cerber-load.php:3494
1156
  msgid "The WP Cerber security plugin is now active"
1157
  msgstr ""
1158
 
1159
- #: ../cerber-load.php:3495 ../cerber-load.php:4280
1160
  msgid "WP Cerber is now active and has started protecting your site"
1161
  msgstr ""
1162
 
1163
- #: ../cerber-load.php:3502
1164
  msgid "New Custom login URL"
1165
  msgstr ""
1166
 
1167
- #: ../cerber-load.php:3506 ../cerber-load.php:3507
1168
  msgid "A new activity has been recorded"
1169
  msgstr ""
1170
 
1171
- #: ../cerber-load.php:3512
1172
  msgid "Weekly report"
1173
  msgstr ""
1174
 
1175
- #: ../cerber-load.php:3515 ../cerber-load.php:3525
1176
  msgid "To change reporting settings visit"
1177
  msgstr ""
1178
 
1179
- #: ../cerber-load.php:3522
1180
  msgid "Scanner Report"
1181
  msgstr ""
1182
 
1183
- #: ../cerber-load.php:3548
1184
  msgid "Your login page:"
1185
  msgstr ""
1186
 
1187
- #: ../cerber-load.php:3552
1188
  msgid "Your license is valid until"
1189
  msgstr ""
1190
 
1191
- #: ../cerber-load.php:3555
1192
  msgid "This message was sent by"
1193
  msgstr ""
1194
 
1195
- #: ../cerber-load.php:3576
1196
  #, php-format
1197
  msgid "Your last sign-in was %s from %s"
1198
  msgstr ""
1199
 
1200
- #: ../cerber-load.php:3646
1201
  msgid "Weekly Report"
1202
  msgstr ""
1203
 
1204
- #: ../cerber-load.php:3658
1205
  msgid "Activity details"
1206
  msgstr ""
1207
 
1208
- #: ../cerber-load.php:3672
1209
  msgid "Attempts to log in with non-existent username"
1210
  msgstr ""
1211
 
1212
- #: ../cerber-load.php:4011
1213
  msgid "User"
1214
  msgstr ""
1215
 
1216
- #: ../cerber-load.php:4019
1217
  msgid "Search string"
1218
  msgstr ""
1219
 
1220
- #: ../cerber-load.php:4040
1221
  msgid "To unsubscribe click here"
1222
  msgstr ""
1223
 
1224
- #: ../cerber-load.php:4246
1225
  #, php-format
1226
  msgid "The WP Cerber requires PHP %s or higher. You are running"
1227
  msgstr ""
1228
 
1229
- #: ../cerber-load.php:4250
1230
  #, php-format
1231
  msgid "The WP Cerber requires WordPress %s or higher. You are running"
1232
  msgstr ""
1233
 
1234
- #: ../cerber-load.php:4259
1235
  msgid "Can't activate WP Cerber due to a database error."
1236
  msgstr ""
1237
 
1238
- #: ../cerber-load.php:4281
1239
  msgid "Your IP address is added to the"
1240
  msgstr ""
1241
 
1242
- #: ../cerber-load.php:4291 ../settings.php:657
1243
  msgid "Main Settings"
1244
  msgstr ""
1245
 
1246
- #: ../cerber-load.php:4292 ../cerber-scanner.php:75
1247
  msgid "Security Scanner"
1248
  msgstr ""
1249
 
1250
- #: ../cerber-load.php:4293 ../settings.php:658 ../cerber-tools.php:92 ../cerber-
1251
- #: tools.php:101 ../cerber-tools.php:188
1252
  msgid "Access Lists"
1253
  msgstr ""
1254
 
1255
- #: ../cerber-load.php:4295 ../settings.php:659
1256
  msgid "Hardening"
1257
  msgstr ""
1258
 
1259
- #: ../cerber-load.php:4296 ../settings.php:83 ../settings.php:107 ../settings.php:
1260
- #: 661
1261
  msgid "Notifications"
1262
  msgstr ""
1263
 
1264
- #: ../cerber-load.php:4297
1265
  msgid "Import settings"
1266
  msgstr ""
1267
 
1268
- #: ../settings.php:75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1269
  msgid "Plugin initialization"
1270
  msgstr ""
1271
 
1272
- #: ../settings.php:76
1273
  msgid "Load security engine"
1274
  msgstr ""
1275
 
1276
- #: ../settings.php:76
1277
  msgid "Legacy mode"
1278
  msgstr ""
1279
 
1280
- #: ../settings.php:76
1281
  msgid "Standard mode"
1282
  msgstr ""
1283
 
1284
- #: ../settings.php:78
1285
  msgid "Limit login attempts"
1286
  msgstr ""
1287
 
1288
- #: ../settings.php:79
1289
  msgid "Attempts"
1290
  msgstr ""
1291
 
1292
- #: ../settings.php:80
1293
  msgid "Lockout duration"
1294
  msgstr ""
1295
 
1296
- #: ../settings.php:80 ../settings.php:106
1297
  msgid "minutes"
1298
  msgstr ""
1299
 
1300
- #: ../settings.php:81
1301
  msgid "Aggressive lockout"
1302
  msgstr ""
1303
 
1304
- #: ../settings.php:82 ../settings.php:295
1305
- msgid "Use White IP Access List"
1306
- msgstr ""
1307
-
1308
- #: ../settings.php:82
1309
  msgid "Apply limit login rules to IP addresses in the White IP Access List"
1310
  msgstr ""
1311
 
1312
- #: ../settings.php:84
1313
  msgid "Site connection"
1314
  msgstr ""
1315
 
1316
- #: ../settings.php:86
1317
  msgid "Proactive security rules"
1318
  msgstr ""
1319
 
1320
- #: ../settings.php:87
1321
  msgid "Block subnet"
1322
  msgstr ""
1323
 
1324
- #: ../settings.php:87
1325
  msgid "Always block entire subnet Class C of intruders IP"
1326
  msgstr ""
1327
 
1328
- #: ../settings.php:88
1329
  msgid "Non-existent users"
1330
  msgstr ""
1331
 
1332
- #: ../settings.php:88
1333
  msgid "Immediately block IP when attempting to login with a non-existent username"
1334
  msgstr ""
1335
 
1336
- #: ../settings.php:89
1337
  msgid "Disable dashboard redirection"
1338
  msgstr ""
1339
 
1340
- #: ../settings.php:89
1341
  msgid ""
1342
  "Disable automatic redirection to the login page when /wp-admin/ is requested "
1343
  "by an unauthorized request"
1344
  msgstr ""
1345
 
1346
- #: ../settings.php:90
1347
  msgid "Request wp-login.php"
1348
  msgstr ""
1349
 
1350
- #: ../settings.php:90
1351
  msgid "Immediately block IP after any request to wp-login.php"
1352
  msgstr ""
1353
 
1354
- #: ../settings.php:91
1355
  msgid "Display 404 page"
1356
  msgstr ""
1357
 
1358
- #: ../settings.php:91
1359
  msgid "Use 404 template from the active theme"
1360
  msgstr ""
1361
 
1362
- #: ../settings.php:91
1363
  msgid "Display simple 404 page"
1364
  msgstr ""
1365
 
1366
- #: ../settings.php:93
1367
  msgid "Custom login page"
1368
  msgstr ""
1369
 
1370
- #: ../settings.php:94
1371
  msgid "Custom login URL"
1372
  msgstr ""
1373
 
1374
- #: ../settings.php:99
1375
  msgid "Custom login URL may contain only letters, numbers, dashes and underscores"
1376
  msgstr ""
1377
 
1378
- #: ../settings.php:100
1379
  msgid "must not overlap with the existing pages or posts slug"
1380
  msgstr ""
1381
 
1382
- #: ../settings.php:102
1383
  msgid "Disable wp-login.php"
1384
  msgstr ""
1385
 
1386
- #: ../settings.php:102
1387
  msgid "Block direct access to wp-login.php and return HTTP 404 Not Found Error"
1388
  msgstr ""
1389
 
1390
- #: ../settings.php:105
1391
  msgid "Threshold"
1392
  msgstr ""
1393
 
1394
- #: ../settings.php:106 ../cerber-scanner.php:3700
1395
  msgid "Duration"
1396
  msgstr ""
1397
 
1398
- #: ../settings.php:107
1399
  msgid "Send notification to admin email"
1400
  msgstr ""
1401
 
1402
- #: ../settings.php:107 ../settings.php:797 ../settings.php:919
1403
  msgid "Click to send test"
1404
  msgstr ""
1405
 
1406
- #: ../settings.php:110 ../settings.php:395
1407
  msgid "Keep records for"
1408
  msgstr ""
1409
 
1410
- #: ../settings.php:110 ../settings.php:192 ../settings.php:399 ../settings.php:470
1411
  msgid "days"
1412
  msgstr ""
1413
 
1414
- #: ../settings.php:111
1415
  msgid "Cerber Lab connection"
1416
  msgstr ""
1417
 
1418
- #: ../settings.php:111
1419
  msgid "Send malicious IP addresses to the Cerber Lab"
1420
  msgstr ""
1421
 
1422
- #: ../settings.php:112
1423
  msgid "Cerber Lab protocol"
1424
  msgstr ""
1425
 
1426
- #: ../settings.php:113
1427
  msgid "Use file"
1428
  msgstr ""
1429
 
1430
- #: ../settings.php:113
1431
  msgid "Write failed login attempts to the file"
1432
  msgstr ""
1433
 
1434
- #: ../settings.php:115
1435
  msgid "Preferences"
1436
  msgstr ""
1437
 
1438
- #: ../settings.php:116
1439
  msgid "Drill down IP"
1440
  msgstr ""
1441
 
1442
- #: ../settings.php:116
1443
  msgid "Retrieve extra WHOIS information for IP"
1444
  msgstr ""
1445
 
1446
- #: ../settings.php:117
1447
  msgid "Date format"
1448
  msgstr ""
1449
 
1450
- #: ../settings.php:117
1451
  #, php-format
1452
  msgid "if empty, the default format %s will be used"
1453
  msgstr ""
1454
 
1455
- #: ../settings.php:118
1456
  msgid "Use English for admin interface"
1457
  msgstr ""
1458
 
1459
- #: ../settings.php:124
1460
  msgid "Hardening WordPress"
1461
  msgstr ""
1462
 
1463
- #: ../settings.php:125
1464
  msgid "Stop user enumeration"
1465
  msgstr ""
1466
 
1467
- #: ../settings.php:125
1468
- msgid "Block access to user pages like /?author=n and user data via REST API"
1469
  msgstr ""
1470
 
1471
- #: ../settings.php:126
1472
  msgid "Protect admin scripts"
1473
  msgstr ""
1474
 
1475
- #: ../settings.php:126
1476
  msgid "Block unauthorized access to load-scripts.php and load-styles.php"
1477
  msgstr ""
1478
 
1479
- #: ../settings.php:129
1480
  msgid "Disable PHP in uploads"
1481
  msgstr ""
1482
 
1483
- #: ../settings.php:129
1484
  msgid "Disable execution of PHP scripts in the WordPress media folder"
1485
  msgstr ""
1486
 
1487
- #: ../settings.php:131
1488
  msgid "Disable PHP error displaying"
1489
  msgstr ""
1490
 
1491
- #: ../settings.php:133
1492
  msgid "Disable XML-RPC"
1493
  msgstr ""
1494
 
1495
- #: ../settings.php:133
1496
  msgid "Block access to the XML-RPC server (including Pingbacks and Trackbacks)"
1497
  msgstr ""
1498
 
1499
- #: ../settings.php:134
1500
  msgid "Disable feeds"
1501
  msgstr ""
1502
 
1503
- #: ../settings.php:134
1504
  msgid "Block access to the RSS, Atom and RDF feeds"
1505
  msgstr ""
1506
 
1507
- #: ../settings.php:135
1508
- msgid "Disable REST API"
1509
  msgstr ""
1510
 
1511
- #: ../settings.php:135
1512
- msgid "Block access to the WordPress REST API except the following"
1513
  msgstr ""
1514
 
1515
- #: ../settings.php:136
1516
- msgid "Allow REST API for logged in users"
1517
  msgstr ""
1518
 
1519
- #: ../settings.php:143
1520
- msgid ""
1521
- "Specify REST API namespaces to be allowed if REST API is disabled. One "
1522
- "string per line."
1523
  msgstr ""
1524
 
1525
- #: ../settings.php:153
1526
- msgid "User related settings"
1527
  msgstr ""
1528
 
1529
- #: ../settings.php:155
1530
- msgid "Registration limit"
1531
  msgstr ""
1532
 
1533
- #: ../settings.php:157
1534
- msgid "Prohibited usernames"
1535
  msgstr ""
1536
 
1537
- #: ../settings.php:163
1538
  msgid ""
1539
- "Usernames from this list are not allowed to log in or register. Any IP "
1540
- "address, have tried to use any of these usernames, will be immediately "
1541
- "blocked. Use comma to separate logins."
1542
- msgstr ""
1543
-
1544
- #: ../settings.php:163
1545
- msgid "To specify a REGEX pattern wrap a pattern in two forward slashes."
1546
- msgstr ""
1547
-
1548
- #: ../settings.php:165
1549
- msgid "User session expire"
1550
- msgstr ""
1551
-
1552
- #: ../settings.php:165
1553
- msgid "in minutes (leave empty to use default WP value)"
1554
- msgstr ""
1555
-
1556
- #: ../settings.php:166
1557
- msgid "Sort users in dashboard"
1558
- msgstr ""
1559
-
1560
- #: ../settings.php:166
1561
- msgid "by date of registration"
1562
  msgstr ""
1563
 
1564
- #: ../settings.php:173
1565
  msgid "Cerber antispam engine"
1566
  msgstr ""
1567
 
1568
- #: ../settings.php:174
1569
  msgid "Comment form"
1570
  msgstr ""
1571
 
1572
- #: ../settings.php:174
1573
  msgid "Protect comment form with bot detection engine"
1574
  msgstr ""
1575
 
1576
- #: ../settings.php:175 ../settings.php:203
1577
  msgid "Registration form"
1578
  msgstr ""
1579
 
1580
- #: ../settings.php:175
1581
  msgid "Protect registration form with bot detection engine"
1582
  msgstr ""
1583
 
1584
- #: ../settings.php:176
1585
  msgid "Other forms"
1586
  msgstr ""
1587
 
1588
- #: ../settings.php:176
1589
  msgid "Protect all forms on the website with bot detection engine"
1590
  msgstr ""
1591
 
1592
- #: ../settings.php:178
1593
  msgid "Adjust antispam engine"
1594
  msgstr ""
1595
 
1596
- #: ../settings.php:179
1597
  msgid "Safe mode"
1598
  msgstr ""
1599
 
1600
- #: ../settings.php:179
1601
  msgid "Use less restrictive policies (allow AJAX)"
1602
  msgstr ""
1603
 
1604
- #: ../settings.php:180
1605
  msgid "Disable bot detection engine for logged in users"
1606
  msgstr ""
1607
 
1608
- #: ../settings.php:181
1609
  msgid "Query whitelist"
1610
  msgstr ""
1611
 
1612
- #: ../settings.php:187
1613
  msgid ""
1614
  "Enter a part of query string or query path to exclude a request from "
1615
  "inspection by the engine. One item per line."
1616
  msgstr ""
1617
 
1618
- #: ../settings.php:187 ../settings.php:306
1619
  msgid "To specify a REGEX pattern, enclose a whole line in two braces."
1620
  msgstr ""
1621
 
1622
- #: ../settings.php:190
1623
  msgid "Comment processing"
1624
  msgstr ""
1625
 
1626
- #: ../settings.php:191
1627
  msgid "If a spam comment detected"
1628
  msgstr ""
1629
 
1630
- #: ../settings.php:191
1631
  msgid "Deny it completely"
1632
  msgstr ""
1633
 
1634
- #: ../settings.php:191
1635
  msgid "Mark it as spam"
1636
  msgstr ""
1637
 
1638
- #: ../settings.php:192
1639
  msgid "Trash spam comments"
1640
  msgstr ""
1641
 
1642
- #: ../settings.php:192
1643
  msgid "Move spam comments to trash after"
1644
  msgstr ""
1645
 
1646
- #: ../settings.php:198
1647
  msgid "reCAPTCHA settings"
1648
  msgstr ""
1649
 
1650
- #: ../settings.php:199
1651
  msgid "Site key"
1652
  msgstr ""
1653
 
1654
- #: ../settings.php:200
1655
  msgid "Secret key"
1656
  msgstr ""
1657
 
1658
- #: ../settings.php:201
1659
  msgid "Invisible reCAPTCHA"
1660
  msgstr ""
1661
 
1662
- #: ../settings.php:201
1663
  msgid "Enable invisible reCAPTCHA"
1664
  msgstr ""
1665
 
1666
- #: ../settings.php:201
1667
  msgid ""
1668
  "(do not enable it unless you get and enter the Site and Secret keys for the "
1669
  "invisible version)"
1670
  msgstr ""
1671
 
1672
- #: ../settings.php:203
1673
  msgid "Enable reCAPTCHA for WordPress registration form"
1674
  msgstr ""
1675
 
1676
- #: ../settings.php:204
1677
  msgid "Enable reCAPTCHA for WooCommerce registration form"
1678
  msgstr ""
1679
 
1680
- #: ../settings.php:206
1681
  msgid "Lost password form"
1682
  msgstr ""
1683
 
1684
- #: ../settings.php:206
1685
  msgid "Enable reCAPTCHA for WordPress lost password form"
1686
  msgstr ""
1687
 
1688
- #: ../settings.php:207
1689
  msgid "Enable reCAPTCHA for WooCommerce lost password form"
1690
  msgstr ""
1691
 
1692
- #: ../settings.php:209
1693
  msgid "Login form"
1694
  msgstr ""
1695
 
1696
- #: ../settings.php:209
1697
  msgid "Enable reCAPTCHA for WordPress login form"
1698
  msgstr ""
1699
 
1700
- #: ../settings.php:210
1701
  msgid "Enable reCAPTCHA for WooCommerce login form"
1702
  msgstr ""
1703
 
1704
- #: ../settings.php:212
1705
  msgid "Enable reCAPTCHA for WordPress comment form"
1706
  msgstr ""
1707
 
1708
- #: ../settings.php:213
1709
  msgid "Disable reCAPTCHA for logged in users"
1710
  msgstr ""
1711
 
1712
- #: ../settings.php:215
1713
  msgid "Limit attempts"
1714
  msgstr ""
1715
 
1716
- #: ../settings.php:215
1717
  #, php-format
1718
  msgid "Lock out IP address for %s minutes after %s failed attempts within %s minutes"
1719
  msgstr ""
1720
 
1721
- #: ../settings.php:221
1722
  msgid "Email notifications"
1723
  msgstr ""
1724
 
1725
- #: ../settings.php:224 ../settings.php:265 ../settings.php:532
1726
  msgid "Email Address"
1727
  msgstr ""
1728
 
1729
- #: ../settings.php:228 ../settings.php:270 ../settings.php:358 ../settings.php:536
1730
  msgid "Use comma to specify multiple values"
1731
  msgstr ""
1732
 
1733
- #: ../settings.php:233
1734
  #, php-format
1735
  msgid "if empty, the admin email %s will be used"
1736
  msgstr ""
1737
 
1738
- #: ../settings.php:236
1739
  msgid "Notification limit"
1740
  msgstr ""
1741
 
1742
- #: ../settings.php:236
1743
  msgid "notification letters allowed per hour (0 means unlimited)"
1744
  msgstr ""
1745
 
1746
- #: ../settings.php:242
1747
  msgid "Push notifications"
1748
  msgstr ""
1749
 
1750
- #: ../settings.php:250
1751
  msgid "All connected devices"
1752
  msgstr ""
1753
 
1754
- #: ../settings.php:253
1755
  msgid "No devices found"
1756
  msgstr ""
1757
 
1758
- #: ../settings.php:257
1759
  msgid "Not available"
1760
  msgstr ""
1761
 
1762
- #: ../settings.php:262
1763
  msgid "Weekly reports"
1764
  msgstr ""
1765
 
1766
- #: ../settings.php:263
1767
  msgid "Enable reporting"
1768
  msgstr ""
1769
 
1770
- #: ../settings.php:275 ../settings.php:541
1771
  msgid "if empty, email from notification settings will be used"
1772
  msgstr ""
1773
 
1774
- #: ../settings.php:283
1775
  msgid "Traffic Inspection"
1776
  msgstr ""
1777
 
1778
- #: ../settings.php:284
1779
  msgid "Enable traffic inspection"
1780
  msgstr ""
1781
 
1782
- #: ../settings.php:291 ../settings.php:317
1783
  msgid "Maximum compatibility"
1784
  msgstr ""
1785
 
1786
- #: ../settings.php:292 ../settings.php:318
1787
  msgid "Maximum security"
1788
  msgstr ""
1789
 
1790
- #: ../settings.php:300
1791
  msgid "Request whitelist"
1792
  msgstr ""
1793
 
1794
- #: ../settings.php:306
1795
  msgid ""
1796
  "Enter a request URI to exclude the request from inspection. One item per "
1797
  "line."
1798
  msgstr ""
1799
 
1800
- #: ../settings.php:309
1801
  msgid "Erroneous Request Shielding"
1802
  msgstr ""
1803
 
1804
- #: ../settings.php:310
1805
  msgid "Enable error shielding"
1806
  msgstr ""
1807
 
1808
- #: ../settings.php:321
1809
- msgid "Disable for logged in users"
1810
  msgstr ""
1811
 
1812
- #: ../settings.php:328
1813
  msgid "Logging"
1814
  msgstr ""
1815
 
1816
- #: ../settings.php:329
1817
  msgid "Logging mode"
1818
  msgstr ""
1819
 
1820
- #: ../settings.php:335
1821
  msgid "Logging disabled"
1822
  msgstr ""
1823
 
1824
- #: ../settings.php:336
1825
  msgid "Smart"
1826
  msgstr ""
1827
 
1828
- #: ../settings.php:337
1829
  msgid "All traffic"
1830
  msgstr ""
1831
 
1832
- #: ../settings.php:341
1833
  msgid "Ignore crawlers"
1834
  msgstr ""
1835
 
1836
- #: ../settings.php:346
1837
  msgid "Save request fields"
1838
  msgstr ""
1839
 
1840
- #: ../settings.php:351
1841
  msgid "Mask these form fields"
1842
  msgstr ""
1843
 
1844
- #: ../settings.php:363
1845
  msgid "Save request headers"
1846
  msgstr ""
1847
 
1848
- #: ../settings.php:369
1849
  msgid "Save $_SERVER"
1850
  msgstr ""
1851
 
1852
- #: ../settings.php:375
1853
  msgid "Save request cookies"
1854
  msgstr ""
1855
 
1856
- #: ../settings.php:381
1857
  msgid "Save software errors"
1858
  msgstr ""
1859
 
1860
- #: ../settings.php:387
1861
  msgid "Page generation time threshold"
1862
  msgstr ""
1863
 
1864
- #: ../settings.php:392
1865
  msgid "milliseconds"
1866
  msgstr ""
1867
 
1868
- #: ../settings.php:408
1869
  msgid "Scanner settings"
1870
  msgstr ""
1871
 
1872
- #: ../settings.php:409
1873
  msgid "Custom signatures"
1874
  msgstr ""
1875
 
1876
- #: ../settings.php:415
1877
  msgid ""
1878
  "Specify custom PHP code signatures. One item per line. To specify a REGEX "
1879
  "pattern, enclose a whole line in two braces."
1880
  msgstr ""
1881
 
1882
- #: ../settings.php:417
1883
  msgid "Unwanted file extensions"
1884
  msgstr ""
1885
 
1886
- #: ../settings.php:423
1887
  msgid ""
1888
  "Specify file extensions to search for. Full scan only. Use comma to separate "
1889
  "items."
1890
  msgstr ""
1891
 
1892
- #: ../settings.php:425
1893
  msgid "Directories to exclude"
1894
  msgstr ""
1895
 
1896
- #: ../settings.php:431
1897
  msgid ""
1898
  "Specify directories to exclude from scanning. Use absolute paths. One item "
1899
  "per line."
1900
  msgstr ""
1901
 
1902
- #: ../settings.php:433
1903
  msgid "Monitor new files"
1904
  msgstr ""
1905
 
1906
- #: ../settings.php:440
1907
  msgid "Monitor modified files"
1908
  msgstr ""
1909
 
1910
- #: ../settings.php:446
1911
  msgid "Scan temporary directory"
1912
  msgstr ""
1913
 
1914
- #: ../settings.php:453
1915
  msgid "Scan session directory"
1916
  msgstr ""
1917
 
1918
- #: ../settings.php:459
1919
  msgid "Enable diagnostic log"
1920
  msgstr ""
1921
 
1922
- #: ../settings.php:465
1923
  msgid "Delete quarantined files after"
1924
  msgstr ""
1925
 
1926
- #: ../settings.php:479
1927
  msgid "Automated recurring scan schedule"
1928
  msgstr ""
1929
 
1930
- #: ../settings.php:480
1931
  msgid "Launch Quick Scan"
1932
  msgstr ""
1933
 
1934
- #: ../settings.php:487
1935
  msgid "Launch Full Scan"
1936
  msgstr ""
1937
 
1938
- #: ../settings.php:495
1939
  msgid "Scan results reporting"
1940
  msgstr ""
1941
 
1942
- #: ../settings.php:497 ../settings.php:557
1943
  msgid "Low severity"
1944
  msgstr ""
1945
 
1946
- #: ../settings.php:497 ../settings.php:557
1947
  msgid "Medium severity"
1948
  msgstr ""
1949
 
1950
- #: ../settings.php:497 ../settings.php:557
1951
  msgid "High severity"
1952
  msgstr ""
1953
 
1954
- #: ../settings.php:498
1955
  msgid "Report an issue if any of the following is true"
1956
  msgstr ""
1957
 
1958
- #: ../settings.php:506
1959
  msgid "Send email report"
1960
  msgstr ""
1961
 
1962
- #: ../settings.php:512
1963
  msgid "After every scan"
1964
  msgstr ""
1965
 
1966
- #: ../settings.php:513
1967
  msgid "If any changes in scan results occurred"
1968
  msgstr ""
1969
 
1970
- #: ../settings.php:514
1971
  msgid "If new issues found"
1972
  msgstr ""
1973
 
1974
- #: ../settings.php:518
1975
  msgid "Include file sizes"
1976
  msgstr ""
1977
 
1978
- #: ../settings.php:525
1979
  msgid "Include scan errors"
1980
  msgstr ""
1981
 
1982
- #: ../settings.php:549
1983
  msgid "Automatic cleanup of malware and suspicious files"
1984
  msgstr ""
1985
 
1986
- #: ../settings.php:551 ../cerber-scanner.php:3732
1987
  msgid "Unattended files"
1988
  msgstr ""
1989
 
1990
- #: ../settings.php:558
1991
  msgid "Files in the uploads folder"
1992
  msgstr ""
1993
 
1994
- #: ../settings.php:565
1995
  msgid "Files with unwanted extensions"
1996
  msgstr ""
1997
 
1998
- #: ../settings.php:572
1999
  msgid "Exclusions"
2000
  msgstr ""
2001
 
2002
- #: ../settings.php:573
2003
  msgid "Files in the temporary directory"
2004
  msgstr ""
2005
 
2006
- #: ../settings.php:579
2007
  msgid "Files in the sessions directory"
2008
  msgstr ""
2009
 
2010
- #: ../settings.php:585
2011
  msgid "Files in these directories"
2012
  msgstr ""
2013
 
2014
- #: ../settings.php:591
2015
  msgid "Use absolute paths. One item per line."
2016
  msgstr ""
2017
 
2018
- #: ../settings.php:593
2019
  msgid "Files with these extensions"
2020
  msgstr ""
2021
 
2022
- #: ../settings.php:599
2023
  msgid "Use comma to separate items."
2024
  msgstr ""
2025
 
2026
- #: ../settings.php:610
2027
  msgid "Make your protection smarter!"
2028
  msgstr ""
2029
 
2030
- #: ../settings.php:614
2031
  msgid ""
2032
  "Please enable Permalinks to use this feature. Set Permalink Settings to "
2033
  "something other than Default."
2034
  msgstr ""
2035
 
2036
- #: ../settings.php:617
2037
  msgid "Be careful about enabling these options."
2038
  msgstr ""
2039
 
2040
- #: ../settings.php:617
2041
  msgid "If you forget your Custom login URL, you will be unable to log in."
2042
  msgstr ""
2043
 
2044
- #: ../settings.php:621
2045
  msgid ""
2046
  "In the Citadel mode nobody is able to log in except IPs from the White IP "
2047
  "Access List. Active user sessions will not be affected."
2048
  msgstr ""
2049
 
2050
- #: ../settings.php:624
2051
- msgid "These settings do not affect hosts from the "
2052
  msgstr ""
2053
 
2054
- #: ../settings.php:627
2055
  msgid ""
2056
  "Before you can start using reCAPTCHA, you have to obtain Site key and Secret "
2057
  "key on the Google website"
2058
  msgstr ""
2059
 
2060
- #: ../settings.php:656
2061
  msgid "Lockouts"
2062
  msgstr ""
2063
 
2064
- #: ../settings.php:660
2065
  msgid "Users"
2066
  msgstr ""
2067
 
2068
- #: ../settings.php:778 ../settings.php:900
2069
  #, php-format
2070
  msgid "%s allowed retries in %s minutes"
2071
  msgstr ""
2072
 
2073
- #: ../settings.php:783 ../settings.php:905
2074
  #, php-format
2075
  msgid "%s allowed registrations in %s minutes from one IP"
2076
  msgstr ""
2077
 
2078
- #: ../settings.php:788 ../settings.php:910
2079
  #, php-format
2080
  msgid "Increase lockout duration to %s hours after %s lockouts in the last %s hours"
2081
  msgstr ""
2082
 
2083
- #: ../settings.php:795 ../settings.php:917
2084
  msgid "Notify admin if the number of active lockouts above"
2085
  msgstr ""
2086
 
2087
- #: ../settings.php:800 ../settings.php:922
2088
  #, php-format
2089
  msgid "Enable after %s failed login attempts in last %s minutes"
2090
  msgstr ""
2091
 
2092
- #: ../settings.php:1019
 
 
 
 
2093
  msgid "Sunday"
2094
  msgstr ""
2095
 
2096
- #: ../settings.php:1020
2097
  msgid "Monday"
2098
  msgstr ""
2099
 
2100
- #: ../settings.php:1021
2101
  msgid "Tuesday"
2102
  msgstr ""
2103
 
2104
- #: ../settings.php:1022
2105
  msgid "Wednesday"
2106
  msgstr ""
2107
 
2108
- #: ../settings.php:1023
2109
  msgid "Thursday"
2110
  msgstr ""
2111
 
2112
- #: ../settings.php:1024
2113
  msgid "Friday"
2114
  msgstr ""
2115
 
2116
- #: ../settings.php:1025
2117
  msgid "Saturday"
2118
  msgstr ""
2119
 
2120
- #: ../settings.php:1035
2121
  msgctxt "preposition of time like: at 11:00"
2122
  msgid "at"
2123
  msgstr ""
2124
 
2125
- #: ../settings.php:1051
2126
  msgid "Click to send now"
2127
  msgstr ""
2128
 
2129
- #: ../settings.php:1062
2130
  msgid "Plugin initialization mode has not been changed"
2131
  msgstr ""
2132
 
2133
- #: ../settings.php:1082 ../settings.php:1083
2134
  msgid "Attention! You have changed the login URL! The new login URL is"
2135
  msgstr ""
2136
 
2137
- #: ../settings.php:1084 ../settings.php:1085
2138
  msgid ""
2139
  "If you use a caching plugin, you have to add your new login URL to the list "
2140
  "of pages not to cache."
2141
  msgstr ""
2142
 
2143
- #: ../settings.php:1168 ../settings.php:1180 ../settings.php:1303
2144
  msgid "<strong>ERROR</strong>: please enter a valid email address."
2145
  msgstr ""
2146
 
2147
- #: ../settings.php:1309
2148
  msgid "The schedule has been updated"
2149
  msgstr ""
2150
 
2151
- #: ../settings.php:1312
2152
  msgid "Unable to update the schedule"
2153
  msgstr ""
2154
 
@@ -2161,71 +2239,75 @@ msgid "Diagnostic"
2161
  msgstr ""
2162
 
2163
  #: ../cerber-tools.php:42
2164
- msgid "License"
2165
  msgstr ""
2166
 
2167
  #: ../cerber-tools.php:43
2168
- msgid "Log"
2169
  msgstr ""
2170
 
2171
- #: ../cerber-tools.php:88
 
 
 
 
2172
  msgid "Export settings to the file"
2173
  msgstr ""
2174
 
2175
- #: ../cerber-tools.php:89
2176
  msgid ""
2177
  "When you click the button below you will get a configuration file, which you "
2178
  "can upload on another site."
2179
  msgstr ""
2180
 
2181
- #: ../cerber-tools.php:90
2182
  msgid "What do you want to export?"
2183
  msgstr ""
2184
 
2185
- #: ../cerber-tools.php:93
2186
  msgid "Download file"
2187
  msgstr ""
2188
 
2189
- #: ../cerber-tools.php:95
2190
  msgid "Import settings from the file"
2191
  msgstr ""
2192
 
2193
- #: ../cerber-tools.php:96
2194
  msgid ""
2195
  "When you click the button below, file will be uploaded and all existing "
2196
  "settings will be overridden."
2197
  msgstr ""
2198
 
2199
- #: ../cerber-tools.php:97
2200
  msgid "Select file to import."
2201
  msgstr ""
2202
 
2203
- #: ../cerber-tools.php:97 ../cerber-scanner.php:3900
2204
  #, php-format
2205
  msgid "Maximum upload file size: %s."
2206
  msgstr ""
2207
 
2208
- #: ../cerber-tools.php:100
2209
  msgid "What do you want to import?"
2210
  msgstr ""
2211
 
2212
- #: ../cerber-tools.php:102 ../cerber-scanner.php:3903
2213
  msgid "Upload file"
2214
  msgstr ""
2215
 
2216
- #: ../cerber-tools.php:151
2217
  msgid "No file was uploaded or file is corrupted"
2218
  msgstr ""
2219
 
2220
- #: ../cerber-tools.php:188
2221
  msgid "Error while updating"
2222
  msgstr ""
2223
 
2224
- #: ../cerber-tools.php:194
2225
  msgid "Settings has imported successfully from"
2226
  msgstr ""
2227
 
2228
- #: ../cerber-tools.php:201
2229
  msgid "Error while parsing file"
2230
  msgstr ""
2231
 
@@ -2320,7 +2402,7 @@ msgstr ""
2320
  msgid "Unable to process file"
2321
  msgstr ""
2322
 
2323
- #: ../cerber-scanner.php:1432 ../cerber-scanner.php:4791
2324
  msgid "Unable to open file"
2325
  msgstr ""
2326
 
@@ -2344,7 +2426,7 @@ msgstr ""
2344
  msgid "Executable code found"
2345
  msgstr ""
2346
 
2347
- #: ../cerber-scanner.php:1443 ../cerber-scanner.php:2666
2348
  msgid "Suspicious directives found"
2349
  msgstr ""
2350
 
@@ -2372,24 +2454,24 @@ msgstr ""
2372
  msgid "Every 6 hours"
2373
  msgstr ""
2374
 
2375
- #: ../cerber-scanner.php:2486
2376
  msgid "Custom signature found"
2377
  msgstr ""
2378
 
2379
- #: ../cerber-scanner.php:2661
2380
  msgid ""
2381
  "This file contains executable code and may contain obfuscated malware. If "
2382
  "this file is a part of a theme or a plugin, it must be located in the theme "
2383
  "or the plugin folder. No exception, no excuses."
2384
  msgstr ""
2385
 
2386
- #: ../cerber-scanner.php:2662
2387
  msgid ""
2388
  "The scanner recognizes this file as \"ownerless\" or \"not bundled\" because it "
2389
  "does not belong to any known part of the website and should not be here."
2390
  msgstr ""
2391
 
2392
- #: ../cerber-scanner.php:2663
2393
  #, php-format
2394
  msgid ""
2395
  "It may remain after upgrading to a newer version of %s. It also may be a "
@@ -2397,15 +2479,15 @@ msgid ""
2397
  "made (bespoke) plugin or theme."
2398
  msgstr ""
2399
 
2400
- #: ../cerber-scanner.php:2664
2401
  msgid "Suspicious code instruction found"
2402
  msgstr ""
2403
 
2404
- #: ../cerber-scanner.php:2665
2405
  msgid "Suspicious code signatures found"
2406
  msgstr ""
2407
 
2408
- #: ../cerber-scanner.php:2667
2409
  msgid ""
2410
  "The contents of the file have been changed and do not match what exists in "
2411
  "the official WordPress repository or a reference file you have uploaded "
@@ -2413,235 +2495,235 @@ msgid ""
2413
  "has been tampered with."
2414
  msgstr ""
2415
 
2416
- #: ../cerber-scanner.php:2668
2417
  #, php-format
2418
  msgid ""
2419
  "To solve this issue you have to reinstall %s or update it to the latest "
2420
  "version."
2421
  msgstr ""
2422
 
2423
- #: ../cerber-scanner.php:2669
2424
  msgid "Please upload a reference ZIP archive"
2425
  msgstr ""
2426
 
2427
- #: ../cerber-scanner.php:2670
2428
  msgid "Resolve issue"
2429
  msgstr ""
2430
 
2431
- #: ../cerber-scanner.php:3606
2432
  msgid "Preparing for the scan"
2433
  msgstr ""
2434
 
2435
- #: ../cerber-scanner.php:3607
2436
  msgid "Scanning folders for files"
2437
  msgstr ""
2438
 
2439
- #: ../cerber-scanner.php:3608
2440
  msgid "Scanning the upload folder for files"
2441
  msgstr ""
2442
 
2443
- #: ../cerber-scanner.php:3609
2444
  msgid "Scanning the temp folder for files"
2445
  msgstr ""
2446
 
2447
- #: ../cerber-scanner.php:3610
2448
  msgid "Scanning the session folder for files"
2449
  msgstr ""
2450
 
2451
- #: ../cerber-scanner.php:3611
2452
  msgid "Parsing the list of files"
2453
  msgstr ""
2454
 
2455
- #: ../cerber-scanner.php:3612
2456
  msgid "Checking for new and modified files"
2457
  msgstr ""
2458
 
2459
- #: ../cerber-scanner.php:3613
2460
  msgid "Verifying the integrity of WordPress"
2461
  msgstr ""
2462
 
2463
- #: ../cerber-scanner.php:3614
2464
  msgid "Verifying the integrity of the plugins"
2465
  msgstr ""
2466
 
2467
- #: ../cerber-scanner.php:3615
2468
  msgid "Verifying the integrity of the themes"
2469
  msgstr ""
2470
 
2471
- #: ../cerber-scanner.php:3616
2472
  msgid "Searching for malicious code"
2473
  msgstr ""
2474
 
2475
- #: ../cerber-scanner.php:3617
2476
  msgid "Finalizing the scan"
2477
  msgstr ""
2478
 
2479
- #: ../cerber-scanner.php:3692
2480
  msgid "Started"
2481
  msgstr ""
2482
 
2483
- #: ../cerber-scanner.php:3696
2484
  msgid "Finished"
2485
  msgstr ""
2486
 
2487
- #: ../cerber-scanner.php:3704
2488
  msgid "Performance"
2489
  msgstr ""
2490
 
2491
- #: ../cerber-scanner.php:3716
2492
  msgid "Vulnerabilities"
2493
  msgstr ""
2494
 
2495
- #: ../cerber-scanner.php:3720
2496
  msgid "New files"
2497
  msgstr ""
2498
 
2499
- #: ../cerber-scanner.php:3724
2500
  msgid "Changed files"
2501
  msgstr ""
2502
 
2503
- #: ../cerber-scanner.php:3728
2504
  msgid "Unwanted extensions"
2505
  msgstr ""
2506
 
2507
- #: ../cerber-scanner.php:3741 ../cerber-scanner.php:5408
2508
  msgid "Scanned"
2509
  msgstr ""
2510
 
2511
- #: ../cerber-scanner.php:3741 ../cerber-scanner.php:3811
2512
  msgid "Files to scan"
2513
  msgstr ""
2514
 
2515
- #: ../cerber-scanner.php:3748 ../cerber-scanner.php:3819
2516
  msgid "Critical issues"
2517
  msgstr ""
2518
 
2519
- #: ../cerber-scanner.php:3748 ../cerber-scanner.php:3823 ../cerber-scanner.php:4981
2520
  msgid "Issues total"
2521
  msgstr ""
2522
 
2523
- #: ../cerber-scanner.php:3897
2524
  msgid "We have not found any integrity data to verify"
2525
  msgstr ""
2526
 
2527
- #: ../cerber-scanner.php:3899
2528
  msgid ""
2529
  "You have to upload a ZIP archive from which you've installed it. This "
2530
  "enables the security scanner to verify the integrity of the code and detect "
2531
  "malware."
2532
  msgstr ""
2533
 
2534
- #: ../cerber-scanner.php:4186
2535
  msgid "The directory is not writable"
2536
  msgstr ""
2537
 
2538
- #: ../cerber-scanner.php:4204
2539
  msgid "Unable to create WP CERBER directory"
2540
  msgstr ""
2541
 
2542
- #: ../cerber-scanner.php:4410
2543
  msgid ""
2544
  "File access error. Possibly scan results are outdated. Please run Quick or "
2545
  "Full Scan."
2546
  msgstr ""
2547
 
2548
- #: ../cerber-scanner.php:4937
2549
  msgid "Full Scan Report"
2550
  msgstr ""
2551
 
2552
- #: ../cerber-scanner.php:4937
2553
  msgid "Quick Scan Report"
2554
  msgstr ""
2555
 
2556
- #: ../cerber-scanner.php:4950
2557
  msgid "Files scanned"
2558
  msgstr ""
2559
 
2560
- #: ../cerber-scanner.php:5031
2561
  msgid "Deleted"
2562
  msgstr ""
2563
 
2564
- #: ../cerber-scanner.php:5078
2565
  msgid "Automatically moved to quarantine"
2566
  msgstr ""
2567
 
2568
- #: ../cerber-scanner.php:5090
2569
  msgid "To view full report visit"
2570
  msgstr ""
2571
 
2572
- #: ../cerber-scanner.php:5318
2573
  msgid "There are no files in the quarantine at the moment."
2574
  msgstr ""
2575
 
2576
- #: ../cerber-scanner.php:5379
2577
  msgid "No files match the specified filter."
2578
  msgstr ""
2579
 
2580
- #: ../cerber-scanner.php:5379
2581
  msgid "Click here to see the full list of files"
2582
  msgstr ""
2583
 
2584
- #: ../cerber-scanner.php:5396
2585
  msgid "Delete permanently"
2586
  msgstr ""
2587
 
2588
- #: ../cerber-scanner.php:5401
2589
  msgid "Restore"
2590
  msgstr ""
2591
 
2592
- #: ../cerber-scanner.php:5409
2593
  msgid "Moved to quarantine"
2594
  msgstr ""
2595
 
2596
- #: ../cerber-scanner.php:5410
2597
  msgid "Automatic deletion"
2598
  msgstr ""
2599
 
2600
- #: ../cerber-scanner.php:5411
2601
  msgid "Size"
2602
  msgstr ""
2603
 
2604
- #: ../cerber-scanner.php:5412 ../cerber-scanner.php:5543
2605
  msgid "File"
2606
  msgstr ""
2607
 
2608
- #: ../cerber-scanner.php:5426
2609
  msgid "All scans"
2610
  msgstr ""
2611
 
2612
- #: ../cerber-scanner.php:5480
2613
  msgid "The file has been deleted permanently."
2614
  msgstr ""
2615
 
2616
- #: ../cerber-scanner.php:5489
2617
  msgid "The file has been restored to its original location."
2618
  msgstr ""
2619
 
2620
- #: ../cerber-scanner.php:5511
2621
  msgid "Apply"
2622
  msgstr ""
2623
 
2624
- #: ../cerber-scanner.php:5512 ../cerber-scanner.php:5537
2625
  msgid "Remove from the list"
2626
  msgstr ""
2627
 
2628
- #: ../cerber-scanner.php:5513
2629
  msgid "User Insights"
2630
  msgstr ""
2631
 
2632
- #: ../cerber-scanner.php:5514
2633
  msgid "Traffic Insights"
2634
  msgstr ""
2635
 
2636
- #: ../cerber-scanner.php:5515
2637
  msgid "Activity Insights"
2638
  msgstr ""
2639
 
2640
- #: ../cerber-scanner.php:5517
2641
  msgid "The list is empty."
2642
  msgstr ""
2643
 
2644
- #: ../cerber-scanner.php:5542
2645
  msgid "Added"
2646
  msgstr ""
2647
 
5
  "Project-Id-Version: WP Cerber\n"
6
  "Report-Msgid-Bugs-To: \n"
7
  "POT-Creation-Date: Tue Sep 08 2015 21:38:11 GMT+0300\n"
8
+ "POT-Revision-Date: Thu Jan 10 2019 20:26:13 GMT+0300 (Moscow Standard Time)\n"
9
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
10
  "Last-Translator: \n"
11
  "Language-Team: \n"
28
  msgid "Cerber Dashboard"
29
  msgstr ""
30
 
31
+ #: ../dashboard.php:55 ../dashboard.php:1376 ../dashboard.php:2193 ../settings.
32
+ #: php:1169
33
  msgid "Dashboard"
34
  msgstr ""
35
 
37
  msgid "Cerber Traffic Inspector"
38
  msgstr ""
39
 
40
+ #: ../dashboard.php:57 ../dashboard.php:1346 ../dashboard.php:2983
41
  msgid "Traffic Inspector"
42
  msgstr ""
43
 
45
  msgid "Cerber Security Rules"
46
  msgstr ""
47
 
48
+ #: ../dashboard.php:61 ../dashboard.php:2645
49
  msgid "Security Rules"
50
  msgstr ""
51
 
57
  msgid "Cerber antispam settings"
58
  msgstr ""
59
 
60
+ #: ../dashboard.php:69 ../cerber-load.php:4401 ../settings.php:713
61
  msgid "Antispam"
62
  msgstr ""
63
 
65
  msgid "Cerber tools"
66
  msgstr ""
67
 
68
+ #: ../dashboard.php:70 ../cerber-tools.php:52
69
  msgid "Tools"
70
  msgstr ""
71
 
73
  msgid "Remove"
74
  msgstr ""
75
 
76
+ #: ../dashboard.php:135 ../dashboard.php:797 ../dashboard.php:3387 ../cerber-load.
77
+ #: php:4114
78
  msgid "IP"
79
  msgstr ""
80
 
81
+ #: ../dashboard.php:136 ../dashboard.php:798
82
  msgid "Hostname"
83
  msgstr ""
84
 
85
+ #: ../dashboard.php:137 ../dashboard.php:799
86
  msgid "Country"
87
  msgstr ""
88
 
90
  msgid "Expires"
91
  msgstr ""
92
 
93
+ #: ../dashboard.php:139 ../cerber-load.php:3573
94
  msgid "Reason"
95
  msgstr ""
96
 
97
+ #: ../dashboard.php:140 ../cerber-scanner.php:5428 ../cerber-scanner.php:5559
98
  msgid "Action"
99
  msgstr ""
100
 
115
  msgid "No lockouts at the moment. The sky is clear."
116
  msgstr ""
117
 
118
+ #: ../dashboard.php:180 ../dashboard.php:772 ../dashboard.php:1001 ../dashboard.
119
+ #: php:1341 ../dashboard.php:3199 ../cerber-load.php:4388
120
  msgid "White IP Access List"
121
  msgstr ""
122
 
124
  msgid "These IPs will never be locked out"
125
  msgstr ""
126
 
127
+ #: ../dashboard.php:182 ../dashboard.php:773 ../dashboard.php:1004 ../dashboard.
128
+ #: php:1342 ../dashboard.php:3200
129
  msgid "Black IP Access List"
130
  msgstr ""
131
 
137
  msgid "Your IP"
138
  msgstr ""
139
 
140
+ #: ../dashboard.php:207 ../dashboard.php:1014 ../dashboard.php:1045 ../dashboard.
141
+ #: php:1159
142
  msgid "Check for activities"
143
  msgstr ""
144
 
176
  msgid "Address %s was added to Black IP Access List"
177
  msgstr ""
178
 
179
+ #: ../dashboard.php:362 ../dashboard.php:3128 ../whois.php:225 ../whois.php:256 ..
180
+ #: /common.php:1044 ../common.php:1459
181
  msgid "Unknown"
182
  msgstr ""
183
 
184
+ #: ../dashboard.php:415
185
  msgid "unknown"
186
  msgstr ""
187
 
188
+ #: ../dashboard.php:446
189
  msgid "Email has been sent to"
190
  msgstr ""
191
 
192
+ #: ../dashboard.php:449
193
  msgid "Unable to send email to"
194
  msgstr ""
195
 
196
+ #: ../dashboard.php:455
197
  #, php-format
198
  msgid "Lockout for %s was removed"
199
  msgstr ""
200
 
201
+ #: ../dashboard.php:474 ../dashboard.php:2024
202
  msgid "Settings saved"
203
  msgstr ""
204
 
205
+ #: ../dashboard.php:585 ../dashboard.php:3034
206
  msgid "IP address"
207
  msgstr ""
208
 
209
+ #: ../dashboard.php:586 ../dashboard.php:800 ../dashboard.php:3035 ../dashboard.
210
+ #: php:3385
211
  msgid "Date"
212
  msgstr ""
213
 
214
+ #: ../dashboard.php:587 ../dashboard.php:801
215
  msgid "Event"
216
  msgstr ""
217
 
218
+ #: ../dashboard.php:588
219
  msgid "Additional Details"
220
  msgstr ""
221
 
222
+ #: ../dashboard.php:589 ../dashboard.php:802 ../dashboard.php:3390
223
  msgid "Local User"
224
  msgstr ""
225
 
226
+ #: ../dashboard.php:590
227
  msgid "User login"
228
  msgstr ""
229
 
230
+ #: ../dashboard.php:591 ../dashboard.php:3040
231
  msgid "User ID"
232
  msgstr ""
233
 
234
+ #: ../dashboard.php:592 ../dashboard.php:803 ../cerber-load.php:4122
235
  msgid "Username used"
236
  msgstr ""
237
 
238
+ #: ../dashboard.php:777 ../dashboard.php:1007 ../dashboard.php:3204 ../common.php:
239
+ #: 988
240
  msgid "Locked out"
241
  msgstr ""
242
 
243
+ #: ../dashboard.php:821 ../dashboard.php:3444
244
  msgid "Export"
245
  msgstr ""
246
 
247
+ #: ../dashboard.php:825
248
  msgid "No activity has been logged."
249
  msgstr ""
250
 
251
+ #: ../dashboard.php:832
252
  msgid "All events"
253
  msgstr ""
254
 
255
+ #: ../dashboard.php:843
256
+ msgid "Filter by registered user"
257
+ msgstr ""
258
+
259
+ #: ../dashboard.php:844
260
  msgid "Search for IP or username"
261
  msgstr ""
262
 
263
+ #: ../dashboard.php:845
264
  msgid "Filter"
265
  msgstr ""
266
 
267
+ #: ../dashboard.php:1041
268
  msgid "Abuse email:"
269
  msgstr ""
270
 
271
+ #: ../dashboard.php:1045
272
  msgid "Network:"
273
  msgstr ""
274
 
275
+ #: ../dashboard.php:1059
276
  msgid "Add network to the Black List"
277
  msgstr ""
278
 
279
+ #: ../dashboard.php:1064
280
  msgid "Add IP to the Black List"
281
  msgstr ""
282
 
283
+ #: ../dashboard.php:1122
284
  msgid "Activated"
285
  msgstr ""
286
 
287
+ #: ../dashboard.php:1143
288
  msgid "Last seen"
289
  msgstr ""
290
 
291
+ #: ../dashboard.php:1153 ../dashboard.php:1206
292
  msgid "Registered"
293
  msgstr ""
294
 
295
+ #: ../dashboard.php:1203
296
  msgid "Comments"
297
  msgstr ""
298
 
299
+ #: ../dashboard.php:1204
300
  msgid "Last login"
301
  msgstr ""
302
 
303
+ #: ../dashboard.php:1205
304
  msgid "Failed login attempts"
305
  msgstr ""
306
 
307
+ #: ../dashboard.php:1237 ../dashboard.php:1324 ../common.php:1185
308
  msgid "Never"
309
  msgstr ""
310
 
311
+ #: ../dashboard.php:1276 ../cerber-users.php:25
312
  msgid "You"
313
  msgstr ""
314
 
315
+ #: ../dashboard.php:1294
316
  msgid "Cerber Quick View"
317
  msgstr ""
318
 
319
+ #: ../dashboard.php:1328 ../dashboard.php:1350
320
  msgid "active"
321
  msgstr ""
322
 
323
+ #: ../dashboard.php:1328
324
  msgid "deactivate"
325
  msgstr ""
326
 
327
+ #: ../dashboard.php:1330
328
  msgid "not active"
329
  msgstr ""
330
 
331
+ #: ../dashboard.php:1331 ../dashboard.php:1345
332
  msgid "disabled"
333
  msgstr ""
334
 
335
+ #: ../dashboard.php:1336
336
  msgid "failed attempts"
337
  msgstr ""
338
 
339
+ #: ../dashboard.php:1336 ../dashboard.php:1337
340
  msgid "in 24 hours"
341
  msgstr ""
342
 
343
+ #: ../dashboard.php:1336 ../dashboard.php:1337
344
  msgid "view all"
345
  msgstr ""
346
 
347
+ #: ../dashboard.php:1337
348
  msgid "lockouts"
349
  msgstr ""
350
 
351
+ #: ../dashboard.php:1339
352
  msgid "Lockouts at the moment"
353
  msgstr ""
354
 
355
+ #: ../dashboard.php:1340
356
  msgid "Last lockout"
357
  msgstr ""
358
 
359
+ #: ../dashboard.php:1341 ../dashboard.php:1342 ../dashboard.php:2171
360
  msgid "entry"
361
  msgid_plural "entries"
362
  msgstr[0] ""
363
  msgstr[1] ""
364
 
365
+ #: ../dashboard.php:1343 ../settings.php:371
366
  msgid "Citadel mode"
367
  msgstr ""
368
 
369
+ #: ../dashboard.php:1345
370
  msgid "enabled"
371
  msgstr ""
372
 
373
+ #: ../dashboard.php:1350
374
  msgid "no connection"
375
  msgstr ""
376
 
377
+ #: ../dashboard.php:1360
378
  msgctxt "Example: Last malware scan: 23 Jan 2018"
379
  msgid "Last malware scan"
380
  msgstr ""
381
 
382
+ #: ../dashboard.php:1363 ../dashboard.php:1365 ../settings.php:806 ../settings.
383
+ #: php:832 ../cerber-scanner.php:1466
384
  msgid "Disabled"
385
  msgstr ""
386
 
387
+ #: ../dashboard.php:1364 ../cerber-scanner.php:915
388
  msgid "Quick Scan"
389
  msgstr ""
390
 
391
+ #: ../dashboard.php:1366 ../cerber-scanner.php:915
392
  msgid "Full Scan"
393
  msgstr ""
394
 
395
+ #: ../dashboard.php:1377 ../dashboard.php:1852 ../cerber-load.php:4105 ..
396
+ #: /settings.php:397 ../settings.php:1170
397
  msgid "Activity"
398
  msgstr ""
399
 
400
+ #: ../dashboard.php:1378
401
  msgid "Traffic"
402
  msgstr ""
403
 
404
+ #: ../dashboard.php:1379
405
  msgid "Integrity"
406
  msgstr ""
407
 
408
+ #: ../dashboard.php:1655 ../settings.php:314
409
  msgid "My site is behind a reverse proxy"
410
  msgstr ""
411
 
412
+ #: ../dashboard.php:1831
413
  msgid "in the last 24 hours"
414
  msgstr ""
415
 
416
+ #: ../dashboard.php:1837 ../dashboard.php:1863
417
  msgid "View all"
418
  msgstr ""
419
 
420
+ #: ../dashboard.php:1845 ../common.php:933
421
  msgid "User registered"
422
  msgstr ""
423
 
424
+ #: ../dashboard.php:1846
425
  msgid "All suspicious activity"
426
  msgstr ""
427
 
428
+ #: ../dashboard.php:1864
429
  msgid "Recently locked out IP addresses"
430
  msgstr ""
431
 
432
+ #: ../dashboard.php:1888
433
  msgid "Confused about some settings?"
434
  msgstr ""
435
 
436
+ #: ../dashboard.php:1889
437
  msgid "You can easily load default recommended settings using button below"
438
  msgstr ""
439
 
440
+ #: ../dashboard.php:1891
441
  msgid "Load default settings"
442
  msgstr ""
443
 
444
+ #: ../dashboard.php:1893 ../cerber-tools.php:654 ../cerber-scanner.php:5404 ..
445
+ #: /cerber-scanner.php:5546
446
  msgid "Are you sure?"
447
  msgstr ""
448
 
449
+ #: ../dashboard.php:1899
450
  msgid "doesn't affect Custom login URL and Access Lists"
451
  msgstr ""
452
 
453
+ #: ../dashboard.php:1900 ../cerber-load.php:3605 ../cerber-load.php:4390
454
  msgid "Getting Started Guide"
455
  msgstr ""
456
 
457
+ #: ../dashboard.php:2007
458
  msgid "Attention! Citadel mode is now active. Nobody is able to log in."
459
  msgstr ""
460
 
461
+ #: ../dashboard.php:2008
462
  msgid "Deactivate"
463
  msgstr ""
464
 
465
+ #: ../dashboard.php:2009 ../dashboard.php:2429
466
  msgid "View Activity"
467
  msgstr ""
468
 
469
+ #: ../dashboard.php:2091
470
  msgid "Subscribe"
471
  msgstr ""
472
 
473
+ #: ../dashboard.php:2092 ../cerber-tools.php:286
474
  msgid "Unsubscribe"
475
  msgstr ""
476
 
477
+ #: ../dashboard.php:2120
478
  msgid "You've subscribed"
479
  msgstr ""
480
 
481
+ #: ../dashboard.php:2123
482
  msgid "You've unsubscribed"
483
  msgstr ""
484
 
485
+ #: ../dashboard.php:2194
486
  msgid "Main settings"
487
  msgstr ""
488
 
489
+ #: ../dashboard.php:2298
490
  msgid "Are you sure you want to delete selected files?"
491
  msgstr ""
492
 
493
+ #: ../dashboard.php:2299
494
  msgid "These files have been moved to the quarantine"
495
  msgstr ""
496
 
497
+ #: ../dashboard.php:2302
498
  msgid "Do you want to add selected files to the ignore list?"
499
  msgstr ""
500
 
501
+ #: ../dashboard.php:2303
502
  msgid "These files have been added to the ignore list"
503
  msgstr ""
504
 
505
+ #: ../dashboard.php:2305
506
  msgid "Some errors occurred"
507
  msgstr ""
508
 
509
+ #: ../dashboard.php:2306
510
  msgid "All files have been processed"
511
  msgstr ""
512
 
513
+ #: ../dashboard.php:2505
514
  msgid "These features are available in a professional version of the plugin."
515
  msgstr ""
516
 
517
+ #: ../dashboard.php:2506
518
  msgid "Know more about all advantages at"
519
  msgstr ""
520
 
521
+ #: ../dashboard.php:2637
522
  msgid "Countries"
523
  msgstr ""
524
 
525
+ #: ../dashboard.php:2706
526
  #, php-format
527
  msgid "Permitted for one country"
528
  msgid_plural "Permitted for %d countries"
529
  msgstr[0] ""
530
  msgstr[1] ""
531
 
532
+ #: ../dashboard.php:2709
533
  #, php-format
534
  msgid "Not permitted for one country"
535
  msgid_plural "Not permitted for %d countries"
536
  msgstr[0] ""
537
  msgstr[1] ""
538
 
539
+ #: ../dashboard.php:2717
540
  msgid "No rule"
541
  msgstr ""
542
 
543
+ #: ../dashboard.php:2773
544
  msgid "Start typing here to find a country"
545
  msgstr ""
546
 
547
+ #: ../dashboard.php:2856
548
  msgid "Click on a country name to add it to the list of selected countries"
549
  msgstr ""
550
 
551
+ #: ../dashboard.php:2860
552
  #, php-format
553
  msgctxt "to is a marker of infinitive, e.g. \"to use it\""
554
  msgid "Selected countries are permitted to %s, other countries are not permitted to"
555
  msgstr ""
556
 
557
+ #: ../dashboard.php:2863
558
  #, php-format
559
  msgctxt "to is a marker of infinitive, e.g. \"to use it\""
560
  msgid "Selected countries are not permitted to %s, other countries are permitted to"
561
  msgstr ""
562
 
563
+ #: ../dashboard.php:2880
564
  msgid "Submit forms"
565
  msgstr ""
566
 
567
+ #: ../dashboard.php:2881
568
  msgid "Post comments"
569
  msgstr ""
570
 
571
+ #: ../dashboard.php:2882
572
  msgid "Log in to the website"
573
  msgstr ""
574
 
575
+ #: ../dashboard.php:2883
576
  msgid "Register on the website"
577
  msgstr ""
578
 
579
+ #: ../dashboard.php:2884
580
  msgid "Use XML-RPC"
581
  msgstr ""
582
 
583
+ #: ../dashboard.php:2885
584
  msgid "Use REST API"
585
  msgstr ""
586
 
587
+ #: ../dashboard.php:2929
588
  msgid "Security rules have been updated"
589
  msgstr ""
590
 
591
+ #: ../dashboard.php:2974
592
  msgid "Live Traffic"
593
  msgstr ""
594
 
595
+ #: ../dashboard.php:2975 ../cerber-tools.php:95 ../cerber-tools.php:104 ../cerber-
596
  #: scanner.php:76
597
  msgid "Settings"
598
  msgstr ""
599
 
600
+ #: ../dashboard.php:3041
601
  msgid "Page generation time"
602
  msgstr ""
603
 
604
+ #: ../dashboard.php:3386
605
  msgid "Request"
606
  msgstr ""
607
 
608
+ #: ../dashboard.php:3388
609
  msgid "Host Info"
610
  msgstr ""
611
 
612
+ #: ../dashboard.php:3389
613
  msgid "User Agent"
614
  msgstr ""
615
 
616
+ #: ../dashboard.php:3406
617
  msgid "No requests have been logged."
618
  msgstr ""
619
 
620
+ #: ../dashboard.php:3414
621
  msgid "All requests"
622
  msgstr ""
623
 
624
+ #: ../dashboard.php:3416
625
  msgid "Suspicious activity"
626
  msgstr ""
627
 
628
+ #: ../dashboard.php:3417
629
  msgid "Errors"
630
  msgstr ""
631
 
632
+ #: ../dashboard.php:3418 ../settings.php:512 ../settings.php:619
633
  msgid "Logged in users"
634
  msgstr ""
635
 
636
+ #: ../dashboard.php:3419
637
  msgid "Not logged in visitors"
638
  msgstr ""
639
 
640
+ #: ../dashboard.php:3422
641
  msgid "Form submissions"
642
  msgstr ""
643
 
644
+ #: ../dashboard.php:3424
645
  msgid "Page Not Found"
646
  msgstr ""
647
 
648
+ #: ../dashboard.php:3433
649
  msgid "Longer than"
650
  msgstr ""
651
 
652
+ #: ../dashboard.php:3449
653
  msgid "Refresh"
654
  msgstr ""
655
 
656
+ #: ../dashboard.php:3714
657
  msgid "Any"
658
  msgstr ""
659
 
660
+ #: ../dashboard.php:3757
661
  msgid "Advanced search"
662
  msgstr ""
663
 
664
+ #: ../dashboard.php:3816
665
  msgid "Antispam engine"
666
  msgstr ""
667
 
668
+ #: ../dashboard.php:3825
669
  msgid "Antispam and bot detection settings"
670
  msgstr ""
671
 
672
+ #: ../dashboard.php:3884
673
  msgid "Help"
674
  msgstr ""
675
 
676
+ #: ../dashboard.php:3906
677
  msgid "Log In"
678
  msgstr ""
679
 
680
+ #: ../dashboard.php:3907
681
  msgid "Log Out"
682
  msgstr ""
683
 
684
+ #: ../dashboard.php:3908
685
  msgid "Register"
686
  msgstr ""
687
 
688
+ #: ../dashboard.php:3911
689
  msgid "WooCommerce Log In"
690
  msgstr ""
691
 
692
+ #: ../dashboard.php:3912
693
  msgid "WooCommerce Log Out"
694
  msgstr ""
695
 
696
+ #: ../dashboard.php:3951 ../dashboard.php:3952
697
  msgid "Add to menu"
698
  msgstr ""
699
 
722
  msgid "Check for requests"
723
  msgstr ""
724
 
725
+ #: ../common.php:192
726
  msgid "Malicious activities mitigated"
727
  msgstr ""
728
 
729
+ #: ../common.php:195
730
  msgid "Spam comments denied"
731
  msgstr ""
732
 
733
+ #: ../common.php:196
734
  msgid "Spam form submissions denied"
735
  msgstr ""
736
 
737
+ #: ../common.php:197
738
  msgid "Malicious IP addresses detected"
739
  msgstr ""
740
 
741
+ #: ../common.php:198
742
  msgid "Lockouts occurred"
743
  msgstr ""
744
 
745
+ #: ../common.php:252 ../common.php:318 ../common.php:323 ../common.php:329 ..
746
+ #: /common.php:334 ../cerber-load.php:696 ../cerber-load.php:708 ../cerber-load.
747
+ #: php:715 ../cerber-load.php:1024 ../cerber-load.php:1293 ../cerber-load.php:
748
+ #: 1299 ../cerber-load.php:1304 ../cerber-load.php:1309 ../cerber-load.php:1315 ..
749
+ #: /cerber-load.php:1322 ../cerber-load.php:1424 ../cerber-load.php:1561 ..
750
+ #: /settings.php:1532 ../settings.php:1617
751
  msgid "ERROR:"
752
  msgstr ""
753
 
754
+ #: ../common.php:932
755
  msgid "User created"
756
  msgstr ""
757
 
758
+ #: ../common.php:934
759
  msgid "Logged in"
760
  msgstr ""
761
 
762
+ #: ../common.php:935
763
  msgid "Logged out"
764
  msgstr ""
765
 
766
+ #: ../common.php:936
767
  msgid "Login failed"
768
  msgstr ""
769
 
770
+ #: ../common.php:939
771
  msgid "IP blocked"
772
  msgstr ""
773
 
774
+ #: ../common.php:940
775
  msgid "Subnet blocked"
776
  msgstr ""
777
 
778
+ #: ../common.php:942
779
  msgid "Citadel activated!"
780
  msgstr ""
781
 
782
+ #: ../common.php:943
783
  msgid "Spam comment denied"
784
  msgstr ""
785
 
786
+ #: ../common.php:944
787
  msgid "Spam form submission denied"
788
  msgstr ""
789
 
790
+ #: ../common.php:945
791
  msgid "Form submission denied"
792
  msgstr ""
793
 
794
+ #: ../common.php:946
795
  msgid "Comment denied"
796
  msgstr ""
797
 
798
+ #: ../common.php:957
799
  msgid "Password changed"
800
  msgstr ""
801
 
802
+ #: ../common.php:958
803
  msgid "Password reset requested"
804
  msgstr ""
805
 
806
+ #: ../common.php:960
807
  msgid "reCAPTCHA verification failed"
808
  msgstr ""
809
 
810
+ #: ../common.php:961
811
  msgid "reCAPTCHA settings are incorrect"
812
  msgstr ""
813
 
814
+ #: ../common.php:962
815
  msgid "Request to the Google reCAPTCHA service failed"
816
  msgstr ""
817
 
818
+ #: ../common.php:964 ../common.php:1048
819
  msgid "Attempt to access prohibited URL"
820
  msgstr ""
821
 
822
+ #: ../common.php:965 ../common.php:1028
823
  msgid "Attempt to log in with non-existent username"
824
  msgstr ""
825
 
826
+ #: ../common.php:966 ../common.php:1029
827
  msgid "Attempt to log in with prohibited username"
828
  msgstr ""
829
 
830
+ #: ../common.php:968
831
  msgid "Attempt to log in denied"
832
  msgstr ""
833
 
834
+ #: ../common.php:969
835
  msgid "Attempt to register denied"
836
  msgstr ""
837
 
838
+ #: ../common.php:970 ../common.php:1033
839
  msgid "Probing for vulnerable PHP code"
840
  msgstr ""
841
 
842
+ #: ../common.php:971
843
  msgid "Attempt to upload malicious file denied"
844
  msgstr ""
845
 
846
+ #: ../common.php:972
847
  msgid "File upload denied"
848
  msgstr ""
849
 
850
+ #: ../common.php:974
851
  msgid "Request to REST API denied"
852
  msgstr ""
853
 
854
+ #: ../common.php:975
855
  msgid "XML-RPC request denied"
856
  msgstr ""
857
 
858
+ #: ../common.php:977
859
  msgid "Malicious request denied"
860
  msgstr ""
861
 
862
+ #: ../common.php:981
863
  msgid "User activated"
864
  msgstr ""
865
 
866
+ #: ../common.php:986
867
  msgid "Bot detected"
868
  msgstr ""
869
 
870
+ #: ../common.php:987
871
  msgid "Citadel mode is active"
872
  msgstr ""
873
 
874
+ #: ../common.php:989
875
  msgid "IP address is locked out"
876
  msgstr ""
877
 
878
+ #: ../common.php:990
879
  msgid "IP blacklisted"
880
  msgstr ""
881
 
882
+ #: ../common.php:992
883
  msgid "Malicious activity detected"
884
  msgstr ""
885
 
886
+ #: ../common.php:993
887
  msgid "Blocked by country rule"
888
  msgstr ""
889
 
890
+ #: ../common.php:994
891
  msgid "Limit reached"
892
  msgstr ""
893
 
894
+ #: ../common.php:995
895
  msgid "Multiple suspicious activities"
896
  msgstr ""
897
 
898
+ #: ../common.php:996
899
  msgid "Denied"
900
  msgstr ""
901
 
902
+ #: ../common.php:997
903
  msgid "Suspicious number of fields"
904
  msgstr ""
905
 
906
+ #: ../common.php:998
907
  msgid "Suspicious number of nested values"
908
  msgstr ""
909
 
910
+ #: ../common.php:999 ../common.php:1034
911
  msgid "Malicious code detected"
912
  msgstr ""
913
 
914
+ #: ../common.php:1000
915
  msgid "Suspicious SQL code detected"
916
  msgstr ""
917
 
918
+ #: ../common.php:1001
919
  msgid "Suspicious JavaScript code detected"
920
  msgstr ""
921
 
922
+ #: ../common.php:1002
923
+ msgid "Blocked by administrator"
924
+ msgstr ""
925
+
926
+ #: ../common.php:1026
927
  msgid "Limit on login attempts is reached"
928
  msgstr ""
929
 
930
+ #: ../common.php:1027
931
  msgid "Attempt to access"
932
  msgstr ""
933
 
934
+ #: ../common.php:1030
935
  msgid "Limit on failed reCAPTCHA verifications is reached"
936
  msgstr ""
937
 
938
+ #: ../common.php:1031
939
  msgid "Bot activity is detected"
940
  msgstr ""
941
 
942
+ #: ../common.php:1032
943
  msgid "Multiple suspicious activities were detected"
944
  msgstr ""
945
 
946
+ #: ../common.php:1035
947
  msgid "Attempt to upload a file with malicious code"
948
  msgstr ""
949
 
950
+ #: ../common.php:1037
951
  msgid "Multiple suspicious requests"
952
  msgstr ""
953
 
954
+ #: ../common.php:1180
955
  #, php-format
956
  msgid "%s ago"
957
  msgstr ""
958
 
959
+ #: ../common.php:1180
960
  #, php-format
961
  msgctxt "preposition of a period of time like: in 6 hours"
962
  msgid "in %s"
963
  msgstr ""
964
 
965
+ #: ../common.php:1266
966
  msgid "Bytes"
967
  msgstr ""
968
 
969
+ #: ../common.php:1364 ../settings.php:754
970
  msgid "New version is available"
971
  msgstr ""
972
 
973
+ #: ../common.php:1371
974
  #, php-format
975
  msgid "Update to version %s of WP Cerber"
976
  msgstr ""
977
 
978
+ #: ../common.php:1390
979
  msgid "Not specified"
980
  msgstr ""
981
 
982
+ #: ../common.php:2216
983
  msgid "Unable to create the directory"
984
  msgstr ""
985
 
986
+ #: ../common.php:2221
987
  msgid "Destination folder access denied"
988
  msgstr ""
989
 
990
+ #: ../common.php:2224
991
  msgid "File not found"
992
  msgstr ""
993
 
994
+ #: ../common.php:2227
995
  msgid "Unable to copy the file"
996
  msgstr ""
997
 
998
+ #: ../common.php:2233
999
  msgid "Unable to delete the file"
1000
  msgstr ""
1001
 
1002
+ #: ../cerber-news.php:147
1003
  msgid "Awesome!"
1004
  msgstr ""
1005
 
1006
+ #: ../cerber-lab.php:770
1007
  msgid "Want to make WP Cerber even more powerful?"
1008
  msgstr ""
1009
 
1010
+ #: ../cerber-lab.php:771
1011
  msgid ""
1012
  "Allow WP Cerber to send locked out malicious IP addresses to Cerber Lab. "
1013
  "This helps the plugin team to develop new algorithms for WP Cerber that will "
1015
  "everyday. You can disable the sending in the plugin settings at any time."
1016
  msgstr ""
1017
 
1018
+ #: ../cerber-lab.php:772
1019
  msgid "OK, nail them all"
1020
  msgstr ""
1021
 
1022
+ #: ../cerber-lab.php:773
1023
  msgid "NO, maybe later"
1024
  msgstr ""
1025
 
1026
+ #: ../cerber-lab.php:774 ../settings.php:1143 ../settings.php:1146
1027
  msgid "Know more"
1028
  msgstr ""
1029
 
1030
+ #: ../cerber-load.php:388
1031
  msgid "You are not allowed to log in. Ask your administrator for assistance."
1032
  msgstr ""
1033
 
1034
+ #: ../cerber-load.php:394
1035
  #, php-format
1036
  msgid ""
1037
  "You have exceeded the number of allowed login attempts. Please try again in "
1038
  "%d minutes."
1039
  msgstr ""
1040
 
1041
+ #: ../cerber-load.php:398
1042
+ msgid "You are not allowed to log in"
1043
+ msgstr ""
1044
+
1045
+ #: ../cerber-load.php:413
1046
  #, php-format
1047
  msgid "You have only one attempt remaining."
1048
  msgid_plural "You have %d attempts remaining."
1049
  msgstr[0] ""
1050
  msgstr[1] ""
1051
 
1052
+ #: ../cerber-load.php:725
1053
  msgid ""
1054
  "Human verification failed. Please click the square box in the reCAPTCHA "
1055
  "block below."
1056
  msgstr ""
1057
 
1058
+ #: ../cerber-load.php:855
1059
  msgid ""
1060
  "> > > Translator of WP Cerber? To get the PRO license for free, drop your "
1061
  "contacts here: https://wpcerber.com/contact/"
1062
  msgstr ""
1063
 
1064
+ #: ../cerber-load.php:1036
1065
  #, php-format
1066
  msgid ""
1067
  "<strong>ERROR</strong>: The password you entered for the username %s is "
1068
  "incorrect."
1069
  msgstr ""
1070
 
1071
+ #: ../cerber-load.php:1294 ../cerber-load.php:1300 ../cerber-load.php:1316 ..
1072
+ #: /cerber-load.php:1323
1073
  msgid "You are not allowed to register."
1074
  msgstr ""
1075
 
1076
+ #: ../cerber-load.php:1310
1077
  msgid "Username is not allowed. Please choose another one."
1078
  msgstr ""
1079
 
1080
+ #: ../cerber-load.php:1561
1081
  msgid "Sorry, human verification failed."
1082
  msgstr ""
1083
 
1084
+ #: ../cerber-load.php:3404
1085
  msgid "We're sorry, you are not allowed to proceed"
1086
  msgstr ""
1087
 
1088
+ #: ../cerber-load.php:3514
1089
  msgid "WP Cerber notify"
1090
  msgstr ""
1091
 
1092
+ #: ../cerber-load.php:3538
1093
  msgid "Citadel mode is activated"
1094
  msgstr ""
1095
 
1096
+ #: ../cerber-load.php:3540
1097
  #, php-format
1098
  msgid "Citadel mode is activated after %d failed login attempts in %d minutes."
1099
  msgstr ""
1100
 
1101
+ #: ../cerber-load.php:3541
1102
  #, php-format
1103
  msgid "Last failed attempt was at %s from IP %s with user login: %s."
1104
  msgstr ""
1105
 
1106
+ #: ../cerber-load.php:3542 ../cerber-load.php:4146
1107
  msgid "View activity in dashboard"
1108
  msgstr ""
1109
 
1110
+ #: ../cerber-load.php:3566
1111
  msgid "unspecified"
1112
  msgstr ""
1113
 
1114
+ #: ../cerber-load.php:3569
1115
  msgid "Number of lockouts is increasing"
1116
  msgstr ""
1117
 
1118
+ #: ../cerber-load.php:3571
1119
  msgid "Number of active lockouts"
1120
  msgstr ""
1121
 
1122
+ #: ../cerber-load.php:3572
1123
  #, php-format
1124
  msgid "Last lockout was added: %s for IP %s"
1125
  msgstr ""
1126
 
1127
+ #: ../cerber-load.php:3574
1128
  msgid "View activity for this IP"
1129
  msgstr ""
1130
 
1131
+ #: ../cerber-load.php:3575
1132
  msgid "View lockouts in dashboard"
1133
  msgstr ""
1134
 
1135
+ #: ../cerber-load.php:3578 ../cerber-load.php:3580
1136
  msgid "A new version of WP Cerber is available to install"
1137
  msgstr ""
1138
 
1139
+ #: ../cerber-load.php:3579
1140
  msgid "Hi!"
1141
  msgstr ""
1142
 
1143
+ #: ../cerber-load.php:3582 ../cerber-load.php:3593
1144
  msgid "Website"
1145
  msgstr ""
1146
 
1147
+ #: ../cerber-load.php:3585 ../cerber-load.php:3586
1148
  msgid "The WP Cerber security plugin has been deactivated"
1149
  msgstr ""
1150
 
1151
+ #: ../cerber-load.php:3588
1152
  msgid "Not logged in"
1153
  msgstr ""
1154
 
1155
+ #: ../cerber-load.php:3594
1156
  msgid "By user"
1157
  msgstr ""
1158
 
1159
+ #: ../cerber-load.php:3595
1160
  msgid "From IP address"
1161
  msgstr ""
1162
 
1163
+ #: ../cerber-load.php:3598
1164
  msgid "From country"
1165
  msgstr ""
1166
 
1167
+ #: ../cerber-load.php:3602
1168
  msgid "The WP Cerber security plugin is now active"
1169
  msgstr ""
1170
 
1171
+ #: ../cerber-load.php:3603 ../cerber-load.php:4387
1172
  msgid "WP Cerber is now active and has started protecting your site"
1173
  msgstr ""
1174
 
1175
+ #: ../cerber-load.php:3610
1176
  msgid "New Custom login URL"
1177
  msgstr ""
1178
 
1179
+ #: ../cerber-load.php:3614 ../cerber-load.php:3615
1180
  msgid "A new activity has been recorded"
1181
  msgstr ""
1182
 
1183
+ #: ../cerber-load.php:3620
1184
  msgid "Weekly report"
1185
  msgstr ""
1186
 
1187
+ #: ../cerber-load.php:3623 ../cerber-load.php:3633
1188
  msgid "To change reporting settings visit"
1189
  msgstr ""
1190
 
1191
+ #: ../cerber-load.php:3630
1192
  msgid "Scanner Report"
1193
  msgstr ""
1194
 
1195
+ #: ../cerber-load.php:3656
1196
  msgid "Your login page:"
1197
  msgstr ""
1198
 
1199
+ #: ../cerber-load.php:3660
1200
  msgid "Your license is valid until"
1201
  msgstr ""
1202
 
1203
+ #: ../cerber-load.php:3663
1204
  msgid "This message was sent by"
1205
  msgstr ""
1206
 
1207
+ #: ../cerber-load.php:3684
1208
  #, php-format
1209
  msgid "Your last sign-in was %s from %s"
1210
  msgstr ""
1211
 
1212
+ #: ../cerber-load.php:3754
1213
  msgid "Weekly Report"
1214
  msgstr ""
1215
 
1216
+ #: ../cerber-load.php:3766
1217
  msgid "Activity details"
1218
  msgstr ""
1219
 
1220
+ #: ../cerber-load.php:3780
1221
  msgid "Attempts to log in with non-existent username"
1222
  msgstr ""
1223
 
1224
+ #: ../cerber-load.php:4118
1225
  msgid "User"
1226
  msgstr ""
1227
 
1228
+ #: ../cerber-load.php:4126
1229
  msgid "Search string"
1230
  msgstr ""
1231
 
1232
+ #: ../cerber-load.php:4147
1233
  msgid "To unsubscribe click here"
1234
  msgstr ""
1235
 
1236
+ #: ../cerber-load.php:4353
1237
  #, php-format
1238
  msgid "The WP Cerber requires PHP %s or higher. You are running"
1239
  msgstr ""
1240
 
1241
+ #: ../cerber-load.php:4357
1242
  #, php-format
1243
  msgid "The WP Cerber requires WordPress %s or higher. You are running"
1244
  msgstr ""
1245
 
1246
+ #: ../cerber-load.php:4366
1247
  msgid "Can't activate WP Cerber due to a database error."
1248
  msgstr ""
1249
 
1250
+ #: ../cerber-load.php:4388
1251
  msgid "Your IP address is added to the"
1252
  msgstr ""
1253
 
1254
+ #: ../cerber-load.php:4398 ../settings.php:1172
1255
  msgid "Main Settings"
1256
  msgstr ""
1257
 
1258
+ #: ../cerber-load.php:4399 ../cerber-scanner.php:75
1259
  msgid "Security Scanner"
1260
  msgstr ""
1261
 
1262
+ #: ../cerber-load.php:4400 ../settings.php:1173 ../cerber-tools.php:96 ../cerber-
1263
+ #: tools.php:105 ../cerber-tools.php:192
1264
  msgid "Access Lists"
1265
  msgstr ""
1266
 
1267
+ #: ../cerber-load.php:4402 ../settings.php:1174
1268
  msgid "Hardening"
1269
  msgstr ""
1270
 
1271
+ #: ../cerber-load.php:4403 ../settings.php:303 ../settings.php:386 ../settings.
1272
+ #: php:1176
1273
  msgid "Notifications"
1274
  msgstr ""
1275
 
1276
+ #: ../cerber-load.php:4404
1277
  msgid "Import settings"
1278
  msgstr ""
1279
 
1280
+ #: ../cerber-users.php:12
1281
+ msgid "Block User"
1282
+ msgstr ""
1283
+
1284
+ #: ../cerber-users.php:16 ../cerber-users.php:22
1285
+ msgid "User is not permitted to log into the website"
1286
+ msgstr ""
1287
+
1288
+ #: ../cerber-users.php:31
1289
+ #, php-format
1290
+ msgctxt "e.g. by John at 11:00"
1291
+ msgid "blocked by %s at %s"
1292
+ msgstr ""
1293
+
1294
+ #: ../cerber-users.php:41 ../settings.php:117
1295
+ msgid "User Message"
1296
+ msgstr ""
1297
+
1298
+ #: ../cerber-users.php:43
1299
+ msgid "An optional message for this user"
1300
+ msgstr ""
1301
+
1302
+ #: ../cerber-users.php:98
1303
+ msgid "Blocked Users"
1304
+ msgstr ""
1305
+
1306
+ #: ../settings.php:99
1307
+ msgid "User related settings"
1308
+ msgstr ""
1309
+
1310
+ #: ../settings.php:103
1311
+ msgid "Authorized users only"
1312
+ msgstr ""
1313
+
1314
+ #: ../settings.php:104
1315
+ msgid "Only registered and logged in website users have access to the website"
1316
+ msgstr ""
1317
+
1318
+ #: ../settings.php:110 ../settings.php:296 ../settings.php:811
1319
+ msgid "Use White IP Access List"
1320
+ msgstr ""
1321
+
1322
+ #: ../settings.php:111
1323
+ msgid "Do not apply this policy to IP addresses in the White IP Access List"
1324
+ msgstr ""
1325
+
1326
+ #: ../settings.php:121 ../settings.php:2029
1327
+ msgid "Only registered and logged in users are allowed to view this website"
1328
+ msgstr ""
1329
+
1330
+ #: ../settings.php:126
1331
+ msgid "Redirect to URL"
1332
+ msgstr ""
1333
+
1334
+ #: ../settings.php:135
1335
+ msgid "Registration limit"
1336
+ msgstr ""
1337
+
1338
+ #: ../settings.php:141
1339
+ msgid "Prohibited usernames"
1340
+ msgstr ""
1341
+
1342
+ #: ../settings.php:142
1343
+ msgid ""
1344
+ "Usernames from this list are not allowed to log in or register. Any IP "
1345
+ "address, have tried to use any of these usernames, will be immediately "
1346
+ "blocked. Use comma to separate logins."
1347
+ msgstr ""
1348
+
1349
+ #: ../settings.php:142
1350
+ msgid "To specify a REGEX pattern wrap a pattern in two forward slashes."
1351
+ msgstr ""
1352
+
1353
+ #: ../settings.php:149
1354
+ msgid "User session expire"
1355
+ msgstr ""
1356
+
1357
+ #: ../settings.php:150
1358
+ msgid "in minutes (leave empty to use default WP value)"
1359
+ msgstr ""
1360
+
1361
+ #: ../settings.php:156
1362
+ msgid "Sort users in dashboard"
1363
+ msgstr ""
1364
+
1365
+ #: ../settings.php:157
1366
+ msgid "by date of registration"
1367
+ msgstr ""
1368
+
1369
+ #: ../settings.php:263
1370
  msgid "Plugin initialization"
1371
  msgstr ""
1372
 
1373
+ #: ../settings.php:264
1374
  msgid "Load security engine"
1375
  msgstr ""
1376
 
1377
+ #: ../settings.php:270
1378
  msgid "Legacy mode"
1379
  msgstr ""
1380
 
1381
+ #: ../settings.php:271
1382
  msgid "Standard mode"
1383
  msgstr ""
1384
 
1385
+ #: ../settings.php:275
1386
  msgid "Limit login attempts"
1387
  msgstr ""
1388
 
1389
+ #: ../settings.php:276
1390
  msgid "Attempts"
1391
  msgstr ""
1392
 
1393
+ #: ../settings.php:282
1394
  msgid "Lockout duration"
1395
  msgstr ""
1396
 
1397
+ #: ../settings.php:287 ../settings.php:383
1398
  msgid "minutes"
1399
  msgstr ""
1400
 
1401
+ #: ../settings.php:290
1402
  msgid "Aggressive lockout"
1403
  msgstr ""
1404
 
1405
+ #: ../settings.php:301
 
 
 
 
1406
  msgid "Apply limit login rules to IP addresses in the White IP Access List"
1407
  msgstr ""
1408
 
1409
+ #: ../settings.php:309
1410
  msgid "Site connection"
1411
  msgstr ""
1412
 
1413
+ #: ../settings.php:317
1414
  msgid "Proactive security rules"
1415
  msgstr ""
1416
 
1417
+ #: ../settings.php:318
1418
  msgid "Block subnet"
1419
  msgstr ""
1420
 
1421
+ #: ../settings.php:322
1422
  msgid "Always block entire subnet Class C of intruders IP"
1423
  msgstr ""
1424
 
1425
+ #: ../settings.php:324
1426
  msgid "Non-existent users"
1427
  msgstr ""
1428
 
1429
+ #: ../settings.php:328
1430
  msgid "Immediately block IP when attempting to login with a non-existent username"
1431
  msgstr ""
1432
 
1433
+ #: ../settings.php:330
1434
  msgid "Disable dashboard redirection"
1435
  msgstr ""
1436
 
1437
+ #: ../settings.php:334
1438
  msgid ""
1439
  "Disable automatic redirection to the login page when /wp-admin/ is requested "
1440
  "by an unauthorized request"
1441
  msgstr ""
1442
 
1443
+ #: ../settings.php:336
1444
  msgid "Request wp-login.php"
1445
  msgstr ""
1446
 
1447
+ #: ../settings.php:340
1448
  msgid "Immediately block IP after any request to wp-login.php"
1449
  msgstr ""
1450
 
1451
+ #: ../settings.php:342
1452
  msgid "Display 404 page"
1453
  msgstr ""
1454
 
1455
+ #: ../settings.php:347
1456
  msgid "Use 404 template from the active theme"
1457
  msgstr ""
1458
 
1459
+ #: ../settings.php:348
1460
  msgid "Display simple 404 page"
1461
  msgstr ""
1462
 
1463
+ #: ../settings.php:352
1464
  msgid "Custom login page"
1465
  msgstr ""
1466
 
1467
+ #: ../settings.php:353
1468
  msgid "Custom login URL"
1469
  msgstr ""
1470
 
1471
+ #: ../settings.php:360
1472
  msgid "Custom login URL may contain only letters, numbers, dashes and underscores"
1473
  msgstr ""
1474
 
1475
+ #: ../settings.php:361
1476
  msgid "must not overlap with the existing pages or posts slug"
1477
  msgstr ""
1478
 
1479
+ #: ../settings.php:363
1480
  msgid "Disable wp-login.php"
1481
  msgstr ""
1482
 
1483
+ #: ../settings.php:368
1484
  msgid "Block direct access to wp-login.php and return HTTP 404 Not Found Error"
1485
  msgstr ""
1486
 
1487
+ #: ../settings.php:372
1488
  msgid "Threshold"
1489
  msgstr ""
1490
 
1491
+ #: ../settings.php:378 ../cerber-scanner.php:3715
1492
  msgid "Duration"
1493
  msgstr ""
1494
 
1495
+ #: ../settings.php:391
1496
  msgid "Send notification to admin email"
1497
  msgstr ""
1498
 
1499
+ #: ../settings.php:394 ../settings.php:1343
1500
  msgid "Click to send test"
1501
  msgstr ""
1502
 
1503
+ #: ../settings.php:398 ../settings.php:910
1504
  msgid "Keep records for"
1505
  msgstr ""
1506
 
1507
+ #: ../settings.php:402 ../settings.php:650 ../settings.php:914 ../settings.php:985
1508
  msgid "days"
1509
  msgstr ""
1510
 
1511
+ #: ../settings.php:405
1512
  msgid "Cerber Lab connection"
1513
  msgstr ""
1514
 
1515
+ #: ../settings.php:409
1516
  msgid "Send malicious IP addresses to the Cerber Lab"
1517
  msgstr ""
1518
 
1519
+ #: ../settings.php:411
1520
  msgid "Cerber Lab protocol"
1521
  msgstr ""
1522
 
1523
+ #: ../settings.php:420
1524
  msgid "Use file"
1525
  msgstr ""
1526
 
1527
+ #: ../settings.php:424
1528
  msgid "Write failed login attempts to the file"
1529
  msgstr ""
1530
 
1531
+ #: ../settings.php:427
1532
  msgid "Preferences"
1533
  msgstr ""
1534
 
1535
+ #: ../settings.php:428
1536
  msgid "Drill down IP"
1537
  msgstr ""
1538
 
1539
+ #: ../settings.php:432
1540
  msgid "Retrieve extra WHOIS information for IP"
1541
  msgstr ""
1542
 
1543
+ #: ../settings.php:434
1544
  msgid "Date format"
1545
  msgstr ""
1546
 
1547
+ #: ../settings.php:439
1548
  #, php-format
1549
  msgid "if empty, the default format %s will be used"
1550
  msgstr ""
1551
 
1552
+ #: ../settings.php:441
1553
  msgid "Use English for admin interface"
1554
  msgstr ""
1555
 
1556
+ #: ../settings.php:452
1557
  msgid "Hardening WordPress"
1558
  msgstr ""
1559
 
1560
+ #: ../settings.php:453 ../settings.php:497
1561
  msgid "Stop user enumeration"
1562
  msgstr ""
1563
 
1564
+ #: ../settings.php:458
1565
+ msgid "Block access to user pages like /?author=n"
1566
  msgstr ""
1567
 
1568
+ #: ../settings.php:460
1569
  msgid "Protect admin scripts"
1570
  msgstr ""
1571
 
1572
+ #: ../settings.php:465
1573
  msgid "Block unauthorized access to load-scripts.php and load-styles.php"
1574
  msgstr ""
1575
 
1576
+ #: ../settings.php:467
1577
  msgid "Disable PHP in uploads"
1578
  msgstr ""
1579
 
1580
+ #: ../settings.php:472
1581
  msgid "Disable execution of PHP scripts in the WordPress media folder"
1582
  msgstr ""
1583
 
1584
+ #: ../settings.php:474
1585
  msgid "Disable PHP error displaying"
1586
  msgstr ""
1587
 
1588
+ #: ../settings.php:480
1589
  msgid "Disable XML-RPC"
1590
  msgstr ""
1591
 
1592
+ #: ../settings.php:485
1593
  msgid "Block access to the XML-RPC server (including Pingbacks and Trackbacks)"
1594
  msgstr ""
1595
 
1596
+ #: ../settings.php:487
1597
  msgid "Disable feeds"
1598
  msgstr ""
1599
 
1600
+ #: ../settings.php:492
1601
  msgid "Block access to the RSS, Atom and RDF feeds"
1602
  msgstr ""
1603
 
1604
+ #: ../settings.php:496
1605
+ msgid "Access to WordPress REST API"
1606
  msgstr ""
1607
 
1608
+ #: ../settings.php:502
1609
+ msgid "Block access to user data via REST API"
1610
  msgstr ""
1611
 
1612
+ #: ../settings.php:505
1613
+ msgid "Disable REST API"
1614
  msgstr ""
1615
 
1616
+ #: ../settings.php:510
1617
+ msgid "Block access to WordPress REST API except any of the following"
 
 
1618
  msgstr ""
1619
 
1620
+ #: ../settings.php:517
1621
+ msgid "Allow REST API for logged in users"
1622
  msgstr ""
1623
 
1624
+ #: ../settings.php:519
1625
+ msgid "Allow REST API for these roles"
1626
  msgstr ""
1627
 
1628
+ #: ../settings.php:525
1629
+ msgid "Allow these namespaces"
1630
  msgstr ""
1631
 
1632
+ #: ../settings.php:532
1633
  msgid ""
1634
+ "Specify REST API namespaces to be allowed if REST API is disabled. One "
1635
+ "string per line."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1636
  msgstr ""
1637
 
1638
+ #: ../settings.php:588
1639
  msgid "Cerber antispam engine"
1640
  msgstr ""
1641
 
1642
+ #: ../settings.php:589
1643
  msgid "Comment form"
1644
  msgstr ""
1645
 
1646
+ #: ../settings.php:594
1647
  msgid "Protect comment form with bot detection engine"
1648
  msgstr ""
1649
 
1650
+ #: ../settings.php:596 ../settings.php:670
1651
  msgid "Registration form"
1652
  msgstr ""
1653
 
1654
+ #: ../settings.php:601
1655
  msgid "Protect registration form with bot detection engine"
1656
  msgstr ""
1657
 
1658
+ #: ../settings.php:603
1659
  msgid "Other forms"
1660
  msgstr ""
1661
 
1662
+ #: ../settings.php:608
1663
  msgid "Protect all forms on the website with bot detection engine"
1664
  msgstr ""
1665
 
1666
+ #: ../settings.php:611
1667
  msgid "Adjust antispam engine"
1668
  msgstr ""
1669
 
1670
+ #: ../settings.php:612
1671
  msgid "Safe mode"
1672
  msgstr ""
1673
 
1674
+ #: ../settings.php:617
1675
  msgid "Use less restrictive policies (allow AJAX)"
1676
  msgstr ""
1677
 
1678
+ #: ../settings.php:624
1679
  msgid "Disable bot detection engine for logged in users"
1680
  msgstr ""
1681
 
1682
+ #: ../settings.php:626
1683
  msgid "Query whitelist"
1684
  msgstr ""
1685
 
1686
+ #: ../settings.php:633
1687
  msgid ""
1688
  "Enter a part of query string or query path to exclude a request from "
1689
  "inspection by the engine. One item per line."
1690
  msgstr ""
1691
 
1692
+ #: ../settings.php:633 ../settings.php:822
1693
  msgid "To specify a REGEX pattern, enclose a whole line in two braces."
1694
  msgstr ""
1695
 
1696
+ #: ../settings.php:636
1697
  msgid "Comment processing"
1698
  msgstr ""
1699
 
1700
+ #: ../settings.php:637
1701
  msgid "If a spam comment detected"
1702
  msgstr ""
1703
 
1704
+ #: ../settings.php:642
1705
  msgid "Deny it completely"
1706
  msgstr ""
1707
 
1708
+ #: ../settings.php:642
1709
  msgid "Mark it as spam"
1710
  msgstr ""
1711
 
1712
+ #: ../settings.php:644
1713
  msgid "Trash spam comments"
1714
  msgstr ""
1715
 
1716
+ #: ../settings.php:649
1717
  msgid "Move spam comments to trash after"
1718
  msgstr ""
1719
 
1720
+ #: ../settings.php:658
1721
  msgid "reCAPTCHA settings"
1722
  msgstr ""
1723
 
1724
+ #: ../settings.php:659
1725
  msgid "Site key"
1726
  msgstr ""
1727
 
1728
+ #: ../settings.php:661
1729
  msgid "Secret key"
1730
  msgstr ""
1731
 
1732
+ #: ../settings.php:663
1733
  msgid "Invisible reCAPTCHA"
1734
  msgstr ""
1735
 
1736
+ #: ../settings.php:668
1737
  msgid "Enable invisible reCAPTCHA"
1738
  msgstr ""
1739
 
1740
+ #: ../settings.php:668
1741
  msgid ""
1742
  "(do not enable it unless you get and enter the Site and Secret keys for the "
1743
  "invisible version)"
1744
  msgstr ""
1745
 
1746
+ #: ../settings.php:675
1747
  msgid "Enable reCAPTCHA for WordPress registration form"
1748
  msgstr ""
1749
 
1750
+ #: ../settings.php:682
1751
  msgid "Enable reCAPTCHA for WooCommerce registration form"
1752
  msgstr ""
1753
 
1754
+ #: ../settings.php:684
1755
  msgid "Lost password form"
1756
  msgstr ""
1757
 
1758
+ #: ../settings.php:689
1759
  msgid "Enable reCAPTCHA for WordPress lost password form"
1760
  msgstr ""
1761
 
1762
+ #: ../settings.php:696
1763
  msgid "Enable reCAPTCHA for WooCommerce lost password form"
1764
  msgstr ""
1765
 
1766
+ #: ../settings.php:698
1767
  msgid "Login form"
1768
  msgstr ""
1769
 
1770
+ #: ../settings.php:703
1771
  msgid "Enable reCAPTCHA for WordPress login form"
1772
  msgstr ""
1773
 
1774
+ #: ../settings.php:710
1775
  msgid "Enable reCAPTCHA for WooCommerce login form"
1776
  msgstr ""
1777
 
1778
+ #: ../settings.php:718
1779
  msgid "Enable reCAPTCHA for WordPress comment form"
1780
  msgstr ""
1781
 
1782
+ #: ../settings.php:725
1783
  msgid "Disable reCAPTCHA for logged in users"
1784
  msgstr ""
1785
 
1786
+ #: ../settings.php:727
1787
  msgid "Limit attempts"
1788
  msgstr ""
1789
 
1790
+ #: ../settings.php:732
1791
  #, php-format
1792
  msgid "Lock out IP address for %s minutes after %s failed attempts within %s minutes"
1793
  msgstr ""
1794
 
1795
+ #: ../settings.php:739
1796
  msgid "Email notifications"
1797
  msgstr ""
1798
 
1799
+ #: ../settings.php:742 ../settings.php:782 ../settings.php:1047
1800
  msgid "Email Address"
1801
  msgstr ""
1802
 
1803
+ #: ../settings.php:746 ../settings.php:787 ../settings.php:873 ../settings.php:1051
1804
  msgid "Use comma to specify multiple values"
1805
  msgstr ""
1806
 
1807
+ #: ../settings.php:750
1808
  #, php-format
1809
  msgid "if empty, the admin email %s will be used"
1810
  msgstr ""
1811
 
1812
+ #: ../settings.php:753
1813
  msgid "Notification limit"
1814
  msgstr ""
1815
 
1816
+ #: ../settings.php:753
1817
  msgid "notification letters allowed per hour (0 means unlimited)"
1818
  msgstr ""
1819
 
1820
+ #: ../settings.php:759
1821
  msgid "Push notifications"
1822
  msgstr ""
1823
 
1824
+ #: ../settings.php:767
1825
  msgid "All connected devices"
1826
  msgstr ""
1827
 
1828
+ #: ../settings.php:770
1829
  msgid "No devices found"
1830
  msgstr ""
1831
 
1832
+ #: ../settings.php:774
1833
  msgid "Not available"
1834
  msgstr ""
1835
 
1836
+ #: ../settings.php:779
1837
  msgid "Weekly reports"
1838
  msgstr ""
1839
 
1840
+ #: ../settings.php:780
1841
  msgid "Enable reporting"
1842
  msgstr ""
1843
 
1844
+ #: ../settings.php:791 ../settings.php:1055
1845
  msgid "if empty, email from notification settings will be used"
1846
  msgstr ""
1847
 
1848
+ #: ../settings.php:799
1849
  msgid "Traffic Inspection"
1850
  msgstr ""
1851
 
1852
+ #: ../settings.php:800
1853
  msgid "Enable traffic inspection"
1854
  msgstr ""
1855
 
1856
+ #: ../settings.php:807 ../settings.php:833
1857
  msgid "Maximum compatibility"
1858
  msgstr ""
1859
 
1860
+ #: ../settings.php:808 ../settings.php:834
1861
  msgid "Maximum security"
1862
  msgstr ""
1863
 
1864
+ #: ../settings.php:816
1865
  msgid "Request whitelist"
1866
  msgstr ""
1867
 
1868
+ #: ../settings.php:822
1869
  msgid ""
1870
  "Enter a request URI to exclude the request from inspection. One item per "
1871
  "line."
1872
  msgstr ""
1873
 
1874
+ #: ../settings.php:825
1875
  msgid "Erroneous Request Shielding"
1876
  msgstr ""
1877
 
1878
+ #: ../settings.php:826
1879
  msgid "Enable error shielding"
1880
  msgstr ""
1881
 
1882
+ #: ../settings.php:837
1883
+ msgid "Ignore logged in users"
1884
  msgstr ""
1885
 
1886
+ #: ../settings.php:844
1887
  msgid "Logging"
1888
  msgstr ""
1889
 
1890
+ #: ../settings.php:845
1891
  msgid "Logging mode"
1892
  msgstr ""
1893
 
1894
+ #: ../settings.php:851
1895
  msgid "Logging disabled"
1896
  msgstr ""
1897
 
1898
+ #: ../settings.php:852
1899
  msgid "Smart"
1900
  msgstr ""
1901
 
1902
+ #: ../settings.php:853
1903
  msgid "All traffic"
1904
  msgstr ""
1905
 
1906
+ #: ../settings.php:857
1907
  msgid "Ignore crawlers"
1908
  msgstr ""
1909
 
1910
+ #: ../settings.php:862
1911
  msgid "Save request fields"
1912
  msgstr ""
1913
 
1914
+ #: ../settings.php:867
1915
  msgid "Mask these form fields"
1916
  msgstr ""
1917
 
1918
+ #: ../settings.php:878
1919
  msgid "Save request headers"
1920
  msgstr ""
1921
 
1922
+ #: ../settings.php:884
1923
  msgid "Save $_SERVER"
1924
  msgstr ""
1925
 
1926
+ #: ../settings.php:890
1927
  msgid "Save request cookies"
1928
  msgstr ""
1929
 
1930
+ #: ../settings.php:896
1931
  msgid "Save software errors"
1932
  msgstr ""
1933
 
1934
+ #: ../settings.php:902
1935
  msgid "Page generation time threshold"
1936
  msgstr ""
1937
 
1938
+ #: ../settings.php:907
1939
  msgid "milliseconds"
1940
  msgstr ""
1941
 
1942
+ #: ../settings.php:923
1943
  msgid "Scanner settings"
1944
  msgstr ""
1945
 
1946
+ #: ../settings.php:924
1947
  msgid "Custom signatures"
1948
  msgstr ""
1949
 
1950
+ #: ../settings.php:930
1951
  msgid ""
1952
  "Specify custom PHP code signatures. One item per line. To specify a REGEX "
1953
  "pattern, enclose a whole line in two braces."
1954
  msgstr ""
1955
 
1956
+ #: ../settings.php:932
1957
  msgid "Unwanted file extensions"
1958
  msgstr ""
1959
 
1960
+ #: ../settings.php:938
1961
  msgid ""
1962
  "Specify file extensions to search for. Full scan only. Use comma to separate "
1963
  "items."
1964
  msgstr ""
1965
 
1966
+ #: ../settings.php:940
1967
  msgid "Directories to exclude"
1968
  msgstr ""
1969
 
1970
+ #: ../settings.php:946
1971
  msgid ""
1972
  "Specify directories to exclude from scanning. Use absolute paths. One item "
1973
  "per line."
1974
  msgstr ""
1975
 
1976
+ #: ../settings.php:948
1977
  msgid "Monitor new files"
1978
  msgstr ""
1979
 
1980
+ #: ../settings.php:955
1981
  msgid "Monitor modified files"
1982
  msgstr ""
1983
 
1984
+ #: ../settings.php:961
1985
  msgid "Scan temporary directory"
1986
  msgstr ""
1987
 
1988
+ #: ../settings.php:968
1989
  msgid "Scan session directory"
1990
  msgstr ""
1991
 
1992
+ #: ../settings.php:974
1993
  msgid "Enable diagnostic log"
1994
  msgstr ""
1995
 
1996
+ #: ../settings.php:980
1997
  msgid "Delete quarantined files after"
1998
  msgstr ""
1999
 
2000
+ #: ../settings.php:994
2001
  msgid "Automated recurring scan schedule"
2002
  msgstr ""
2003
 
2004
+ #: ../settings.php:995
2005
  msgid "Launch Quick Scan"
2006
  msgstr ""
2007
 
2008
+ #: ../settings.php:1002
2009
  msgid "Launch Full Scan"
2010
  msgstr ""
2011
 
2012
+ #: ../settings.php:1010
2013
  msgid "Scan results reporting"
2014
  msgstr ""
2015
 
2016
+ #: ../settings.php:1012 ../settings.php:1071
2017
  msgid "Low severity"
2018
  msgstr ""
2019
 
2020
+ #: ../settings.php:1012 ../settings.php:1071
2021
  msgid "Medium severity"
2022
  msgstr ""
2023
 
2024
+ #: ../settings.php:1012 ../settings.php:1071
2025
  msgid "High severity"
2026
  msgstr ""
2027
 
2028
+ #: ../settings.php:1013
2029
  msgid "Report an issue if any of the following is true"
2030
  msgstr ""
2031
 
2032
+ #: ../settings.php:1021
2033
  msgid "Send email report"
2034
  msgstr ""
2035
 
2036
+ #: ../settings.php:1027
2037
  msgid "After every scan"
2038
  msgstr ""
2039
 
2040
+ #: ../settings.php:1028
2041
  msgid "If any changes in scan results occurred"
2042
  msgstr ""
2043
 
2044
+ #: ../settings.php:1029
2045
  msgid "If new issues found"
2046
  msgstr ""
2047
 
2048
+ #: ../settings.php:1033
2049
  msgid "Include file sizes"
2050
  msgstr ""
2051
 
2052
+ #: ../settings.php:1040
2053
  msgid "Include scan errors"
2054
  msgstr ""
2055
 
2056
+ #: ../settings.php:1063
2057
  msgid "Automatic cleanup of malware and suspicious files"
2058
  msgstr ""
2059
 
2060
+ #: ../settings.php:1065 ../cerber-scanner.php:3747
2061
  msgid "Unattended files"
2062
  msgstr ""
2063
 
2064
+ #: ../settings.php:1072
2065
  msgid "Files in the uploads folder"
2066
  msgstr ""
2067
 
2068
+ #: ../settings.php:1079
2069
  msgid "Files with unwanted extensions"
2070
  msgstr ""
2071
 
2072
+ #: ../settings.php:1086
2073
  msgid "Exclusions"
2074
  msgstr ""
2075
 
2076
+ #: ../settings.php:1087
2077
  msgid "Files in the temporary directory"
2078
  msgstr ""
2079
 
2080
+ #: ../settings.php:1093
2081
  msgid "Files in the sessions directory"
2082
  msgstr ""
2083
 
2084
+ #: ../settings.php:1099
2085
  msgid "Files in these directories"
2086
  msgstr ""
2087
 
2088
+ #: ../settings.php:1105
2089
  msgid "Use absolute paths. One item per line."
2090
  msgstr ""
2091
 
2092
+ #: ../settings.php:1107
2093
  msgid "Files with these extensions"
2094
  msgstr ""
2095
 
2096
+ #: ../settings.php:1113
2097
  msgid "Use comma to separate items."
2098
  msgstr ""
2099
 
2100
+ #: ../settings.php:1124
2101
  msgid "Make your protection smarter!"
2102
  msgstr ""
2103
 
2104
+ #: ../settings.php:1128
2105
  msgid ""
2106
  "Please enable Permalinks to use this feature. Set Permalink Settings to "
2107
  "something other than Default."
2108
  msgstr ""
2109
 
2110
+ #: ../settings.php:1131
2111
  msgid "Be careful about enabling these options."
2112
  msgstr ""
2113
 
2114
+ #: ../settings.php:1131
2115
  msgid "If you forget your Custom login URL, you will be unable to log in."
2116
  msgstr ""
2117
 
2118
+ #: ../settings.php:1135
2119
  msgid ""
2120
  "In the Citadel mode nobody is able to log in except IPs from the White IP "
2121
  "Access List. Active user sessions will not be affected."
2122
  msgstr ""
2123
 
2124
+ #: ../settings.php:1139
2125
+ msgid "These restrictions do not apply to IP addresses in the White IP Access List"
2126
  msgstr ""
2127
 
2128
+ #: ../settings.php:1142
2129
  msgid ""
2130
  "Before you can start using reCAPTCHA, you have to obtain Site key and Secret "
2131
  "key on the Google website"
2132
  msgstr ""
2133
 
2134
+ #: ../settings.php:1171
2135
  msgid "Lockouts"
2136
  msgstr ""
2137
 
2138
+ #: ../settings.php:1175
2139
  msgid "Users"
2140
  msgstr ""
2141
 
2142
+ #: ../settings.php:1321
2143
  #, php-format
2144
  msgid "%s allowed retries in %s minutes"
2145
  msgstr ""
2146
 
2147
+ #: ../settings.php:1326
2148
  #, php-format
2149
  msgid "%s allowed registrations in %s minutes from one IP"
2150
  msgstr ""
2151
 
2152
+ #: ../settings.php:1331
2153
  #, php-format
2154
  msgid "Increase lockout duration to %s hours after %s lockouts in the last %s hours"
2155
  msgstr ""
2156
 
2157
+ #: ../settings.php:1338
2158
  msgid "Notify admin if the number of active lockouts above"
2159
  msgstr ""
2160
 
2161
+ #: ../settings.php:1346
2162
  #, php-format
2163
  msgid "Enable after %s failed login attempts in last %s minutes"
2164
  msgstr ""
2165
 
2166
+ #: ../settings.php:1464
2167
+ msgid "Select one or more roles"
2168
+ msgstr ""
2169
+
2170
+ #: ../settings.php:1490
2171
  msgid "Sunday"
2172
  msgstr ""
2173
 
2174
+ #: ../settings.php:1491
2175
  msgid "Monday"
2176
  msgstr ""
2177
 
2178
+ #: ../settings.php:1492
2179
  msgid "Tuesday"
2180
  msgstr ""
2181
 
2182
+ #: ../settings.php:1493
2183
  msgid "Wednesday"
2184
  msgstr ""
2185
 
2186
+ #: ../settings.php:1494
2187
  msgid "Thursday"
2188
  msgstr ""
2189
 
2190
+ #: ../settings.php:1495
2191
  msgid "Friday"
2192
  msgstr ""
2193
 
2194
+ #: ../settings.php:1496
2195
  msgid "Saturday"
2196
  msgstr ""
2197
 
2198
+ #: ../settings.php:1506
2199
  msgctxt "preposition of time like: at 11:00"
2200
  msgid "at"
2201
  msgstr ""
2202
 
2203
+ #: ../settings.php:1522
2204
  msgid "Click to send now"
2205
  msgstr ""
2206
 
2207
+ #: ../settings.php:1533
2208
  msgid "Plugin initialization mode has not been changed"
2209
  msgstr ""
2210
 
2211
+ #: ../settings.php:1553 ../settings.php:1554
2212
  msgid "Attention! You have changed the login URL! The new login URL is"
2213
  msgstr ""
2214
 
2215
+ #: ../settings.php:1555 ../settings.php:1556
2216
  msgid ""
2217
  "If you use a caching plugin, you have to add your new login URL to the list "
2218
  "of pages not to cache."
2219
  msgstr ""
2220
 
2221
+ #: ../settings.php:1641 ../settings.php:1653 ../settings.php:1776
2222
  msgid "<strong>ERROR</strong>: please enter a valid email address."
2223
  msgstr ""
2224
 
2225
+ #: ../settings.php:1782
2226
  msgid "The schedule has been updated"
2227
  msgstr ""
2228
 
2229
+ #: ../settings.php:1785
2230
  msgid "Unable to update the schedule"
2231
  msgstr ""
2232
 
2239
  msgstr ""
2240
 
2241
  #: ../cerber-tools.php:42
2242
+ msgid "Log"
2243
  msgstr ""
2244
 
2245
  #: ../cerber-tools.php:43
2246
+ msgid "Changelog"
2247
  msgstr ""
2248
 
2249
+ #: ../cerber-tools.php:44
2250
+ msgid "License"
2251
+ msgstr ""
2252
+
2253
+ #: ../cerber-tools.php:92
2254
  msgid "Export settings to the file"
2255
  msgstr ""
2256
 
2257
+ #: ../cerber-tools.php:93
2258
  msgid ""
2259
  "When you click the button below you will get a configuration file, which you "
2260
  "can upload on another site."
2261
  msgstr ""
2262
 
2263
+ #: ../cerber-tools.php:94
2264
  msgid "What do you want to export?"
2265
  msgstr ""
2266
 
2267
+ #: ../cerber-tools.php:97
2268
  msgid "Download file"
2269
  msgstr ""
2270
 
2271
+ #: ../cerber-tools.php:99
2272
  msgid "Import settings from the file"
2273
  msgstr ""
2274
 
2275
+ #: ../cerber-tools.php:100
2276
  msgid ""
2277
  "When you click the button below, file will be uploaded and all existing "
2278
  "settings will be overridden."
2279
  msgstr ""
2280
 
2281
+ #: ../cerber-tools.php:101
2282
  msgid "Select file to import."
2283
  msgstr ""
2284
 
2285
+ #: ../cerber-tools.php:101 ../cerber-scanner.php:3915
2286
  #, php-format
2287
  msgid "Maximum upload file size: %s."
2288
  msgstr ""
2289
 
2290
+ #: ../cerber-tools.php:104
2291
  msgid "What do you want to import?"
2292
  msgstr ""
2293
 
2294
+ #: ../cerber-tools.php:106 ../cerber-scanner.php:3918
2295
  msgid "Upload file"
2296
  msgstr ""
2297
 
2298
+ #: ../cerber-tools.php:155
2299
  msgid "No file was uploaded or file is corrupted"
2300
  msgstr ""
2301
 
2302
+ #: ../cerber-tools.php:192
2303
  msgid "Error while updating"
2304
  msgstr ""
2305
 
2306
+ #: ../cerber-tools.php:198
2307
  msgid "Settings has imported successfully from"
2308
  msgstr ""
2309
 
2310
+ #: ../cerber-tools.php:205
2311
  msgid "Error while parsing file"
2312
  msgstr ""
2313
 
2402
  msgid "Unable to process file"
2403
  msgstr ""
2404
 
2405
+ #: ../cerber-scanner.php:1432 ../cerber-scanner.php:4806
2406
  msgid "Unable to open file"
2407
  msgstr ""
2408
 
2426
  msgid "Executable code found"
2427
  msgstr ""
2428
 
2429
+ #: ../cerber-scanner.php:1443 ../cerber-scanner.php:2663
2430
  msgid "Suspicious directives found"
2431
  msgstr ""
2432
 
2454
  msgid "Every 6 hours"
2455
  msgstr ""
2456
 
2457
+ #: ../cerber-scanner.php:2483
2458
  msgid "Custom signature found"
2459
  msgstr ""
2460
 
2461
+ #: ../cerber-scanner.php:2658
2462
  msgid ""
2463
  "This file contains executable code and may contain obfuscated malware. If "
2464
  "this file is a part of a theme or a plugin, it must be located in the theme "
2465
  "or the plugin folder. No exception, no excuses."
2466
  msgstr ""
2467
 
2468
+ #: ../cerber-scanner.php:2659
2469
  msgid ""
2470
  "The scanner recognizes this file as \"ownerless\" or \"not bundled\" because it "
2471
  "does not belong to any known part of the website and should not be here."
2472
  msgstr ""
2473
 
2474
+ #: ../cerber-scanner.php:2660
2475
  #, php-format
2476
  msgid ""
2477
  "It may remain after upgrading to a newer version of %s. It also may be a "
2479
  "made (bespoke) plugin or theme."
2480
  msgstr ""
2481
 
2482
+ #: ../cerber-scanner.php:2661
2483
  msgid "Suspicious code instruction found"
2484
  msgstr ""
2485
 
2486
+ #: ../cerber-scanner.php:2662
2487
  msgid "Suspicious code signatures found"
2488
  msgstr ""
2489
 
2490
+ #: ../cerber-scanner.php:2664
2491
  msgid ""
2492
  "The contents of the file have been changed and do not match what exists in "
2493
  "the official WordPress repository or a reference file you have uploaded "
2495
  "has been tampered with."
2496
  msgstr ""
2497
 
2498
+ #: ../cerber-scanner.php:2665
2499
  #, php-format
2500
  msgid ""
2501
  "To solve this issue you have to reinstall %s or update it to the latest "
2502
  "version."
2503
  msgstr ""
2504
 
2505
+ #: ../cerber-scanner.php:2666
2506
  msgid "Please upload a reference ZIP archive"
2507
  msgstr ""
2508
 
2509
+ #: ../cerber-scanner.php:2667
2510
  msgid "Resolve issue"
2511
  msgstr ""
2512
 
2513
+ #: ../cerber-scanner.php:3621
2514
  msgid "Preparing for the scan"
2515
  msgstr ""
2516
 
2517
+ #: ../cerber-scanner.php:3622
2518
  msgid "Scanning folders for files"
2519
  msgstr ""
2520
 
2521
+ #: ../cerber-scanner.php:3623
2522
  msgid "Scanning the upload folder for files"
2523
  msgstr ""
2524
 
2525
+ #: ../cerber-scanner.php:3624
2526
  msgid "Scanning the temp folder for files"
2527
  msgstr ""
2528
 
2529
+ #: ../cerber-scanner.php:3625
2530
  msgid "Scanning the session folder for files"
2531
  msgstr ""
2532
 
2533
+ #: ../cerber-scanner.php:3626
2534
  msgid "Parsing the list of files"
2535
  msgstr ""
2536
 
2537
+ #: ../cerber-scanner.php:3627
2538
  msgid "Checking for new and modified files"
2539
  msgstr ""
2540
 
2541
+ #: ../cerber-scanner.php:3628
2542
  msgid "Verifying the integrity of WordPress"
2543
  msgstr ""
2544
 
2545
+ #: ../cerber-scanner.php:3629
2546
  msgid "Verifying the integrity of the plugins"
2547
  msgstr ""
2548
 
2549
+ #: ../cerber-scanner.php:3630
2550
  msgid "Verifying the integrity of the themes"
2551
  msgstr ""
2552
 
2553
+ #: ../cerber-scanner.php:3631
2554
  msgid "Searching for malicious code"
2555
  msgstr ""
2556
 
2557
+ #: ../cerber-scanner.php:3632
2558
  msgid "Finalizing the scan"
2559
  msgstr ""
2560
 
2561
+ #: ../cerber-scanner.php:3707
2562
  msgid "Started"
2563
  msgstr ""
2564
 
2565
+ #: ../cerber-scanner.php:3711
2566
  msgid "Finished"
2567
  msgstr ""
2568
 
2569
+ #: ../cerber-scanner.php:3719
2570
  msgid "Performance"
2571
  msgstr ""
2572
 
2573
+ #: ../cerber-scanner.php:3731
2574
  msgid "Vulnerabilities"
2575
  msgstr ""
2576
 
2577
+ #: ../cerber-scanner.php:3735
2578
  msgid "New files"
2579
  msgstr ""
2580
 
2581
+ #: ../cerber-scanner.php:3739
2582
  msgid "Changed files"
2583
  msgstr ""
2584
 
2585
+ #: ../cerber-scanner.php:3743
2586
  msgid "Unwanted extensions"
2587
  msgstr ""
2588
 
2589
+ #: ../cerber-scanner.php:3756 ../cerber-scanner.php:5423
2590
  msgid "Scanned"
2591
  msgstr ""
2592
 
2593
+ #: ../cerber-scanner.php:3756 ../cerber-scanner.php:3826
2594
  msgid "Files to scan"
2595
  msgstr ""
2596
 
2597
+ #: ../cerber-scanner.php:3763 ../cerber-scanner.php:3834
2598
  msgid "Critical issues"
2599
  msgstr ""
2600
 
2601
+ #: ../cerber-scanner.php:3763 ../cerber-scanner.php:3838 ../cerber-scanner.php:4996
2602
  msgid "Issues total"
2603
  msgstr ""
2604
 
2605
+ #: ../cerber-scanner.php:3912
2606
  msgid "We have not found any integrity data to verify"
2607
  msgstr ""
2608
 
2609
+ #: ../cerber-scanner.php:3914
2610
  msgid ""
2611
  "You have to upload a ZIP archive from which you've installed it. This "
2612
  "enables the security scanner to verify the integrity of the code and detect "
2613
  "malware."
2614
  msgstr ""
2615
 
2616
+ #: ../cerber-scanner.php:4201
2617
  msgid "The directory is not writable"
2618
  msgstr ""
2619
 
2620
+ #: ../cerber-scanner.php:4219
2621
  msgid "Unable to create WP CERBER directory"
2622
  msgstr ""
2623
 
2624
+ #: ../cerber-scanner.php:4425
2625
  msgid ""
2626
  "File access error. Possibly scan results are outdated. Please run Quick or "
2627
  "Full Scan."
2628
  msgstr ""
2629
 
2630
+ #: ../cerber-scanner.php:4952
2631
  msgid "Full Scan Report"
2632
  msgstr ""
2633
 
2634
+ #: ../cerber-scanner.php:4952
2635
  msgid "Quick Scan Report"
2636
  msgstr ""
2637
 
2638
+ #: ../cerber-scanner.php:4965
2639
  msgid "Files scanned"
2640
  msgstr ""
2641
 
2642
+ #: ../cerber-scanner.php:5046
2643
  msgid "Deleted"
2644
  msgstr ""
2645
 
2646
+ #: ../cerber-scanner.php:5093
2647
  msgid "Automatically moved to quarantine"
2648
  msgstr ""
2649
 
2650
+ #: ../cerber-scanner.php:5105
2651
  msgid "To view full report visit"
2652
  msgstr ""
2653
 
2654
+ #: ../cerber-scanner.php:5333
2655
  msgid "There are no files in the quarantine at the moment."
2656
  msgstr ""
2657
 
2658
+ #: ../cerber-scanner.php:5394
2659
  msgid "No files match the specified filter."
2660
  msgstr ""
2661
 
2662
+ #: ../cerber-scanner.php:5394
2663
  msgid "Click here to see the full list of files"
2664
  msgstr ""
2665
 
2666
+ #: ../cerber-scanner.php:5411
2667
  msgid "Delete permanently"
2668
  msgstr ""
2669
 
2670
+ #: ../cerber-scanner.php:5416
2671
  msgid "Restore"
2672
  msgstr ""
2673
 
2674
+ #: ../cerber-scanner.php:5424
2675
  msgid "Moved to quarantine"
2676
  msgstr ""
2677
 
2678
+ #: ../cerber-scanner.php:5425
2679
  msgid "Automatic deletion"
2680
  msgstr ""
2681
 
2682
+ #: ../cerber-scanner.php:5426
2683
  msgid "Size"
2684
  msgstr ""
2685
 
2686
+ #: ../cerber-scanner.php:5427 ../cerber-scanner.php:5558
2687
  msgid "File"
2688
  msgstr ""
2689
 
2690
+ #: ../cerber-scanner.php:5441
2691
  msgid "All scans"
2692
  msgstr ""
2693
 
2694
+ #: ../cerber-scanner.php:5495
2695
  msgid "The file has been deleted permanently."
2696
  msgstr ""
2697
 
2698
+ #: ../cerber-scanner.php:5504
2699
  msgid "The file has been restored to its original location."
2700
  msgstr ""
2701
 
2702
+ #: ../cerber-scanner.php:5526
2703
  msgid "Apply"
2704
  msgstr ""
2705
 
2706
+ #: ../cerber-scanner.php:5527 ../cerber-scanner.php:5552
2707
  msgid "Remove from the list"
2708
  msgstr ""
2709
 
2710
+ #: ../cerber-scanner.php:5528
2711
  msgid "User Insights"
2712
  msgstr ""
2713
 
2714
+ #: ../cerber-scanner.php:5529
2715
  msgid "Traffic Insights"
2716
  msgstr ""
2717
 
2718
+ #: ../cerber-scanner.php:5530
2719
  msgid "Activity Insights"
2720
  msgstr ""
2721
 
2722
+ #: ../cerber-scanner.php:5532
2723
  msgid "The list is empty."
2724
  msgstr ""
2725
 
2726
+ #: ../cerber-scanner.php:5557
2727
  msgid "Added"
2728
  msgstr ""
2729
 
modules/aaa-wp-cerber.php CHANGED
@@ -8,8 +8,8 @@
8
  Text Domain: wp-cerber
9
  Network: true
10
 
11
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
12
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
13
 
14
  Licenced under the GNU GPL.
15
 
8
  Text Domain: wp-cerber
9
  Network: true
10
 
11
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
12
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
13
 
14
  Licenced under the GNU GPL.
15
 
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: security, malware scanner, antispam, firewall, limit login attempts, custo
5
  Requires at least: 4.5
6
  Requires PHP: 5.4
7
  Tested up to: 5.0
8
- Stable tag: 7.9.3
9
  License: GPLv2
10
 
11
  Protection against hacker attacks and bots. Malware scanner & integrity checker. User activity log. Antispam reCAPTCHA. Limit login attempts.
@@ -14,11 +14,11 @@ Protection against hacker attacks and bots. Malware scanner & integrity checker.
14
 
15
  Defends WordPress against hacker attacks, spam, trojans and malware.
16
  Mitigates brute force attacks by limiting the number of login attempts through the login form, XML-RPC / REST API requests or using auth cookies.
17
- Restricts access with the Black IP Access List and the White IP Access List.
18
  Tracks user and intruder activity with powerful email, mobile and desktop notifications.
19
- Stops spam: activates Cerber anti-spam engine and Google reCAPTCHA to protect registration, contact and comments forms.
20
  Advanced malware scanner, integrity checker and file monitor.
21
- Hardening WordPress with a set of security rules and sophisticated security algorithms.
 
22
 
23
  **Features you will love**
24
 
@@ -26,32 +26,36 @@ Hardening WordPress with a set of security rules and sophisticated security algo
26
  * Monitors logins made by login forms, XML-RPC requests or auth cookies.
27
  * Permit or restrict access by [White IP Access list and Black IP Access List](https://wpcerber.com/using-ip-access-lists-to-protect-wordpress/) with a single IP, IP range or subnet.
28
  * Create **Custom login URL** ([rename wp-login.php](https://wpcerber.com/how-to-rename-wp-login-php/)).
29
- * Cerber antispam engine for protecting any contact form. Automatically detects and moves spam comments to trash or deny it completely.
30
- * Log users, bots, hacker and other suspicious activities.
31
- * Verify the integrity of all WordPress files, plugins and themes.
32
- * Monitor file changes and new files.
33
- * Cool notifications with powerful event filters.
34
- * Hide wp-login.php, wp-signup.php and wp-register.php from possible attacks.
35
- * Hide wp-admin (dashboard) when a user isn't logged in.
36
- * Immediately block an IP or a subnet when attempting to log in with non-existent or prohibited username.
 
37
  * Restrict user registration or login with a username matching REGEX patterns.
38
- * Disable WP REST API or restrict access with your own security rules
39
- * Disable XML-RPC (block access to the XML-RPC interface including Pingbacks and Trackbacks)
40
- * Disable feeds (block access to the RSS, Atom and RDF feeds)
 
41
  * Restrict access to XML-RPC, REST API and feeds by **White IP Access list** by an IP address or an IP range.
42
- * Disable automatic redirection to the login page.
43
- * **Stop user enumeration** (block access to pages like /?author=n and user REST API)
 
 
44
  * Proactively **blocks IP subnet class C** for intruder's IP.
45
  * Anti-spam: **reCAPTCHA** to protect WordPress login, register and comment forms.
46
  * [reCAPTCHA for WooCommerce & WordPress forms](https://wpcerber.com/how-to-setup-recaptcha/).
47
- * Invisible reCAPTCHA for WordPress comments forms
48
- * Citadel mode for **massive brute force attack**.
49
- * [Play nice with **fail2ban**](https://wpcerber.com/how-to-protect-wordpress-with-fail2ban/): write failed attempts to the syslog or a custom log file.
50
  * Filter out and inspect activities by IP address, user, username or a particular activity.
51
  * Filter out activities and export them to a CSV file.
52
  * Reporting: get weekly reports to specified email addresses.
53
  * Limit login attempts works on a site/server behind a reverse proxy.
54
- * [Get notifications by email or via mobile push notifications](https://wpcerber.com/wordpress-notifications-made-easy/).
55
  * Trigger and action for the [jetFlow.io automation plugin](http://jetflow.io).
56
  * Protection against (DoS) attacks (CVE-2018-6389).
57
 
@@ -308,6 +312,17 @@ To get access to your dashboard you need to copy the WP Cerber Reset folder to t
308
 
309
  == Changelog ==
310
 
 
 
 
 
 
 
 
 
 
 
 
311
  = 7.9.3 =
312
  * New: New settings for [the Traffic Inspector firewall](https://wpcerber.com/traffic-inspector-in-a-nutshell/) allow you to fine-tune its behavior. You can enable less or more restrictive firewall rules.
313
  * Update: Troubleshooting of possible issues with scheduled maintenance tasks has been improved.
@@ -434,31 +449,6 @@ To get access to your dashboard you need to copy the WP Cerber Reset folder to t
434
  * New: Traffic Inspector optionally logs all or just suspicious and malicious requests so you can inspect them.
435
  * New: Added ability to clean up Cerber’s DB tables.
436
  * New: If the web server has some issues and those issues can affect plugin functionality, they are shown on the Diagnostic page.
437
- * Added protection to prevent scheduled tasks from being executed multiple times an hour.
438
- * JavaScript antispam code is improved to eliminate excessive fields in GET requests.
439
- * To eliminate possible warning messages, the inet_pton() function has been replaced with filter_var().
440
-
441
- = 5.9 =
442
- * New: You can add comments for new entries in the access lists
443
- * Improved compatibility with exotic hosting environments: now the plugin handles URLs with the MultiViews server option enabled.
444
- * Improved compatibility with caching plugins
445
- * Bug fixed: The plugin logs a logout event if the actual logout doesn't happen
446
- * [Read more](https://wpcerber.com/wp-cerber-security-5-9/)
447
-
448
- = 5.8.6 =
449
- * New: Regular expressions (REGEX) in the list of prohibited usernames.
450
- * New: Enable/disable weekly reports, a new setting to specify email addresses for weekly reports.
451
- * Improved compatibility with non-standard authentication processes, WooCommerce and exotic/outdated hosting environments.
452
- * Bug fixed: Some interface elements of WordPress Customizer might not work.
453
- * [Read more](https://wpcerber.com/wp-cerber-security-5-8-6/)
454
-
455
- = 5.8 =
456
- * New: Now the plugin will send a brief security report (activity for past seven days) to specified email addresses.
457
- * Plugin admin interface pages: compatibility with screen readers has been improved.
458
- * REST API: the deprecated rest_enabled filter is used for WordPress older than 4.7.
459
- * Bug fixed: After updating the plugin to the 5.7 version some disabled checkboxes (and corresponding disabled settings) are set to their default, enabled states.
460
- * Bug fixed: An IP address in the white access list may be locked out as a suspicious IP.
461
- * [Read more](https://wpcerber.com/wp-cerber-security-5-8/)
462
 
463
  == Other Notes ==
464
 
5
  Requires at least: 4.5
6
  Requires PHP: 5.4
7
  Tested up to: 5.0
8
+ Stable tag: 7.9.7
9
  License: GPLv2
10
 
11
  Protection against hacker attacks and bots. Malware scanner & integrity checker. User activity log. Antispam reCAPTCHA. Limit login attempts.
14
 
15
  Defends WordPress against hacker attacks, spam, trojans and malware.
16
  Mitigates brute force attacks by limiting the number of login attempts through the login form, XML-RPC / REST API requests or using auth cookies.
 
17
  Tracks user and intruder activity with powerful email, mobile and desktop notifications.
18
+ Stops spam: activates a specialized Cerber anti-spam engine and Google reCAPTCHA to protect registration, contact and comments forms.
19
  Advanced malware scanner, integrity checker and file monitor.
20
+ Hardening WordPress with a set of flexible security rules and sophisticated security algorithms.
21
+ Restricts access with the Black IP Access List and the White IP Access List.
22
 
23
  **Features you will love**
24
 
26
  * Monitors logins made by login forms, XML-RPC requests or auth cookies.
27
  * Permit or restrict access by [White IP Access list and Black IP Access List](https://wpcerber.com/using-ip-access-lists-to-protect-wordpress/) with a single IP, IP range or subnet.
28
  * Create **Custom login URL** ([rename wp-login.php](https://wpcerber.com/how-to-rename-wp-login-php/)).
29
+ * Cerber anti-spam engine for protecting contact and registration forms.
30
+ * Automatically detects and moves spam comments to trash or denies them completely.
31
+ * Logs users, bots, hacker and other suspicious activities.
32
+ * Security scanner verifies the integrity of WordPress files, plugins and themes.
33
+ * Monitors file changes and new files with email notifications and reports.
34
+ * [Mobile and email notifications with a set of flexible filters](https://wpcerber.com/wordpress-notifications-made-easy/).
35
+ * Protects wp-login.php, wp-signup.php and wp-register.php from attacks.
36
+ * Hides wp-admin (dashboard) if a visitor isn't logged in.
37
+ * Immediately blocks an intruder IP when attempting to log in with non-existent or prohibited username.
38
  * Restrict user registration or login with a username matching REGEX patterns.
39
+ * [Restrict access to WP REST API with your own role-based security rules](https://wpcerber.com/restrict-access-to-wordpress-rest-api/).
40
+ * Disable WordPress REST API completely.
41
+ * Disable XML-RPC (block access to XML-RPC including Pingbacks and Trackbacks).
42
+ * Disable feeds (block access to the RSS, Atom and RDF feeds).
43
  * Restrict access to XML-RPC, REST API and feeds by **White IP Access list** by an IP address or an IP range.
44
+ * [Authorized users only mode](https://wpcerber.com/only-logged-in-wordpress-users/)
45
+ * [Block a user account](https://wpcerber.com/how-to-block-wordpress-user/).
46
+ * Disable automatic redirection to the hidden login page.
47
+ * **Stop user enumeration** (blocks access to author pages and prevents user data leaks via REST API).
48
  * Proactively **blocks IP subnet class C** for intruder's IP.
49
  * Anti-spam: **reCAPTCHA** to protect WordPress login, register and comment forms.
50
  * [reCAPTCHA for WooCommerce & WordPress forms](https://wpcerber.com/how-to-setup-recaptcha/).
51
+ * Invisible reCAPTCHA for WordPress comments forms.
52
+ * A special Citadel mode for **massive brute force attacks**.
53
+ * [Play nice with fail2ban](https://wpcerber.com/how-to-protect-wordpress-with-fail2ban/): write failed attempts to the syslog or a custom log file.
54
  * Filter out and inspect activities by IP address, user, username or a particular activity.
55
  * Filter out activities and export them to a CSV file.
56
  * Reporting: get weekly reports to specified email addresses.
57
  * Limit login attempts works on a site/server behind a reverse proxy.
58
+ * [Be notified via mobile push notifications](https://wpcerber.com/wordpress-mobile-and-browser-notifications-pushbullet/).
59
  * Trigger and action for the [jetFlow.io automation plugin](http://jetflow.io).
60
  * Protection against (DoS) attacks (CVE-2018-6389).
61
 
312
 
313
  == Changelog ==
314
 
315
+ = 7.9.7 =
316
+ * New: [Authorized users only mode](https://wpcerber.com/only-logged-in-wordpress-users/).
317
+ * New: [An ability to block a user account](https://wpcerber.com/how-to-block-wordpress-user/).
318
+ * New: [Role-based access to WordPress REST API](https://wpcerber.com/restrict-access-to-wordpress-rest-api/).
319
+ * Update: Added ability to search and filter a user on the Activity page.
320
+ * Update: A new, separate setting for preventing user enumeration via WordPress REST API.
321
+ * Update: A new Changelog section on the Tools page.
322
+ * Update: Improved handling scheduled maintenance tasks on a multi-site WordPress installation.
323
+ * Fixed: Several HTML markup errors on plugin admin pages.
324
+ * [Read more](https://wpcerber.com/wp-cerber-security-7-9-7/)
325
+
326
  = 7.9.3 =
327
  * New: New settings for [the Traffic Inspector firewall](https://wpcerber.com/traffic-inspector-in-a-nutshell/) allow you to fine-tune its behavior. You can enable less or more restrictive firewall rules.
328
  * Update: Troubleshooting of possible issues with scheduled maintenance tasks has been improved.
449
  * New: Traffic Inspector optionally logs all or just suspicious and malicious requests so you can inspect them.
450
  * New: Added ability to clean up Cerber’s DB tables.
451
  * New: If the web server has some issues and those issues can affect plugin functionality, they are shown on the Diagnostic page.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
452
 
453
  == Other Notes ==
454
 
ripe.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
4
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
1
  <?php
2
  /*
3
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
4
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
settings.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
4
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
@@ -47,6 +47,192 @@ define('CERBER_OPT_S','cerber-scanner');
47
  define('CERBER_OPT_E','cerber-schedule');
48
  define('CERBER_OPT_P','cerber-policies');
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  /**
51
  * A set of Cerber setting (WP options)
52
  *
@@ -67,152 +253,484 @@ function cerber_settings_init(){
67
  return;
68
  }
69
 
 
 
70
  // Main Settings tab ---------------------------------------------------------------------
71
 
72
- $tab='main'; // 'cerber-main' settings
73
- register_setting( 'cerberus-'.$tab, 'cerber-'.$tab );
74
-
75
- add_settings_section( 'boot', __( 'Plugin initialization', 'wp-cerber' ), 'cerber_sapi_section', 'cerber-' . $tab );
76
- add_settings_field('boot-mode',__('Load security engine','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'boot',array('group'=>$tab, 'option'=>'boot-mode', 'type'=>'select', 'set' => array(__('Legacy mode','wp-cerber'), __('Standard mode','wp-cerber'))));
77
-
78
- add_settings_section('cerber', __('Limit login attempts','wp-cerber'), 'cerber_sapi_section', 'cerber-' . $tab);
79
- add_settings_field('attempts',__('Attempts','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'cerber',array('group'=>$tab,'option'=>'attempts','type'=>'attempts'));
80
- add_settings_field('lockout',__('Lockout duration','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'cerber',array('group'=>$tab,'option'=>'lockout','type'=>'text','label'=>__('minutes','wp-cerber'),'size'=>3));
81
- add_settings_field('aggressive',__('Aggressive lockout','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'cerber',array('group'=>$tab,'option'=>'aggressive','type'=>'aggressive'));
82
- add_settings_field('limitwhite',__('Use White IP Access List','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'cerber',array('group'=>$tab,'option'=>'limitwhite','type'=>'checkbox','label'=>__('Apply limit login rules to IP addresses in the White IP Access List','wp-cerber')));
83
- add_settings_field('notify',__('Notifications','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'cerber',array('group'=>$tab,'type'=>'notify','option'=>'notify'));
84
- add_settings_field('proxy',__('Site connection','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'cerber',array('group'=>$tab,'option'=>'proxy','type'=>'checkbox','label'=>__('My site is behind a reverse proxy','wp-cerber')));
85
-
86
- add_settings_section('proactive', __('Proactive security rules','wp-cerber'), 'cerber_sapi_section', 'cerber-' . $tab);
87
- add_settings_field('subnet',__('Block subnet','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'proactive',array('group'=>$tab,'option'=>'subnet','type'=>'checkbox','label'=>__('Always block entire subnet Class C of intruders IP','wp-cerber')));
88
- add_settings_field('nonusers',__('Non-existent users','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'proactive',array('group'=>$tab,'option'=>'nonusers','type'=>'checkbox','label'=>__('Immediately block IP when attempting to login with a non-existent username','wp-cerber')));
89
- add_settings_field('noredirect',__('Disable dashboard redirection','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'proactive',array('group'=>$tab,'option'=>'noredirect','type'=>'checkbox','label'=>__('Disable automatic redirection to the login page when /wp-admin/ is requested by an unauthorized request','wp-cerber')));
90
- add_settings_field('wplogin',__('Request wp-login.php','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'proactive',array('group'=>$tab,'option'=>'wplogin','type'=>'checkbox','label'=>__('Immediately block IP after any request to wp-login.php','wp-cerber')));
91
- add_settings_field('page404',__('Display 404 page','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'proactive',array('group'=>$tab, 'option'=>'page404', 'type'=>'select', 'set' => array(__('Use 404 template from the active theme','wp-cerber'), __('Display simple 404 page','wp-cerber'))));
92
-
93
- add_settings_section('custom', __('Custom login page','wp-cerber'), 'cerber_sapi_section', 'cerber-' . $tab);
94
- add_settings_field( 'loginpath', __( 'Custom login URL', 'wp-cerber' ), 'cerber_field_show', 'cerber-' . $tab, 'custom', array(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  'group' => $tab,
96
- 'setting' => 'loginpath',
97
  'type' => 'text',
98
- 'pattern' => '[a-zA-Z0-9\-_]{1,100}',
99
- 'title' => __( 'Custom login URL may contain only letters, numbers, dashes and underscores', 'wp-cerber' ),
100
- 'label' => __( 'must not overlap with the existing pages or posts slug', 'wp-cerber' )
 
 
 
 
101
  ) );
102
- add_settings_field('loginnowp',__('Disable wp-login.php','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'custom',array('group'=>$tab,'option'=>'loginnowp','type'=>'checkbox','label'=>__('Block direct access to wp-login.php and return HTTP 404 Not Found Error','wp-cerber')));
103
 
104
- add_settings_section('citadel', __('Citadel mode','wp-cerber'), 'cerber_sapi_section', 'cerber-' . $tab);
105
- add_settings_field('citadel',__('Threshold','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'citadel',array('group'=>$tab,'option'=>'citadel','type'=>'citadel'));
106
- add_settings_field('ciduration',__('Duration','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'citadel',array('group'=>$tab,'option'=>'ciduration','type'=>'text','label'=>__('minutes','wp-cerber'),'size'=>3));
107
- add_settings_field('cinotify',__('Notifications','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'citadel',array('group'=>$tab,'option'=>'cinotify','type'=>'checkbox','label'=>__('Send notification to admin email','wp-cerber').' [ <a href="'.wp_nonce_url(add_query_arg(array('testnotify'=>'citadel', 'settings-updated' => 0)),'control','cerber_nonce').'">'.__('Click to send test','wp-cerber').'</a> ]'));
108
 
109
- add_settings_section('activity', __('Activity','wp-cerber'), 'cerber_sapi_section', 'cerber-' . $tab);
110
- add_settings_field('keeplog',__('Keep records for','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'activity',array('group'=>$tab,'option'=>'keeplog','type'=>'text','label'=>__('days','wp-cerber'),'size'=>3));
111
- add_settings_field('cerberlab',__('Cerber Lab connection','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'activity',array('group'=>$tab,'option'=>'cerberlab','type'=>'checkbox','label'=>__('Send malicious IP addresses to the Cerber Lab','wp-cerber').' <a target="_blank" href="http://wpcerber.com/cerber-laboratory/">Know more</a>'));
112
- add_settings_field('cerberproto',__('Cerber Lab protocol','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'activity',array('group'=>$tab,'option'=>'cerberproto','type'=>'select','set'=> array('HTTP', 'HTTPS')));
113
- add_settings_field('usefile',__('Use file','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'activity',array('group'=>$tab,'option'=>'usefile','type'=>'checkbox','label'=>__('Write failed login attempts to the file','wp-cerber')));
114
 
115
- add_settings_section('prefs', __('Preferences','wp-cerber'), 'cerber_sapi_section', 'cerber-' . $tab);
116
- add_settings_field('ip_extra',__('Drill down IP','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'prefs',array('group'=>$tab,'option'=>'ip_extra','type'=>'checkbox','label'=>__('Retrieve extra WHOIS information for IP','wp-cerber').' <a href="' . cerber_admin_link('help') . '">Know more</a>'));
117
- add_settings_field( 'dateformat', __( 'Date format', 'wp-cerber' ), 'cerberus_field_show', 'cerber-' . $tab, 'prefs', array( 'group' => $tab, 'option' => 'dateformat', 'type' => 'text', 'label' => sprintf(__('if empty, the default format %s will be used','wp-cerber'),'<b>'.cerber_date(time()).'</b>') . ' <a target="_blank" href="http://wpcerber.com/date-format-setting/">Know more</a>' ) );
118
- add_settings_field('admin_lang',__('Use English for admin interface','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'prefs',array('group'=>$tab,'option'=>'admin_lang','type'=>'checkbox'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
 
120
- // Hardening tab --------------------------------------------------------------------------
121
 
122
- $tab='hardening'; // 'cerber-hardening' settings
123
- register_setting( 'cerberus-'.$tab, CERBER_OPT_H);
124
- add_settings_section('hwp', __('Hardening WordPress','wp-cerber'), 'cerber_sapi_section', CERBER_OPT_H);
125
- add_settings_field('stopenum',__('Stop user enumeration','wp-cerber'),'cerberus_field_show',CERBER_OPT_H,'hwp',array('group'=>$tab,'option'=>'stopenum','type'=>'checkbox','label'=>__('Block access to user pages like /?author=n and user data via REST API','wp-cerber')));
126
- add_settings_field('adminphp',__('Protect admin scripts','wp-cerber'),'cerberus_field_show',CERBER_OPT_H,'hwp',array('group'=>$tab,'option'=>'adminphp','type'=>'checkbox','label'=>__('Block unauthorized access to load-scripts.php and load-styles.php','wp-cerber')));
 
 
 
127
 
128
- //if ( crb_is_php_mod() ) {
129
- add_settings_field('phpnoupl',__('Disable PHP in uploads','wp-cerber'),'cerber_field_show',CERBER_OPT_H,'hwp',array('group'=>$tab,'setting'=>'phpnoupl','type'=>'checkbox','label'=>__('Disable execution of PHP scripts in the WordPress media folder','wp-cerber')));
130
- //}
131
- add_settings_field('nophperr',__('Disable PHP error displaying','wp-cerber'),'cerber_field_show',CERBER_OPT_H,'hwp',array('group'=>$tab,'setting'=>'nophperr','type'=>'checkbox'));
132
-
133
- add_settings_field('xmlrpc',__('Disable XML-RPC','wp-cerber'),'cerberus_field_show',CERBER_OPT_H,'hwp',array('group'=>$tab,'option'=>'xmlrpc','type'=>'checkbox','label'=>__('Block access to the XML-RPC server (including Pingbacks and Trackbacks)','wp-cerber')));
134
- add_settings_field('nofeeds',__('Disable feeds','wp-cerber'),'cerberus_field_show',CERBER_OPT_H,'hwp',array('group'=>$tab,'option'=>'nofeeds','type'=>'checkbox','label'=>__('Block access to the RSS, Atom and RDF feeds','wp-cerber')));
135
- add_settings_field('norest',__('Disable REST API','wp-cerber'),'cerberus_field_show',CERBER_OPT_H,'hwp',array('group'=>$tab,'option'=>'norest','type'=>'checkbox','label'=>__('Block access to the WordPress REST API except the following','wp-cerber')));
136
- add_settings_field('restauth', '','cerberus_field_show',CERBER_OPT_H,'hwp',array('group'=>$tab,'option'=>'restauth','type'=>'checkbox','label'=>__('Allow REST API for logged in users','wp-cerber')));
137
- add_settings_field( 'restwhite', '', 'cerber_field_show', CERBER_OPT_H, 'hwp',
138
- array( 'group' => $tab,
139
- 'setting' => 'restwhite',
140
- 'type' => 'textarea',
141
- 'delimiter' => "\n",
142
- 'list' => true,
143
- 'label' => __( 'Specify REST API namespaces to be allowed if REST API is disabled. One string per line.', 'wp-cerber' ) . ' <a target="_blank" href="https://wpcerber.com/restrict-access-to-wordpress-rest-api/">Read more</a>',
 
 
 
 
 
 
 
 
 
 
 
 
144
  ) );
145
  //add_settings_field('hashauthor',__('Hide author usernames','wp-cerber'),'cerberus_field_show',CERBER_OPT_H,'hwp',array('group'=>$tab,'option'=>'hashauthor','type'=>'checkbox','label'=>__('Replace author username with hash for author pages and URLs','wp-cerber')));
146
  //add_settings_field('cleanhead',__('Clean up HEAD','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'hwp',array('group'=>$tab,'option'=>'cleanhead','type'=>'checkbox','label'=>__('Remove generator and version tags from HEAD section','wp-cerber')));
147
  //add_settings_field('ping',__('Disable Pingback','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'hwp',array('group'=>$tab,'option'=>'ping','type'=>'checkbox','label'=>__('Block access to ping functional','wp-cerber')));
148
 
149
  // Users tab -----------------------------------------------------------------------------
150
-
151
- $tab='users'; // 'cerber-users' settings
152
- register_setting( 'cerberus-'.$tab, CERBER_OPT_U);
153
- add_settings_section('us', __('User related settings','wp-cerber'), 'cerber_sapi_section', CERBER_OPT_U);
154
- if (lab_lab()) {
155
- add_settings_field('reglimit',__('Registration limit','wp-cerber'),'cerberus_field_show', CERBER_OPT_U,'us',array('group'=>$tab,'option'=>'reglimit','type'=>'reglimit'));
 
 
 
 
 
 
 
 
 
 
 
 
156
  }
157
  add_settings_field( 'prohibited', __( 'Prohibited usernames', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_U, 'us',
158
- array( 'group' => $tab,
159
- 'setting' => 'prohibited',
160
- 'type' => 'textarea',
161
- 'delimiter' => ',',
162
- 'list' => true,
163
- 'label' => __( 'Usernames from this list are not allowed to log in or register. Any IP address, have tried to use any of these usernames, will be immediately blocked. Use comma to separate logins.', 'wp-cerber' ) . ' ' . __( 'To specify a REGEX pattern wrap a pattern in two forward slashes.', 'wp-cerber' )
 
164
  ) );
165
- add_settings_field('auth_expire',__('User session expire','wp-cerber'),'cerberus_field_show',CERBER_OPT_U,'us',array('group'=>$tab,'option'=>'auth_expire','type'=>'text','label'=>__('in minutes (leave empty to use default WP value)','wp-cerber'),'size' => 6));
166
- add_settings_field('usersort',__('Sort users in dashboard','wp-cerber'),'cerberus_field_show',CERBER_OPT_U,'us',array('group'=>$tab,'option'=>'usersort','type'=>'checkbox','label'=>__('by date of registration','wp-cerber')));
167
-
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  // Antibot & reCAPTCHA -----------------------------------------------------------------------------
169
 
170
- $tab='antispam'; // 'cerber-recaptcha' settings
171
- register_setting( 'cerberus-'.$tab, CERBER_OPT_A);
172
 
173
- add_settings_section('antibot', __('Cerber antispam engine','wp-cerber'), 'cerber_sapi_section', CERBER_OPT_A);
174
- add_settings_field('botscomm',__('Comment form','wp-cerber'),'cerberus_field_show',CERBER_OPT_A,'antibot',array('group'=>$tab,'option'=>'botscomm','type'=>'checkbox','label'=>__('Protect comment form with bot detection engine','wp-cerber') ));
175
- add_settings_field('botsreg',__('Registration form','wp-cerber'),'cerberus_field_show',CERBER_OPT_A,'antibot',array('group'=>$tab,'option'=>'botsreg','type'=>'checkbox','label'=>__('Protect registration form with bot detection engine','wp-cerber') ));
176
- add_settings_field('botsany',__('Other forms','wp-cerber'),'cerberus_field_show',CERBER_OPT_A,'antibot',array('group'=>$tab,'option'=>'botsany','type'=>'checkbox','label'=>__('Protect all forms on the website with bot detection engine','wp-cerber') ));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
- add_settings_section('antibot_more', __('Adjust antispam engine','wp-cerber'), 'cerber_sapi_section', CERBER_OPT_A);
179
- add_settings_field('botssafe',__('Safe mode','wp-cerber'),'cerberus_field_show',CERBER_OPT_A,'antibot_more',array('group'=>$tab,'option'=>'botssafe','type'=>'checkbox','label'=>__('Use less restrictive policies (allow AJAX)','wp-cerber') ));
180
- add_settings_field('botsnoauth',__('Logged in users','wp-cerber'),'cerberus_field_show',CERBER_OPT_A,'antibot_more',array('group'=>$tab,'option'=>'botsnoauth','type'=>'checkbox','label'=>__('Disable bot detection engine for logged in users','wp-cerber') ));
 
 
 
 
 
 
 
 
 
 
 
 
181
  add_settings_field( 'botswhite', __( 'Query whitelist', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_A, 'antibot_more',
182
- array( 'group' => $tab,
183
- 'setting' => 'botswhite',
184
- 'type' => 'textarea',
185
- 'delimiter' => "\n",
186
- 'list' => true,
187
- 'label' => __( 'Enter a part of query string or query path to exclude a request from inspection by the engine. One item per line.', 'wp-cerber' ) . ' ' . __( 'To specify a REGEX pattern, enclose a whole line in two braces.', 'wp-cerber' ) . ' <a href="https://wpcerber.com/antispam-for-wordpress-contact-forms/" target="_blank">Read more</a>',
 
188
  ) );
189
 
190
- add_settings_section('commproc', __('Comment processing','wp-cerber'), 'cerber_sapi_section', CERBER_OPT_A);
191
- add_settings_field('spamcomm',__('If a spam comment detected','wp-cerber'),'cerberus_field_show',CERBER_OPT_A,'commproc',array('group'=>$tab, 'option'=>'spamcomm', 'type'=>'select', 'set' => array(__('Deny it completely','wp-cerber'),__('Mark it as spam','wp-cerber'))));
192
- add_settings_field('trashafter',__('Trash spam comments','wp-cerber'),'cerberus_field_show',CERBER_OPT_A,'commproc',array('group'=>$tab,'option'=>'trashafter','type'=>'text','enabled'=>__('Move spam comments to trash after'),'label'=>__('days','wp-cerber'),'size'=>3));
193
- //add_settings_field('deleteafter',__('Delete comments from trash after','wp-cerber'),'cerberus_field_show',CERBER_OPT_A,'commproc',array('group'=>$tab,'option'=>'deleteafter','type'=>'text','label'=>__('days','wp-cerber'),'size'=>3));
194
-
195
- $tab='recaptcha'; // 'cerber-recaptcha' settings
196
- register_setting( 'cerberus-'.$tab, CERBER_OPT_C);
197
-
198
- add_settings_section('recap', __('reCAPTCHA settings','wp-cerber'), 'cerber_sapi_section', CERBER_OPT_C);
199
- add_settings_field('sitekey',__('Site key','wp-cerber'),'cerberus_field_show',CERBER_OPT_C,'recap',array('group'=>$tab,'option'=>'sitekey','type'=>'text','size' => 60));
200
- add_settings_field('secretkey',__('Secret key','wp-cerber'),'cerberus_field_show',CERBER_OPT_C,'recap',array('group'=>$tab,'option'=>'secretkey','type'=>'text','size' => 60));
201
- add_settings_field('invirecap',__('Invisible reCAPTCHA','wp-cerber'),'cerberus_field_show',CERBER_OPT_C,'recap',array('group'=>$tab,'option'=>'invirecap','type'=>'checkbox','label'=>__('Enable invisible reCAPTCHA','wp-cerber') .' '. __('(do not enable it unless you get and enter the Site and Secret keys for the invisible version)','wp-cerber')));
202
-
203
- add_settings_field('recapreg',__('Registration form','wp-cerber'),'cerberus_field_show',CERBER_OPT_C,'recap',array('group'=>$tab,'option'=>'recapreg','type'=>'checkbox','label'=>__('Enable reCAPTCHA for WordPress registration form','wp-cerber')));
204
- add_settings_field('recapwooreg', '' ,'cerberus_field_show',CERBER_OPT_C,'recap',array('group'=>$tab,'option'=>'recapwooreg','type'=>'checkbox','label'=>__('Enable reCAPTCHA for WooCommerce registration form','wp-cerber')));
 
 
205
 
206
- add_settings_field('recaplost',__('Lost password form','wp-cerber'),'cerberus_field_show',CERBER_OPT_C,'recap',array('group'=>$tab,'option'=>'recaplost','type'=>'checkbox','label'=>__('Enable reCAPTCHA for WordPress lost password form','wp-cerber')));
207
- add_settings_field('recapwoolost', '' ,'cerberus_field_show',CERBER_OPT_C,'recap',array('group'=>$tab,'option'=>'recapwoolost','type'=>'checkbox','label'=>__('Enable reCAPTCHA for WooCommerce lost password form','wp-cerber')));
208
 
209
- add_settings_field('recaplogin',__('Login form','wp-cerber'),'cerberus_field_show',CERBER_OPT_C,'recap',array('group'=>$tab,'option'=>'recaplogin','type'=>'checkbox','label'=>__('Enable reCAPTCHA for WordPress login form','wp-cerber')));
210
- add_settings_field('recapwoologin', '' ,'cerberus_field_show',CERBER_OPT_C,'recap',array('group'=>$tab,'option'=>'recapwoologin','type'=>'checkbox','label'=>__('Enable reCAPTCHA for WooCommerce login form','wp-cerber')));
211
 
212
- add_settings_field('recapcom',__('Antispam','wp-cerber'),'cerberus_field_show',CERBER_OPT_C,'recap',array('group'=>$tab,'option'=>'recapcom','type'=>'checkbox','label'=>__('Enable reCAPTCHA for WordPress comment form','wp-cerber')));
213
- add_settings_field('recapcomauth', '' ,'cerberus_field_show',CERBER_OPT_C,'recap',array('group'=>$tab,'option'=>'recapcomauth','type'=>'checkbox','label'=>__('Disable reCAPTCHA for logged in users','wp-cerber')));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
- add_settings_field('recaplimit',__('Limit attempts','wp-cerber'),'cerberus_field_show',CERBER_OPT_C,'recap',array('group'=>$tab,'option'=>'recaplimit','type'=>'limitz','label' => __('Lock out IP address for %s minutes after %s failed attempts within %s minutes','wp-cerber') ));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
 
217
  // Notifications -----------------------------------------------------------------------------
218
 
@@ -228,7 +746,6 @@ function cerber_settings_init(){
228
  'placeholder' => __( 'Use comma to specify multiple values', 'wp-cerber' ),
229
  'delimiter' => ',',
230
  'list' => true,
231
- 'size' => 60,
232
  'maxlength' => 1000,
233
  'label' => sprintf( __( 'if empty, the admin email %s will be used', 'wp-cerber' ), $def_email )
234
  ) );
@@ -240,7 +757,7 @@ function cerber_settings_init(){
240
  ) );
241
 
242
  add_settings_section('pushit', __('Push notifications','wp-cerber'), 'cerber_sapi_section', CERBER_OPT_N);
243
- add_settings_field('pbtoken','Pushbullet access token','cerber_field_show',CERBER_OPT_N,'pushit',array('group'=>$group,'setting'=>'pbtoken','type'=>'text','size'=>60));
244
 
245
  $set = array();
246
  if ( cerber_is_admin_page( false, array( 'tab' => 'notifications' ) ) ) {
@@ -270,7 +787,6 @@ function cerber_settings_init(){
270
  'placeholder' => __( 'Use comma to specify multiple values', 'wp-cerber' ),
271
  'delimiter' => ',',
272
  'list' => true,
273
- 'size' => 60,
274
  'maxlength' => 1000,
275
  'label' => __( 'if empty, email from notification settings will be used', 'wp-cerber' )
276
  ) );
@@ -353,7 +869,6 @@ function cerber_settings_init(){
353
  'group' => $group,
354
  'setting' => 'timask',
355
  'type' => 'text',
356
- 'size' => 60,
357
  'maxlength' => 1000,
358
  'placeholder' => __( 'Use comma to specify multiple values', 'wp-cerber' ),
359
  'delimiter' => ',',
@@ -536,7 +1051,6 @@ function cerber_settings_init(){
536
  'placeholder' => __( 'Use comma to specify multiple values', 'wp-cerber' ),
537
  'delimiter' => ',',
538
  'list' => true,
539
- 'size' => 60,
540
  'maxlength' => 1000,
541
  'label' => sprintf( __( 'if empty, email from notification settings will be used', 'wp-cerber' ), $def_email )
542
  ) );
@@ -621,7 +1135,8 @@ function cerber_sapi_section( $args ) {
621
  _e( 'In the Citadel mode nobody is able to log in except IPs from the White IP Access List. Active user sessions will not be affected.', 'wp-cerber' );
622
  break;
623
  case 'hwp':
624
- echo __( 'These settings do not affect hosts from the ', 'wp-cerber' ) . ' ' . __( 'White IP Access List', 'wp-cerber' );
 
625
  break;
626
  case 'recap':
627
  _e( 'Before you can start using reCAPTCHA, you have to obtain Site key and Secret key on the Google website', 'wp-cerber' );
@@ -655,7 +1170,7 @@ function cerber_settings_page(){
655
  'activity' => array( 'bx-pulse', __( 'Activity', 'wp-cerber' ) ),
656
  'lockouts' => array( 'bxs-shield', __( 'Lockouts', 'wp-cerber' ) . ' <sup class="loctotal">' . $blocked . '</sup>' ),
657
  'main' => array( 'bx-slider', __( 'Main Settings', 'wp-cerber' ) ),
658
- 'acl' => array( 'bx-lock', __( 'Access Lists', 'wp-cerber' ) . ' <sup class="acltotal">' . $acl . '</sup></a>' ),
659
  'hardening' => array( 'bx-shield-alt', __( 'Hardening', 'wp-cerber' ) ),
660
  'users' => array( 'bx-group', __( 'Users', 'wp-cerber' ) ),
661
  'notifications' => array( 'bx-bell', __( 'Notifications', 'wp-cerber' ) ),
@@ -664,7 +1179,7 @@ function cerber_settings_page(){
664
  $tab = cerber_get_active_tab( $tabs );
665
 
666
  ?>
667
- <div class="wrap crb-admin">
668
 
669
  <h1>WP Cerber Security</h1>
670
 
@@ -717,151 +1232,48 @@ function cerber_show_settings_page( $group = null ) {
717
  else {
718
  $action = 'options.php'; // Display form with settings fields via Settings API
719
  }
720
- echo '<form method="post" action="' . $action . '">';
721
 
722
  settings_fields( 'cerberus-' . $group ); // option group name, the same as used in register_setting().
723
  do_settings_sections( 'cerber-' . $group ); // the same as used in add_settings_section() $page
724
- echo '<div style="padding-left: 220px">';
725
- submit_button();
726
- echo '</div>';
727
- echo '</form>';
728
- }
729
- /*
730
- * Prepare values to display.
731
- * Generate HTML for one input field on the settings page.
732
- *
733
- *
734
- */
735
- function cerberus_field_show($args){
736
-
737
- $settings = get_site_option('cerber-'.$args['group']);
738
- if ( is_array( $settings ) ) {
739
- array_walk_recursive( $settings, 'esc_html' );
740
- }
741
- $pre = '';
742
- $value = '';
743
- $disabled = '';
744
- if ( ! empty( $args['label'] ) ) {
745
- $label = $args['label'];
746
- } else {
747
- $label = '';
748
- }
749
- if ( isset( $args['option'] ) ) {
750
- if ( isset( $settings[ $args['option'] ] ) ) {
751
- $value = $settings[ $args['option'] ];
752
- }
753
- if ( ( $args['option'] == 'loginnowp' || $args['option'] == 'loginpath' ) && ! cerber_is_permalink_enabled() ) {
754
- $disabled = ' disabled="disabled" ';
755
- }
756
- if ( $args['option'] == 'loginpath' ) {
757
- $pre = rtrim( get_home_url(), '/' ) . '/';
758
- $value = urldecode( $value );
759
- }
760
- }
761
-
762
- $name = 'cerber-'.$args['group'].'['.$args['option'].']';
763
-
764
- switch ($args['type']) {
765
 
766
- case 'limitz':
767
- $s1 = $args['group'].'-period';
768
- $s2 = $args['group'].'-number';
769
- $s3 = $args['group'].'-within';
770
-
771
- $html=sprintf( $args['label'] ,
772
- '<input type="text" name="cerber-'.$args['group'].'['.$s1.']" value="'.$settings[$s1].'" size="3" maxlength="3" />',
773
- '<input type="text" name="cerber-'.$args['group'].'['.$s2.']" value="'.$settings[$s2].'" size="3" maxlength="3" />',
774
- '<input type="text" name="cerber-'.$args['group'].'['.$s3.']" value="'.$settings[$s3].'" size="3" maxlength="3" />');
775
- break;
776
 
777
- case 'attempts':
778
- $html=sprintf(__('%s allowed retries in %s minutes','wp-cerber'),
779
- '<input type="text" id="attempts" name="cerber-'.$args['group'].'[attempts]" value="'.$settings['attempts'].'" size="3" maxlength="3" />',
780
- '<input type="text" id="period" name="cerber-'.$args['group'].'[period]" value="'.$settings['period'].'" size="3" maxlength="3" />');
781
- break;
782
- case 'reglimit':
783
- $html=sprintf(__('%s allowed registrations in %s minutes from one IP','wp-cerber'),
784
- '<input type="text" id="reglimit-num" name="cerber-'.$args['group'].'[reglimit_num]" value="'.$settings['reglimit_num'].'" size="3" maxlength="3" />',
785
- '<input type="text" id="reglimit-min" name="cerber-'.$args['group'].'[reglimit_min]" value="'.$settings['reglimit_min'].'" size="4" maxlength="4" />');
786
- break;
787
- case 'aggressive':
788
- $html=sprintf(__('Increase lockout duration to %s hours after %s lockouts in the last %s hours','wp-cerber'),
789
- '<input type="text" id="agperiod" name="cerber-'.$args['group'].'[agperiod]" value="'.$settings['agperiod'].'" size="3" maxlength="3" />',
790
- '<input type="text" id="aglocks" name="cerber-'.$args['group'].'[aglocks]" value="'.$settings['aglocks'].'" size="3" maxlength="3" />',
791
- '<input type="text" id="aglast" name="cerber-'.$args['group'].'[aglast]" value="'.$settings['aglast'].'" size="3" maxlength="3" />');
792
- break;
793
- case 'notify':
794
- $html= '<label class="crb-switch"><input class="screen-reader-text" type="checkbox" id="'.$args['option'].'" name="cerber-'.$args['group'].'['.$args['option'].']" value="1" '.checked(1,$value,false).$disabled.' /><span class="crb-slider round"></span></label>'
795
- .__('Notify admin if the number of active lockouts above','wp-cerber').
796
- ' <input type="text" id="above" name="cerber-'.$args['group'].'[above]" value="'.$settings['above'].'" size="3" maxlength="3" />'.
797
- ' [ <a href="' . wp_nonce_url( add_query_arg( array( 'testnotify' => 'lockout', 'settings-updated' => 0 ) ), 'control', 'cerber_nonce' ) . '">' . __( 'Click to send test', 'wp-cerber' ) . '</a> ]';
798
- break;
799
- case 'citadel':
800
- $html=sprintf(__('Enable after %s failed login attempts in last %s minutes','wp-cerber'),
801
- '<input type="text" id="cilimit" name="cerber-'.$args['group'].'[cilimit]" value="'.$settings['cilimit'].'" size="3" maxlength="3" />',
802
- '<input type="text" id="ciperiod" name="cerber-'.$args['group'].'[ciperiod]" value="'.$settings['ciperiod'].'" size="3" maxlength="3" />');
803
- break;
804
- case 'checkbox':
805
- $html='<label class="crb-switch"><input class="screen-reader-text" type="checkbox" id="'.$args['option'].'" name="'.$name.'" value="1" '.checked(1,$value,false).$disabled.' /><span class="crb-slider round"></span></label>';
806
- //$html.= $args['label'];
807
- $html.= '<label for="'.$args['option'].'">'.$label.'</label>';
808
- break;
809
- case 'textarea':
810
- //$name = 'cerber-'.$args['group'].'['.$args['option'].']';
811
- $html='<textarea class="large-text code" id="'.$args['option'].'" name="'.$name.'" '.$disabled.' />'.$value.'</textarea>';
812
- $html.= '<br><label for="'.$args['option'].'">'.$args['label'].'</label>';
813
- break;
814
- case 'select':
815
- //$name = 'cerber-'.$args['group'].'['.$args['option'].']';
816
- $html=cerber_select($name,$args['set'],$value);
817
- break;
818
- case 'text':
819
- default:
820
- //$name = 'cerber-'.$args['group'].'['.$args['option'].']';
821
- if ( isset( $args['size'] ) ) {
822
- $size = ' size="' . $args['size'] . '" maxlength="' . $args['size'] . '" ';
823
- } else {
824
- $size = '';
825
- }
826
- if ( isset( $args['placeholder'] ) ) {
827
- $plh = ' placeholder="' . $args['placeholder'] . '"';
828
- } else {
829
- $plh = '';
830
- }
831
- $html = $pre . '<input type="text" id="' . $args['option'] . '" name="'.$name.'" value="' . $value . '"' . $disabled . $size . $plh. '/>';
832
- $html .= ' <label for="' . $args['option'] . '">' . $label . '</label>';
833
- break;
834
  }
835
 
836
- if (!empty($args['enabled'])){
837
- $name = 'cerber-'.$args['group'].'['.$args['option'].'-enabled]';
838
- $value = 0;
839
- if ( isset( $settings[ $args['option'] . '-enabled' ] ) ) {
840
- $value = $settings[ $args['option'] . '-enabled' ];
841
- }
842
- $checkbox = '<label class="crb-switch"><input class="screen-reader-text" type="checkbox" id="' . $args['option'] . '-enabled" name="' . $name . '" value="1" ' . checked( 1, $value, false ) . ' /><span class="crb-slider round"></span></label>' . $args['enabled'];
843
- $html = $checkbox . $html;
844
- }
845
-
846
- echo $html."\n";
847
  }
848
 
849
  /**
850
- * A new version of cerberus_field_show()
 
851
  *
852
  * @param $args
853
  */
854
- function cerber_field_show($args){
855
 
856
- $settings = get_site_option('cerber-'.$args['group']);
 
857
  if ( is_array( $settings ) ) {
858
  array_walk_recursive( $settings, 'esc_html' );
859
  }
860
- $pre = '';
861
- $value = '';
862
  $disabled = '';
863
 
864
  $label = empty( $args['label'] ) ? '' : $args['label'];
 
 
 
 
 
 
 
 
865
 
866
  if ( isset( $args['setting'] ) ) {
867
  if ( isset( $settings[ $args['setting'] ] ) ) {
@@ -872,76 +1284,90 @@ function cerber_field_show($args){
872
  $disabled = ' disabled="disabled" ';
873
  }
874
  if ( $args['setting'] == 'loginpath' ) {
875
- $pre = rtrim( get_home_url(), '/' ) . '/';
876
  $value = urldecode( $value );
877
  }
878
  }
879
 
880
  if ( isset( $args['list'] ) ) {
881
- $value = cerber_array2text($value, $args['delimiter']);
882
  }
883
 
884
- $name = 'cerber-'.$args['group'].'['.$args['setting'].']';
 
885
 
886
- switch ($args['type']) {
 
 
 
 
 
 
 
 
887
 
888
  case 'limitz':
889
- $s1 = $args['group'].'-period';
890
- $s2 = $args['group'].'-number';
891
- $s3 = $args['group'].'-within';
892
-
893
- $html=sprintf( $label ,
894
- '<input type="text" name="cerber-'.$args['group'].'['.$s1.']" value="'.$settings[$s1].'" size="3" maxlength="3" />',
895
- '<input type="text" name="cerber-'.$args['group'].'['.$s2.']" value="'.$settings[$s2].'" size="3" maxlength="3" />',
896
- '<input type="text" name="cerber-'.$args['group'].'['.$s3.']" value="'.$settings[$s3].'" size="3" maxlength="3" />');
897
  break;
898
 
899
  case 'attempts':
900
- $html=sprintf(__('%s allowed retries in %s minutes','wp-cerber'),
901
- '<input type="text" id="attempts" name="cerber-'.$args['group'].'[attempts]" value="'.$settings['attempts'].'" size="3" maxlength="3" />',
902
- '<input type="text" id="period" name="cerber-'.$args['group'].'[period]" value="'.$settings['period'].'" size="3" maxlength="3" />');
903
  break;
904
  case 'reglimit':
905
- $html=sprintf(__('%s allowed registrations in %s minutes from one IP','wp-cerber'),
906
- '<input type="text" id="reglimit-num" name="cerber-'.$args['group'].'[reglimit_num]" value="'.$settings['reglimit_num'].'" size="3" maxlength="3" />',
907
- '<input type="text" id="reglimit-min" name="cerber-'.$args['group'].'[reglimit_min]" value="'.$settings['reglimit_min'].'" size="3" maxlength="3" />');
908
  break;
909
  case 'aggressive':
910
- $html=sprintf(__('Increase lockout duration to %s hours after %s lockouts in the last %s hours','wp-cerber'),
911
- '<input type="text" id="agperiod" name="cerber-'.$args['group'].'[agperiod]" value="'.$settings['agperiod'].'" size="3" maxlength="3" />',
912
- '<input type="text" id="aglocks" name="cerber-'.$args['group'].'[aglocks]" value="'.$settings['aglocks'].'" size="3" maxlength="3" />',
913
- '<input type="text" id="aglast" name="cerber-'.$args['group'].'[aglast]" value="'.$settings['aglast'].'" size="3" maxlength="3" />');
914
  break;
915
  case 'notify':
916
- $html= '<label class="crb-switch"><input class="screen-reader-text" type="checkbox" id="'.$args['setting'].'" name="cerber-'.$args['group'].'['.$args['setting'].']" value="1" '.checked(1,$value,false).$disabled.' /><span class="crb-slider round"></span></label>'
917
- .__('Notify admin if the number of active lockouts above','wp-cerber').
918
- ' <input type="text" id="above" name="cerber-'.$args['group'].'[above]" value="'.$settings['above'].'" size="3" maxlength="3" />'.
919
- ' [ <a href="' . wp_nonce_url( add_query_arg( array( 'testnotify' => 'lockout', 'settings-updated' => 0 ) ), 'control', 'cerber_nonce' ) . '">' . __( 'Click to send test', 'wp-cerber' ) . '</a> ]';
 
 
 
920
  break;
921
  case 'citadel':
922
- $html=sprintf(__('Enable after %s failed login attempts in last %s minutes','wp-cerber'),
923
- '<input type="text" id="cilimit" name="cerber-'.$args['group'].'[cilimit]" value="'.$settings['cilimit'].'" size="3" maxlength="3" />',
924
- '<input type="text" id="ciperiod" name="cerber-'.$args['group'].'[ciperiod]" value="'.$settings['ciperiod'].'" size="3" maxlength="3" />');
925
  break;
926
  case 'checkbox':
927
- $html='<label class="crb-switch"><input class="screen-reader-text" type="checkbox" id="'.$args['setting'].'" name="'.$name.'" value="1" '.checked(1,$value,false).$disabled.' /><span class="crb-slider round"></span></label>';
928
- $html.= '<label for="'.$args['setting'].'">'.$label.'</label>';
929
  break;
930
  case 'textarea':
931
- $html = '<textarea class="large-text code" id="' . $args['setting'] . '" name="' . $name . '" ' . $disabled . ' />' . $value . '</textarea>';
932
- $html .= '<br><label for="' . $args['setting'] . '">' . $label . '</label>';
933
  break;
934
  case 'select':
935
  $html = cerber_select( $name, $args['set'], $value );
936
  break;
 
 
 
937
  case 'checkbox_set':
938
  $html = '<div class="crb-checkbox_set" style="line-height: 2em;">';
939
  foreach ( $args['set'] as $key => $item ) {
940
  $v = ( ! empty( $value[ $key ] ) ) ? $value[ $key ] : 0;
941
- $html .= '<input type="checkbox" value="1" name="' . $name . '[' . $key . ']" ' . checked( 1, $v, false ) . $disabled . '/>' . $item . '</br>';
942
  }
943
  $html .= '</div>';
944
- //$html='<textarea class="large-text code" id="'.$args['setting'].'" name="'.$name.'" '.$disabled.' />'.$value.'</textarea>';
945
  break;
946
  case 'reptime':
947
  $html = cerber_time_select( $args, $settings );
@@ -952,31 +1378,41 @@ function cerber_field_show($args){
952
  break;
953
  case 'text':
954
  default:
955
- $size = '';
956
- $maxlength = '';
957
- $attrs = '';
958
- if ( isset( $args['size'] ) ) {
959
- //$size = ' size="' . $args['size'] . '" maxlength="' . $args['size'] . '" ';
960
- $size = ' size="' . $args['size'] . '"';
961
- }
962
- if ( isset( $args['maxlength'] ) ) {
963
- $maxlength = ' maxlength="' . $args['maxlength'] . '" ';
964
  }
965
- elseif ( isset( $args['size'] ) ) {
966
- $maxlength = ' maxlength="' . $args['size'] . '" ';
967
- }
968
- if ( isset( $args['placeholder'] ) ) {
969
- $attrs .= ' placeholder="' . $args['placeholder'] . '"';
970
- }
971
- if ( isset( $args['pattern'] ) ) {
972
- $attrs .= ' pattern="' . $args['pattern'] . '"';
973
- }
974
- if ( isset( $args['title'] ) ) {
975
- $attrs .= ' title="' . $args['title'] . '"';
976
- }
977
- $html = $pre . '<input type="text" id="' . $args['setting'] . '" name="' . $name . '" value="' . $value . '"' . $disabled . $size . $maxlength . $attrs . '/>';
978
- $html .= ' <label for="' . $args['setting'] . '">' . $label . '</label>';
979
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
980
  }
981
 
982
  if ( ! empty( $args['enabled'] ) ) {
@@ -989,7 +1425,7 @@ function cerber_field_show($args){
989
  $html = $checkbox . ' ' . $html;
990
  }
991
 
992
- echo $html."\n";
993
  }
994
 
995
  /**
@@ -1001,15 +1437,50 @@ function cerber_field_show($args){
1001
  *
1002
  * @return string
1003
  */
1004
- function cerber_select( $name, $list, $selected = null, $class = '', $multiple = '' ) {
1005
  $options = array();
1006
  foreach ( $list as $key => $value ) {
1007
  $s = ( $selected == (string) $key ) ? 'selected' : '';
1008
  $options[] = '<option value="' . $key . '" ' . $s . '>' . htmlspecialchars( $value ) . '</option>';
1009
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1010
  $m = ( $multiple ) ? 'multiple="multiple"' : '';
1011
 
1012
- return ' <select name="' . $name . '" class="crb-select ' . $class . '" ' . $m . '>' . implode( "\n", $options ) . '</select>';
 
 
 
 
 
 
 
1013
  }
1014
 
1015
  function cerber_time_select($args, $settings){
@@ -1075,7 +1546,7 @@ add_filter( 'pre_update_option_'.CERBER_OPT, function ($new, $old, $option) {
1075
  $new['loginpath'] = urlencode( str_replace( '/', '', $new['loginpath'] ) );
1076
  $new['loginpath'] = sanitize_text_field($new['loginpath']);
1077
  if ( $new['loginpath'] && $new['loginpath'] != $old['loginpath'] ) {
1078
- $href = get_home_url() . '/' . $new['loginpath'] . '/';
1079
  $url = urldecode( $href );
1080
  $msg = array();
1081
  $msg_e = array();
@@ -1116,6 +1587,8 @@ add_filter( 'pre_update_option_'.CERBER_OPT_U, function ($new, $old, $option) {
1116
 
1117
  $new['prohibited'] = cerber_text2array($new['prohibited'], ',', 'strtolower');
1118
 
 
 
1119
  return $new;
1120
  }, 10, 3 );
1121
  /*
@@ -1466,9 +1939,14 @@ function cerber_ms_update() {
1466
  if ( !cerber_is_http_post() || ! isset( $_POST['action'] ) || $_POST['action'] != 'update' ) {
1467
  return;
1468
  }
1469
- if ( ! isset( $_POST['option_page'] ) || false === strpos( $_POST['option_page'], 'cerberus-' ) ) {
 
 
 
 
1470
  return;
1471
  }
 
1472
  if ( ! current_user_can( 'manage_options' ) ) {
1473
  return;
1474
  }
@@ -1476,7 +1954,9 @@ function cerber_ms_update() {
1476
  // See wp_nonce_field() in the settings_fields() function
1477
  check_admin_referer($_POST['option_page'].'-options');
1478
 
1479
- $opt_name = 'cerber-' . substr( $_POST['option_page'], 9 ); // 8 = length of 'cerberus-'
 
 
1480
 
1481
  $old = (array) get_site_option( $opt_name );
1482
  $new = $_POST[ $opt_name ];
@@ -1535,18 +2015,24 @@ function cerber_get_defaults() {
1535
  'nophperr' => 1,
1536
  'xmlrpc' => 0,
1537
  'nofeeds' => 0,
 
1538
  'norest' => 0,
1539
  'restauth' => 1,
 
1540
  'restwhite' => 'oembed',
1541
  'hashauthor' => 0,
1542
  'cleanhead' => 1,
1543
  ),
1544
  CERBER_OPT_U => array(
1545
- 'reglimit_num' => 3,
1546
- 'reglimit_min' => 60,
1547
- 'prohibited' => array(),
1548
- 'auth_expire' => '',
1549
- 'usersort' => '',
 
 
 
 
1550
  ),
1551
  CERBER_OPT_A => array(
1552
  'botscomm' => 1,
@@ -1643,7 +2129,7 @@ function cerber_get_defaults() {
1643
  * Upgrade plugin options
1644
  *
1645
  */
1646
- function cerber_upgrade_options() {
1647
  // @since 4.4, move fields to a new option
1648
  if ( $main = get_site_option( CERBER_OPT ) ) {
1649
  if ( ! empty( $main['email'] ) || ! empty( $main['emailrate'] ) ) {
@@ -1689,6 +2175,13 @@ function cerber_upgrade_options() {
1689
 
1690
  update_site_option( $option_name, $values );
1691
  }
 
 
 
 
 
 
 
1692
  }
1693
 
1694
  /**
@@ -1717,7 +2210,7 @@ function crb_move_fields( $from, $to, $fields ) {
1717
  * @since 2.0
1718
  *
1719
  */
1720
- function cerber_save_options( $options ) {
1721
  foreach ( cerber_get_defaults() as $option_name => $fields ) {
1722
  $filtered = array();
1723
  foreach ( $fields as $field_name => $def ) {
@@ -1895,7 +2388,7 @@ function cerber_load_defaults() {
1895
  if ( ! empty( $old['loginpath'] ) ) {
1896
  $save['loginpath'] = $old['loginpath'];
1897
  }
1898
- cerber_save_options( $save );
1899
  }
1900
 
1901
  /**
@@ -1957,7 +2450,7 @@ function cerber_cloud_sync( $data = array() ) {
1957
  );
1958
  $scan_scheduling = array( // Is used for scheduled scans
1959
  'client' => $set,
1960
- 'site_url' => home_url(),
1961
  'gmt_offset' => (int) get_option( 'gmt_offset' ),
1962
  'dtf' => cerber_get_dt_format(),
1963
  );
1
  <?php
2
  /*
3
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
4
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
47
  define('CERBER_OPT_E','cerber-schedule');
48
  define('CERBER_OPT_P','cerber-policies');
49
 
50
+ function cerber_get_setting_page_id() {
51
+ $id = crb_array_get( $_GET, 'tab' );
52
+ if ( ! $id ) {
53
+ $id = cerber_get_wp_option_id();
54
+ }
55
+ if ( ! $id ) {
56
+ $id = 'antispam';
57
+ }
58
+ // Some tabs doesn't match WP setting names
59
+ $map = array(
60
+ 'scan_settings' => 'scanner',
61
+ 'scan_schedule' => 'schedule',
62
+ 'scan_policy' => 'policies',
63
+ 'ti_settings' => 'traffic',
64
+ 'captcha' => 'recaptcha',
65
+ );
66
+
67
+ if ( isset( $map[ $id ] ) ) {
68
+ return $map[ $id ];
69
+ }
70
+
71
+ return $id;
72
+ }
73
+
74
+ /**
75
+ * During the updating WP options
76
+ *
77
+ * @return bool|string
78
+ */
79
+ function cerber_get_wp_option_id() {
80
+
81
+ $op = crb_array_get( $_POST, 'option_page' );
82
+ if ( $op && ( 0 === strpos( $op, 'cerberus-' ) ) ) {
83
+ return substr( $op, 9 ); // 8 = length of 'cerberus-'
84
+ }
85
+
86
+ return false;
87
+ }
88
+
89
+ function cerber_settings_config( $args = array() ) {
90
+ if ( $args && ! is_array( $args ) ) {
91
+ return false;
92
+ }
93
+ // WP setting is: 'cerber-'.$screen_id
94
+ $screens = array(
95
+ 'users' => array( 'us' ), // CERBER_OPT_U
96
+ );
97
+ $sections = array(
98
+ 'us' => array(
99
+ 'name' => __( 'User related settings', 'wp-cerber' ),
100
+ //'info' => __( 'User related settings', 'wp-cerber' ),
101
+ 'fields' => array(
102
+ 'authonly' => array(
103
+ 'title' => __( 'Authorized users only', 'wp-cerber' ),
104
+ 'label' => __( 'Only registered and logged in website users have access to the website', 'wp-cerber' ),
105
+ 'doclink' => 'https://wpcerber.com/only-logged-in-wordpress-users/',
106
+ 'type' => 'checkbox',
107
+ 'default' => 0,
108
+ ),
109
+ 'authonlyacl' => array(
110
+ 'title' => __( 'Use White IP Access List', 'wp-cerber' ),
111
+ 'label' => __( 'Do not apply this policy to IP addresses in the White IP Access List', 'wp-cerber' ),
112
+ 'type' => 'checkbox',
113
+ 'default' => 0,
114
+ 'enabler' => array( 'authonly' ),
115
+ ),
116
+ 'authonlymsg' => array(
117
+ 'title' => __( 'User Message', 'wp-cerber' ),
118
+ 'placeholder' => 'An optional login form message',
119
+ 'type' => 'textarea',
120
+ //'filter' => 'strip_tags',
121
+ 'default' => __( 'Only registered and logged in users are allowed to view this website', 'wp-cerber' ),
122
+ 'enabler' => array( 'authonly' ),
123
+ 'class' => ''
124
+ ),
125
+ 'authonlyredir' => array(
126
+ 'title' => __( 'Redirect to URL', 'wp-cerber' ),
127
+ //'label' => __( 'if empty, visitors are redirected to the login page', 'wp-cerber' )
128
+ 'placeholder' => 'http://',
129
+ 'type' => 'url',
130
+ 'default' => '',
131
+ 'maxlength' => 1000,
132
+ 'enabler' => array( 'authonly' ),
133
+ ),
134
+ 'reglimit' => array(
135
+ 'title' => __( 'Registration limit', 'wp-cerber' ),
136
+ 'type' => 'reglimit',
137
+ 'default' => array( 3, 60 ),
138
+ 'pro' => 1
139
+ ),
140
+ 'prohibited' => array(
141
+ 'title' => __( 'Prohibited usernames', 'wp-cerber' ),
142
+ 'label' => __( 'Usernames from this list are not allowed to log in or register. Any IP address, have tried to use any of these usernames, will be immediately blocked. Use comma to separate logins.', 'wp-cerber' ) . ' ' . __( 'To specify a REGEX pattern wrap a pattern in two forward slashes.', 'wp-cerber' ),
143
+ 'type' => 'textarea',
144
+ 'delimiter' => ',',
145
+ 'list' => true,
146
+ 'default' => array(),
147
+ ),
148
+ 'auth_expire' => array(
149
+ 'title' => __( 'User session expire', 'wp-cerber' ),
150
+ 'label' => __( 'in minutes (leave empty to use default WP value)', 'wp-cerber' ),
151
+ 'default' => '',
152
+ 'type' => 'text',
153
+ 'size' => 6,
154
+ ),
155
+ 'usersort' => array(
156
+ 'title' => __( 'Sort users in dashboard', 'wp-cerber' ),
157
+ 'label' => __( 'by date of registration', 'wp-cerber' ),
158
+ 'default' => '',
159
+ 'type' => 'checkbox',
160
+ ),
161
+ )
162
+ ),
163
+ );
164
+
165
+ if ( $screen_id = crb_array_get( $args, 'screen_id' ) ) {
166
+ if ( empty( $screens[ $screen_id ] ) ) {
167
+ return false;
168
+ }
169
+
170
+ return array_intersect_key( $sections, array_flip( $screens[ $screen_id ] ) );
171
+ }
172
+
173
+ if ( $setting = crb_array_get( $args, 'setting' ) ) {
174
+ foreach ( $sections as $s ) {
175
+ if ( isset( $s['fields'][ $setting ] ) ) {
176
+ return $s['fields'][ $setting ];
177
+ }
178
+ }
179
+
180
+ return false;
181
+
182
+ }
183
+
184
+ return $sections;
185
+ }
186
+
187
+ /**
188
+ * Configure WP Settings API stuff for a given admin page
189
+ *
190
+ * @since 7.9.7
191
+ *
192
+ * @param $screen_id string
193
+ */
194
+ function cerber_wp_settings_setup( $screen_id ) {
195
+ if ( ! $sections = cerber_settings_config( array( 'screen_id' => $screen_id ) ) ) {
196
+ return;
197
+ }
198
+ $option = 'cerber-' . $screen_id;
199
+ register_setting( 'cerberus-' . $screen_id, $option );
200
+ foreach ( $sections as $section => $section_config ) {
201
+ add_settings_section( $section, $section_config['name'], 'cerber_sapi_section', $option );
202
+ foreach ( $section_config['fields'] as $field => $config ) {
203
+ if ( isset( $config['pro'] ) && !lab_lab() ) {
204
+ continue;
205
+ }
206
+ $config['setting'] = $field;
207
+ $config['group'] = $screen_id;
208
+
209
+ // Enabling/disabling conditional inputs
210
+ $enabled = true;
211
+ if ( isset( $config['enabler'][0] ) ) {
212
+ $enab_val = crb_get_settings( $config['enabler'][0] );
213
+ if ( isset( $config['enabler'][1] ) ) {
214
+ if ( $enab_val != $config['enabler'][1] ) {
215
+ $enabled = false;
216
+ }
217
+ }
218
+ else {
219
+ if ( empty( $enab_val ) ) {
220
+ $enabled = false;
221
+ }
222
+ }
223
+ }
224
+ if ( ! $enabled ) {
225
+ if ( ! isset( $config['class'] ) ) {
226
+ $config['class'] = '';
227
+ }
228
+ $config['class'] .= ' crb-disable-this';
229
+ }
230
+
231
+ add_settings_field( $field, $config['title'], 'cerber_field_show', $option, $section, $config );
232
+ }
233
+ }
234
+ }
235
+
236
  /**
237
  * A set of Cerber setting (WP options)
238
  *
253
  return;
254
  }
255
 
256
+ cerber_wp_settings_setup( cerber_get_setting_page_id() );
257
+
258
  // Main Settings tab ---------------------------------------------------------------------
259
 
260
+ $tab = 'main'; // 'cerber-main' settings
261
+ register_setting( 'cerberus-' . $tab, CERBER_OPT );
262
+
263
+ add_settings_section( 'boot', __( 'Plugin initialization', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT );
264
+ add_settings_field( 'boot-mode', __( 'Load security engine', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'boot',
265
+ array(
266
+ 'group' => $tab,
267
+ 'setting' => 'boot-mode',
268
+ 'type' => 'select',
269
+ 'set' => array(
270
+ __( 'Legacy mode', 'wp-cerber' ),
271
+ __( 'Standard mode', 'wp-cerber' )
272
+ )
273
+ ) );
274
+
275
+ add_settings_section( 'liloa', __( 'Limit login attempts', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT );
276
+ add_settings_field( 'attempts', __( 'Attempts', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'liloa',
277
+ array(
278
+ 'group' => $tab,
279
+ 'setting' => 'attempts',
280
+ 'type' => 'attempts'
281
+ ) );
282
+ add_settings_field( 'lockout', __( 'Lockout duration', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'liloa',
283
+ array(
284
+ 'group' => $tab,
285
+ 'setting' => 'lockout',
286
+ 'type' => 'text',
287
+ 'label' => __( 'minutes', 'wp-cerber' ),
288
+ 'size' => 3
289
+ ) );
290
+ add_settings_field( 'aggressive', __( 'Aggressive lockout', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'liloa',
291
+ array(
292
+ 'group' => $tab,
293
+ 'setting' => 'aggressive',
294
+ 'type' => 'aggressive'
295
+ ) );
296
+ add_settings_field( 'limitwhite', __( 'Use White IP Access List', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'liloa',
297
+ array(
298
+ 'group' => $tab,
299
+ 'setting' => 'limitwhite',
300
+ 'type' => 'checkbox',
301
+ 'label' => __( 'Apply limit login rules to IP addresses in the White IP Access List', 'wp-cerber' )
302
+ ) );
303
+ add_settings_field( 'notify', __( 'Notifications', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'liloa',
304
+ array(
305
+ 'group' => $tab,
306
+ 'setting' => 'notify',
307
+ 'type' => 'notify'
308
+ ) );
309
+ add_settings_field( 'proxy', __( 'Site connection', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'liloa',
310
+ array(
311
+ 'group' => $tab,
312
+ 'setting' => 'proxy',
313
+ 'type' => 'checkbox',
314
+ 'label' => __( 'My site is behind a reverse proxy', 'wp-cerber' )
315
+ ) );
316
+
317
+ add_settings_section( 'proactive', __( 'Proactive security rules', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT );
318
+ add_settings_field( 'subnet', __( 'Block subnet', 'wp-cerber' ), 'cerber_field_show', 'cerber-' . $tab, 'proactive', array(
319
+ 'group' => $tab,
320
+ 'setting' => 'subnet',
321
+ 'type' => 'checkbox',
322
+ 'label' => __( 'Always block entire subnet Class C of intruders IP', 'wp-cerber' )
323
+ ) );
324
+ add_settings_field( 'nonusers', __( 'Non-existent users', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'proactive', array(
325
+ 'group' => $tab,
326
+ 'setting' => 'nonusers',
327
+ 'type' => 'checkbox',
328
+ 'label' => __( 'Immediately block IP when attempting to login with a non-existent username', 'wp-cerber' )
329
+ ) );
330
+ add_settings_field( 'noredirect', __( 'Disable dashboard redirection', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'proactive', array(
331
+ 'group' => $tab,
332
+ 'setting' => 'noredirect',
333
+ 'type' => 'checkbox',
334
+ 'label' => __( 'Disable automatic redirection to the login page when /wp-admin/ is requested by an unauthorized request', 'wp-cerber' )
335
+ ) );
336
+ add_settings_field( 'wplogin', __( 'Request wp-login.php', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'proactive', array(
337
+ 'group' => $tab,
338
+ 'setting' => 'wplogin',
339
+ 'type' => 'checkbox',
340
+ 'label' => __( 'Immediately block IP after any request to wp-login.php', 'wp-cerber' )
341
+ ) );
342
+ add_settings_field( 'page404', __( 'Display 404 page', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'proactive', array(
343
+ 'group' => $tab,
344
+ 'setting' => 'page404',
345
+ 'type' => 'select',
346
+ 'set' => array(
347
+ __( 'Use 404 template from the active theme', 'wp-cerber' ),
348
+ __( 'Display simple 404 page', 'wp-cerber' )
349
+ )
350
+ ) );
351
+
352
+ add_settings_section( 'custom', __( 'Custom login page', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT );
353
+ add_settings_field( 'loginpath', __( 'Custom login URL', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'custom',
354
+ array(
355
+ 'group' => $tab,
356
+ 'setting' => 'loginpath',
357
+ 'size' => 30,
358
+ 'type' => 'text',
359
+ 'pattern' => '[a-zA-Z0-9\-_]{1,100}',
360
+ 'title' => __( 'Custom login URL may contain only letters, numbers, dashes and underscores', 'wp-cerber' ),
361
+ 'label' => __( 'must not overlap with the existing pages or posts slug', 'wp-cerber' )
362
+ ) );
363
+ add_settings_field( 'loginnowp', __( 'Disable wp-login.php', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'custom',
364
+ array(
365
+ 'group' => $tab,
366
+ 'setting' => 'loginnowp',
367
+ 'type' => 'checkbox',
368
+ 'label' => __( 'Block direct access to wp-login.php and return HTTP 404 Not Found Error', 'wp-cerber' )
369
+ ) );
370
+
371
+ add_settings_section( 'citadel', __( 'Citadel mode', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT );
372
+ add_settings_field( 'citadel', __( 'Threshold', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'citadel',
373
+ array(
374
+ 'group' => $tab,
375
+ 'setting' => 'citadel',
376
+ 'type' => 'citadel'
377
+ ) );
378
+ add_settings_field( 'ciduration', __( 'Duration', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'citadel',
379
+ array(
380
+ 'group' => $tab,
381
+ 'setting' => 'ciduration',
382
+ 'type' => 'text',
383
+ 'label' => __( 'minutes', 'wp-cerber' ),
384
+ 'size' => 3
385
+ ) );
386
+ add_settings_field( 'cinotify', __( 'Notifications', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'citadel',
387
+ array(
388
+ 'group' => $tab,
389
+ 'setting' => 'cinotify',
390
+ 'type' => 'checkbox',
391
+ 'label' => __( 'Send notification to admin email', 'wp-cerber' ) . ' [ <a href="' . wp_nonce_url( add_query_arg( array(
392
+ 'testnotify' => 'citadel',
393
+ 'settings-updated' => 0
394
+ ) ), 'control', 'cerber_nonce' ) . '">' . __( 'Click to send test', 'wp-cerber' ) . '</a> ]'
395
+ ) );
396
+
397
+ add_settings_section( 'activity', __( 'Activity', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT );
398
+ add_settings_field( 'keeplog', __( 'Keep records for', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'activity', array(
399
+ 'group' => $tab,
400
+ 'setting' => 'keeplog',
401
+ 'type' => 'text',
402
+ 'label' => __( 'days', 'wp-cerber' ),
403
+ 'size' => 3
404
+ ) );
405
+ add_settings_field( 'cerberlab', __( 'Cerber Lab connection', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'activity', array(
406
+ 'group' => $tab,
407
+ 'setting' => 'cerberlab',
408
+ 'type' => 'checkbox',
409
+ 'label' => __( 'Send malicious IP addresses to the Cerber Lab', 'wp-cerber' ) . ' <a target="_blank" href="http://wpcerber.com/cerber-laboratory/">Know more</a>'
410
+ ) );
411
+ add_settings_field( 'cerberproto', __( 'Cerber Lab protocol', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'activity', array(
412
+ 'group' => $tab,
413
+ 'setting' => 'cerberproto',
414
+ 'type' => 'select',
415
+ 'set' => array(
416
+ 'HTTP',
417
+ 'HTTPS'
418
+ )
419
+ ) );
420
+ add_settings_field( 'usefile', __( 'Use file', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'activity', array(
421
+ 'group' => $tab,
422
+ 'setting' => 'usefile',
423
+ 'type' => 'checkbox',
424
+ 'label' => __( 'Write failed login attempts to the file', 'wp-cerber' )
425
+ ) );
426
+
427
+ add_settings_section( 'prefs', __( 'Preferences', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT );
428
+ add_settings_field( 'ip_extra', __( 'Drill down IP', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'prefs', array(
429
+ 'group' => $tab,
430
+ 'setting' => 'ip_extra',
431
+ 'type' => 'checkbox',
432
+ 'label' => __( 'Retrieve extra WHOIS information for IP', 'wp-cerber' ) . ' <a href="' . cerber_admin_link( 'help' ) . '">Know more</a>'
433
+ ) );
434
+ add_settings_field( 'dateformat', __( 'Date format', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'prefs', array(
435
  'group' => $tab,
436
+ 'setting' => 'dateformat',
437
  'type' => 'text',
438
+ 'size' => 16,
439
+ 'label' => sprintf( __( 'if empty, the default format %s will be used', 'wp-cerber' ), '<b>' . cerber_date( time() ) . '</b>' ) . ' <a target="_blank" href="http://wpcerber.com/date-format-setting/">Know more</a>'
440
+ ) );
441
+ add_settings_field( 'admin_lang', __( 'Use English for admin interface', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT, 'prefs', array(
442
+ 'group' => $tab,
443
+ 'setting' => 'admin_lang',
444
+ 'type' => 'checkbox'
445
  ) );
 
446
 
447
+ // Hardening tab --------------------------------------------------------------------------
 
 
 
448
 
449
+ $tab = 'hardening'; // 'cerber-hardening' settings
450
+ register_setting( 'cerberus-' . $tab, CERBER_OPT_H );
 
 
 
451
 
452
+ add_settings_section( 'hwp', __( 'Hardening WordPress', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT_H );
453
+ add_settings_field( 'stopenum', __( 'Stop user enumeration', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_H, 'hwp',
454
+ array(
455
+ 'group' => $tab,
456
+ 'setting' => 'stopenum',
457
+ 'type' => 'checkbox',
458
+ 'label' => __( 'Block access to user pages like /?author=n', 'wp-cerber' )
459
+ ) );
460
+ add_settings_field( 'adminphp', __( 'Protect admin scripts', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_H, 'hwp',
461
+ array(
462
+ 'group' => $tab,
463
+ 'setting' => 'adminphp',
464
+ 'type' => 'checkbox',
465
+ 'label' => __( 'Block unauthorized access to load-scripts.php and load-styles.php', 'wp-cerber' )
466
+ ) );
467
+ add_settings_field( 'phpnoupl', __( 'Disable PHP in uploads', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_H, 'hwp',
468
+ array(
469
+ 'group' => $tab,
470
+ 'setting' => 'phpnoupl',
471
+ 'type' => 'checkbox',
472
+ 'label' => __( 'Disable execution of PHP scripts in the WordPress media folder', 'wp-cerber' )
473
+ ) );
474
+ add_settings_field( 'nophperr', __( 'Disable PHP error displaying', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_H, 'hwp',
475
+ array(
476
+ 'group' => $tab,
477
+ 'setting' => 'nophperr',
478
+ 'type' => 'checkbox'
479
+ ) );
480
+ add_settings_field( 'xmlrpc', __( 'Disable XML-RPC', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_H, 'hwp',
481
+ array(
482
+ 'group' => $tab,
483
+ 'setting' => 'xmlrpc',
484
+ 'type' => 'checkbox',
485
+ 'label' => __( 'Block access to the XML-RPC server (including Pingbacks and Trackbacks)', 'wp-cerber' )
486
+ ) );
487
+ add_settings_field( 'nofeeds', __( 'Disable feeds', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_H, 'hwp',
488
+ array(
489
+ 'group' => $tab,
490
+ 'setting' => 'nofeeds',
491
+ 'type' => 'checkbox',
492
+ 'label' => __( 'Block access to the RSS, Atom and RDF feeds', 'wp-cerber' )
493
+ ) );
494
 
 
495
 
496
+ add_settings_section( 'rapi', __( 'Access to WordPress REST API', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT_H );
497
+ add_settings_field( 'norestuser', __( 'Stop user enumeration', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_H, 'rapi',
498
+ array(
499
+ 'group' => $tab,
500
+ 'setting' => 'norestuser',
501
+ 'type' => 'checkbox',
502
+ 'label' => __( 'Block access to user data via REST API', 'wp-cerber' )
503
+ ) );
504
 
505
+ add_settings_field( 'norest', __( 'Disable REST API', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_H, 'rapi',
506
+ array(
507
+ 'group' => $tab,
508
+ 'setting' => 'norest',
509
+ 'type' => 'checkbox',
510
+ 'label' => __( 'Block access to WordPress REST API except any of the following', 'wp-cerber' )
511
+ ) );
512
+ add_settings_field( 'restauth', __( 'Logged in users', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_H, 'rapi',
513
+ array(
514
+ 'group' => $tab,
515
+ 'setting' => 'restauth',
516
+ 'type' => 'checkbox',
517
+ 'label' => __( 'Allow REST API for logged in users', 'wp-cerber' )
518
+ ) );
519
+ add_settings_field( 'restroles', __( 'Allow REST API for these roles', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_H, 'rapi',
520
+ array(
521
+ 'group' => $tab,
522
+ 'setting' => 'restroles',
523
+ 'type' => 'role_select',
524
+ ) );
525
+ add_settings_field( 'restwhite', __( 'Allow these namespaces', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_H, 'rapi',
526
+ array(
527
+ 'group' => $tab,
528
+ 'setting' => 'restwhite',
529
+ 'type' => 'textarea',
530
+ 'delimiter' => "\n",
531
+ 'list' => true,
532
+ 'label' => __( 'Specify REST API namespaces to be allowed if REST API is disabled. One string per line.', 'wp-cerber' ) . ' <a target="_blank" href="https://wpcerber.com/restrict-access-to-wordpress-rest-api/">Read more</a>',
533
  ) );
534
  //add_settings_field('hashauthor',__('Hide author usernames','wp-cerber'),'cerberus_field_show',CERBER_OPT_H,'hwp',array('group'=>$tab,'option'=>'hashauthor','type'=>'checkbox','label'=>__('Replace author username with hash for author pages and URLs','wp-cerber')));
535
  //add_settings_field('cleanhead',__('Clean up HEAD','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'hwp',array('group'=>$tab,'option'=>'cleanhead','type'=>'checkbox','label'=>__('Remove generator and version tags from HEAD section','wp-cerber')));
536
  //add_settings_field('ping',__('Disable Pingback','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'hwp',array('group'=>$tab,'option'=>'ping','type'=>'checkbox','label'=>__('Block access to ping functional','wp-cerber')));
537
 
538
  // Users tab -----------------------------------------------------------------------------
539
+ /*
540
+ $tab = 'users'; // 'cerber-users' settings
541
+ register_setting( 'cerberus-' . $tab, CERBER_OPT_U );
542
+ add_settings_section( 'us', __( 'User related settings', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT_U );
543
+ add_settings_field( 'authonly', __( 'Authorized users only', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_U, 'us',
544
+ array(
545
+ 'group' => $tab,
546
+ 'setting' => 'authonly',
547
+ 'type' => 'checkbox',
548
+ 'label' => __( 'Only registered and authorized website users have access to the website', 'wp-cerber' )
549
+ ) );
550
+ if ( lab_lab() ) {
551
+ add_settings_field( 'reglimit', __( 'Registration limit', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_U, 'us',
552
+ array(
553
+ 'group' => $tab,
554
+ 'setting' => 'reglimit',
555
+ 'type' => 'reglimit'
556
+ ) );
557
  }
558
  add_settings_field( 'prohibited', __( 'Prohibited usernames', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_U, 'us',
559
+ array(
560
+ 'group' => $tab,
561
+ 'setting' => 'prohibited',
562
+ 'type' => 'textarea',
563
+ 'delimiter' => ',',
564
+ 'list' => true,
565
+ 'label' => __( 'Usernames from this list are not allowed to log in or register. Any IP address, have tried to use any of these usernames, will be immediately blocked. Use comma to separate logins.', 'wp-cerber' ) . ' ' . __( 'To specify a REGEX pattern wrap a pattern in two forward slashes.', 'wp-cerber' )
566
  ) );
567
+ add_settings_field( 'auth_expire', __( 'User session expire', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_U, 'us',
568
+ array(
569
+ 'group' => $tab,
570
+ 'setting' => 'auth_expire',
571
+ 'type' => 'text',
572
+ 'label' => __( 'in minutes (leave empty to use default WP value)', 'wp-cerber' ),
573
+ 'size' => 6
574
+ ) );
575
+ add_settings_field( 'usersort', __( 'Sort users in dashboard', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_U, 'us',
576
+ array(
577
+ 'group' => $tab,
578
+ 'setting' => 'usersort',
579
+ 'type' => 'checkbox',
580
+ 'label' => __( 'by date of registration', 'wp-cerber' )
581
+ ) );
582
+ */
583
  // Antibot & reCAPTCHA -----------------------------------------------------------------------------
584
 
585
+ $tab = 'antispam'; // 'cerber-recaptcha' settings
586
+ register_setting( 'cerberus-' . $tab, CERBER_OPT_A );
587
 
588
+ add_settings_section( 'antibot', __( 'Cerber antispam engine', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT_A );
589
+ add_settings_field( 'botscomm', __( 'Comment form', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_A, 'antibot',
590
+ array(
591
+ 'group' => $tab,
592
+ 'setting' => 'botscomm',
593
+ 'type' => 'checkbox',
594
+ 'label' => __( 'Protect comment form with bot detection engine', 'wp-cerber' )
595
+ ) );
596
+ add_settings_field( 'botsreg', __( 'Registration form', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_A, 'antibot',
597
+ array(
598
+ 'group' => $tab,
599
+ 'setting' => 'botsreg',
600
+ 'type' => 'checkbox',
601
+ 'label' => __( 'Protect registration form with bot detection engine', 'wp-cerber' )
602
+ ) );
603
+ add_settings_field( 'botsany', __( 'Other forms', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_A, 'antibot',
604
+ array(
605
+ 'group' => $tab,
606
+ 'setting' => 'botsany',
607
+ 'type' => 'checkbox',
608
+ 'label' => __( 'Protect all forms on the website with bot detection engine', 'wp-cerber' )
609
+ ) );
610
 
611
+ add_settings_section( 'antibot_more', __( 'Adjust antispam engine', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT_A );
612
+ add_settings_field( 'botssafe', __( 'Safe mode', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_A, 'antibot_more',
613
+ array(
614
+ 'group' => $tab,
615
+ 'setting' => 'botssafe',
616
+ 'type' => 'checkbox',
617
+ 'label' => __( 'Use less restrictive policies (allow AJAX)', 'wp-cerber' )
618
+ ) );
619
+ add_settings_field( 'botsnoauth', __( 'Logged in users', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_A, 'antibot_more',
620
+ array(
621
+ 'group' => $tab,
622
+ 'setting' => 'botsnoauth',
623
+ 'type' => 'checkbox',
624
+ 'label' => __( 'Disable bot detection engine for logged in users', 'wp-cerber' )
625
+ ) );
626
  add_settings_field( 'botswhite', __( 'Query whitelist', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_A, 'antibot_more',
627
+ array(
628
+ 'group' => $tab,
629
+ 'setting' => 'botswhite',
630
+ 'type' => 'textarea',
631
+ 'delimiter' => "\n",
632
+ 'list' => true,
633
+ 'label' => __( 'Enter a part of query string or query path to exclude a request from inspection by the engine. One item per line.', 'wp-cerber' ) . ' ' . __( 'To specify a REGEX pattern, enclose a whole line in two braces.', 'wp-cerber' ) . ' <a href="https://wpcerber.com/antispam-for-wordpress-contact-forms/" target="_blank">Read more</a>',
634
  ) );
635
 
636
+ add_settings_section( 'commproc', __( 'Comment processing', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT_A );
637
+ add_settings_field( 'spamcomm', __( 'If a spam comment detected', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_A, 'commproc',
638
+ array(
639
+ 'group' => $tab,
640
+ 'setting' => 'spamcomm',
641
+ 'type' => 'select',
642
+ 'set' => array( __( 'Deny it completely', 'wp-cerber' ), __( 'Mark it as spam', 'wp-cerber' ) )
643
+ ) );
644
+ add_settings_field( 'trashafter', __( 'Trash spam comments', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_A, 'commproc',
645
+ array(
646
+ 'group' => $tab,
647
+ 'setting' => 'trashafter',
648
+ 'type' => 'text',
649
+ 'enabled' => __( 'Move spam comments to trash after' ),
650
+ 'label' => __( 'days', 'wp-cerber' ),
651
+ 'size' => 3
652
+ ) );
653
 
 
 
654
 
655
+ $tab = 'recaptcha'; // 'cerber-recaptcha' settings
656
+ register_setting( 'cerberus-' . $tab, CERBER_OPT_C );
657
 
658
+ add_settings_section( 'recap', __( 'reCAPTCHA settings', 'wp-cerber' ), 'cerber_sapi_section', CERBER_OPT_C );
659
+ add_settings_field( 'sitekey', __( 'Site key', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_C, 'recap',
660
+ array( 'group' => $tab, 'setting' => 'sitekey', 'type' => 'text' ) );
661
+ add_settings_field( 'secretkey', __( 'Secret key', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_C, 'recap',
662
+ array( 'group' => $tab, 'setting' => 'secretkey', 'type' => 'text' ) );
663
+ add_settings_field( 'invirecap', __( 'Invisible reCAPTCHA', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_C, 'recap',
664
+ array(
665
+ 'group' => $tab,
666
+ 'setting' => 'invirecap',
667
+ 'type' => 'checkbox',
668
+ 'label' => __( 'Enable invisible reCAPTCHA', 'wp-cerber' ) . ' ' . __( '(do not enable it unless you get and enter the Site and Secret keys for the invisible version)', 'wp-cerber' )
669
+ ) );
670
+ add_settings_field( 'recapreg', __( 'Registration form', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_C, 'recap',
671
+ array(
672
+ 'group' => $tab,
673
+ 'setting' => 'recapreg',
674
+ 'type' => 'checkbox',
675
+ 'label' => __( 'Enable reCAPTCHA for WordPress registration form', 'wp-cerber' )
676
+ ) );
677
+ add_settings_field( 'recapwooreg', '', 'cerber_field_show', CERBER_OPT_C, 'recap',
678
+ array(
679
+ 'group' => $tab,
680
+ 'setting' => 'recapwooreg',
681
+ 'type' => 'checkbox',
682
+ 'label' => __( 'Enable reCAPTCHA for WooCommerce registration form', 'wp-cerber' )
683
+ ) );
684
+ add_settings_field( 'recaplost', __( 'Lost password form', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_C, 'recap',
685
+ array(
686
+ 'group' => $tab,
687
+ 'setting' => 'recaplost',
688
+ 'type' => 'checkbox',
689
+ 'label' => __( 'Enable reCAPTCHA for WordPress lost password form', 'wp-cerber' )
690
+ ) );
691
+ add_settings_field( 'recapwoolost', '', 'cerber_field_show', CERBER_OPT_C, 'recap',
692
+ array(
693
+ 'group' => $tab,
694
+ 'setting' => 'recapwoolost',
695
+ 'type' => 'checkbox',
696
+ 'label' => __( 'Enable reCAPTCHA for WooCommerce lost password form', 'wp-cerber' )
697
+ ) );
698
+ add_settings_field( 'recaplogin', __( 'Login form', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_C, 'recap',
699
+ array(
700
+ 'group' => $tab,
701
+ 'setting' => 'recaplogin',
702
+ 'type' => 'checkbox',
703
+ 'label' => __( 'Enable reCAPTCHA for WordPress login form', 'wp-cerber' )
704
+ ) );
705
+ add_settings_field( 'recapwoologin', '', 'cerber_field_show', CERBER_OPT_C, 'recap',
706
+ array(
707
+ 'group' => $tab,
708
+ 'setting' => 'recapwoologin',
709
+ 'type' => 'checkbox',
710
+ 'label' => __( 'Enable reCAPTCHA for WooCommerce login form', 'wp-cerber' )
711
+ ) );
712
 
713
+ add_settings_field( 'recapcom', __( 'Antispam', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_C, 'recap',
714
+ array(
715
+ 'group' => $tab,
716
+ 'setting' => 'recapcom',
717
+ 'type' => 'checkbox',
718
+ 'label' => __( 'Enable reCAPTCHA for WordPress comment form', 'wp-cerber' )
719
+ ) );
720
+ add_settings_field( 'recapcomauth', '', 'cerber_field_show', CERBER_OPT_C, 'recap',
721
+ array(
722
+ 'group' => $tab,
723
+ 'setting' => 'recapcomauth',
724
+ 'type' => 'checkbox',
725
+ 'label' => __( 'Disable reCAPTCHA for logged in users', 'wp-cerber' )
726
+ ) );
727
+ add_settings_field( 'recaplimit', __( 'Limit attempts', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_C, 'recap',
728
+ array(
729
+ 'group' => $tab,
730
+ 'setting' => 'recaplimit',
731
+ 'type' => 'limitz',
732
+ 'label' => __( 'Lock out IP address for %s minutes after %s failed attempts within %s minutes', 'wp-cerber' )
733
+ ) );
734
 
735
  // Notifications -----------------------------------------------------------------------------
736
 
746
  'placeholder' => __( 'Use comma to specify multiple values', 'wp-cerber' ),
747
  'delimiter' => ',',
748
  'list' => true,
 
749
  'maxlength' => 1000,
750
  'label' => sprintf( __( 'if empty, the admin email %s will be used', 'wp-cerber' ), $def_email )
751
  ) );
757
  ) );
758
 
759
  add_settings_section('pushit', __('Push notifications','wp-cerber'), 'cerber_sapi_section', CERBER_OPT_N);
760
+ add_settings_field('pbtoken','Pushbullet access token','cerber_field_show',CERBER_OPT_N,'pushit',array('group'=>$group,'setting'=>'pbtoken','type'=>'text'));
761
 
762
  $set = array();
763
  if ( cerber_is_admin_page( false, array( 'tab' => 'notifications' ) ) ) {
787
  'placeholder' => __( 'Use comma to specify multiple values', 'wp-cerber' ),
788
  'delimiter' => ',',
789
  'list' => true,
 
790
  'maxlength' => 1000,
791
  'label' => __( 'if empty, email from notification settings will be used', 'wp-cerber' )
792
  ) );
869
  'group' => $group,
870
  'setting' => 'timask',
871
  'type' => 'text',
 
872
  'maxlength' => 1000,
873
  'placeholder' => __( 'Use comma to specify multiple values', 'wp-cerber' ),
874
  'delimiter' => ',',
1051
  'placeholder' => __( 'Use comma to specify multiple values', 'wp-cerber' ),
1052
  'delimiter' => ',',
1053
  'list' => true,
 
1054
  'maxlength' => 1000,
1055
  'label' => sprintf( __( 'if empty, email from notification settings will be used', 'wp-cerber' ), $def_email )
1056
  ) );
1135
  _e( 'In the Citadel mode nobody is able to log in except IPs from the White IP Access List. Active user sessions will not be affected.', 'wp-cerber' );
1136
  break;
1137
  case 'hwp':
1138
+ case 'rapi':
1139
+ echo __( 'These restrictions do not apply to IP addresses in the White IP Access List', 'wp-cerber' );
1140
  break;
1141
  case 'recap':
1142
  _e( 'Before you can start using reCAPTCHA, you have to obtain Site key and Secret key on the Google website', 'wp-cerber' );
1170
  'activity' => array( 'bx-pulse', __( 'Activity', 'wp-cerber' ) ),
1171
  'lockouts' => array( 'bxs-shield', __( 'Lockouts', 'wp-cerber' ) . ' <sup class="loctotal">' . $blocked . '</sup>' ),
1172
  'main' => array( 'bx-slider', __( 'Main Settings', 'wp-cerber' ) ),
1173
+ 'acl' => array( 'bx-lock', __( 'Access Lists', 'wp-cerber' ) . ' <sup class="acltotal">' . $acl . '</sup>' ),
1174
  'hardening' => array( 'bx-shield-alt', __( 'Hardening', 'wp-cerber' ) ),
1175
  'users' => array( 'bx-group', __( 'Users', 'wp-cerber' ) ),
1176
  'notifications' => array( 'bx-bell', __( 'Notifications', 'wp-cerber' ) ),
1179
  $tab = cerber_get_active_tab( $tabs );
1180
 
1181
  ?>
1182
+ <div id="crb-admin" class="wrap">
1183
 
1184
  <h1>WP Cerber Security</h1>
1185
 
1232
  else {
1233
  $action = 'options.php'; // Display form with settings fields via Settings API
1234
  }
1235
+ echo '<form id="crb-settings" method="post" action="' . $action . '">';
1236
 
1237
  settings_fields( 'cerberus-' . $group ); // option group name, the same as used in register_setting().
1238
  do_settings_sections( 'cerber-' . $group ); // the same as used in add_settings_section() $page
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1239
 
1240
+ echo '<div style="padding-left: 220px">';
 
 
 
 
 
 
 
 
 
1241
 
1242
+ if ( $group == 'hardening' ) {
1243
+ echo '<p><a href="' . cerber_admin_link( 'traffic', array( 'filter_wp_type' => 520 ) ) . '">View REST API requests</a> | <a href="' . cerber_admin_link( 'activity', array( 'filter_activity' => 70 ) ) . '">View denied REST API requests</a></p>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1244
  }
1245
 
1246
+ submit_button();
1247
+ echo '</div>';
1248
+ echo '</form>';
 
 
 
 
 
 
 
 
1249
  }
1250
 
1251
  /**
1252
+ * Generates HTML for a single input field on the settings page.
1253
+ * Prepares values to display.
1254
  *
1255
  * @param $args
1256
  */
1257
+ function cerber_field_show( $args ) {
1258
 
1259
+ //$settings = get_site_option( 'cerber-' . $args['group'] );
1260
+ $settings = crb_get_settings();
1261
  if ( is_array( $settings ) ) {
1262
  array_walk_recursive( $settings, 'esc_html' );
1263
  }
1264
+ $pre = '';
1265
+ $value = '';
1266
  $disabled = '';
1267
 
1268
  $label = empty( $args['label'] ) ? '' : $args['label'];
1269
+ if ( ! empty( $args['doclink'] ) ) {
1270
+ $label .= ' &nbsp; <a target="_blank" href="' . $args['doclink'] . '">Read more</a>';
1271
+ }
1272
+
1273
+ $placeholder = '';
1274
+ if ( isset( $args['placeholder'] ) ) {
1275
+ $placeholder = ' placeholder="' . $args['placeholder'] . '" ';
1276
+ }
1277
 
1278
  if ( isset( $args['setting'] ) ) {
1279
  if ( isset( $settings[ $args['setting'] ] ) ) {
1284
  $disabled = ' disabled="disabled" ';
1285
  }
1286
  if ( $args['setting'] == 'loginpath' ) {
1287
+ $pre = cerber_get_home_url() . '/';
1288
  $value = urldecode( $value );
1289
  }
1290
  }
1291
 
1292
  if ( isset( $args['list'] ) ) {
1293
+ $value = cerber_array2text( $value, $args['delimiter'] );
1294
  }
1295
 
1296
+ $name = 'cerber-' . $args['group'] . '[' . $args['setting'] . ']';
1297
+ $id = 'crb-input-' . $args['setting'];
1298
 
1299
+ $data = '';
1300
+ if ( isset( $args['enabler'][0] ) ) {
1301
+ $data .= ' data-enabler="crb-input-' . $args['enabler'][0] . '" ';
1302
+ }
1303
+ if ( isset( $args['enabler'][1] ) ) {
1304
+ $data .= ' data-enabler_value="' . $args['enabler'][1] . '" ';
1305
+ }
1306
+
1307
+ switch ( $args['type'] ) {
1308
 
1309
  case 'limitz':
1310
+ $s1 = $args['group'] . '-period';
1311
+ $s2 = $args['group'] . '-number';
1312
+ $s3 = $args['group'] . '-within';
1313
+
1314
+ $html = sprintf( $label,
1315
+ '<input type="text" name="cerber-' . $args['group'] . '[' . $s1 . ']" value="' . $settings[ $s1 ] . '" size="3" maxlength="3" />',
1316
+ '<input type="text" name="cerber-' . $args['group'] . '[' . $s2 . ']" value="' . $settings[ $s2 ] . '" size="3" maxlength="3" />',
1317
+ '<input type="text" name="cerber-' . $args['group'] . '[' . $s3 . ']" value="' . $settings[ $s3 ] . '" size="3" maxlength="3" />' );
1318
  break;
1319
 
1320
  case 'attempts':
1321
+ $html = sprintf( __( '%s allowed retries in %s minutes', 'wp-cerber' ),
1322
+ '<input type="text" id="attempts" name="cerber-' . $args['group'] . '[attempts]" value="' . $settings['attempts'] . '" size="3" maxlength="3" />',
1323
+ '<input type="text" id="period" name="cerber-' . $args['group'] . '[period]" value="' . $settings['period'] . '" size="3" maxlength="3" />' );
1324
  break;
1325
  case 'reglimit':
1326
+ $html = sprintf( __( '%s allowed registrations in %s minutes from one IP', 'wp-cerber' ),
1327
+ '<input type="text" id="reglimit-num" name="cerber-' . $args['group'] . '[reglimit_num]" value="' . $settings['reglimit_num'] . '" size="3" maxlength="3" />',
1328
+ '<input type="text" id="reglimit-min" name="cerber-' . $args['group'] . '[reglimit_min]" value="' . $settings['reglimit_min'] . '" size="4" maxlength="4" />' );
1329
  break;
1330
  case 'aggressive':
1331
+ $html = sprintf( __( 'Increase lockout duration to %s hours after %s lockouts in the last %s hours', 'wp-cerber' ),
1332
+ '<input type="text" id="agperiod" name="cerber-' . $args['group'] . '[agperiod]" value="' . $settings['agperiod'] . '" size="3" maxlength="3" />',
1333
+ '<input type="text" id="aglocks" name="cerber-' . $args['group'] . '[aglocks]" value="' . $settings['aglocks'] . '" size="3" maxlength="3" />',
1334
+ '<input type="text" id="aglast" name="cerber-' . $args['group'] . '[aglast]" value="' . $settings['aglast'] . '" size="3" maxlength="3" />' );
1335
  break;
1336
  case 'notify':
1337
+ $html = '<label class="crb-switch"><input class="screen-reader-text" type="checkbox" id="' . $args['setting'] . '" name="cerber-' . $args['group'] . '[' . $args['setting'] . ']" value="1" ' . checked( 1, $value, false ) . $disabled . ' /><span class="crb-slider round"></span></label>'
1338
+ . __( 'Notify admin if the number of active lockouts above', 'wp-cerber' ) .
1339
+ ' <input type="text" id="above" name="cerber-' . $args['group'] . '[above]" value="' . $settings['above'] . '" size="3" maxlength="3" />' .
1340
+ ' [ <a href="' . wp_nonce_url( add_query_arg( array(
1341
+ 'testnotify' => 'lockout',
1342
+ 'settings-updated' => 0
1343
+ ) ), 'control', 'cerber_nonce' ) . '">' . __( 'Click to send test', 'wp-cerber' ) . '</a> ]';
1344
  break;
1345
  case 'citadel':
1346
+ $html = sprintf( __( 'Enable after %s failed login attempts in last %s minutes', 'wp-cerber' ),
1347
+ '<input type="text" id="cilimit" name="cerber-' . $args['group'] . '[cilimit]" value="' . $settings['cilimit'] . '" size="3" maxlength="3" />',
1348
+ '<input type="text" id="ciperiod" name="cerber-' . $args['group'] . '[ciperiod]" value="' . $settings['ciperiod'] . '" size="3" maxlength="3" />' );
1349
  break;
1350
  case 'checkbox':
1351
+ $html = '<label class="crb-switch"><input class="screen-reader-text" type="checkbox" id="' . $id . '" name="' . $name . '" value="1" ' . checked( 1, $value, false ) . $disabled . ' /><span class="crb-slider round"></span></label>';
1352
+ $html .= '<label for="' . $args['setting'] . '">' . $label . '</label><i '.$data.'></i>';
1353
  break;
1354
  case 'textarea':
1355
+ $html = '<textarea class="large-text code" id="' . $id . '" name="' . $name . '" ' . $disabled . $placeholder . $data.'>' . $value . '</textarea>';
1356
+ $html .= '<br/><label class="crb-below" for="' . $args['setting'] . '">' . $label . '</label>';
1357
  break;
1358
  case 'select':
1359
  $html = cerber_select( $name, $args['set'], $value );
1360
  break;
1361
+ case 'role_select':
1362
+ $html = cerber_role_select( $name.'[]', $value, '', true, '', '95%' );
1363
+ break;
1364
  case 'checkbox_set':
1365
  $html = '<div class="crb-checkbox_set" style="line-height: 2em;">';
1366
  foreach ( $args['set'] as $key => $item ) {
1367
  $v = ( ! empty( $value[ $key ] ) ) ? $value[ $key ] : 0;
1368
+ $html .= '<input type="checkbox" value="1" name="' . $name . '[' . $key . ']" ' . checked( 1, $v, false ) . $disabled . '/>' . $item . '<br />';
1369
  }
1370
  $html .= '</div>';
 
1371
  break;
1372
  case 'reptime':
1373
  $html = cerber_time_select( $args, $settings );
1378
  break;
1379
  case 'text':
1380
  default:
1381
+ $type = 'text';
1382
+ if ( in_array( $args['type'], array( 'url' ) ) ) {
1383
+ $type = $args['type'];
 
 
 
 
 
 
1384
  }
1385
+ $size = '';
1386
+ $maxlength = '';
1387
+ $attrs = '';
1388
+ $class = 'crb-wide';
1389
+ if ( isset( $args['size'] ) ) {
1390
+ //$size = ' size="' . $args['size'] . '" maxlength="' . $args['size'] . '" ';
1391
+ $size = ' size="' . $args['size'] . '"';
1392
+ $class = '';
1393
+ }
1394
+ if ( isset( $args['maxlength'] ) ) {
1395
+ $maxlength = ' maxlength="' . $args['maxlength'] . '" ';
1396
+ }
1397
+ elseif ( isset( $args['size'] ) ) {
1398
+ $maxlength = ' maxlength="' . $args['size'] . '" ';
1399
+ }
1400
+ $attrs .= $placeholder;
1401
+ if ( isset( $args['pattern'] ) ) {
1402
+ $attrs .= ' pattern="' . $args['pattern'] . '"';
1403
+ }
1404
+ if ( isset( $args['title'] ) ) {
1405
+ $attrs .= ' title="' . $args['title'] . '"';
1406
+ }
1407
+ $html = $pre . '<input type="'.$type.'" id="' . $args['setting'] . '" name="' . $name . '" value="' . $value . '"' . $disabled . ' class="' . $class . '" ' . $size . $maxlength . $attrs . $data . ' />';
1408
+ if ( $size ) {
1409
+ $label = ' <label for="' . $args['setting'] . '">' . $label . '</label>';
1410
+ }
1411
+ else {
1412
+ $label = '<br/><label class="crb-below" for="' . $args['setting'] . '">' . $label . '</label>';
1413
+ }
1414
+ $html .= $label;
1415
+ break;
1416
  }
1417
 
1418
  if ( ! empty( $args['enabled'] ) ) {
1425
  $html = $checkbox . ' ' . $html;
1426
  }
1427
 
1428
+ echo $html . "\n";
1429
  }
1430
 
1431
  /**
1437
  *
1438
  * @return string
1439
  */
1440
+ function cerber_select( $name, $list, $selected = null, $class = '', $multiple = '', $placeholder = '', $data = array() ) {
1441
  $options = array();
1442
  foreach ( $list as $key => $value ) {
1443
  $s = ( $selected == (string) $key ) ? 'selected' : '';
1444
  $options[] = '<option value="' . $key . '" ' . $s . '>' . htmlspecialchars( $value ) . '</option>';
1445
  }
1446
+ $p = ( $placeholder ) ? ' data-placeholder="'.$placeholder.'" placeholder="'.$placeholder.'" ' : '';
1447
+ $m = ( $multiple ) ? ' multiple="multiple" ' : '';
1448
+ $d = '';
1449
+ if ( $data ) {
1450
+ foreach ( $data as $att => $val ) {
1451
+ $d .= ' data-' . $att . '="' . $val . '"';
1452
+ }
1453
+ }
1454
+
1455
+ return ' <select name="' . $name . '" class="crb-select ' . $class . '" ' . $m . $p . $d . '>' . implode( "\n", $options ) . '</select>';
1456
+ }
1457
+
1458
+ function cerber_role_select( $name = 'cerber-roles', $selected = array(), $class = '', $multiple = '', $placeholder = '', $width = '100%' ) {
1459
+
1460
+ if ( ! is_array( $selected ) ) {
1461
+ $selected = array( $selected );
1462
+ }
1463
+ if ( ! $placeholder ) {
1464
+ $placeholder = __( 'Select one or more roles', 'wp-cerber' );
1465
+ }
1466
+ //$roles = wp_roles();
1467
+ $roles = $GLOBALS['wp_roles'];
1468
+ $options = array();
1469
+ foreach ( $roles->get_names() as $key => $title ) {
1470
+ $s = ( in_array( $key, $selected ) ) ? 'selected' : '';
1471
+ $options[] = '<option value="' . $key . '" ' . $s . '>' . $title . '</option>';
1472
+ }
1473
+
1474
  $m = ( $multiple ) ? 'multiple="multiple"' : '';
1475
 
1476
+ // Setting width via class is not working
1477
+ $style = '';
1478
+ if ( $width ) {
1479
+ //$style = 'max-width: ' . $width.'; min-width:500px;';
1480
+ $style = 'width: ' . $width.';';
1481
+ }
1482
+
1483
+ return ' <select style="' . $style . '" name="' . $name . '" class="crb-select2 ' . $class . '" ' . $m . ' data-placeholder="' . $placeholder . '" data-allow-clear="true">' . implode( "\n", $options ) . '</select>';
1484
  }
1485
 
1486
  function cerber_time_select($args, $settings){
1546
  $new['loginpath'] = urlencode( str_replace( '/', '', $new['loginpath'] ) );
1547
  $new['loginpath'] = sanitize_text_field($new['loginpath']);
1548
  if ( $new['loginpath'] && $new['loginpath'] != $old['loginpath'] ) {
1549
+ $href = cerber_get_home_url() . '/' . $new['loginpath'] . '/';
1550
  $url = urldecode( $href );
1551
  $msg = array();
1552
  $msg_e = array();
1587
 
1588
  $new['prohibited'] = cerber_text2array($new['prohibited'], ',', 'strtolower');
1589
 
1590
+ $new['authonlymsg'] = strip_tags( $new['authonlymsg'] );
1591
+
1592
  return $new;
1593
  }, 10, 3 );
1594
  /*
1939
  if ( !cerber_is_http_post() || ! isset( $_POST['action'] ) || $_POST['action'] != 'update' ) {
1940
  return;
1941
  }
1942
+ /*if ( ! isset( $_POST['option_page'] ) || false === strpos( $_POST['option_page'], 'cerberus-' ) ) {
1943
+ return;
1944
+ }*/
1945
+
1946
+ if ( ! $wp_id = cerber_get_wp_option_id() ) { // 7.9.7
1947
  return;
1948
  }
1949
+
1950
  if ( ! current_user_can( 'manage_options' ) ) {
1951
  return;
1952
  }
1954
  // See wp_nonce_field() in the settings_fields() function
1955
  check_admin_referer($_POST['option_page'].'-options');
1956
 
1957
+ //$opt_name = 'cerber-' . substr( $_POST['option_page'], 9 ); // 8 = length of 'cerberus-'
1958
+
1959
+ $opt_name = 'cerber-' . $wp_id;
1960
 
1961
  $old = (array) get_site_option( $opt_name );
1962
  $new = $_POST[ $opt_name ];
2015
  'nophperr' => 1,
2016
  'xmlrpc' => 0,
2017
  'nofeeds' => 0,
2018
+ 'norestuser' => 1,
2019
  'norest' => 0,
2020
  'restauth' => 1,
2021
+ 'restroles' => array(),
2022
  'restwhite' => 'oembed',
2023
  'hashauthor' => 0,
2024
  'cleanhead' => 1,
2025
  ),
2026
  CERBER_OPT_U => array(
2027
+ 'authonly' => 0,
2028
+ 'authonlyacl' => 0,
2029
+ 'authonlymsg' => __( 'Only registered and logged in users are allowed to view this website', 'wp-cerber' ),
2030
+ 'authonlyredir' => '',
2031
+ 'reglimit_num' => 3,
2032
+ 'reglimit_min' => 60,
2033
+ 'prohibited' => array(),
2034
+ 'auth_expire' => '',
2035
+ 'usersort' => '',
2036
  ),
2037
  CERBER_OPT_A => array(
2038
  'botscomm' => 1,
2129
  * Upgrade plugin options
2130
  *
2131
  */
2132
+ function cerber_upgrade_settings() {
2133
  // @since 4.4, move fields to a new option
2134
  if ( $main = get_site_option( CERBER_OPT ) ) {
2135
  if ( ! empty( $main['email'] ) || ! empty( $main['emailrate'] ) ) {
2175
 
2176
  update_site_option( $option_name, $values );
2177
  }
2178
+ // @since 7.9.4 Stop user enumeration for REST API
2179
+ if ( $h = get_site_option( CERBER_OPT_H ) ) {
2180
+ if ( $h['stopenum'] ) {
2181
+ $h['norestuser'] = 1;
2182
+ update_site_option( CERBER_OPT_H, $h );
2183
+ }
2184
+ }
2185
  }
2186
 
2187
  /**
2210
  * @since 2.0
2211
  *
2212
  */
2213
+ function cerber_save_settings( $options ) {
2214
  foreach ( cerber_get_defaults() as $option_name => $fields ) {
2215
  $filtered = array();
2216
  foreach ( $fields as $field_name => $def ) {
2388
  if ( ! empty( $old['loginpath'] ) ) {
2389
  $save['loginpath'] = $old['loginpath'];
2390
  }
2391
+ cerber_save_settings( $save );
2392
  }
2393
 
2394
  /**
2450
  );
2451
  $scan_scheduling = array( // Is used for scheduled scans
2452
  'client' => $set,
2453
+ 'site_url' => cerber_get_home_url(),
2454
  'gmt_offset' => (int) get_option( 'gmt_offset' ),
2455
  'dtf' => cerber_get_dt_format(),
2456
  );
whois.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
4
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
1
  <?php
2
  /*
3
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
4
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
5
 
6
  Licenced under the GNU GPL.
7
 
wp-cerber.php CHANGED
@@ -5,13 +5,13 @@
5
  Description: Defends WordPress against hacker attacks, spam, trojans, and viruses. Malware scanner and integrity checker. Hardening WordPress with a set of comprehensive security algorithms. Spam protection with a sophisticated bot detection engine and reCAPTCHA. Tracks user and intruder activity with powerful email, mobile and desktop notifications.
6
  Author: Gregory
7
  Author URI: https://wpcerber.com
8
- Version: 7.9.3
9
  Text Domain: wp-cerber
10
  Domain Path: /languages
11
  Network: true
12
 
13
- Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
14
- Copyright (C) 2015-18 CERBER TECH INC., https://wpcerber.com
15
 
16
  Licenced under the GNU GPL.
17
 
@@ -31,7 +31,7 @@
31
 
32
  */
33
 
34
- define( 'CERBER_VER', '7.9.3' );
35
 
36
  function cerber_plugin_file() {
37
  return __FILE__;
5
  Description: Defends WordPress against hacker attacks, spam, trojans, and viruses. Malware scanner and integrity checker. Hardening WordPress with a set of comprehensive security algorithms. Spam protection with a sophisticated bot detection engine and reCAPTCHA. Tracks user and intruder activity with powerful email, mobile and desktop notifications.
6
  Author: Gregory
7
  Author URI: https://wpcerber.com
8
+ Version: 7.9.7
9
  Text Domain: wp-cerber
10
  Domain Path: /languages
11
  Network: true
12
 
13
+ Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
14
+ Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
15
 
16
  Licenced under the GNU GPL.
17
 
31
 
32
  */
33
 
34
+ define( 'CERBER_VER', '7.9.7' );
35
 
36
  function cerber_plugin_file() {
37
  return __FILE__;