Defender Security – Malware Scanner, Login Security & Firewall - Version 1.7

Version Description

  • New: Now you can enable 2 factors authentication with Defender and Google Authenticator app, support for iOS and Android
  • New: We can define how long the "Remember me" can take affect, via a new Security Tweak, called "Manage Login Duration"
  • Improvement: IP Lockout logs now have separate tables, better for performance.
  • Fix: Ignore a file in Scanning section sometimes coming back after couple of scans.
  • Other minor enhancements/fixes
Download this release

Release Info

Developer paulkevini
Plugin Icon 128x128 Defender Security – Malware Scanner, Login Security & Firewall
Version 1.7
Comparing to
See all releases

Code changes from version 1.6.2 to 1.7

Files changed (90) hide show
  1. app/behavior/utils.php +27 -75
  2. app/controller/dashboard.php +122 -2
  3. app/module/advanced-tools.php +15 -0
  4. app/module/advanced-tools/component/auth-api.php +307 -0
  5. app/module/advanced-tools/controller/main.php +463 -0
  6. app/module/advanced-tools/css/login-admin.css +34 -0
  7. app/module/advanced-tools/css/login.css +21 -0
  8. app/module/advanced-tools/img/2factor-disabled.svg +85 -0
  9. app/module/advanced-tools/img/spinner.svg +49 -0
  10. app/module/advanced-tools/js/scripts.js +47 -0
  11. app/module/advanced-tools/model/auth-settings.php +95 -0
  12. app/module/advanced-tools/view/disabled.php +24 -0
  13. app/module/advanced-tools/view/layouts/layout.php +30 -0
  14. app/module/advanced-tools/view/login/disabled.php +97 -0
  15. app/module/advanced-tools/view/login/enabled.php +52 -0
  16. app/module/advanced-tools/view/login/otp.php +316 -0
  17. app/module/advanced-tools/view/main.php +123 -0
  18. app/module/audit/view/pro-feature.php +1 -1
  19. app/module/hardener/behavior/widget.php +1 -1
  20. app/module/hardener/component/disable-file-editor.php +44 -0
  21. app/module/hardener/component/login-duration-service.php +58 -0
  22. app/module/hardener/component/login-duration.php +216 -0
  23. app/module/hardener/component/prevent-php.php +31 -0
  24. app/module/hardener/component/security-key.php +8 -3
  25. app/module/hardener/component/servers/apache-service.php +7 -1
  26. app/module/hardener/controller/main.php +30 -0
  27. app/module/hardener/js/scripts.js +29 -8
  28. app/module/hardener/model/settings.php +3 -8
  29. app/module/hardener/view/rules/change-admin.php +1 -1
  30. app/module/hardener/view/rules/login-duration.php +53 -0
  31. app/module/hardener/view/rules/prevent-php-executed.php +49 -18
  32. app/module/ip-lockout/component/login-protection-api.php +55 -4
  33. app/module/ip-lockout/controller/main.php +118 -43
  34. app/module/ip-lockout/js/script.js +33 -1
  35. app/module/ip-lockout/model/ip-model-legacy.php +167 -0
  36. app/module/ip-lockout/model/ip-model.php +3 -120
  37. app/module/ip-lockout/model/log-model-legacy.php +166 -0
  38. app/module/ip-lockout/model/log-model.php +3 -42
  39. app/module/ip-lockout/model/settings.php +1 -1
  40. app/module/ip-lockout/view/layouts/layout.php +3 -3
  41. app/module/ip-lockout/view/locked.php +62 -61
  42. app/module/ip-lockout/view/migration.php +35 -0
  43. app/module/ip-lockout/view/notification/report-free.php +1 -1
  44. app/module/ip-lockout/view/pro-feature.php +1 -1
  45. app/module/scan/behavior/core-result.php +20 -6
  46. app/module/scan/component/scan-api.php +33 -8
  47. app/module/scan/controller/main.php +0 -1
  48. app/module/scan/view/automation-free.php +1 -1
  49. app/module/scan/view/pro-feature.php +1 -1
  50. app/module/scan/view/setting-free.php +1 -1
  51. app/view/pro-feature.php +1 -1
  52. assets/css/defender-icon.css +14 -0
  53. assets/css/styles.css +10 -0
  54. assets/img/2factor-disabled.svg +85 -0
  55. assets/img/android-download.svg +75 -0
  56. assets/img/ios-download.svg +49 -0
  57. changelog.txt +11 -1
  58. languages/wpdef-default.pot +485 -178
  59. main-activator.php +7 -0
  60. phpunit.xml +0 -14
  61. readme.txt +10 -2
  62. uninstall.php +1 -0
  63. vendor/binary-to-text-php/Base2n.php +302 -0
  64. vendor/binary-to-text-php/LICENSE.txt +21 -0
  65. vendor/binary-to-text-php/README.md +279 -0
  66. vendor/binary-to-text-php/composer.json +20 -0
  67. vendor/hammer/base/db-model.php +292 -0
  68. vendor/hammer/base/view.php +0 -1
  69. vendor/hammer/vendor/psr/log/.gitignore +0 -1
  70. vendor/hammer/vendor/wixel/gump/examples/basic_tags.php +0 -24
  71. vendor/hammer/vendor/wixel/gump/examples/contains.php +0 -48
  72. vendor/hammer/vendor/wixel/gump/examples/credit_card.php +0 -16
  73. vendor/hammer/vendor/wixel/gump/examples/custom_validator.php +0 -44
  74. vendor/hammer/vendor/wixel/gump/examples/escaping_mysql_strings.php +0 -38
  75. vendor/hammer/vendor/wixel/gump/examples/explicit_fields.php +0 -26
  76. vendor/hammer/vendor/wixel/gump/examples/files.php +0 -41
  77. vendor/hammer/vendor/wixel/gump/examples/full_example.php +0 -62
  78. vendor/hammer/vendor/wixel/gump/examples/guid.php +0 -18
  79. vendor/hammer/vendor/wixel/gump/examples/handling_errors.php +0 -74
  80. vendor/hammer/vendor/wixel/gump/examples/match.php +0 -22
  81. vendor/hammer/vendor/wixel/gump/examples/noise_words.php +0 -18
  82. vendor/hammer/vendor/wixel/gump/examples/sanitize_string.php +0 -16
  83. vendor/hammer/vendor/wixel/gump/examples/sanitize_whitelist.php +0 -45
  84. vendor/hammer/vendor/wixel/gump/examples/street_address.php +0 -22
  85. vendor/hammer/vendor/wixel/gump/examples/url_exists.php +0 -26
  86. vendor/hammer/vendor/wixel/gump/examples/utf-8.php +0 -24
  87. vendor/hammer/vendor/wixel/gump/gump.class.php +2 -0
  88. vendor/hammer/wp/model.php +37 -9
  89. vendor/hammer/wp/settings.php +3 -1
  90. wp-defender.php +1 -2
app/behavior/utils.php CHANGED
@@ -484,81 +484,6 @@ class Utils extends Behavior {
484
  return $defDir;
485
  }
486
 
487
- /**
488
- * @return array|void
489
- */
490
- public function submitStatsToDev() {
491
- if ( ! $this->getAPIKey() ) {
492
- return;
493
- }
494
-
495
- $issues = array();
496
- $rules = Settings::instance()->getIssues();
497
- foreach ( $rules as $rule ) {
498
- $issues[] = array(
499
- 'label' => $rule->getTitle(),
500
- 'url' => network_admin_url( 'admin.php?page=wdf-hardener' ) . '#' . $rule::$slug
501
- );
502
- }
503
-
504
- $model = Scan_Api::getLastScan();
505
- $count = 0;
506
- if ( is_object( $model ) ) {
507
- $timestamp = strtotime( $model->dateFinished );
508
-
509
- $res = array(
510
- 'core_integrity' => $model->getCount( 'core' ),
511
- 'vulnerability_db' => $model->getCount( 'vuln' ),
512
- 'file_suspicious' => $model->getCount( 'content' )
513
- );
514
-
515
- $count = $model->countAll( Result_Item::STATUS_ISSUE );
516
- } else {
517
- $timestamp = '';
518
- $res = array(
519
- 'core_integrity' => 0,
520
- 'vulnerability_db' => 0,
521
- 'file_suspicious' => 0
522
- );
523
- }
524
- $labels = array(
525
- 'core_integrity' => esc_html__( "WordPress Core Integrity", wp_defender()->domain ),
526
- 'vulnerability_db' => esc_html__( "Plugins & Themes vulnerability", wp_defender()->domain ),
527
- 'file_suspicious' => esc_html__( "Suspicious Code", wp_defender()->domain )
528
- );
529
-
530
- $data = array(
531
- 'domain' => network_home_url(),
532
- 'timestamp' => $timestamp,
533
- 'warnings' => $count,
534
- 'cautions' => count( $issues ),
535
- 'data_version' => '20160220',
536
- 'scan_data' => json_encode( array(
537
- 'scan_result' => $res,
538
- 'hardener_result' => $issues,
539
- 'scan_schedule' => array(
540
- 'is_activated' => \WP_Defender\Module\Scan\Model\Settings::instance()->notification,
541
- 'time' => \WP_Defender\Module\Scan\Model\Settings::instance()->time,
542
- 'day' => \WP_Defender\Module\Scan\Model\Settings::instance()->day,
543
- 'frequency' => \WP_Defender\Module\Scan\Model\Settings::instance()->frequency
544
- ),
545
- 'audit_enabled' => false,
546
- 'audit_page_url' => network_admin_url( 'admin.php?page=wdf-logging' ),
547
- 'labels' => $labels,
548
- 'scan_page_url' => network_admin_url( 'admin.php?page=wdf-scan' ),
549
- 'hardener_page_url' => network_admin_url( 'admin.php?page=wdf-hardener' ),
550
- 'new_scan_url' => network_admin_url( 'admin.php?page=wdf-scan&wdf-action=new_scan' ),
551
- 'schedule_scans_url' => network_admin_url( 'admin.php?page=wdf-schedule-scan' ),
552
- 'settings_page_url' => network_admin_url( 'admin.php?page=wdf-settings' )
553
- ) ),
554
- );
555
-
556
- $end_point = "https://premium.wpmudev.org/api/defender/v1/scan-results";
557
- $this->devCall( $end_point, $data, array(
558
- 'method' => 'POST'
559
- ) );
560
- }
561
-
562
  /**
563
  * @param null $result
564
  *
@@ -616,4 +541,31 @@ class Utils extends Behavior {
616
  'iis-7' => 'IIS 7'
617
  ) );
618
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
619
  }
484
  return $defDir;
485
  }
486
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  /**
488
  * @param null $result
489
  *
541
  'iis-7' => 'IIS 7'
542
  ) );
543
  }
544
+
545
+ /**
546
+ * Get the current page URL
547
+ *
548
+ * @return String
549
+ */
550
+ public function currentPageURL() {
551
+ $protocol = "http";
552
+ if ( is_ssl() ) {
553
+ $protocol .= "s";
554
+ }
555
+ $url = "$protocol://";
556
+ if ( $_SERVER["SERVER_PORT"] != "80" ) {
557
+ $url .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
558
+ } else {
559
+ $url .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
560
+ }
561
+
562
+ return apply_filters( 'defender_current_page_url', $url );
563
+ }
564
+
565
+ /**
566
+ * Blank function
567
+ */
568
+ public function submitStatsToDev() {
569
+ return;
570
+ }
571
  }
app/controller/dashboard.php CHANGED
@@ -33,6 +33,7 @@ class Dashboard extends Controller {
33
  $this->add_ajax_action( 'toggleBlacklistWidget', 'toggleBlacklistWidget' );
34
  $this->add_ajax_action( 'activateModule', 'activateModule' );
35
  $this->add_ajax_action( 'skipActivator', 'skipActivator' );
 
36
  $this->add_filter( 'wdp_register_hub_action', 'addMyEndpoint' );
37
  add_filter( 'custom_menu_order', '__return_true' );
38
  $this->add_filter( 'menu_order', 'menuOrder' );
@@ -73,14 +74,25 @@ class Dashboard extends Controller {
73
  return $menu_order;
74
  }
75
 
 
 
 
 
 
 
76
  /**
77
  * @param $actions
78
  *
79
  * @return mixed
80
  */
81
  public function addMyEndpoint( $actions ) {
82
- $actions['defender_new_scan'] = array( &$this, 'new_scan' );
83
- $actions['defender_schedule_scan'] = array( &$this, 'schedule_scan' );
 
 
 
 
 
84
 
85
  return $actions;
86
  }
@@ -120,6 +132,114 @@ class Dashboard extends Controller {
120
  wp_send_json_success();
121
  }
122
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  public function actionIndex() {
124
  $this->render( 'dashboard' );
125
  }
33
  $this->add_ajax_action( 'toggleBlacklistWidget', 'toggleBlacklistWidget' );
34
  $this->add_ajax_action( 'activateModule', 'activateModule' );
35
  $this->add_ajax_action( 'skipActivator', 'skipActivator' );
36
+ $this->add_action( 'defenderSubmitStats', 'defenderSubmitStats' );
37
  $this->add_filter( 'wdp_register_hub_action', 'addMyEndpoint' );
38
  add_filter( 'custom_menu_order', '__return_true' );
39
  $this->add_filter( 'menu_order', 'menuOrder' );
74
  return $menu_order;
75
  }
76
 
77
+ public function defenderSubmitStats() {
78
+ if ( $this->hasMethod( '_submitStatsToDev' ) ) {
79
+ $this->_submitStatsToDev();
80
+ }
81
+ }
82
+
83
  /**
84
  * @param $actions
85
  *
86
  * @return mixed
87
  */
88
  public function addMyEndpoint( $actions ) {
89
+ $actions['defender_new_scan'] = array( &$this, 'new_scan' );
90
+ $actions['defender_schedule_scan'] = array( &$this, 'schedule_scan' );
91
+ $actions['defender_manage_audit_log'] = array( &$this, 'manage_audit_log' );
92
+ $actions['defender_manage_lockout'] = array( &$this, 'manage_lockout' );
93
+ $actions['defender_whitelist_ip'] = array( &$this, 'whitelist_ip' );
94
+ $actions['defender_blacklist_ip'] = array( &$this, 'blacklist_ip' );
95
+ $actions['defender_get_stats'] = array( &$this, 'get_stats' );
96
 
97
  return $actions;
98
  }
132
  wp_send_json_success();
133
  }
134
 
135
+ /**
136
+ * Hub Audit log endpoint
137
+ *
138
+ * @param $params
139
+ * @param $action
140
+ */
141
+ public function manage_audit_log( $params, $action ) {
142
+ $response = null;
143
+ if ( class_exists( '\WP_Defender\Module\Audit\Model\Settings' ) ) {
144
+ $response = array();
145
+ $settings = \WP_Defender\Module\Audit\Model\Settings::instance();
146
+ if ( $settings->enabled == true ) {
147
+ $settings->enabled = false;
148
+ $response['enabled'] = false;
149
+ } else {
150
+ $settings->enabled = true;
151
+ $response['enabled'] = true;
152
+ }
153
+ $settings->save();
154
+ }
155
+ wp_send_json_success( $response );
156
+ }
157
+
158
+ /**
159
+ * Hub Lockouts endpoint
160
+ *
161
+ * @param $params
162
+ * @param $action
163
+ */
164
+ public function manage_lockout( $params, $action ) {
165
+ $type = $params['type'];
166
+ $settings = \WP_Defender\Module\IP_Lockout\Model\Settings::instance();
167
+ $response = array();
168
+ if ( $type == 'login' ) {
169
+ if ( $settings->login_protection ) {
170
+ $settings->login_protection = 0;
171
+ $response[ $type ] = 'disabled';
172
+ } else {
173
+ $settings->login_protection = 1;
174
+ $response[ $type ] = 'enabled';
175
+ }
176
+ $settings->save();
177
+ } else if ( $type == '404' ) {
178
+ if ( $settings->detect_404 ) {
179
+ $settings->detect_404 = 0;
180
+ $response[ $type ] = 'disabled';
181
+ } else {
182
+ $settings->detect_404 = 1;
183
+ $response[ $type ] = 'enabled';
184
+ }
185
+ $settings->save();
186
+ } else {
187
+ $response[ $type ] = 'invalid';
188
+ }
189
+ wp_send_json_success();
190
+ }
191
+
192
+ /**
193
+ * Hub Whitelist IP endpoint
194
+ *
195
+ * @param $params
196
+ * @param $action
197
+ */
198
+ public function whitelist_ip( $params, $action ) {
199
+ $settings = \WP_Defender\Module\IP_Lockout\Model\Settings::instance();
200
+ $ip = $params['ip'];
201
+ if ( $ip && filter_var( $ip, FILTER_VALIDATE_IP ) ) {
202
+ $settings->removeIpFromList( $ip, 'blacklist' );
203
+ $settings->addIpToList( $ip, 'whitelist' );
204
+ } else {
205
+ wp_send_json_error();
206
+ }
207
+ wp_send_json_success();
208
+ }
209
+
210
+ /**
211
+ * Hub Blacklist IP endpoint
212
+ *
213
+ * @param $params
214
+ * @param $action
215
+ */
216
+ public function blacklist_ip( $params, $action ) {
217
+ $settings = \WP_Defender\Module\IP_Lockout\Model\Settings::instance();
218
+ $ip = $params['ip'];
219
+ if ( $ip && filter_var( $ip, FILTER_VALIDATE_IP ) ) {
220
+ $settings->removeIpFromList( $ip, 'whitelist' );
221
+ $settings->addIpToList( $ip, 'blacklist' );
222
+ } else {
223
+ wp_send_json_error();
224
+ }
225
+ wp_send_json_success();
226
+ }
227
+
228
+ /**
229
+ * Hub Stats endpoint
230
+ *
231
+ * @param $params
232
+ * @param $action
233
+ */
234
+ public function get_stats( $params, $action ) {
235
+ $stats = Utils::instance()->generateStats();
236
+ wp_send_json_success(
237
+ array(
238
+ 'stats' => $stats
239
+ )
240
+ );
241
+ }
242
+
243
  public function actionIndex() {
244
  $this->render( 'dashboard' );
245
  }
app/module/advanced-tools.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Author: Hoang Ngo
4
+ */
5
+
6
+ namespace WP_Defender\Module;
7
+
8
+ use Hammer\Base\Module;
9
+ use WP_Defender\Module\Advanced_Tools\Controller\Main;
10
+
11
+ class Advanced_Tools extends Module {
12
+ public function __construct() {
13
+ $main = new Main();
14
+ }
15
+ }
app/module/advanced-tools/component/auth-api.php ADDED
@@ -0,0 +1,307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Author: Hoang Ngo
4
+ */
5
+
6
+ namespace WP_Defender\Module\Advanced_Tools\Component;
7
+
8
+ use Hammer\Base\Component;
9
+ use WP_Defender\Module\Advanced_Tools\Model\Auth_Settings;
10
+
11
+ class Auth_API extends Component {
12
+ /**
13
+ * @param int $length
14
+ *
15
+ * @return string
16
+ */
17
+ public static function generateSecret( $length = 16 ) {
18
+ $strings = "ABCDEFGHIJKLMNOPQRSTUVWXYS234567";
19
+ $secret = array();
20
+ for ( $i = 0; $i < $length; $i ++ ) {
21
+ $secret[] = $strings[ rand( 0, strlen( $strings ) - 1 ) ];
22
+ }
23
+
24
+ return implode( "", $secret );
25
+ }
26
+
27
+ /**
28
+ * @param $name
29
+ * @param $secret
30
+ * @param int $width
31
+ * @param int $height
32
+ * @param null $title
33
+ *
34
+ * @return string
35
+ */
36
+ public static function generateQRCode( $name, $secret, $width = 200, $height = 200, $title = null ) {
37
+ $chl = urlencode( 'otpauth://totp/' . $name . '?secret=' . $secret . '' );
38
+ if ( ! is_null( $title ) ) {
39
+ $chl .= urlencode( '&issuer=' . $title );
40
+ }
41
+
42
+ return "https://chart.googleapis.com/chart?cht=qr&chs={$width}x{$height}&chl=$chl&chld=M|0";
43
+ }
44
+
45
+ /**
46
+ * Calculate the TOTP code
47
+ *
48
+ * @param $secret
49
+ * @param $counter
50
+ *
51
+ * @return \string
52
+ *
53
+ * reference: https://tools.ietf.org/html/rfc4226#section-5.3
54
+ * https://garbagecollected.org/2014/09/14/how-google-authenticator-works/
55
+ */
56
+ public static function generateCode( $secret, $counter = null ) {
57
+ //secret should be base 32, as GA want it
58
+ include_once wp_defender()->getPluginPath() . 'vendor/binary-to-text-php/Base2n.php';
59
+ $base32 = new \Base2n( 5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', false, true, true );
60
+ $secret = $base32->decode( $secret );
61
+ //timestep fixed at 30
62
+ if ( is_null( $counter ) ) {
63
+ $counter = time();
64
+ }
65
+ $input = floor( $counter / 30 );
66
+ //according to https://tools.ietf.org/html/rfc4226#section-5.3, should be a 8 bytes value
67
+ $time = chr( 0 ) . chr( 0 ) . chr( 0 ) . chr( 0 ) . pack( 'N*', $input );
68
+ $hmac = hash_hmac( 'sha1', $time, $secret, true );
69
+ //now we have 20 bytes sha1, need to short it down
70
+ //getting last byte of the hmac
71
+ $offset = ord( substr( $hmac, - 1 ) ) & 0x0F;
72
+ $four_bytes = substr( $hmac, $offset, 4 );
73
+ //now convert it into INT
74
+ $value = unpack( 'N', $four_bytes );
75
+ $value = $value[1];
76
+ //make sure it always act like 32 bits
77
+ $value = $value & 0x7FFFFFFF;;
78
+ //we so close
79
+ $code = $value % pow( 10, 6 );
80
+ //in some case we have the 0 before, so it become lesser than 6, make sure it always right
81
+ $code = str_pad( $code, 6, '0', STR_PAD_LEFT );
82
+
83
+ return $code;
84
+ }
85
+
86
+ /**
87
+ * @param $secret
88
+ * @param $userCode
89
+ * @param int $window
90
+ *
91
+ * @return bool
92
+ */
93
+ public static function compare( $secret, $userCode, $window = 1 ) {
94
+ if ( strlen( $userCode ) != 6 ) {
95
+ return false;
96
+ }
97
+
98
+ /**
99
+ * window is 30 seconds, before and after
100
+ */
101
+ for ( $i = - $window; $i <= $window; $i ++ ) {
102
+ $counter = $i == 0 ? null : $i * 30 + time();
103
+ $code = self::generateCode( $secret, $counter );
104
+ if ( self::hasEqual( $code, $userCode ) ) {
105
+ return true;
106
+ }
107
+ }
108
+
109
+ return false;
110
+ }
111
+
112
+ /**
113
+ * Timing attack safe string comparison, replacement of has_equals which only on 5.6+
114
+ *
115
+ * @param $known_string
116
+ * @param $user_string
117
+ *
118
+ * @return bool
119
+ * reference: http://php.net/manual/en/function.hash-equals.php#119576
120
+ */
121
+ private static function hasEqual( $known_string, $user_string ) {
122
+ if ( function_exists( 'hash_equals' ) ) {
123
+ return hash_equals( $known_string, $user_string );
124
+ }
125
+
126
+ $ret = 0;
127
+
128
+ if ( strlen( $known_string ) !== strlen( $user_string ) ) {
129
+ $user_string = $known_string;
130
+ $ret = 1;
131
+ }
132
+
133
+ $res = $known_string ^ $user_string;
134
+
135
+ for ( $i = strlen( $res ) - 1; $i >= 0; -- $i ) {
136
+ $ret |= ord( $res[ $i ] );
137
+ }
138
+
139
+ return ! $ret;
140
+ }
141
+
142
+ /**
143
+ * @return bool
144
+ */
145
+ public static function isEnableForCurrentRole( $user = null ) {
146
+ if ( $user == null ) {
147
+ $user = wp_get_current_user();
148
+ }
149
+ if ( ! $user instanceof \WP_User ) {
150
+ return false;
151
+ }
152
+ $settings = Auth_Settings::instance();
153
+ $allowedForThisRole = array_intersect( $settings->userRoles, $user->roles );
154
+
155
+ return count( $allowedForThisRole ) > 0;
156
+ }
157
+
158
+ /**
159
+ * @return bool|mixed|string
160
+ */
161
+ public static function createSecretForCurrentUser() {
162
+ if ( ! is_user_logged_in() ) {
163
+ return false;
164
+ }
165
+
166
+ $secret = get_user_meta( get_current_user_id(), 'defenderAuthSecret', true );
167
+ if ( ! $secret ) {
168
+ $secret = self::generateSecret();
169
+ update_user_meta( get_current_user_id(), 'defenderAuthSecret', $secret );
170
+ }
171
+
172
+ return $secret;
173
+ }
174
+
175
+ /**
176
+ * @param null $userID
177
+ *
178
+ * @return bool|mixed
179
+ */
180
+ public static function getUserSecret( $userID = null ) {
181
+ if ( $userID == null ) {
182
+ $userID = get_current_user_id();
183
+ }
184
+ $secret = get_user_meta( $userID, 'defenderAuthSecret', true );
185
+ if ( ! $secret ) {
186
+ return false;
187
+ }
188
+
189
+ return $secret;
190
+ }
191
+
192
+ /**
193
+ * @param $userID
194
+ *
195
+ * @return mixed
196
+ */
197
+ public static function isUserEnableOTP( $userID ) {
198
+ if ( $userID instanceof \WP_User ) {
199
+ $user = $userID;
200
+ $userID = $user->ID;
201
+ } else {
202
+ $user = get_user_by( 'id', $userID );
203
+ }
204
+ if ( ! self::isEnableForCurrentRole( $user ) ) {
205
+ return false;
206
+ }
207
+
208
+ $isOn = get_user_meta( $userID, 'defenderAuthOn', true );
209
+
210
+ return $isOn;
211
+ }
212
+
213
+ /**
214
+ * @param $userID
215
+ *
216
+ * @return bool|mixed|string
217
+ */
218
+ public static function getBackupEmail( $userID ) {
219
+ $email = get_user_meta( $userID, 'defenderAuthEmail', true );
220
+ if ( empty( $email ) ) {
221
+ $user = get_user_by( 'id', $userID );
222
+ if ( ! is_object( $user ) ) {
223
+ return false;
224
+ }
225
+ $email = $user->user_email;
226
+ }
227
+
228
+ return $email;
229
+ }
230
+
231
+ /**
232
+ * Generate single code, use in case lost phone
233
+ *
234
+ * @param $userID
235
+ *
236
+ * @return string
237
+ */
238
+ public static function createBackupCode( $userID ) {
239
+ $code = wp_generate_password( 20, false );
240
+ update_user_meta( $userID, 'defenderBackupCode', array(
241
+ 'code' => $code,
242
+ 'time' => time()
243
+ ) );
244
+
245
+ return $code;
246
+ }
247
+
248
+ /**
249
+ * @return bool
250
+ */
251
+ public static function isJetPackSSO() {
252
+ if ( is_plugin_active_for_network( 'jetpack/jetpack.php' ) ) {
253
+ //loop through all sites
254
+ $settings = Auth_Settings::instance();
255
+ $isConflict = $settings->isConflict( 'jetpack/jetpack.php' );
256
+ if ( $isConflict === 0 ) {
257
+ //no data, init
258
+ global $wpdb;
259
+ $sql = "SELECT blog_id FROM `{$wpdb->prefix}blogs`";
260
+ $blogs = $wpdb->get_col( $sql );
261
+ foreach ( $blogs as $id ) {
262
+ $options = get_blog_option( $id, 'jetpack_active_modules', array() );
263
+ if ( array_search( 'sso', $options ) ) {
264
+ $settings->markAsConflict( 'jetpack/jetpack.php' );
265
+
266
+ return true;
267
+ }
268
+ }
269
+ } else {
270
+ //get the data from cache
271
+ return $isConflict;
272
+ }
273
+
274
+ } elseif ( is_plugin_active( 'jetpack/jetpack.php' ) ) {
275
+ //ugly but faster
276
+ $settings = Auth_Settings::instance();
277
+ $isConflict = $settings->isConflict( 'jetpack/jetpack.php' );
278
+ if ( $isConflict === 0 ) {
279
+ $options = get_option( 'jetpack_active_modules', array() );
280
+ if ( array_search( 'sso', $options ) ) {
281
+ $settings->markAsConflict( 'jetpack/jetpack.php' );
282
+
283
+ return true;
284
+ }
285
+ } else {
286
+ return $isConflict;
287
+ }
288
+
289
+ }
290
+
291
+ return false;
292
+ }
293
+
294
+ /**
295
+ * @return bool
296
+ */
297
+ public static function isTML() {
298
+ if ( is_plugin_active( 'theme-my-login/theme-my-login.php' ) || is_plugin_active_for_network( 'theme-my-login/theme-my-login.php' ) ) {
299
+ $settings = Auth_Settings::instance();
300
+ $settings->markAsConflict( 'theme-my-login/theme-my-login.php' );
301
+
302
+ return true;
303
+ }
304
+
305
+ return false;
306
+ }
307
+ }
app/module/advanced-tools/controller/main.php ADDED
@@ -0,0 +1,463 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Author: Hoang Ngo
4
+ */
5
+
6
+ namespace WP_Defender\Module\Advanced_Tools\Controller;
7
+
8
+ use Hammer\Helper\HTTP_Helper;
9
+ use Hammer\Helper\WP_Helper;
10
+ use WP_Defender\Behavior\Utils;
11
+ use WP_Defender\Controller;
12
+ use WP_Defender\Module\Advanced_Tools\Component\Auth_API;
13
+ use WP_Defender\Module\Advanced_Tools\Model\Auth_Settings;
14
+
15
+ class Main extends Controller {
16
+ protected $slug = 'wdf-advanced-tools';
17
+ protected $sessionToken;
18
+ public $layout = 'layout';
19
+
20
+ /**
21
+ * @return array
22
+ */
23
+ public function behaviors() {
24
+ return array(
25
+ 'utils' => '\WP_Defender\Behavior\Utils'
26
+ );
27
+ }
28
+
29
+ public function __construct() {
30
+ if ( $this->is_network_activate( wp_defender()->plugin_slug ) ) {
31
+ $this->add_action( 'network_admin_menu', 'adminMenu' );
32
+ } else {
33
+ $this->add_action( 'admin_menu', 'adminMenu' );
34
+ }
35
+
36
+ if ( $this->isInPage() || $this->isDashboard() ) {
37
+ $this->add_action( 'defender_enqueue_assets', 'scripts', 11 );
38
+ }
39
+ $this->add_ajax_action( 'saveAdvancedSettings', 'saveSettings' );
40
+ $setting = Auth_Settings::instance();
41
+ if ( $setting->enabled ) {
42
+ $this->add_action( 'update_option_jetpack_available_modules', 'listenForJetpackOption', 10, 3 );
43
+ //prepare for the login part
44
+ $isJetpackSSO = Auth_API::isJetPackSSO();
45
+ $isTML = Auth_API::isTML();
46
+ if ( ! defined( 'DOING_AJAX' ) && ! $isJetpackSSO && ! $isTML ) {
47
+ /**
48
+ * hook into wordpress login, can't use authenticate hook as that badly conflict
49
+ */
50
+ $this->add_action( 'wp_login', 'maybeShowOTPLogin', 50, 2 );
51
+ $this->add_action( 'login_form_defenderVerifyOTP', 'defenderVerifyOTP' );
52
+ $this->add_action( 'set_logged_in_cookie', 'storeSessionKey' );
53
+ /**
54
+ * end
55
+ */
56
+ } else {
57
+ if ( $isJetpackSSO ) {
58
+ wp_defender()->global['compatibility'][] = __( "You enabled Jetpack WordPress.com login, so Defender will disable the 2 factors login for avoiding conflict", wp_defender()->domain );
59
+ }
60
+ if ( $isTML ) {
61
+ wp_defender()->global['compatibility'][] = __( "You enabled the plugin Theme My Login, so Defender will disable the 2 factors login for avoiding conflict", wp_defender()->domain );
62
+ }
63
+ }
64
+ $this->add_filter( 'ms_shortcode_ajax_login', 'm2NoAjax' );
65
+ $this->add_action( 'show_user_profile', 'showUsers2FactorActivation' );
66
+ $this->add_action( 'profile_update', 'saveBackupEmail' );
67
+ $this->add_ajax_action( 'defVerifyOTP', 'verifyConfigOTP' );
68
+ $this->add_ajax_action( 'defDisableOTP', 'disableOTP' );
69
+ $this->add_ajax_action( 'defRetrieveOTP', 'retrieveOTP', false, true );
70
+ if ( Utils::instance()->isActivatedSingle() ) {
71
+ $this->add_filter( 'manage_users_columns', 'alterUsersTable' );
72
+ $this->add_filter( 'manage_users_custom_column', 'alterUsersTableRow', 10, 3 );
73
+ } else {
74
+ $this->add_filter( 'wpmu_users_columns', 'alterUsersTable' );
75
+ $this->add_filter( 'manage_users_custom_column', 'alterUsersTableRow', 10, 3 );
76
+ }
77
+ }
78
+ }
79
+
80
+ /**
81
+ * We have some feature conflict with jetpack, so listen to know when Defender can on
82
+ *
83
+ * @param $old_value
84
+ * @param $value
85
+ * @param $option
86
+ */
87
+ public function listenForJetpackOption( $old_value, $value, $option ) {
88
+ $settings = Auth_Settings::instance();
89
+ if ( array_search( 'sso', $value ) ) {
90
+ $settings->markAsConflict( 'jetpack/jetpack.php' );
91
+ } else {
92
+ $settings->markAsUnConflict( 'jetpack/jetpack.php' );
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Stop ajax login on membership 2
98
+ * @return bool
99
+ */
100
+ public function m2NoAjax() {
101
+ return false;
102
+ }
103
+
104
+ /**
105
+ * Return 2 factor auth status
106
+ *
107
+ * @param $val
108
+ * @param $column_name
109
+ * @param $user_id
110
+ *
111
+ * @return string
112
+ */
113
+ public function alterUsersTableRow( $val, $column_name, $user_id ) {
114
+ if ( $column_name != 'defAuth' ) {
115
+ return $val;
116
+ }
117
+
118
+ if ( Auth_API::isUserEnableOTP( $user_id ) ) {
119
+ return '<span class="def-oval oval-green"></span>';
120
+ }
121
+
122
+ return '<span class="def-oval"></span>';
123
+ }
124
+
125
+ /**
126
+ * Add the auth column inside users on single site
127
+ *
128
+ * @param $columns
129
+ *
130
+ * @return mixed
131
+ *
132
+ */
133
+ public function alterUsersTable( $columns ) {
134
+ $columns = array_slice( $columns, 0, count( $columns ) - 1 ) + array(
135
+ 'defAuth' => __( "2 Factor", wp_defender()->domain )
136
+ ) + array_slice( $columns, count( $columns ) - 1 );
137
+
138
+ return $columns;
139
+ }
140
+
141
+ /**
142
+ * Generate an email for backup otp
143
+ */
144
+ public function retrieveOTP() {
145
+ if ( ! wp_verify_nonce( HTTP_Helper::retrieve_get( 'nonce' ), 'defRetrieveOTP' ) ) {
146
+ wp_send_json_error( array() );
147
+ }
148
+
149
+ $token = HTTP_Helper::retrieve_get( 'token' );
150
+ $query = new \WP_User_Query( array(
151
+ 'meta_key' => 'defOTPLoginToken',
152
+ 'meta_value' => $token
153
+ ) );
154
+ $res = $query->get_results();
155
+ if ( empty( $res ) ) {
156
+ //no user
157
+ wp_send_json_error( array(
158
+ 'message' => __( "Your token is invalid", wp_defender()->domain )
159
+ ) );
160
+ }
161
+
162
+ $user = $res[0];
163
+ //create a backup code for this user
164
+ $code = Auth_API::createBackupCode( $user->ID );
165
+ //send email
166
+ $backupEmail = Auth_API::getBackupEmail( $user->ID );
167
+ //send
168
+ wp_mail( $backupEmail, 'Your OTP code', $code );
169
+ wp_send_json_success( array(
170
+ 'message' => __( "Your code has been sent to your email.", wp_defender()->domain )
171
+ ) );
172
+ }
173
+
174
+ /**
175
+ * disable OTP feature
176
+ */
177
+ public function disableOTP() {
178
+ if ( ! is_user_logged_in() ) {
179
+ return;
180
+ }
181
+
182
+ update_user_meta( get_current_user_id(), 'defenderAuthOn', 0 );
183
+ wp_send_json_success();
184
+ }
185
+
186
+ /**
187
+ * Saving backup email when profile saved
188
+ *
189
+ * @param $userID
190
+ */
191
+ public function saveBackupEmail( $userID ) {
192
+ $email = HTTP_Helper::retrieve_post( 'def_backup_email' );
193
+ if ( $email && get_current_user_id() == $userID ) {
194
+ update_user_meta( $userID, 'defenderAuthEmail', $email );
195
+ }
196
+ }
197
+
198
+ /**
199
+ * An ajax function for verify the OTP user input when configuring the 2 factors
200
+ */
201
+ public function verifyConfigOTP() {
202
+ if ( ! wp_verify_nonce( HTTP_Helper::retrieve_post( 'nonce' ), 'defVerifyOTP' ) ) {
203
+ return;
204
+ }
205
+
206
+ if ( ! is_user_logged_in() ) {
207
+ return;
208
+ }
209
+
210
+ $otp = HTTP_Helper::retrieve_post( 'otp' );
211
+ $otp = trim( $otp );
212
+ if ( strlen( $otp ) == 0 ) {
213
+ wp_send_json_error( array(
214
+ 'message' => __( "Please input a valid OTP code", wp_defender()->domain )
215
+ ) );
216
+ }
217
+
218
+ $secret = Auth_API::getUserSecret();
219
+ //at this stage, secret should have value, do not need to check
220
+ $res = Auth_API::compare( $secret, $otp );
221
+ if ( $res ) {
222
+ //save it
223
+ update_user_meta( get_current_user_id(), 'defenderAuthOn', 1 );
224
+ wp_send_json_success();
225
+ } else {
226
+ //now need to check if the current user have backup otp
227
+ wp_send_json_error( array(
228
+ 'message' => __( "Your OTP code is incorrect. Please try again.", wp_defender()->domain )
229
+ ) );
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Show an section inside my profile page for user can activate 2 factor login
235
+ *
236
+ * @param $profileuser
237
+ */
238
+ public function showUsers2FactorActivation( $profileuser ) {
239
+ if ( ! Auth_API::isEnableForCurrentRole() ) {
240
+ return;
241
+ }
242
+
243
+ $isOn = get_user_meta( $profileuser->ID, 'defenderAuthOn', true );
244
+ wp_enqueue_style( 'defAuth', wp_defender()->getPluginUrl() . 'app/module/advanced-tools/css/login-admin.css' );
245
+ $secretKey = Auth_API::createSecretForCurrentUser();
246
+ if ( $isOn && $isOn == 1 ) {
247
+ $email = Auth_API::getBackupEmail( $profileuser->ID );
248
+ $this->renderPartial( 'login/enabled', array(
249
+ 'email' => $email
250
+ ) );
251
+ } else {
252
+ //show the screen
253
+ $this->renderPartial( 'login/disabled', array(
254
+ 'secretKey' => $secretKey
255
+ ) );
256
+ }
257
+ }
258
+
259
+ /**
260
+ * We will check and show the OTP screen if user signon successfully
261
+ *
262
+ * @param $userLogin
263
+ * @param $user
264
+ */
265
+ public function maybeShowOTPLogin( $userLogin, $user ) {
266
+ if ( ! Auth_API::isUserEnableOTP( $user->ID ) ) {
267
+ //no enable, then just return
268
+ return;
269
+ }
270
+
271
+ //clean up session and auth cookies for preventing
272
+ $token = $this->sessionToken;
273
+ if ( $token ) {
274
+ $sManager = \WP_Session_Tokens::get_instance( $user->ID );
275
+ $sManager->destroy( $token );
276
+ }
277
+ wp_clear_auth_cookie();
278
+
279
+ $this->showOTPScreen( $user );
280
+ }
281
+
282
+ /**
283
+ * verify OTP code which user input in order to login
284
+ */
285
+ public function defenderVerifyOTP() {
286
+ if ( ( $otp = HTTP_Helper::retrieve_post( 'otp', null ) ) != null ) {
287
+ $params = array();
288
+ if ( ! wp_verify_nonce( HTTP_Helper::retrieve_post( '_wpnonce' ), 'DefOtpCheck' ) ) {
289
+ $params['error'] = new \WP_Error( 'security_fail', __( "Some error happen", wp_defender()->domain ) );
290
+ }
291
+
292
+ $login_token = HTTP_Helper::retrieve_post( 'login_token' );
293
+ $query = new \WP_User_Query( array(
294
+ 'meta_key' => 'defOTPLoginToken',
295
+ 'meta_value' => $login_token
296
+ ) );
297
+ $res = $query->get_results();
298
+ if ( empty( $res ) ) {
299
+ //no users, redirect to the login page immediatly
300
+ wp_redirect( site_url( 'wp-login.php', 'login_post' ) );
301
+ exit;
302
+ } else {
303
+ $user = $res[0];
304
+ $secret = Auth_API::getUserSecret( $user->ID );
305
+ $redirect = HTTP_Helper::retrieve_post( 'redirect_to', admin_url() );
306
+ if ( empty( $redirect ) ) {
307
+ $redirect = admin_url();
308
+ }
309
+ if ( Auth_API::compare( $secret, $otp ) ) {
310
+ //sign in
311
+ delete_user_meta( $user->ID, 'defOTPLoginToken' );
312
+ wp_set_current_user( $user->ID, $user->user_login );
313
+ wp_set_auth_cookie( $user->ID, true );
314
+ wp_redirect( $redirect );
315
+ exit;
316
+ } else {
317
+ $backupCode = get_user_meta( $user->ID, 'defenderBackupCode', true );
318
+ if ( $backupCode && $backupCode['code'] == $otp && strtotime( '+3 minutes', $backupCode['time'] ) > time() ) {
319
+ delete_user_meta( $user->ID, 'defOTPLoginToken' );
320
+ delete_user_meta( $user->ID, 'defenderBackupCode' );
321
+ wp_set_current_user( $user->ID, $user->user_login );
322
+ wp_set_auth_cookie( $user->ID, true );
323
+ wp_redirect( $redirect );
324
+ exit;
325
+ } else {
326
+ $params['error'] = new \WP_Error( 'opt_fail', __( "Whoops, the passcode you entered was incorrect or expired.", wp_defender()->domain ) );
327
+ $this->showOTPScreen( $user, $params );
328
+ }
329
+ }
330
+ }
331
+ }
332
+ }
333
+
334
+ /**
335
+ * Show the OTP screen
336
+ *
337
+ * @param $user
338
+ * @param $params
339
+ */
340
+ private function showOTPScreen( $user, $params = array() ) {
341
+ //now show the OTP screen
342
+ $this->add_action( 'login_enqueue_scripts', 'includeAuthStyles' );
343
+ wp_enqueue_script( 'jquery' );
344
+ $params['loginToken'] = $this->createLoginToken( $user );
345
+ $params['redirect_to'] = HTTP_Helper::retrieve_post( 'redirect_to' );
346
+ if ( ! isset( $params['error'] ) ) {
347
+ $params['error'] = null;
348
+ }
349
+ //if this goes here then the current user is ok, need to show the 2 auth
350
+ $this->renderPartial( 'login/otp', $params );
351
+ exit;
352
+ }
353
+
354
+ /**
355
+ * We will empty all auth cookies or session, so should not rely on wp_get_session_token
356
+ *
357
+ * @param $cookie
358
+ */
359
+ public function storeSessionKey( $cookie ) {
360
+ $cookie = wp_parse_auth_cookie( $cookie, 'logged_in' );
361
+ $this->sessionToken = ! empty( $cookie['token'] ) ? $cookie['token'] : '';
362
+ }
363
+
364
+ /**
365
+ * Create a unique token to retrieve user later
366
+ *
367
+ * @param $user
368
+ *
369
+ * @return string
370
+ */
371
+ private function createLoginToken( $user ) {
372
+ $tmp = uniqid();
373
+ // create and store a login token so we can query this user again
374
+ update_user_meta( $user->ID, 'defOTPLoginToken', $tmp );
375
+
376
+ return $tmp;
377
+ }
378
+
379
+ /**
380
+ * add css for OTP page
381
+ */
382
+ public function includeAuthStyles() {
383
+ //enqueue css here
384
+ wp_enqueue_style( 'defAuth', wp_defender()->getPluginUrl() . 'app/module/advanced-tools/css/login.css' );
385
+ }
386
+
387
+ /**
388
+ * Add submit admin page
389
+ */
390
+ public function adminMenu() {
391
+ $cap = is_multisite() ? 'manage_network_options' : 'manage_options';
392
+ add_submenu_page( 'wp-defender', esc_html__( "Advanced Tools", wp_defender()->domain ), esc_html__( "Advanced Tools", wp_defender()->domain ), $cap, $this->slug, array(
393
+ &$this,
394
+ 'actionIndex'
395
+ ) );
396
+ }
397
+
398
+ /**
399
+ * a simple router
400
+ */
401
+ public function actionIndex() {
402
+ $view = HTTP_Helper::retrieve_get( 'view' );
403
+ switch ( $view ) {
404
+ default:
405
+ $this->viewAuth();
406
+ break;
407
+ }
408
+ }
409
+
410
+ /**
411
+ * View the 2 factor main admin page
412
+ */
413
+ public function viewAuth() {
414
+ $settings = Auth_Settings::instance();
415
+ if ( $settings->enabled == false ) {
416
+ $this->render( 'disabled' );
417
+ } else {
418
+ $this->render( 'main', array(
419
+ 'settings' => $settings
420
+ ) );
421
+ }
422
+ }
423
+
424
+ /**
425
+ * Enqueue scripts & styles
426
+ */
427
+ public function scripts() {
428
+ if ( $this->isInPage() ) {
429
+ \WDEV_Plugin_Ui::load( wp_defender()->getPluginUrl() . 'shared-ui/' );
430
+ wp_enqueue_script( 'defender' );
431
+ wp_enqueue_style( 'defender' );
432
+ wp_enqueue_script( 'adtools', wp_defender()->getPluginUrl() . 'app/module/advanced-tools/js/scripts.js' );
433
+ }
434
+ }
435
+
436
+ /**
437
+ * Saving settings in admin area
438
+ */
439
+ public function saveSettings() {
440
+ if ( ! $this->checkPermission() ) {
441
+ return;
442
+ }
443
+
444
+ if ( ! wp_verify_nonce( HTTP_Helper::retrieve_post( '_wpnonce' ), 'saveAdvancedSettings' ) ) {
445
+ return;
446
+ }
447
+
448
+ $data = $_POST;
449
+ $setting = Auth_Settings::instance();
450
+ $tmp = $setting->enabled;
451
+ $setting->import( $data );
452
+ $setting->save();
453
+
454
+ $res = array(
455
+ 'message' => __( "Your settings have been updated.", wp_defender()->domain )
456
+ );
457
+ if ( $tmp != $setting->enabled ) {
458
+ $res['reload'] = 1;
459
+ }
460
+
461
+ wp_send_json_success( $res );
462
+ }
463
+ }
app/module/advanced-tools/css/login-admin.css ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .def-notification {
2
+ padding: 10px 20px;
3
+ border-radius: 4px;
4
+ background-color: #D1F1EA;
5
+ color: #666;
6
+ display: block;
7
+ clear: right;
8
+ width: 50%;
9
+ margin-bottom: 10px;
10
+ }
11
+
12
+ .card {
13
+ margin-top: 10px;
14
+ padding: 30px 30px;
15
+ }
16
+
17
+ .well {
18
+ border-radius: 5px;
19
+ background-color: #F9F9F9;
20
+ padding: 15px;
21
+ margin-top: 15px;
22
+ width: 50%;
23
+ }
24
+
25
+ .line {
26
+ margin-bottom: 20px;
27
+ }
28
+
29
+ .error {
30
+ color: #FF6D6D;
31
+ font-size: 12px !important;
32
+ font-weight: 500;
33
+ padding-bottom: 10px;
34
+ }
app/module/advanced-tools/css/login.css ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body.login div#login h1 a {
2
+ background-image: url("../img/2factor-disabled.svg");
3
+ }
4
+
5
+ body.login div#login form {
6
+ padding-bottom: 26px;
7
+ }
8
+
9
+ .float-r {
10
+ float: right;
11
+ }
12
+
13
+ .clearfix {
14
+ clear: both;
15
+ }
16
+
17
+ .def-ajaxloader {
18
+ width: 20px;
19
+ position: relative;
20
+ top: 5px;
21
+ }
app/module/advanced-tools/img/2factor-disabled.svg ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg width="128px" height="128px" viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
+ <!-- Generator: Sketch 45.1 (43504) - http://www.bohemiancoding.com/sketch -->
4
+ <title>graphic-defender-2factor-disabled</title>
5
+ <desc>Created with Sketch.</desc>
6
+ <defs>
7
+ <circle id="path-1" cx="64" cy="64" r="64"></circle>
8
+ <polygon id="path-3" points="0.327466846 0.3500558 3.88734603 0.3500558 3.88734603 21.3428699 0.327466846 21.3428699 0.327466846 0.3500558"></polygon>
9
+ <polygon id="path-5" points="51.1257801 0.184853857 51.1257801 49.0738103 0.330536413 49.0738103 0.330536413 0.184853857"></polygon>
10
+ </defs>
11
+ <g id="Security-Plugin" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
12
+ <g id="Advanced-Tools---2-Factor---Disabled" transform="translate(-726.000000, -223.000000)">
13
+ <g id="graphic-defender-2factor-disabled" transform="translate(726.000000, 223.000000)">
14
+ <mask id="mask-2" fill="white">
15
+ <use xlink:href="#path-1"></use>
16
+ </mask>
17
+ <use id="mask" fill="#333333" xlink:href="#path-1"></use>
18
+ <g id="graphic" mask="url(#mask-2)">
19
+ <g transform="translate(-6.000000, 10.000000)">
20
+ <path d="M39.4062404,173.10829 C44.5020972,174.081424 53.4377494,173.063861 54.0267519,168.804431 C53.575243,166.584784 53.2010742,166.272707 53.2010742,166.272707 C53.2010742,166.272707 66.6772379,143.156842 65.7953453,123.921688 C64.9134527,104.686534 45.3095141,107.332196 45.3095141,107.332196 C45.3095141,107.332196 37.373913,118.626064 34.904757,136.272889 C32.4359591,153.919715 37.417954,162.29669 37.417954,162.29669 C37.417954,162.29669 35.7354476,166.837383 34.6032737,173.249817 C34.7436317,172.456549 34.891867,171.690869 35.044399,170.959585 C35.3802558,171.617418 36.4050128,172.535016 39.4062404,173.10829" id="Fill-19" fill="#9F5622"></path>
21
+ <path d="M98.7215192,173.10829 C93.6256624,174.081424 84.6900102,173.063861 84.1006496,168.804431 C84.5525166,166.584784 84.9266854,166.272707 84.9266854,166.272707 C84.9266854,166.272707 71.4505217,143.156842 72.3324143,123.921688 C73.2143069,104.686534 92.8182455,107.332196 92.8182455,107.332196 C92.8182455,107.332196 100.753847,118.626064 103.223003,136.272889 C105.691801,153.919715 100.709806,162.29669 100.709806,162.29669 C100.709806,162.29669 102.392312,166.837383 103.524486,173.249817 C103.384128,172.456549 103.235893,171.690869 103.083361,170.959585 C102.747504,171.617418 101.722747,172.535016 98.7215192,173.10829" id="Fill-77" fill="#9F5622"></path>
22
+ <path d="M45.5730793,111.169696 C44.4412634,111.145332 43.5396777,111.197643 42.9821841,111.245655 C42.9291918,111.344187 42.8747673,111.447376 42.8207008,111.549132 C45.055688,112.721121 54.9878107,118.292633 62.1181432,128.225332 C63.6098056,130.696504 64.5615192,132.467564 65.1673504,133.735218 C65.5007008,131.627717 65.7244859,129.513409 65.8032583,127.424898 C60.5981944,123.105273 50.4301125,115.602542 45.5730793,111.169696" id="Fill-123" fill="#98480C"></path>
23
+ <path d="M95.3429003,111.617065 C95.2684246,111.475897 95.1939488,111.334728 95.1216215,111.200725 C91.5313913,110.649665 73.9902148,108.978569 72.3789616,128.537265 C72.495688,130.435162 72.7262762,132.348825 73.0445882,134.254963 C74.7668389,130.825706 78.878399,123.432255 86.114,117.877224 C91.3011611,113.894757 94.0055601,112.275973 95.3429003,111.617065" id="Fill-125" fill="#98480C"></path>
24
+ <path d="M100.613739,76.4418678 C106.021821,71.862837 111.178547,67.119348 111.178547,67.119348 L111.178547,70.2465609 C119.016399,59.9806461 122.406118,48.4047988 122.238905,47.40121 C122.0409,46.2105903 119.117013,44.801768 115.563662,39.7637592 C102.081412,32.6214743 69.0639693,25.4283113 69.0639693,25.4283113 C69.0639693,25.4283113 38.0946087,33.1162819 24.6123581,40.2589251 C19.0610537,41.4491865 16.0870384,46.2105903 15.8886752,47.40121 C15.7228951,48.3961997 19.056399,59.7882408 26.7553248,69.9896623 L28.2978312,69.1609222 L36.5098517,74.7177445 L31.6094936,75.5826725 C31.6728696,75.6457327 31.7355294,75.7095095 31.7996215,75.7722115 C34.3769105,77.9549545 35.7650946,78.1530925 35.7650946,78.1530925 C35.7650946,78.1530925 39.7799795,83.113351 42.1592634,84.5021087 C49.0983939,85.69237 69.0639693,85.2437827 69.0639693,85.2437827 C69.0639693,85.2437827 89.0291867,85.69237 95.9686752,84.5021087 C98.3479591,83.113351 102.362844,78.1530925 102.362844,78.1530925 C102.362844,78.1530925 102.51645,78.1298032 102.810414,78.0230308 C100.344123,78.2670308 98.7471918,78.0223142 100.613739,76.4418678" id="Fill-127" fill="#9F5622"></path>
25
+ <path d="M82.4067212,34.5627971 L69.0637545,31.4660394 L55.7211458,34.5627971 L55.499509,37.0296693 C55.499509,37.0296693 60.1549565,40.9662743 62.0845217,42.1733756 C64.014087,43.3804769 65.8169003,45.3865797 65.8169003,45.3865797 L66.623601,45.9931759 L69.0637545,45.9931759 L71.504266,45.9931759 L72.3109668,45.3865797 C72.3109668,45.3865797 74.1137801,43.3804769 76.0433453,42.1733756 C77.9729105,40.9662743 82.6283581,37.0296693 82.6283581,37.0296693 L82.4067212,34.5627971 Z" id="Fill-129" fill="#98480C"></path>
26
+ <path d="M68.0702916,21.3509674 C67.9360205,19.1470849 67.4053811,10.2917838 67.2954578,6.37237709 C67.2199079,3.67010396 67.526046,1.65253568 67.7824143,0.467290455 C66.6745882,0.59090279 64.8008798,0.851026138 61.97689,1.39993656 C56.8996522,2.38740206 54.2400102,7.87149016 54.2400102,10.2297985 C54.2400102,10.8908558 54.3234373,13.0567589 54.4491151,15.8432317 C54.0899847,16.1409762 53.6216471,16.6067618 53.5629258,17.0546326 C53.5396522,17.2334226 53.5503939,17.6859512 53.5840512,18.2839483 C54.0459437,18.8876781 54.4791918,19.419032 54.620624,19.4867501 C54.9657903,19.6515665 57.1918261,24.4624153 59.2427724,26.2796957 C60.7566343,27.6215166 62.5981176,28.5348147 63.6006752,28.9748029 C63.6364808,28.837217 63.6726445,28.6996311 63.7095243,28.5631201 C64.6053811,25.2481598 66.7372481,22.5136399 68.0702916,21.3509674" id="Fill-131" fill="#FF5B0C"></path>
27
+ <path d="M60.4257545,37.7939518 C61.9381841,38.0959959 62.4806394,33.2980458 63.6006394,28.9748388 C62.5980818,28.5348505 60.7565985,27.6215524 59.2427366,26.2797316 C57.1917903,24.4624511 54.9657545,19.6516023 54.6205882,19.4867859 C54.479156,19.4190678 54.0459079,18.8873557 53.5843734,18.2839841 C53.6896419,20.1528593 54.0201279,23.4516963 54.2399744,24.3241486 C54.4308184,25.0815877 54.7480563,25.5523894 54.943555,25.7877903 C55.1963427,30.4553204 55.4437596,34.4015994 55.5458056,34.6309093 C55.6782864,34.9297286 60.6420205,37.9225803 60.4257545,37.7939518" id="Fill-133" fill="#FFBC00"></path>
28
+ <path d="M70.0574322,21.3509674 C70.1917033,19.1470849 70.7223427,10.2917838 70.832266,6.37237709 C70.9078159,3.67010396 70.6016777,1.65253568 70.3453095,0.467290455 C71.4531355,0.59090279 73.326844,0.851026138 76.1508338,1.39993656 C81.2280716,2.38740206 83.8877136,7.87149016 83.8877136,10.2297985 C83.8877136,10.8908558 83.8042864,13.0567589 83.6786087,15.8432317 C84.0377391,16.1409762 84.5060767,16.6067618 84.564798,17.0546326 C84.5880716,17.2334226 84.5773299,17.6859512 84.5436726,18.2839483 C84.0817801,18.8876781 83.648532,19.419032 83.5070997,19.4867501 C83.1619335,19.6515665 80.9358977,24.4624153 78.8849514,26.2796957 C77.3710895,27.6215166 75.5296061,28.5348147 74.5270486,28.9748029 C74.491243,28.837217 74.4550793,28.6996311 74.4181995,28.5631201 C73.5223427,25.2481598 71.3904757,22.5136399 70.0574322,21.3509674" id="Fill-135" fill="#FF5B0C"></path>
29
+ <g id="Group-139" stroke-width="1" fill="none" transform="translate(66.956522, 0.008241)">
30
+ <mask id="mask-4" fill="white">
31
+ <use xlink:href="#path-3"></use>
32
+ </mask>
33
+ <g id="Clip-138"></g>
34
+ <path d="M3.38871611,0.459192952 C2.50431714,0.361019677 2.10723274,0.349912482 2.10723274,0.349912482 C2.10723274,0.349912482 1.71050639,0.361019677 0.826107417,0.459192952 C0.569381074,1.64443818 0.263601023,3.66200646 0.339150895,6.36392129 C0.449074169,10.2836863 0.979713555,19.1386291 1.1136266,21.3428699 C1.55976471,20.9537598 1.91638875,20.7405733 2.10723274,20.7405733 C2.29843478,20.7405733 2.65505882,20.9537598 3.10083887,21.3428699 C3.23510997,19.1386291 3.76574936,10.2836863 3.87567263,6.36392129 C3.95122251,3.66200646 3.6450844,1.64443818 3.38871611,0.459192952" id="Fill-137" fill="#FFBC00" mask="url(#mask-4)"></path>
35
+ </g>
36
+ <path d="M63.7094527,29.1566743 C64.6053095,25.841714 66.7371765,23.1071941 68.0702199,21.9445216 C68.5163581,21.5554115 68.8729821,21.342225 69.0638261,21.342225 C69.2546701,21.342225 69.6112941,21.5554115 70.0574322,21.9445216 C71.3904757,23.1071941 73.5223427,25.841714 74.4181995,29.1566743 C74.4550793,29.2931853 74.491243,29.4304129 74.5270486,29.5683571 C75.471601,33.2143836 76.0054629,37.1982837 77.0567161,38.1753586 C77.2002967,38.0908006 77.3413708,38.0080341 77.4860256,37.9224012 C77.5579949,37.8797639 77.6299642,37.8367683 77.7019335,37.7937727 C76.1895038,38.096175 75.6470486,33.2978667 74.5270486,28.9746596 C74.491243,28.8370737 74.4550793,28.6998461 74.4181995,28.5629768 C73.5223427,25.2480164 71.3904757,22.5134966 70.0574322,21.3508241 C69.6112941,20.9620722 69.2546701,20.7488858 69.0638261,20.7488858 C68.8729821,20.7488858 68.5163581,20.9620722 68.0702199,21.3508241 C66.7371765,22.5134966 64.6053095,25.2480164 63.7094527,28.5629768 C63.6725729,28.6998461 63.6364092,28.8370737 63.6006036,28.9746596 C62.4806036,33.2978667 61.9381483,38.096175 60.4257187,37.7937727 C60.497688,37.8367683 60.5696573,37.8797639 60.6419847,37.9224012 C60.7862813,38.0080341 60.9273555,38.0908006 61.0709361,38.1753586 C62.1221893,37.1982837 62.6560512,33.2143836 63.6006036,29.5683571 C63.6364092,29.4304129 63.6725729,29.2931853 63.7094527,29.1566743" id="Fill-140" fill="#98480C"></path>
37
+ <path d="M62.1412379,38.8049932 C62.167734,38.8204 62.1938721,38.8358068 62.2207263,38.8512135 C62.3263529,38.9128405 62.4305473,38.973751 62.5336675,39.0339448 C62.5648184,39.0518596 62.5959693,39.0701327 62.6267621,39.0880476 C62.7220051,39.1432253 62.8154578,39.1976863 62.9078363,39.2514308 C62.9414936,39.2707789 62.975867,39.2904852 63.0091662,39.3098332 C63.249422,39.4492106 63.4789361,39.5817803 63.6941279,39.7053927 C63.7188338,39.7197245 63.7424655,39.7329815 63.7668133,39.7469551 C63.8502404,39.7949668 63.9318772,39.8419037 64.0106496,39.8866907 C64.0378619,39.9024558 64.0647161,39.9175043 64.0912123,39.932911 C64.1606752,39.9723236 64.2272737,40.0103031 64.2920818,40.0475659 C64.3232327,40.0651225 64.3550997,40.0830373 64.3851765,40.1002355 C64.4507008,40.1374984 64.5126445,40.1726115 64.573156,40.2070079 C64.5928491,40.2181151 64.6146905,40.2306555 64.6340256,40.2414044 C64.713156,40.2861915 64.7876317,40.3277539 64.8563785,40.3664499 C64.8678363,40.3728993 64.8775038,40.3782737 64.8886036,40.3843648 C64.9430281,40.41482 64.9938721,40.4434837 65.0407775,40.4692811 C65.0608286,40.4803883 65.0787315,40.4904206 65.0973504,40.5004529 C65.1320818,40.5198009 65.1639488,40.5373574 65.1936675,40.5534808 C65.2108542,40.5627965 65.2273248,40.5717539 65.2427212,40.5799947 C65.2695754,40.5946849 65.2928491,40.6072253 65.3143325,40.6183325 C65.3250742,40.6240652 65.3372481,40.6305145 65.3469156,40.6355307 C65.3741279,40.6495043 65.3966854,40.6609698 65.4102916,40.6674191 C65.8940256,40.8866966 69.0638977,40.9963354 69.0638977,40.9963354 C69.0638977,40.9963354 72.2337698,40.8866966 72.7175038,40.6674191 C72.73111,40.6609698 72.7536675,40.6495043 72.7808798,40.6355307 C72.7905473,40.6305145 72.8027212,40.6240652 72.8134629,40.6183325 C72.8349463,40.6072253 72.8582199,40.5946849 72.8850742,40.5799947 C72.9004706,40.5717539 72.9169412,40.5627965 72.9341279,40.5534808 C72.9638465,40.5373574 72.9957136,40.5198009 73.030445,40.5004529 C73.0490639,40.4904206 73.0669668,40.4803883 73.0870179,40.4692811 C73.1339233,40.4434837 73.1847673,40.41482 73.2391918,40.3843648 C73.2502916,40.3782737 73.2599591,40.3728993 73.2714169,40.3664499 C73.3401637,40.3277539 73.4146394,40.2861915 73.4937698,40.2414044 C73.5131049,40.2306555 73.5345882,40.2181151 73.5546394,40.2070079 C73.6151509,40.1726115 73.6770946,40.1374984 73.7426189,40.1002355 C73.7726957,40.0830373 73.8045627,40.0651225 73.8357136,40.0475659 C73.9005217,40.0103031 73.9671202,39.9723236 74.0365831,39.932911 C74.0630793,39.9175043 74.0899335,39.9024558 74.1171458,39.8866907 C74.1959182,39.8419037 74.277555,39.7949668 74.3609821,39.7469551 C74.3853299,39.7329815 74.4089616,39.7197245 74.4336675,39.7053927 C74.6488593,39.5817803 74.8783734,39.4492106 75.1186292,39.3098332 C75.1519284,39.2904852 75.1863018,39.2707789 75.2199591,39.2514308 C75.3123376,39.1976863 75.4057903,39.1432253 75.5010332,39.0880476 C75.5318261,39.0701327 75.562977,39.0518596 75.5941279,39.0339448 C75.6972481,38.973751 75.8014425,38.9128405 75.9070691,38.8512135 C75.9339233,38.8358068 75.9600614,38.8204 75.9865575,38.8049932 C76.1265575,38.7229433 76.2687059,38.6401768 76.4119284,38.5559771 C76.6231816,38.4320065 76.8408798,38.3030197 77.0567877,38.1754661 C76.0055345,37.1983912 75.4716726,33.214491 74.5271202,29.5684646 C74.4913146,29.4305204 74.4551509,29.2932928 74.4182711,29.1567818 C73.5224143,25.8418214 71.3905473,23.1073016 70.0575038,21.9446291 C69.6113657,21.5555189 69.2547417,21.3423325 69.0638977,21.3423325 C68.8730537,21.3423325 68.5164297,21.5555189 68.0702916,21.9446291 C66.7372481,23.1073016 64.6053811,25.8418214 63.7095243,29.1567818 C63.6726445,29.2932928 63.6364808,29.4305204 63.6006752,29.5684646 C62.6561228,33.214491 62.1222609,37.1983912 61.0710077,38.1754661 C61.2869156,38.3030197 61.5046138,38.4320065 61.715867,38.5559771 C61.8590895,38.6401768 62.0012379,38.7229433 62.1412379,38.8049932" id="Fill-142" fill="#9F5622"></path>
38
+ <path d="M77.7019693,37.7939518 C76.1895396,38.0959959 75.6470844,33.2980458 74.5270844,28.9748388 C75.5296419,28.5348505 77.3711253,27.6215524 78.8849872,26.2797316 C80.9359335,24.4624511 83.1619693,19.6516023 83.5071355,19.4867859 C83.6485678,19.4190678 84.0818159,18.8873557 84.5433504,18.2839841 C84.4380818,20.1528593 84.1075959,23.4516963 83.8877494,24.3241486 C83.6969054,25.0815877 83.3796675,25.5523894 83.1841688,25.7877903 C82.9313811,30.4553204 82.6839642,34.4015994 82.5819182,34.6309093 C82.4494373,34.9297286 77.4857033,37.9225803 77.7019693,37.7939518" id="Fill-144" fill="#FFBC00"></path>
39
+ <path d="M69.0638619,21.8109128 C68.2421228,21.7654091 66.4196164,23.9409862 66.6924552,24.9556822 C67.0827366,25.1900082 69.2282097,25.7364106 69.9690281,25.7364106 C70.7102046,25.7364106 72.3092839,25.1423548 72.1921995,24.6196 C72.0751151,24.0968452 70.07,21.866807 69.0638619,21.8109128" id="Fill-146" fill="#98480C"></path>
40
+ <path d="M64.7448082,30.6150849 C64.6058824,31.069405 64.9764706,29.5201304 65.1325831,28.9748029 C65.2883376,28.4294755 67.8713555,27.6487471 69.9538107,27.6487471 C72.036266,27.6487471 73.3231202,26.9987971 73.7914578,28.0457398 C74.2594373,29.0926825 74.2984655,29.4832258 74.2984655,29.4832258 C74.2984655,29.4832258 73.442711,28.7806062 73.3829156,28.5853345 C73.3231202,28.3904211 72.9722251,28.8153609 70.4758568,29.0321304 C67.9798465,29.2488999 66.0295141,28.7763066 65.8343734,29.0321304 C65.6395908,29.2879542 64.864399,30.2248999 64.7448082,30.6150849" id="Fill-148" fill="#98480C"></path>
41
+ <path d="M69.5063836,31.2004341 C70.2028031,30.4981727 70.5533402,29.6393357 71.7431611,29.795553 C72.9333402,29.951412 73.7135448,31.9030537 73.0890946,31.7858907 C72.4653606,31.6687278 71.5598363,31.1613797 71.4080205,31.1613797 C71.2562046,31.1613797 69.5063836,31.2004341 69.5063836,31.2004341" id="Fill-150" fill="#98480C"></path>
42
+ <path d="M57.8664041,17.6369721 C57.6744859,17.2525198 63.2447673,17.2084493 63.8488082,17.2084493 C64.452491,17.2084493 66.2810844,16.8429868 66.3372992,17.4502996 C66.3935141,18.057254 64.961289,20.6258825 64.2179642,20.8125551 C63.4746394,20.9995859 59.2184246,20.3456946 57.8664041,17.6369721" id="Fill-152" fill="#1F191A"></path>
43
+ <path d="M80.294046,17.7116769 C80.4859642,17.3272247 75.1308747,17.0724758 74.5271918,17.0724758 C73.923509,17.0724758 71.8739949,16.8159354 71.8181381,17.4232482 C71.7619233,18.0302026 73.1937903,20.5988311 73.9374731,20.785862 C74.680798,20.9725345 78.9416675,20.4203994 80.294046,17.7116769" id="Fill-154" fill="#1F191A"></path>
44
+ <path d="M94.7082813,75.6808458 L100.201223,76.8281116 C100.313652,76.7091571 100.449355,76.5808869 100.613703,76.4418678 C106.021785,71.862837 111.178512,67.119348 111.178512,67.119348 L111.178512,70.2465609 C113.456465,67.263025 115.355954,64.1702085 116.904189,61.2568987 L113.182194,53.8505492 C113.182194,53.8505492 102.36424,53.9677122 100.094164,55.6234009 C97.824445,57.2787313 100.595801,60.469721 100.410685,62.0906549 C99.873243,66.7954479 98.0990742,68.495207 98.0990742,68.495207 C98.0990742,68.495207 99.141376,69.1168517 99.186133,71.0294391 C99.23089,72.9416681 97.5168747,73.5661791 94.7082813,75.6808458" id="Fill-156" fill="#98480C"></path>
45
+ <path d="M41.3225575,68.7320053 C40.1828645,67.469368 38.6013299,59.9103841 38.6013299,59.9103841 C38.3517647,55.955506 39.2884399,55.7545016 38.5798465,55.100252 C37.8712532,54.4456441 34.6555499,56.6817733 34.6555499,56.6817733 L28.4719182,69.2784076 L36.5099233,74.718067 L31.6095652,75.5826367 C31.6729412,75.6456969 31.735601,75.7094737 31.7996931,75.7721756 C32.8820972,76.6890567 33.7518159,77.2526573 34.4002558,77.6016382 C36.4322251,77.7782784 46.7392327,78.5643812 44.5751407,76.1523283 C42.1772379,73.4801521 41.0565217,70.5345956 41.3225575,68.7320053" id="Fill-158" fill="#98480C"></path>
46
+ <path d="M35.7649872,78.1532358 C35.7649872,78.1532358 40.873734,79.3065927 45.099156,79.6104282 C49.3249361,79.914622 55.3284655,73.2814767 69.0638619,73.2814767 L69.0638619,74.2209304 C69.0638619,74.2209304 58.0801279,76.5702814 48.5239642,81.1858584 C47.5575703,81.7383518 37.5058568,80.2886837 35.7649872,78.1532358" id="Fill-160" fill="#98480C"></path>
47
+ <path d="M39.5202097,79.7762479 C39.5202097,79.7762479 40.3763223,82.7332699 41.895555,83.1481774 C40.6248133,83.8113844 37.0517698,81.6279248 36.5096726,78.4494755 C39.503023,79.3061627 39.5202097,79.7762479 39.5202097,79.7762479" id="Fill-162" fill="#98480C"></path>
48
+ <path d="M66.0684706,45.7797028 C66.2947621,45.9380699 59.2184962,42.6288423 38.4469361,41.7442079 C35.2981893,41.9100993 37.1761944,40.6940405 39.2203376,40.1963665 C41.2644808,39.6986925 51.6499028,36.547832 52.9206445,35.884625 C54.1913862,35.2210596 55.9036113,34.9448129 54.578087,36.4926543 C53.2522046,38.0404957 45.6284706,40.4174355 44.523509,40.8043959 C43.4189054,41.1913562 61.0965013,42.2970596 66.0684706,45.7797028" id="Fill-164" fill="#98480C"></path>
49
+ <path d="M30.8233811,67.6705874 C36.5096726,68.1127254 57.8924348,69.0525374 67.1732532,66.399351 C64.5218465,68.0575477 60.2677801,69.3291424 50.0477801,69.3291424 C39.8277801,69.3291424 31.5412839,68.7762907 30.8233811,67.6705874" id="Fill-166" fill="#98480C"></path>
50
+ <path d="M102.362772,78.1532358 C102.362772,78.1532358 97.2540256,79.3065927 93.0286036,79.6104282 C88.8028235,79.914622 82.7992941,73.2814767 69.0638977,73.2814767 L69.0638977,74.2209304 C69.0638977,74.2209304 80.0476317,76.5702814 89.6037954,81.1858584 C90.5701893,81.7383518 100.621903,80.2886837 102.362772,78.1532358" id="Fill-168" fill="#98480C"></path>
51
+ <path d="M98.6075499,79.7762479 C98.6075499,79.7762479 97.7514373,82.7332699 96.2322046,83.1481774 C97.5029463,83.8113844 101.07599,81.6279248 101.618087,78.4494755 C98.6247366,79.3061627 98.6075499,79.7762479 98.6075499,79.7762479" id="Fill-170" fill="#98480C"></path>
52
+ <path d="M72.059289,45.7797028 C71.8329974,45.9380699 78.9092634,42.6288423 99.6808235,41.7442079 C102.829928,41.9100993 100.951565,40.6940405 98.907422,40.1963665 C96.8632788,39.6986925 86.4778568,36.547832 85.2071151,35.884625 C83.9363734,35.2210596 82.2241483,34.9448129 83.5496726,36.4926543 C84.875555,38.0404957 92.499289,40.4174355 93.6042506,40.8043959 C94.7088542,41.1913562 77.0312583,42.2970596 72.059289,45.7797028" id="Fill-172" fill="#98480C"></path>
53
+ <path d="M107.304414,67.6705874 C101.618123,68.1127254 80.2353606,69.0525374 70.9541841,66.399351 C73.6059488,68.0575477 77.8600153,69.3291424 88.0800153,69.3291424 C98.3000153,69.3291424 106.586153,68.7762907 107.304414,67.6705874" id="Fill-174" fill="#98480C"></path>
54
+ <path d="M69.2970997,45.2821363 C69.2970997,43.7894725 69.0640051,43.3473345 69.0640051,43.3473345 C69.0640051,43.3473345 68.8305524,43.7894725 68.8305524,45.2821363 C68.8305524,46.7748 68.1122916,62.6401744 68.0571509,63.3033815 C68.0020102,63.9669468 68.5788389,64.3539072 69.0640051,64.3539072 C69.5488133,64.3539072 70.1256419,63.9669468 70.0705013,63.3033815 C70.0153606,62.6401744 69.2970997,46.7748 69.2970997,45.2821363" id="Fill-176" fill="#98480C"></path>
55
+ <path d="M93.986046,104.143571 L69.0638977,104.143571 L44.1417494,104.143571 L42.3571969,111.286214 C55.8394476,115.253991 65.4145882,130.614526 65.4145882,130.614526 C65.4145882,130.614526 66.9416982,131.919442 69.0638977,131.919442 C71.1860972,131.919442 72.7132072,130.614526 72.7132072,130.614526 C72.7132072,130.614526 82.2883478,115.253991 95.7702404,111.286214 L93.986046,104.143571 Z" id="Fill-178" fill="#1F191A"></path>
56
+ <path d="M96.7585115,83.8684969 L95.9686394,84.5019653 C95.9686394,84.5019653 90.2730384,85.0311695 69.0639335,85.0311695 C47.8548286,85.0311695 42.1592276,84.5019653 42.1592276,84.5019653 L41.3693555,83.8684969 C41.3693555,83.8684969 40.0373862,84.4679272 40.4076164,86.8384176 C40.7015806,88.7241327 42.2261841,89.3593927 42.2261841,89.3593927 C42.2261841,89.3593927 42.8588696,98.5156628 42.7707877,99.2655777 C41.8455703,99.7062825 41.4048031,103.939199 44.1417852,104.143428 C52.4304297,104.480227 69.0639335,104.732826 69.0639335,104.732826 C69.0639335,104.732826 85.6970793,104.480227 93.9860818,104.143428 C96.7227059,103.939199 96.2822967,99.7062825 95.3567212,99.2655777 C95.2686394,98.5156628 95.9013248,89.3593927 95.9013248,89.3593927 C95.9013248,89.3593927 97.4259284,88.7241327 97.7202506,86.8384176 C98.0901228,84.4679272 96.7585115,83.8684969 96.7585115,83.8684969" id="Fill-180" fill="#FFBC00"></path>
57
+ <path d="M97.7202864,86.8382385 C98.0901586,84.4681063 96.7585473,83.8683178 96.7585473,83.8683178 L95.9686752,84.5017862 C95.9686752,84.5017862 90.2730742,85.0309903 69.0639693,85.0309903 C47.8548645,85.0309903 42.1592634,84.5017862 42.1592634,84.5017862 L41.3693913,83.8683178 C41.3693913,83.8683178 40.037422,84.4681063 40.4076522,86.8382385 C40.7016164,88.7239536 42.2262199,89.3595718 42.2262199,89.3595718 C42.2262199,89.3595718 42.4038159,91.9317833 42.5577801,94.4609991 C45.7312327,93.6591313 47.6615141,93.0145557 47.6615141,93.0145557 C47.6615141,93.0145557 53.1952737,93.8920241 54.7030486,93.7666203 C56.2111816,93.6412164 58.7168593,94.3932811 62.7260153,94.3932811 C66.7348133,94.3932811 68.5587519,92.3875366 68.5587519,92.3875366 C68.5587519,92.3875366 70.914046,92.2266614 70.9545064,90.8654925 C70.9759898,90.1331342 71.0651458,89.4874837 71.1761432,88.9102678 C71.0533299,90.2700035 71.8961944,89.7744793 72.5739949,90.3961239 C73.2528696,91.0188435 73.7000818,92.7748552 77.0260665,93.1779389 C80.3520512,93.5813809 83.7786496,91.7662502 85.0887775,91.6652106 C86.3989054,91.5645292 91.640133,92.1696922 92.696757,92.1696922 C92.9681637,92.1696922 94.0430486,92.4563295 95.6679079,92.8902267 C95.7903632,90.967607 95.9013606,89.3595718 95.9013606,89.3595718 C95.9013606,89.3595718 97.4259642,88.7239536 97.7202864,86.8382385" id="Fill-182" fill="#FF9000"></path>
58
+ <polygon id="Fill-184" fill="#98480C" points="70.36289 71.8627295 75.0011509 71.8627295 75.0011509 85.0161568 70.954399 85.0161568 70.0742967 78.0616194"></polygon>
59
+ <path d="M71.5167621,76.4331254 C71.5751253,74.6670814 69.7175294,74.374353 69.7483223,73.2815483 C69.7791151,72.1883853 71.3585013,72.839052 71.2346138,71.1969786 C71.1107263,69.5549051 68.8710844,67.5366203 67.1735396,67.8641034 C66.80689,67.4789345 66.6210588,66.1464294 66.2186036,65.7745175 C65.8161483,65.4029639 64.1440256,65.3409786 63.3079642,65.6817186 C62.4719028,66.0224587 62.1005985,66.6423119 60.7378363,66.983052 C59.3757903,67.3237921 58.7255601,67.2929786 57.9202916,68.3463706 C57.1153811,69.3997627 54.7930281,74.9770079 51.9446905,75.1317921 C49.0959949,75.2865762 48.2910844,75.1317921 42.841468,74.7290667 C37.3918517,74.3263413 32.716711,73.5689022 31.5089872,73.2815483 C30.3016215,72.9938361 29.3105217,72.4051548 29.3105217,72.4051548 C29.3105217,72.4051548 23.7735396,74.049378 19.9262251,79.3206379 C17.4305729,82.7402209 16.7538465,88.1261357 16.5855601,91.4901827 C11.0596777,90.9860593 8.00581586,89.5378244 6.5137954,88.647099 C8.57870588,89.8817891 13.6409054,92.1906526 24.138757,91.5664999 C36.7924655,90.8144352 47.6616215,87.1787994 47.6616215,87.1787994 C47.6616215,87.1787994 53.1953811,88.0562678 54.703156,87.930864 C56.211289,87.8054602 58.7169668,88.5578831 62.7257647,88.5578831 C66.7349207,88.5578831 68.5588593,86.5517803 68.5588593,86.5517803 C68.5588593,86.5517803 70.9141535,86.3909051 70.9542558,85.0297363 C70.9947161,83.6685674 71.2654066,82.5986937 71.4823887,81.7316159 C71.6990128,80.8638214 70.8321586,80.8018361 70.6151765,79.1285909 C70.3985524,77.455704 71.458399,78.1991695 71.5167621,76.4331254" id="Fill-192" fill="#FF5B0C"></path>
60
+ <path d="M18.2097391,67.119348 C18.2097391,67.119348 22.3531662,69.7255977 23.7144962,70.0810279 C25.0758261,70.4360999 29.3105575,72.4052981 29.3105575,72.4052981 C29.3105575,72.4052981 32.5617084,72.0025727 35.5342916,68.160558 C38.5068747,64.3185433 40.6741893,59.9806461 40.6741893,59.9806461 C40.6741893,59.9806461 40.9216061,61.3131512 41.7576675,63.0791953 C42.5937289,64.8452394 45.814087,67.8642467 45.814087,67.8642467 L48.4458005,51.4599941 L24.6125013,40.2589251 C24.6125013,40.2589251 15.0216061,40.4731865 11.3970026,53.8505492 C-0.254506394,61.8738855 3.60354987,65.5292276 2.24293606,69.1609222 C2.06140153,69.6446226 -0.416705882,78.6031131 0.460531969,83.2670602 C1.21209207,88.0564112 4.46932992,87.3039883 5.5968491,88.0564112 C4.99961125,67.1773921 18.2097391,67.119348 18.2097391,67.119348" id="Fill-196" fill="#9F5622"></path>
61
+ <path d="M19.9262609,79.3206737 C23.7735754,74.0494138 29.3105575,72.4051906 29.3105575,72.4051906 C29.3105575,72.4051906 25.0758261,70.4363507 23.7144962,70.0809204 C22.3531662,69.7254902 18.2097391,67.1192405 18.2097391,67.1192405 C18.2097391,67.1192405 4.99961125,67.1772846 5.5968491,88.0563037 C5.64053197,88.0853257 5.6910179,88.1193639 5.74544246,88.1562684 C5.76262916,88.1677339 5.78089003,88.179916 5.79879284,88.1920981 C5.82493095,88.2096546 5.85214322,88.2279278 5.88042967,88.2469175 C5.89833248,88.2587413 5.91766752,88.2712816 5.93628645,88.283822 C6.04119693,88.3529733 6.16042967,88.4303653 6.29577494,88.5145651 C6.30938107,88.5231642 6.32298721,88.531405 6.33730946,88.5400041 C6.38421483,88.5690261 6.43291049,88.5987648 6.48375448,88.62922 C6.49342199,88.635311 6.50380563,88.6414021 6.5138312,88.6471348 C8.00585166,89.5378602 11.0597136,90.9860952 16.5855959,91.4902185 C16.7538824,88.1261715 17.4306087,82.7402567 19.9262609,79.3206737" id="Fill-206" fill="#FFAD00"></path>
62
+ <path d="M120.61734,86.0000752 C120.437238,85.4146185 120.830384,82.7951119 120.109974,80.0928388 C118.219795,73.3371559 109.964092,71.469714 109.964092,71.469714 C108.012685,72.4600458 106.509207,72.8452147 104.303223,73.0150473 C102.097596,73.1845216 96.0457289,73.863852 91.973555,73.665714 C87.9013811,73.4675759 87.2507928,72.1092734 86.6571355,70.5248858 C86.0631202,68.9401398 84.5925831,66.5345363 83.5463427,65.9652029 C82.5001023,65.3958696 79.361023,64.1575965 78.2864962,63.3654026 C77.2119693,62.5728505 75.1474169,64.6670943 73.9880307,65.9652029 C72.9135038,65.6219548 71.3115601,66.4976317 70.4529412,67.864175 C69.5946803,69.2307184 71.5181586,71.1189416 71.5181586,71.1189416 C71.5181586,71.1189416 70.4529412,72.2224952 70.3684399,73.5524922 C70.2835806,74.8824893 71.6692583,75.2504599 71.7258312,76.12757 C71.7824041,77.0050385 70.6513043,77.4009562 70.5864962,78.701573 C70.522046,80.002548 71.8672634,80.3156993 71.838977,80.8581604 C71.8103325,81.4009797 71.3015345,81.7023072 71.1762148,83.0692088 C71.0508951,84.4361104 71.8955499,83.9380781 72.5740665,84.5604394 C73.2529412,85.1831589 73.7001535,86.9391706 77.0257801,87.3426126 C80.3517647,87.7460546 83.7787212,85.9305656 85.0888491,85.829526 C86.398977,85.7288446 91.6398465,86.3340076 92.6964706,86.3340076 C93.7534527,86.3340076 106.959284,90.6704717 117.541637,91.1749533 C118.268491,91.2097081 118.952737,91.2240399 119.604041,91.2236816 C120.32445,90.3411971 120.797442,86.5851736 120.61734,86.0000752" id="Fill-208" fill="#FF5B0C"></path>
63
+ <path d="M120.61734,86.0000752 C120.437238,85.4146185 120.830384,82.7951119 120.109974,80.0928388 C118.219795,73.3371559 109.964092,71.469714 109.964092,71.469714 C108.012685,72.4600458 106.509207,72.8452147 104.303223,73.0150473 C102.097596,73.1845216 96.0457289,73.863852 91.973555,73.665714 C87.9013811,73.4675759 87.2507928,72.1092734 86.6571355,70.5248858 C86.0631202,68.9401398 84.5925831,66.5345363 83.5463427,65.9652029 C82.5001023,65.3958696 79.361023,64.1575965 78.2864962,63.3654026 C77.2119693,62.5728505 75.1474169,64.6670943 73.9880307,65.9652029 C72.9135038,65.6219548 71.3115601,66.4976317 70.4529412,67.864175 C69.5946803,69.2307184 71.5181586,71.1189416 71.5181586,71.1189416 C71.5181586,71.1189416 70.4529412,72.2224952 70.3684399,73.5524922 C70.2835806,74.8824893 71.6692583,75.2504599 71.7258312,76.12757 C71.7824041,77.0050385 70.6513043,77.4009562 70.5864962,78.701573 C70.522046,80.002548 71.8672634,80.3156993 71.838977,80.8581604 C71.8103325,81.4009797 71.3015345,81.7023072 71.1762148,83.0692088 C71.0508951,84.4361104 71.8955499,83.9380781 72.5740665,84.5604394 C73.2529412,85.1831589 73.7001535,86.9391706 77.0257801,87.3426126 C80.3517647,87.7460546 83.7787212,85.9305656 85.0888491,85.829526 C86.398977,85.7288446 91.6398465,86.3340076 92.6964706,86.3340076 C93.7534527,86.3340076 106.959284,90.6704717 117.541637,91.1749533 C118.268491,91.2097081 118.952737,91.2240399 119.604041,91.2236816 C120.32445,90.3411971 120.797442,86.5851736 120.61734,86.0000752" id="Fill-210" fill="#FF5B0C"></path>
64
+ <g id="Group-222" stroke-width="1" fill="none" transform="translate(88.797954, 39.420869)">
65
+ <mask id="mask-6" fill="white">
66
+ <use xlink:href="#path-5"></use>
67
+ </mask>
68
+ <g id="Clip-221"></g>
69
+ <path d="M49.9089258,32.9952493 C48.1451407,26.1080717 47.9159847,22.6809645 46.842532,20.1868617 C44.3651407,14.4297515 37.9154731,12.160659 36.5043734,9.44584552 C33.7831458,2.68872952 26.765601,0.342961527 26.765601,0.342961527 C20.9217647,-1.75199883 0.178132992,17.6623037 0.331381074,17.7755254 C0.484987212,17.8887471 6.62565217,26.4061744 6.62565217,26.4061744 C6.62565217,26.4061744 8.32248082,24.5953433 9.11414322,22.4727941 C9.90616368,20.3506032 10.1270844,18.0868852 10.1270844,18.0868852 C10.1270844,18.0868852 10.1324552,17.945358 11.5177749,20.4355195 C12.9034527,22.9256811 16.952711,30.9454344 21.1659591,32.048988 C21.1659591,32.048988 24.7687212,30.7526708 24.9037084,30.7075254 C25.0386957,30.6627383 26.7938875,30.1220687 27.5314834,29.7168352 C28.2687212,29.3116018 31.8346036,27.4197956 31.8346036,27.4197956 C31.8346036,27.4197956 36.6157289,26.2273844 41.9167519,36.0672846 C44.8836061,41.574662 43.616087,47.3636605 43.1348593,49.0738103 C44.080844,48.7230379 45.016087,48.4432082 46.079156,48.3249703 C50.6146547,47.8204887 51.017468,44.39159 51.1184399,43.8462626 C51.2190537,43.3009351 50.2734271,34.4176869 49.9089258,32.9952493" id="Fill-220" fill="#9F5622" mask="url(#mask-6)"></path>
70
+ </g>
71
+ <path d="M130.714598,75.4880464 C125.413575,65.6481463 120.632808,66.8405574 120.632808,66.8405574 C120.632808,66.8405574 117.066926,68.7323636 116.32933,69.1375971 C115.592092,69.5428305 113.836542,70.0835001 113.701555,70.1286455 C113.566568,70.1734326 109.963806,71.4697498 109.963806,71.4697498 C109.963806,71.4697498 118.219867,73.3371918 120.110046,80.0928746 C120.830455,82.7951477 120.437309,85.4146543 120.617412,86.000111 C120.797514,86.5852094 120.324164,90.3412329 119.604113,91.2237175 C126.214189,91.2212094 129.120174,89.5393651 131.932706,88.4949304 C132.413934,86.7844223 133.681453,80.9954238 130.714598,75.4880464" id="Fill-223" fill="#FFAD00"></path>
72
+ <path d="M62.0177801,68.6410338 C61.1788542,68.6009046 61.4982404,69.1609222 61.4982404,69.1609222 C61.4982404,69.1609222 64.5349156,68.5210044 65.0941995,68.6808047 C65.5084706,68.7994009 66.930312,68.0688341 67.8462199,67.8491982 C67.6170639,67.8198179 67.3907724,67.822326 67.1734322,67.8642467 C67.1734322,67.8642467 62.8567059,68.6808047 62.0177801,68.6410338" id="Fill-225" fill="#E43500"></path>
73
+ <path d="M69.5144041,79.6354015 C70.5277033,79.9553604 70.9018721,80.1954191 70.9541483,80.2953838 C70.8130742,80.0137627 70.6827417,79.649375 70.6154271,79.12877 C70.398445,77.4558831 71.4582916,78.1993486 71.5166547,76.4329463 C71.5750179,74.6669022 70.3275499,74.3945968 70.3583427,73.3014338 C70.3894936,72.2082708 71.6419744,72.7611225 71.518087,71.119049 C71.4539949,70.2720358 70.5427417,69.4056746 69.7177801,68.7320769 C69.9938414,69.460494 70.5201841,71.0778449 70.074046,71.8392253 C69.4889821,72.8388728 69.4492379,73.0388023 69.5688286,73.4784323 C69.6887775,73.9180623 70.8979335,75.0294984 71.1668338,75.397469 C71.4360921,75.7657979 71.2423836,77.6937921 70.7253504,78.0449228 C70.2079591,78.3960535 68.5011049,79.3154426 69.5144041,79.6354015" id="Fill-227" fill="#E43500"></path>
74
+ <path d="M70.9543274,85.0296288 C70.9944297,83.6684599 71.2654783,82.5989445 71.4824604,81.7315084 C71.6317698,81.1338696 71.2669105,80.918175 70.9543274,80.2954555 C71.0066036,80.3954203 70.5676266,81.4344805 70.5676266,82.7537286 C70.5676266,84.0650943 71.0961176,85.0127888 70.6628696,85.7347565 C70.8322302,85.5452176 70.9460921,85.3151912 70.9543274,85.0296288" id="Fill-229" fill="#FF3500"></path>
75
+ <path d="M84.2314476,85.592262 C82.9130844,85.6721621 79.7167161,86.4718802 78.1985575,86.1519213 C76.680399,85.8319624 75.2023427,84.3127847 75.2023427,84.3127847 C75.2023427,84.3127847 73.0446957,84.2730138 72.8449003,84.1931137 C72.6451049,84.1132135 71.2698107,83.1135659 71.5183018,82.6338068 C71.7664348,82.1540476 72.4127263,81.7495307 72.1259233,81.3038097 C71.8387621,80.858447 71.6296573,79.7953809 71.5183018,79.2357216 C71.4065882,78.675704 71.6464859,78.1959448 71.7664348,77.5563853 C71.8860256,76.9168258 72.3257187,75.9573075 71.9261279,75.4374191 C71.5265371,74.917889 70.5279182,73.798212 70.5676624,73.3188112 C70.6077647,72.8386937 72.6053606,71.1998449 72.6053606,71.1998449 C72.6053606,71.1998449 71.1419847,70.0987994 70.2371765,68.7225821 C70.2873043,69.9071107 71.5183018,71.1188699 71.5183018,71.1188699 C71.5183018,71.1188699 70.4530844,72.2227818 70.3682251,73.5524206 C70.2833657,74.8824176 71.6694015,75.2503883 71.7256164,76.1274984 C71.7574834,76.6208728 71.4137494,76.9623295 71.0950793,77.3976599 C71.0027008,77.6964793 70.8788133,77.9404793 70.7255652,78.0447436 C70.6507315,78.2371489 70.5988133,78.4524852 70.5866394,78.7018596 C70.5221893,80.0024764 71.8670486,80.3156276 71.8387621,80.858447 C71.8104757,81.4009081 71.3016777,81.7025938 71.1763581,83.0691372 C71.0510384,84.4360388 71.895335,83.9380065 72.5742097,84.560726 C73.2527263,85.1830872 73.6999386,86.939099 77.0259233,87.342541 C80.3519079,87.745983 83.7785064,85.930494 85.0889923,85.8298126 C85.2007059,85.8212135 85.3428542,85.8179888 85.5064859,85.8187054 C85.2379437,85.6764617 84.8301176,85.556074 84.2314476,85.592262" id="Fill-231" fill="#E43500"></path>
76
+ <path d="M45.1709821,99.3815941 C46.4009054,99.526346 58.6414169,99.7434737 71.0423376,99.8158496 C83.4432583,99.8885838 93.7889361,99.5987219 93.7889361,99.5987219 C93.7889361,99.5987219 87.6393197,99.3815941 68.5395243,98.9473386 C49.4393708,98.5130831 45.1709821,99.3815941 45.1709821,99.3815941" id="Fill-233" fill="#F9D400"></path>
77
+ <path d="M44.4475294,89.2460634 C44.4475294,89.2460634 62.4208798,90.0425568 70.0743325,89.6803189 C77.7274271,89.3184394 93.4994476,89.2460634 93.4994476,89.2460634 C93.4994476,89.2460634 84.6303939,89.1736875 70.3629258,89.2460634 C56.0954578,89.3184394 44.4475294,89.2460634 44.4475294,89.2460634" id="Fill-235" fill="#FF7E00"></path>
78
+ <path d="M28.6531662,40.2588176 C26.7139335,40.2606091 26.462578,40.6927148 28.4719898,41.4390467 C30.4810435,42.1850203 35.3151611,47.8891025 40.4622199,48.6590819 C45.6092788,49.4294197 34.4056982,43.2129733 38.3457494,41.4630526 C44.1179744,38.8997985 32.8141381,41.1982714 32.2609412,41.0778837 C31.7077442,40.957496 29.5429361,40.258101 28.6531662,40.2588176" id="Fill-237" fill="#98480C"></path>
79
+ <path d="M100.438578,45.1806667 C101.692133,45.8399325 103.048092,44.966047 106.193616,42.8198502 C109.339499,40.6736535 111.877402,40.2085844 109.267887,39.4575947 C106.658373,38.7062467 105.292389,41.8047959 99.719601,40.4343113 C94.1471714,39.064185 95.2553555,40.3515448 95.2553555,40.3515448 C95.2553555,40.3515448 102.118578,42.3193098 101.153616,43.5353686 C100.188297,44.7514273 98.3292685,44.0717386 100.438578,45.1806667" id="Fill-239" fill="#98480C"></path>
80
+ </g>
81
+ </g>
82
+ </g>
83
+ </g>
84
+ </g>
85
+ </svg>
app/module/advanced-tools/img/spinner.svg ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <svg class="lds-spinner" width="28px" height="28px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" style="background: none;"><g transform="rotate(0 50 50)">
2
+ <rect x="47" y="24" rx="9.4" ry="4.8" width="6" height="12" fill="#1d0e0b">
3
+ <animate attributeName="opacity" values="1;0" times="0;1" dur="1s" begin="-0.9166666666666666s" repeatCount="indefinite"></animate>
4
+ </rect>
5
+ </g><g transform="rotate(30 50 50)">
6
+ <rect x="47" y="24" rx="9.4" ry="4.8" width="6" height="12" fill="#1d0e0b">
7
+ <animate attributeName="opacity" values="1;0" times="0;1" dur="1s" begin="-0.8333333333333334s" repeatCount="indefinite"></animate>
8
+ </rect>
9
+ </g><g transform="rotate(60 50 50)">
10
+ <rect x="47" y="24" rx="9.4" ry="4.8" width="6" height="12" fill="#1d0e0b">
11
+ <animate attributeName="opacity" values="1;0" times="0;1" dur="1s" begin="-0.75s" repeatCount="indefinite"></animate>
12
+ </rect>
13
+ </g><g transform="rotate(90 50 50)">
14
+ <rect x="47" y="24" rx="9.4" ry="4.8" width="6" height="12" fill="#1d0e0b">
15
+ <animate attributeName="opacity" values="1;0" times="0;1" dur="1s" begin="-0.6666666666666666s" repeatCount="indefinite"></animate>
16
+ </rect>
17
+ </g><g transform="rotate(120 50 50)">
18
+ <rect x="47" y="24" rx="9.4" ry="4.8" width="6" height="12" fill="#1d0e0b">
19
+ <animate attributeName="opacity" values="1;0" times="0;1" dur="1s" begin="-0.5833333333333334s" repeatCount="indefinite"></animate>
20
+ </rect>
21
+ </g><g transform="rotate(150 50 50)">
22
+ <rect x="47" y="24" rx="9.4" ry="4.8" width="6" height="12" fill="#1d0e0b">
23
+ <animate attributeName="opacity" values="1;0" times="0;1" dur="1s" begin="-0.5s" repeatCount="indefinite"></animate>
24
+ </rect>
25
+ </g><g transform="rotate(180 50 50)">
26
+ <rect x="47" y="24" rx="9.4" ry="4.8" width="6" height="12" fill="#1d0e0b">
27
+ <animate attributeName="opacity" values="1;0" times="0;1" dur="1s" begin="-0.4166666666666667s" repeatCount="indefinite"></animate>
28
+ </rect>
29
+ </g><g transform="rotate(210 50 50)">
30
+ <rect x="47" y="24" rx="9.4" ry="4.8" width="6" height="12" fill="#1d0e0b">
31
+ <animate attributeName="opacity" values="1;0" times="0;1" dur="1s" begin="-0.3333333333333333s" repeatCount="indefinite"></animate>
32
+ </rect>
33
+ </g><g transform="rotate(240 50 50)">
34
+ <rect x="47" y="24" rx="9.4" ry="4.8" width="6" height="12" fill="#1d0e0b">
35
+ <animate attributeName="opacity" values="1;0" times="0;1" dur="1s" begin="-0.25s" repeatCount="indefinite"></animate>
36
+ </rect>
37
+ </g><g transform="rotate(270 50 50)">
38
+ <rect x="47" y="24" rx="9.4" ry="4.8" width="6" height="12" fill="#1d0e0b">
39
+ <animate attributeName="opacity" values="1;0" times="0;1" dur="1s" begin="-0.16666666666666666s" repeatCount="indefinite"></animate>
40
+ </rect>
41
+ </g><g transform="rotate(300 50 50)">
42
+ <rect x="47" y="24" rx="9.4" ry="4.8" width="6" height="12" fill="#1d0e0b">
43
+ <animate attributeName="opacity" values="1;0" times="0;1" dur="1s" begin="-0.08333333333333333s" repeatCount="indefinite"></animate>
44
+ </rect>
45
+ </g><g transform="rotate(330 50 50)">
46
+ <rect x="47" y="24" rx="9.4" ry="4.8" width="6" height="12" fill="#1d0e0b">
47
+ <animate attributeName="opacity" values="1;0" times="0;1" dur="1s" begin="0s" repeatCount="indefinite"></animate>
48
+ </rect>
49
+ </g></svg>
app/module/advanced-tools/js/scripts.js ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(function ($) {
2
+ Adtools.formHandler();
3
+
4
+ $('div.advanced-tools').on('form-submitted', function (e, data, form) {
5
+ if (form.attr('id') != 'advanced-settings-frm') {
6
+ return;
7
+ }
8
+ if (data.success == true) {
9
+ Defender.showNotification('success', data.data.message);
10
+ } else {
11
+ Defender.showNotification('error', data.data.message);
12
+ }
13
+ })
14
+ $('.deactivate-2factor').click(function () {
15
+ $('#advanced-settings-frm').append('<input type="hidden" name="enabled" value="0"/>');
16
+ $(this).attr('disabled', 'disabled');
17
+ $('#advanced-settings-frm').submit();
18
+ })
19
+ });
20
+ window.Adtools = window.Adtools || {};
21
+ Adtools.formHandler = function () {
22
+ var jq = jQuery;
23
+ jq('body').on('submit', '.advanced-settings-frm', function () {
24
+ var data = jq(this).serialize();
25
+ var that = jq(this);
26
+ jq.ajax({
27
+ type: 'POST',
28
+ url: ajaxurl,
29
+ data: data,
30
+ beforeSend: function () {
31
+ that.find('button[type="submit"]').attr('disabled', 'disabled');
32
+ },
33
+ success: function (data) {
34
+ if (data.data.reload != undefined) {
35
+ Defender.showNotification('success', data.data.message);
36
+ location.reload();
37
+ } else if (data.data != undefined && data.data.url != undefined) {
38
+ location.href = data.data.url;
39
+ } else {
40
+ that.find('button[type="submit"]').removeAttr('disabled');
41
+ jq('div.advanced-tools').trigger('form-submitted', [data, that])
42
+ }
43
+ }
44
+ })
45
+ return false;
46
+ })
47
+ }
app/module/advanced-tools/model/auth-settings.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Author: Hoang Ngo
5
+ */
6
+
7
+ namespace WP_Defender\Module\Advanced_Tools\Model;
8
+
9
+ use Hammer\Helper\WP_Helper;
10
+
11
+ class Auth_Settings extends \Hammer\WP\Settings {
12
+ private static $_instance;
13
+ public $enabled = false;
14
+ public $lostPhone = true;
15
+ public $userRoles = array();
16
+ public $isConflict = array();
17
+
18
+ public function __construct( $id, $is_multi ) {
19
+ //fetch the userRoles
20
+ if ( ! function_exists( 'get_editable_roles' ) ) {
21
+ include_once ABSPATH . 'wp-admin/includes/user.php';
22
+ }
23
+ $this->userRoles = array_keys( get_editable_roles() );
24
+ //remove subscriber from the list
25
+ unset( $this->userRoles[ array_search( 'subscriber', $this->userRoles ) ] );
26
+ parent::__construct( $id, $is_multi );
27
+ }
28
+
29
+ /**
30
+ * @return Auth_Settings
31
+ */
32
+ public static function instance() {
33
+ if ( is_null( self::$_instance ) ) {
34
+ $class = new Auth_Settings( 'wd_2auth_settings', WP_Helper::is_network_activate( wp_defender()->plugin_slug ) );
35
+ self::$_instance = $class;
36
+ }
37
+
38
+ return self::$_instance;
39
+ }
40
+
41
+ /**
42
+ * @param $plugin
43
+ *
44
+ * @return bool|int
45
+ */
46
+ public function isConflict( $plugin ) {
47
+ if ( in_array( $plugin, $this->isConflict ) ) {
48
+ return true;
49
+ } elseif ( in_array( '!' . $plugin, $this->isConflict ) ) {
50
+ return false;
51
+ }
52
+
53
+ return 0;
54
+ }
55
+
56
+ /**
57
+ * @param $plugin
58
+ */
59
+ public function markAsConflict( $plugin ) {
60
+ if ( ! in_array( $plugin, $this->isConflict ) ) {
61
+ $this->isConflict [] = $plugin;
62
+ $this->save();
63
+ }
64
+ }
65
+
66
+ /**
67
+ * @param $plugin
68
+ */
69
+ public function markAsUnConflict( $plugin ) {
70
+ if ( ( $i = array_search( $plugin, $this->isConflict ) ) !== false ) {
71
+ unset( $this->isConflict[ $i ] );
72
+ }
73
+
74
+ if ( ! in_array( '!' . $plugin, $this->isConflict ) ) {
75
+ $this->isConflict [] = '!' . $plugin;
76
+ $this->save();
77
+ }
78
+ }
79
+
80
+ public function events() {
81
+ $that = $this;
82
+
83
+ return array(
84
+ self::EVENT_AFTER_DELETED => array(
85
+ array(
86
+ function () use ( $that ) {
87
+ global $wpdb;
88
+ $sql = "DELETE from " . $wpdb->usermeta . " WHERE meta_key IN ('defOTPLoginToken','defenderBackupCode','defenderAuthSecret','defenderAuthOn','defenderAuthEmail')";
89
+ $wpdb->query( $sql );
90
+ }
91
+ )
92
+ )
93
+ );
94
+ }
95
+ }
app/module/advanced-tools/view/disabled.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="dev-box">
2
+ <div class="box-title">
3
+ <h3 class="def-issues-title">
4
+ <?php _e( "2 Factor Authentication", wp_defender()->domain ) ?>
5
+ </h3>
6
+ </div>
7
+ <div class="box-content issues-box-content tc">
8
+ <img src="<?php echo wp_defender()->getPluginUrl() . 'assets/img/2factor-disabled.svg' ?>"/>
9
+ <p>
10
+ <?php _e( "Beef up your website’s security with 2-Step verification. Protect your user accounts by requiring a second passcode sent to users phones in order to get past your login screen - the best protection against brute force attacks.", wp_defender()->domain ) ?>
11
+ </p>
12
+ <form method="post" id="advanced-settings-frm" class="advanced-settings-frm">
13
+
14
+ <div class="clear line"></div>
15
+ <input type="hidden" name="action" value="saveAdvancedSettings"/>
16
+ <?php wp_nonce_field( 'saveAdvancedSettings' ) ?>
17
+ <input type="hidden" name="enabled" value="1"/>
18
+ <button type="submit" class="button button-primary">
19
+ <?php _e( "Activate", wp_defender()->domain ) ?>
20
+ </button>
21
+ <div class="clear"></div>
22
+ </form>
23
+ </div>
24
+ </div>
app/module/advanced-tools/view/layouts/layout.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wrap">
2
+ <div id="wp-defender" class="wp-defender">
3
+ <div class="advanced-tools">
4
+ <h2 class="title">
5
+ <?php _e( "Advanced Tools", wp_defender()->domain ) ?>
6
+ </h2>
7
+ <div class="row">
8
+ <div class="col-third">
9
+ <ul class="inner-nav is-hidden-mobile">
10
+ <li class="issues-nav">
11
+ <a class="<?php echo \Hammer\Helper\HTTP_Helper::retrieve_get( 'view', false ) == false ? 'active' : null ?>"
12
+ href="<?php echo network_admin_url( 'admin.php?page=wdf-advanced-tools' ) ?>">
13
+ <?php _e( "2 Factor Authentication", wp_defender()->domain ) ?>
14
+ </a>
15
+ </li>
16
+ </ul>
17
+ <div class="is-hidden-tablet mline">
18
+ <select class="mobile-nav">
19
+ <option <?php selected( '', \Hammer\Helper\HTTP_Helper::retrieve_get( 'view' ) ) ?>
20
+ value="<?php echo network_admin_url( 'admin.php?page=wdf-advanced-tools' ) ?>"><?php _e( "2 Factor Authentication", wp_defender()->domain ) ?></option>
21
+ </select>
22
+ </div>
23
+ </div>
24
+ <div class="col-two-third">
25
+ <?php echo $contents ?>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ </div>
30
+ </div>
app/module/advanced-tools/view/login/disabled.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wrap">
2
+ <h2><?php _e( "Security", wp_defender()->domain ) ?></h2>
3
+ <table class="form-table">
4
+ <tbody>
5
+ <tr class="user-sessions-wrap hide-if-no-js">
6
+ <th><?php _e( "2 Factor Authentication", wp_defender()->domain ) ?></th>
7
+ <td aria-live="assertive">
8
+ <div id="def2">
9
+ <div class="destroy-sessions">
10
+ <button type="button" class="button" id="show2AuthActivator">
11
+ <?php _e( "Enable", wp_defender()->domain ) ?>
12
+ </button>
13
+ </div>
14
+ <p class="description">
15
+ <?php _e( "Use the Google Authenticator app to sign in with a separate passcode.", wp_defender()->domain ) ?>
16
+ </p>
17
+ </div>
18
+ <div id="def2qr">
19
+ <button type="button" id="hide2AuthActivator"
20
+ class="button"><?php _e( "Cancel", wp_defender()->domain ) ?></button>
21
+ <p><?php _e( "Use the Google Authenticator app to sign in with a separate passcode.", wp_defender()->domain ) ?></p>
22
+ <div class="card">
23
+ <p>
24
+ <strong><?php _e( "1. Install the Verification app", wp_defender()->domain ) ?></strong>
25
+ </p>
26
+ <p>
27
+ <?php _e( "Download and install the Google Authenticator app on your device using the links below.", wp_defender()->domain ) ?>
28
+ </p>
29
+ <a href="https://itunes.apple.com/vn/app/google-authenticator/id388497605?mt=8">
30
+ <img src="<?php echo wp_defender()->getPluginUrl() . 'assets/img/ios-download.svg' ?>"/>
31
+ </a>
32
+ <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">
33
+ <img src="<?php echo wp_defender()->getPluginUrl() . 'assets/img/android-download.svg' ?>"/>
34
+ </a>
35
+ <div class="line"></div>
36
+ <p><strong><?php _e( "2. Scan the barcode", wp_defender()->domain ) ?></strong></p>
37
+ <p><?php _e( "Open the Google Authenticator app you just downloaded, tap the “+” symbol and then use your phone’s camera to scan the barcode below.", wp_defender()->domain ) ?></p>
38
+ <img class="barcode"
39
+ src="<?php echo \WP_Defender\Module\Advanced_Tools\Component\Auth_API::generateQRCode( get_site_url(), $secretKey, 149, 149, 'wp-defender' ) ?>"/>
40
+ <div class="line"></div>
41
+ <p><strong><?php _e( "3. Enter passcode", wp_defender()->domain ) ?></strong></p>
42
+ <p>
43
+ <?php _e( "Enter the 6 digit passcode that is shown on your device into the input field below and hit “Verify”.", wp_defender()->domain ) ?>
44
+ </p>
45
+ <div class="well">
46
+ <p class="error"></p>
47
+ <input type="text" id="otpCode" class="def-small-text">
48
+ <button type="button" class="button button-primary" id="verifyOTP">
49
+ <?php _e( "Verify", wp_defender()->domain ) ?>
50
+ </button>
51
+ <input type="hidden" id="defNonce" value="<?php echo wp_create_nonce( 'defVerifyOTP' ) ?>"/>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ </td>
56
+ </tr>
57
+ </tbody>
58
+ </table>
59
+ </div>
60
+ <script type="text/javascript">
61
+ jQuery(function ($) {
62
+ $('#def2qr').hide();
63
+ $('#show2AuthActivator').click(function () {
64
+ $('#def2').hide();
65
+ $('#def2qr').show();
66
+ });
67
+ $('#hide2AuthActivator').click(function () {
68
+ $('#def2qr').hide();
69
+ $('#def2').show();
70
+ })
71
+ $('#verifyOTP').click(function () {
72
+ var data = {
73
+ action: 'defVerifyOTP',
74
+ otp: $('#otpCode').val(),
75
+ nonce: $('#defNonce').val()
76
+ }
77
+ var that = $(this);
78
+ var parent = that.closest('.well');
79
+ $.ajax({
80
+ type: 'POST',
81
+ url: ajaxurl,
82
+ data: data,
83
+ beforeSend: function () {
84
+ that.attr('disabled', 'disabled');
85
+ },
86
+ success: function (data) {
87
+ if (data.success == true) {
88
+ location.reload();
89
+ } else {
90
+ that.removeAttr('disabled');
91
+ parent.find('.error').text(data.data.message);
92
+ }
93
+ }
94
+ })
95
+ })
96
+ })
97
+ </script>
app/module/advanced-tools/view/login/enabled.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wrap">
2
+ <h2><?php _e( "Security", wp_defender()->domain ) ?></h2>
3
+ <table class="form-table">
4
+ <tbody>
5
+ <tr class="user-sessions-wrap hide-if-no-js">
6
+ <th><?php _e( "2 Factor Authentication", wp_defender()->domain ) ?></th>
7
+ <td aria-live="assertive">
8
+ <div class="def-notification">
9
+ <?php _e( "2 factor authentication is active.", wp_defender()->domain ) ?>
10
+ </div>
11
+ <button type="button" class="button" id="disableOTP">
12
+ <?php _e( "Disabled", wp_defender()->domain ) ?>
13
+ </button>
14
+ </td>
15
+ </tr>
16
+ <tr class="user-sessions-wrap hide-if-no-js">
17
+ <th><?php _e( "Fallback email address", wp_defender()->domain ) ?></th>
18
+ <td aria-live="assertive">
19
+ <input type="text" class="regular-text" name="def_backup_email" value="<?php echo $email ?>"/>
20
+ <p class="description">
21
+ <?php _e( "If you ever lose your device, you can send a fallback passcode to this email address.", wp_defender()->domain ) ?>
22
+ </p>
23
+ </td>
24
+ </tr>
25
+ </tbody>
26
+ </table>
27
+ </div>
28
+ <script type="text/javascript">
29
+ jQuery(function ($) {
30
+ $('#disableOTP').click(function () {
31
+ var data = {
32
+ action: 'defDisableOTP'
33
+ }
34
+ var that = $(this);
35
+ $.ajax({
36
+ type: 'POST',
37
+ url: ajaxurl,
38
+ data: data,
39
+ beforeSend: function () {
40
+ that.attr('disabled', 'disabled');
41
+ },
42
+ success: function (data) {
43
+ if (data.success == true) {
44
+ location.reload();
45
+ } else {
46
+ that.removeAttr('disabled');
47
+ }
48
+ }
49
+ })
50
+ })
51
+ })
52
+ </script>
app/module/advanced-tools/view/login/otp.php ADDED
@@ -0,0 +1,316 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! function_exists( 'login_header' ) ) {
3
+ //copy from wp-login
4
+ /**
5
+ * Output the login page header.
6
+ *
7
+ * @param string $title Optional. WordPress login Page title to display in the `<title>` element.
8
+ * Default 'Log In'.
9
+ * @param string $message Optional. Message to display in header. Default empty.
10
+ * @param WP_Error $wp_error Optional. The error to pass. Default empty.
11
+ */
12
+ function login_header( $title = 'Log In', $message = '', $wp_error = '' ) {
13
+ global $error, $interim_login, $action;
14
+
15
+ if ( empty( $wp_error ) ) {
16
+ $wp_error = new WP_Error();
17
+ }
18
+
19
+ // Shake it!
20
+ $shake_error_codes = array(
21
+ 'empty_password',
22
+ 'empty_email',
23
+ 'invalid_email',
24
+ 'invalidcombo',
25
+ 'empty_username',
26
+ 'invalid_username',
27
+ 'incorrect_password'
28
+ );
29
+ /**
30
+ * Filters the error codes array for shaking the login form.
31
+ *
32
+ * @since 3.0.0
33
+ *
34
+ * @param array $shake_error_codes Error codes that shake the login form.
35
+ */
36
+ $shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );
37
+
38
+ if ( $shake_error_codes && $wp_error->get_error_code() && in_array( $wp_error->get_error_code(), $shake_error_codes ) ) {
39
+ add_action( 'login_head', 'wp_shake_js', 12 );
40
+ }
41
+
42
+ $separator = is_rtl() ? ' &rsaquo; ' : ' &lsaquo; ';
43
+
44
+ ?><!DOCTYPE html>
45
+ <!--[if IE 8]>
46
+ <html xmlns="http://www.w3.org/1999/xhtml" class="ie8" <?php language_attributes(); ?>>
47
+ <![endif]-->
48
+ <!--[if !(IE 8) ]><!-->
49
+ <html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
50
+ <!--<![endif]-->
51
+ <head>
52
+ <meta http-equiv="Content-Type"
53
+ content="<?php bloginfo( 'html_type' ); ?>; charset=<?php bloginfo( 'charset' ); ?>"/>
54
+ <title><?php echo get_bloginfo( 'name', 'display' ) . $separator . $title; ?></title>
55
+ <?php
56
+
57
+ wp_enqueue_style( 'login' );
58
+
59
+ /*
60
+ * Remove all stored post data on logging out.
61
+ * This could be added by add_action('login_head'...) like wp_shake_js(),
62
+ * but maybe better if it's not removable by plugins
63
+ */
64
+ if ( 'loggedout' == $wp_error->get_error_code() ) {
65
+ ?>
66
+ <script>if ("sessionStorage" in window) {
67
+ try {
68
+ for (var key in sessionStorage) {
69
+ if (key.indexOf("wp-autosave-") != -1) {
70
+ sessionStorage.removeItem(key)
71
+ }
72
+ }
73
+ } catch (e) {
74
+ }
75
+ }
76
+ ;</script>
77
+ <?php
78
+ }
79
+
80
+ /**
81
+ * Enqueue scripts and styles for the login page.
82
+ *
83
+ * @since 3.1.0
84
+ */
85
+ do_action( 'login_enqueue_scripts' );
86
+
87
+ /**
88
+ * Fires in the login page header after scripts are enqueued.
89
+ *
90
+ * @since 2.1.0
91
+ */
92
+ do_action( 'login_head' );
93
+
94
+ if ( is_multisite() ) {
95
+ $login_header_url = network_home_url();
96
+ $login_header_title = get_network()->site_name;
97
+ } else {
98
+ $login_header_url = __( 'https://wordpress.org/' );
99
+ $login_header_title = __( 'Powered by WordPress' );
100
+ }
101
+
102
+ /**
103
+ * Filters link URL of the header logo above login form.
104
+ *
105
+ * @since 2.1.0
106
+ *
107
+ * @param string $login_header_url Login header logo URL.
108
+ */
109
+ $login_header_url = apply_filters( 'login_headerurl', $login_header_url );
110
+
111
+ /**
112
+ * Filters the title attribute of the header logo above login form.
113
+ *
114
+ * @since 2.1.0
115
+ *
116
+ * @param string $login_header_title Login header logo title attribute.
117
+ */
118
+ $login_header_title = apply_filters( 'login_headertitle', $login_header_title );
119
+
120
+ $classes = array( 'login-action-' . $action, 'wp-core-ui' );
121
+ if ( is_rtl() ) {
122
+ $classes[] = 'rtl';
123
+ }
124
+ if ( $interim_login ) {
125
+ $classes[] = 'interim-login';
126
+ ?>
127
+ <style type="text/css">html {
128
+ background-color: transparent;
129
+ }</style>
130
+ <?php
131
+
132
+ if ( 'success' === $interim_login ) {
133
+ $classes[] = 'interim-login-success';
134
+ }
135
+ }
136
+ $classes[] = ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
137
+
138
+ /**
139
+ * Filters the login page body classes.
140
+ *
141
+ * @since 3.5.0
142
+ *
143
+ * @param array $classes An array of body classes.
144
+ * @param string $action The action that brought the visitor to the login page.
145
+ */
146
+ $classes = apply_filters( 'login_body_class', $classes, $action );
147
+
148
+ ?>
149
+ </head>
150
+ <body class="login <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
151
+ <?php
152
+ /**
153
+ * Fires in the login page header after the body tag is opened.
154
+ *
155
+ * @since 4.6.0
156
+ */
157
+ do_action( 'login_header' );
158
+ ?>
159
+ <div id="login">
160
+ <h1><a href="<?php echo esc_url( $login_header_url ); ?>" title="<?php echo esc_attr( $login_header_title ); ?>"
161
+ tabindex="-1"><?php bloginfo( 'name' ); ?></a></h1>
162
+ <?php
163
+
164
+ unset( $login_header_url, $login_header_title );
165
+
166
+ /**
167
+ * Filters the message to display above the login form.
168
+ *
169
+ * @since 2.1.0
170
+ *
171
+ * @param string $message Login message text.
172
+ */
173
+ $message = apply_filters( 'login_message', $message );
174
+ if ( ! empty( $message ) ) {
175
+ echo $message . "\n";
176
+ }
177
+
178
+ // In case a plugin uses $error rather than the $wp_errors object
179
+ if ( ! empty( $error ) ) {
180
+ $wp_error->add( 'error', $error );
181
+ unset( $error );
182
+ }
183
+
184
+ if ( $wp_error->get_error_code() ) {
185
+ $errors = '';
186
+ $messages = '';
187
+ foreach ( $wp_error->get_error_codes() as $code ) {
188
+ $severity = $wp_error->get_error_data( $code );
189
+ foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
190
+ if ( 'message' == $severity ) {
191
+ $messages .= ' ' . $error_message . "<br />\n";
192
+ } else {
193
+ $errors .= ' ' . $error_message . "<br />\n";
194
+ }
195
+ }
196
+ }
197
+ if ( ! empty( $errors ) ) {
198
+ /**
199
+ * Filters the error messages displayed above the login form.
200
+ *
201
+ * @since 2.1.0
202
+ *
203
+ * @param string $errors Login error message.
204
+ */
205
+ echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";
206
+ }
207
+ if ( ! empty( $messages ) ) {
208
+ /**
209
+ * Filters instructional messages displayed above the login form.
210
+ *
211
+ * @since 2.5.0
212
+ *
213
+ * @param string $messages Login messages.
214
+ */
215
+ echo '<p class="message">' . apply_filters( 'login_messages', $messages ) . "</p>\n";
216
+ }
217
+ }
218
+ }
219
+ }
220
+ login_header( '', '', $error );
221
+ ?>
222
+ <form method="post"
223
+ action="<?php echo esc_url( add_query_arg( 'action', 'defenderVerifyOTP', site_url( 'wp-login.php', 'login_post' ) ) ); ?>">
224
+ <p><?php _e( "Enter 6 digit passcode", wp_defender()->domain ) ?></p>
225
+ <input type="text" value="" name="otp">
226
+ <button class="button button-primary float-r"
227
+ type="submit"><?php _e( "Authenticate", wp_defender()->domain ) ?></button>
228
+ <input type="hidden" name="login_token" value="<?php echo $loginToken ?>"/>
229
+ <input type="hidden" name="redirect_to" value="<?php echo $redirect_to ?>"/>
230
+ <?php wp_nonce_field( 'DefOtpCheck' ) ?>
231
+ </form>
232
+ <?php if ( \WP_Defender\Module\Advanced_Tools\Model\Auth_Settings::instance()->lostPhone ): ?>
233
+ <p id="nav">
234
+ <a id="lostPhone"
235
+ href="<?php echo admin_url( 'admin-ajax.php?action=defRetrieveOTP&token=' . $loginToken . '&nonce=' . wp_create_nonce( 'defRetrieveOTP' ) ) ?>">
236
+ <?php _e( "Lost your device?", wp_defender()->domain ) ?></a>
237
+ <img class="def-ajaxloader" src="<?php echo wp_defender()->getPluginUrl().'app/module/advanced-tools/img/spinner.svg' ?>"/>
238
+ <strong class="notification">
239
+
240
+ </strong>
241
+ </p>
242
+ <script type="text/javascript">
243
+ jQuery(function ($) {
244
+ $('.def-ajaxloader').hide();
245
+ var isSent = false;
246
+ $('#lostPhone').click(function (e) {
247
+ e.preventDefault();
248
+ var that = $(this);
249
+ if (isSent == false) {
250
+ isSent = true;
251
+ $.ajax({
252
+ type: 'GET',
253
+ url: that.attr('href'),
254
+ beforeSend: function () {
255
+ that.attr('disabled', 'disabled');
256
+ $('.def-ajaxloader').show();
257
+ },
258
+ success: function (data) {
259
+ that.removeAttr('disabled');
260
+ $('.def-ajaxloader').hide();
261
+ $('.notification').text(data.data.message);
262
+ isSent = false;
263
+ }
264
+ })
265
+ }
266
+
267
+ })
268
+ })
269
+ </script>
270
+ <?php endif; ?>
271
+ <?php
272
+ if ( ! function_exists( 'login_footer' ) ) {
273
+ //copy from wp login
274
+ /**
275
+ * Outputs the footer for the login page.
276
+ *
277
+ * @param string $input_id Which input to auto-focus
278
+ */
279
+ function login_footer( $input_id = '' ) {
280
+ global $interim_login;
281
+
282
+ // Don't allow interim logins to navigate away from the page.
283
+ if ( ! $interim_login ): ?>
284
+ <p id="backtoblog"><a href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php
285
+ /* translators: %s: site title */
286
+ printf( _x( '&larr; Back to %s', 'site' ), get_bloginfo( 'title', 'display' ) );
287
+ ?></a></p>
288
+ <?php endif; ?>
289
+
290
+ </div>
291
+
292
+ <?php if ( ! empty( $input_id ) ) : ?>
293
+ <script type="text/javascript">
294
+ try {
295
+ document.getElementById('<?php echo $input_id; ?>').focus();
296
+ } catch (e) {
297
+ }
298
+ if (typeof wpOnload == 'function') wpOnload();
299
+ </script>
300
+ <?php endif; ?>
301
+
302
+ <?php
303
+ /**
304
+ * Fires in the login page footer.
305
+ *
306
+ * @since 3.1.0
307
+ */
308
+ do_action( 'login_footer' ); ?>
309
+ <div class="clear"></div>
310
+ </body>
311
+ </html>
312
+ <?php
313
+ }
314
+ }
315
+ login_footer();
316
+ ?>
app/module/advanced-tools/view/main.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="dev-box">
2
+ <div class="box-title">
3
+ <h3 class="def-issues-title">
4
+ <?php _e( "2 Factor Authentication", wp_defender()->domain ) ?>
5
+ </h3>
6
+ </div>
7
+ <div class="box-content issues-box-content">
8
+ <form method="post" id="advanced-settings-frm" class="advanced-settings-frm">
9
+ <p class="<?php echo isset( wp_defender()->global['compatibility'] ) ? 'line' : null ?>"><?php _e( "Configure your 2 factor authentication settings, our recommendations are on by default.", wp_defender()->domain ) ?></p>
10
+ <?php if ( isset( wp_defender()->global['compatibility'] ) ): ?>
11
+ <div class="well well-error with-cap">
12
+ <i class="def-icon icon-warning icon-yellow "></i>
13
+ <?php echo implode( '<br/>', wp_defender()->global['compatibility'] ); ?>
14
+ </div>
15
+ <?php endif; ?>
16
+ <div class="columns">
17
+ <div class="column is-one-third">
18
+ <label><?php _e( "User Roles", wp_defender()->domain ) ?></label>
19
+ <span class="sub">
20
+ <?php _e( "Choose what user roles you want to enable 2 factor authentication for. They must then use the Google Authenticator app to login.", wp_defender()->domain ) ?>
21
+ </span>
22
+ </div>
23
+ <div class="column">
24
+ <ul class="dev-list marginless">
25
+ <li class="list-header">
26
+ <div>
27
+ <span class="list-label"><?php _e( "User role", wp_defender()->domain ) ?></span>
28
+ </div>
29
+ </li>
30
+ <?php
31
+ $enabledRoles = $settings->userRoles;
32
+ $allRoles = get_editable_roles();
33
+ foreach ( $allRoles as $role => $detail ):
34
+ ?>
35
+ <li>
36
+ <div>
37
+ <span class="list-label">
38
+ <?php echo $detail['name'] ?>
39
+ </span>
40
+ <div class="list-detail">
41
+ <span class="toggle">
42
+ <input type="checkbox" <?php echo in_array( $role, $enabledRoles ) ? 'checked="checked"' : null ?>
43
+ name="userRoles[]"
44
+ value="<?php echo esc_attr( $role ) ?>"
45
+ class="toggle-checkbox"
46
+ id="toggle_<?php echo esc_attr( $role ) ?>_role"/>
47
+ <label class="toggle-label"
48
+ for="toggle_<?php echo esc_attr( $role ) ?>_role"></label>
49
+ </span>
50
+ </div>
51
+ </div>
52
+ </li>
53
+ <?php endforeach; ?>
54
+ </ul>
55
+ </div>
56
+ </div>
57
+ <div class="columns">
58
+ <div class="column is-one-third">
59
+ <label><?php _e( "Lost Phone", wp_defender()->domain ) ?></label>
60
+ <span class="sub">
61
+ <?php _e( "If a user is unable to access their phone, you can allow an option to send the one time password to their registered email.", wp_defender()->domain ) ?>
62
+ </span>
63
+ </div>
64
+ <div class="column">
65
+ <span class="toggle">
66
+ <input type="hidden" name="lostPhone" value="0"/>
67
+ <input type="checkbox" checked="checked" name="lostPhone" value="1"
68
+ class="toggle-checkbox" id="toggle_lost_phone"/>
69
+ <label class="toggle-label" for="toggle_lost_phone"></label>
70
+ </span>&nbsp;
71
+ <span><?php _e( "Enable lost phone option", wp_defender()->domain ) ?></span>
72
+ </div>
73
+ </div>
74
+ <div class="columns">
75
+ <div class="column is-one-third">
76
+ <label><?php _e( "App Download", wp_defender()->domain ) ?></label>
77
+ <span class="sub">
78
+ <?php _e( "Need the app? Here’s links to the official Google Authenticator apps.", wp_defender()->domain ) ?>
79
+ </span>
80
+ </div>
81
+ <div class="column">
82
+ <a href="https://itunes.apple.com/vn/app/google-authenticator/id388497605?mt=8">
83
+ <img src="<?php echo wp_defender()->getPluginUrl() . 'assets/img/ios-download.svg' ?>"/>
84
+ </a>
85
+ <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">
86
+ <img src="<?php echo wp_defender()->getPluginUrl() . 'assets/img/android-download.svg' ?>"/>
87
+ </a>
88
+ </div>
89
+ </div>
90
+ <div class="columns">
91
+ <div class="column is-one-third">
92
+ <label><?php _e( "Active Users", wp_defender()->domain ) ?></label>
93
+ <span class="sub">
94
+ <?php _e( "Here’s a quick link to see which of your users have enabled 2 step verification.", wp_defender()->domain ) ?>
95
+ </span>
96
+ </div>
97
+ <div class="column">
98
+ <?php printf( __( "<a href=\"%s\">View users</a> who have enabled this feature.", wp_defender()->domain ), network_admin_url( 'users.php' ) ) ?>
99
+ </div>
100
+ </div>
101
+ <div class="columns mline">
102
+ <div class="column is-one-third">
103
+ <label><?php _e( "Deactivate", wp_defender()->domain ) ?></label>
104
+ <span class="sub">
105
+ <?php _e( "Turn off the 2 factor authentication feature completely.", wp_defender()->domain ) ?>
106
+ </span>
107
+ </div>
108
+ <div class="column">
109
+ <button type="button" class="button button-secondary deactivate-2factor">
110
+ <?php _e( "Deactivate", wp_defender()->domain ) ?>
111
+ </button>
112
+ </div>
113
+ </div>
114
+ <div class="clear line"></div>
115
+ <input type="hidden" name="action" value="saveAdvancedSettings"/>
116
+ <?php wp_nonce_field( 'saveAdvancedSettings' ) ?>
117
+ <button type="submit" class="button button-primary float-r">
118
+ <?php _e( "SAVE SETTINGS", wp_defender()->domain ) ?>
119
+ </button>
120
+ <div class="clear"></div>
121
+ </form>
122
+ </div>
123
+ </div>
app/module/audit/view/pro-feature.php CHANGED
@@ -32,7 +32,7 @@
32
  </p>
33
  </div>
34
  <div class="tc">
35
- <a class="button button-green mline" href="https://premium.wpmudev.org/project/wp-defender/"><?php _e( "Get Defender Pro for Free", wp_defender()->domain ) ?></a>
36
  <p class="is-marginless"><?php _e( "As part part of a WPMU DEV free trial.", wp_defender()->domain ) ?></p>
37
  </div>
38
  </div>
32
  </p>
33
  </div>
34
  <div class="tc">
35
+ <a class="button button-green mline" href="https://premium.wpmudev.org/project/wp-defender/?utm_source=defender&utm_medium=plugin&utm_campaign=defender_modal_upgrade"><?php _e( "Get Defender Pro for Free", wp_defender()->domain ) ?></a>
36
  <p class="is-marginless"><?php _e( "As part part of a WPMU DEV free trial.", wp_defender()->domain ) ?></p>
37
  </div>
38
  </div>
app/module/hardener/behavior/widget.php CHANGED
@@ -31,7 +31,7 @@ class Widget extends Behavior {
31
  <div class="box-content">
32
  <?php $count = count( $issues ); ?>
33
  <div class="line <?php echo $count ? 'end' : null ?>">
34
- <?php _e( " Defender checks for security tweaks you can make to enhance your website’s
35
  defense against hackers and bots.", wp_defender()->domain ) ?>
36
  </div>
37
  <?php if ( $count ): ?>
31
  <div class="box-content">
32
  <?php $count = count( $issues ); ?>
33
  <div class="line <?php echo $count ? 'end' : null ?>">
34
+ <?php _e( "Defender checks for security tweaks you can make to enhance your website’s
35
  defense against hackers and bots.", wp_defender()->domain ) ?>
36
  </div>
37
  <?php if ( $count ): ?>
app/module/hardener/component/disable-file-editor.php CHANGED
@@ -27,6 +27,18 @@ class Disable_File_Editor extends Rule {
27
  function addHooks() {
28
  $this->add_action( 'processingHardener' . self::$slug, 'process' );
29
  $this->add_action( 'processRevert' . self::$slug, 'revert' );
 
 
 
 
 
 
 
 
 
 
 
 
30
  }
31
 
32
  function revert() {
@@ -68,4 +80,36 @@ class Disable_File_Editor extends Rule {
68
 
69
  return self::$service;
70
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  }
27
  function addHooks() {
28
  $this->add_action( 'processingHardener' . self::$slug, 'process' );
29
  $this->add_action( 'processRevert' . self::$slug, 'revert' );
30
+ //Extra hardener actions incase setup is messed
31
+ if ( $this->check() ) {
32
+ $this->add_action( 'current_screen', 'current_screen' );
33
+ if ( is_network_admin() ) {
34
+ $this->add_action( 'network_admin_menu', 'editor_admin_menu', 999 );
35
+ } elseif ( is_user_admin() ) {
36
+ $this->add_action( 'user_admin_menu', 'editor_admin_menu', 999 );
37
+ } else {
38
+ $this->add_action( 'admin_menu', 'editor_admin_menu', 999 );
39
+ }
40
+ $this->add_filter( 'plugin_action_links', 'action_links', 10, 4 );
41
+ }
42
  }
43
 
44
  function revert() {
80
 
81
  return self::$service;
82
  }
83
+
84
+ /**
85
+ * Sometimes the roles are messed in the installation
86
+ * So we manually check if the pages are accessed and disable access to the,
87
+ */
88
+ function current_screen() {
89
+ $current_screen = get_current_screen();
90
+ if( $current_screen->id == 'theme-editor-network' || $current_screen->id == 'theme-editor' ){
91
+ wp_die('<p>'.__('Sorry, you are not allowed to edit templates for this site.').'</p>');
92
+ }
93
+ if( $current_screen->id == 'plugin-editor-network' || $current_screen->id == 'plugin-editor' ){
94
+ wp_die('<p>'.__('Sorry, you are not allowed to edit plugins for this site.').'</p>');
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Remove the edit in the admin menu
100
+ */
101
+ function editor_admin_menu() {
102
+ remove_submenu_page( 'themes.php','theme-editor.php' );
103
+ remove_submenu_page( 'plugins.php','plugin-editor.php' );
104
+ }
105
+
106
+ /**
107
+ * Remove any edit links from the plugin list
108
+ *
109
+ */
110
+ function action_links( $actions, $plugin_file, $plugin_data, $context) {
111
+ if ( isset( $actions['edit'] ) )
112
+ unset( $actions['edit'] );
113
+ return $actions;
114
+ }
115
  }
app/module/hardener/component/login-duration-service.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @author Paul Kevin
4
+ */
5
+
6
+ namespace WP_Defender\Module\Hardener\Component;
7
+
8
+ use WP_Defender\Module\Hardener\IRule_Service;
9
+ use WP_Defender\Module\Hardener\Rule_Service;
10
+ use WP_Defender\Module\Hardener\Model\Settings;
11
+
12
+ class Login_Duration_Service extends Rule_Service implements IRule_Service {
13
+
14
+ const CACHE_KEY = 'login_duration';
15
+ const DURATION_CACHE_KEY = 'login_duration_days';
16
+ const DEFAULT_DAYS = 14;
17
+
18
+ protected $duration;
19
+
20
+ /**
21
+ * @param mixed $duration
22
+ */
23
+ public function setDuration( $duration ) {
24
+ $this->duration = $duration;
25
+ }
26
+
27
+ /**
28
+ * @return bool
29
+ */
30
+ public function check() {
31
+ $key = Settings::instance()->getDValues( self::CACHE_KEY );
32
+
33
+ return ( $key == 1 );
34
+ }
35
+
36
+ public function process() {
37
+ Settings::instance()->setDValues( self::CACHE_KEY, 1 );
38
+ Settings::instance()->setDValues( self::DURATION_CACHE_KEY, $this->duration );
39
+ return true;
40
+ }
41
+
42
+ public function revert() {
43
+ Settings::instance()->setDValues( self::CACHE_KEY, 0 );
44
+ Settings::instance()->setDValues( self::DURATION_CACHE_KEY, self::DEFAULT_DAYS );
45
+ return true;
46
+ }
47
+
48
+ public function getDuration( $in_seconds = false ) {
49
+ $duration = Settings::instance()->getDValues( self::DURATION_CACHE_KEY );
50
+ if ( !empty( $duration ) ) {
51
+ $duration = intval( $duration );
52
+ return ( $in_seconds ) ? $duration * DAY_IN_SECONDS : $duration;
53
+ } else {
54
+ return ( $in_seconds ) ? self::DEFAULT_DAYS * DAY_IN_SECONDS : self::DEFAULT_DAYS;
55
+ }
56
+ }
57
+ }
58
+ ?>
app/module/hardener/component/login-duration.php ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @author Paul Kevin
4
+ */
5
+
6
+ namespace WP_Defender\Module\Hardener\Component;
7
+
8
+ use Hammer\Helper\WP_Helper;
9
+ use Hammer\Helper\HTTP_Helper;
10
+ use WP_Defender\Module\Hardener\Model\Settings;
11
+ use WP_Defender\Module\Hardener\Rule;
12
+ use WP_Defender\Behavior\Utils;
13
+
14
+ class Login_Duration extends Rule {
15
+
16
+ static $slug = 'login-duration';
17
+
18
+ static $service;
19
+
20
+ /**
21
+ * @return Login_Duration_Service
22
+ */
23
+ public function getService() {
24
+ if ( self::$service == null ) {
25
+ self::$service = new Login_Duration_Service();
26
+ }
27
+ return self::$service;
28
+ }
29
+
30
+ function getDescription() {
31
+ $this->renderPartial( 'rules/login-duration' );
32
+ }
33
+
34
+ /**
35
+ * @return string
36
+ */
37
+ public function getTitle() {
38
+ return __( "Manage Login Duration", wp_defender()->domain );
39
+ }
40
+
41
+ /**
42
+ * @return bool
43
+ */
44
+ function check() {
45
+ return $this->getService()->check();
46
+ }
47
+
48
+ function addHooks() {
49
+ $this->add_action( 'processingHardener' . self::$slug, 'process' );
50
+ $this->add_action( 'processRevert' . self::$slug, 'revert' );
51
+ $this->add_action( 'wp_login', 'login_action_handler', 10, 2 );
52
+ if ( $this->check() ) {
53
+ $this->add_filter( 'auth_cookie_expiration', 'cookie_duration', 10, 3 );
54
+ $this->add_filter( 'login_message', 'login_message' );
55
+ $this->add_action( 'wp_loaded', 'check_login' );
56
+ }
57
+
58
+ }
59
+
60
+ function revert() {
61
+ if ( ! $this->verifyNonce() ) {
62
+ return;
63
+ }
64
+ $settings = Settings::instance();
65
+ $service = $this->getService();
66
+ $ret = $service->revert();
67
+ if ( ! is_wp_error( $ret ) ) {
68
+ Settings::instance()->addToIssues( self::$slug );
69
+ } else {
70
+ wp_send_json_error( array(
71
+ 'message' => $ret->get_error_message()
72
+ ) );
73
+ }
74
+ }
75
+
76
+ function process() {
77
+ if ( ! $this->verifyNonce() ) {
78
+ return;
79
+ }
80
+ $service = $this->getService();
81
+ $duration = HTTP_Helper::retrieve_post( 'duration' );
82
+ if ( is_numeric( $duration ) ) {
83
+ $service->setDuration( $duration );
84
+ $ret = $service->process();
85
+ if ( ! is_wp_error( $ret ) ) {
86
+ Settings::instance()->addToResolved( self::$slug );
87
+ } else {
88
+ wp_send_json_error( array(
89
+ 'message' => $ret->get_error_message()
90
+ ) );
91
+ }
92
+ } else {
93
+ wp_send_json_error( array(
94
+ 'message' => __( 'Duration can only be a number', wp_defender()->domain )
95
+ ) );
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Set the last login user meta
101
+ */
102
+ function login_action_handler( $user_login, $user = '' ) {
103
+ if ( $user == '' ){
104
+ $user = get_user_by( 'login', $user_login );
105
+ }
106
+ if ( !$user ){
107
+ return;
108
+ }
109
+ $last_login_time = current_time( 'mysql' );
110
+ update_user_meta( $user->ID, 'last_login_time', $last_login_time );
111
+ }
112
+
113
+ /**
114
+ * Check login of users
115
+ */
116
+ function check_login() {
117
+ $defender_logout = HTTP_Helper::retrieve_get( 'defender_logout', false );
118
+ if( is_user_logged_in() ) {
119
+ if ( !$defender_logout ) {
120
+ $current_user = wp_get_current_user();
121
+ $user_id = $current_user->ID;
122
+ $current_time = current_time( 'mysql' );
123
+ $last_login_time = get_user_meta( $user_id, 'last_login_time', true );
124
+ $login_period = $this->getService()->getDuration( true );
125
+ if ( $last_login_time ) {
126
+ $diff = strtotime( $current_time ) - strtotime( $last_login_time );
127
+ if( $diff > $login_period ) {
128
+ $current_url = Utils::instance()->currentPageURL();
129
+ $after_logout_payload = array( 'redirect_to' => $current_url, 'msg'=>'session_expired' );
130
+ if ( is_multisite() ) {
131
+ set_site_transient( 'defender_logout_payload', $after_logout_payload, 30 * 60 );
132
+ }
133
+ set_transient( 'defender_logout_payload', $after_logout_payload, 30 * 60 );
134
+ $logout_url = add_query_arg( 'defender_logout', '1', site_url() );
135
+ wp_redirect( $logout_url );
136
+ exit;
137
+ }
138
+ } else {
139
+ //Incase the user already was logged in
140
+ $last_login_time = current_time( 'mysql' );
141
+ update_user_meta( $user_id, 'last_login_time', $last_login_time );
142
+ }
143
+ } else{
144
+ wp_logout();
145
+ $after_logout = HTTP_Helper::retrieve_get( 'after_logout', false );
146
+ if ( $after_logout ) {
147
+ $after_logout_url = esc_url( $after_logout );
148
+ wp_redirect( $after_logout_url );
149
+ exit;
150
+ }
151
+ $login_url = wp_login_url();
152
+ $logout_payload = ( is_multisite() ? get_site_transient( 'defender_logout_payload' ) : get_transient( 'defender_logout_payload' ) );
153
+
154
+ $login_url = add_query_arg( array(
155
+ 'redirect_to' => $logout_payload['redirect_to'],
156
+ 'defender_login_message' => $logout_payload['msg'],
157
+ ), $login_url );
158
+ wp_redirect( $login_url );
159
+ exit;
160
+ }
161
+ } else if ( $defender_logout ) {
162
+ $after_logout = HTTP_Helper::retrieve_get( 'after_logout', false );
163
+ if ( $after_logout ) {
164
+ $after_logout_url = esc_url( $after_logout );
165
+ wp_redirect( $after_logout_url );
166
+ }
167
+ $login_url = wp_login_url();
168
+ $logout_payload = ( is_multisite() ? get_site_transient( 'defender_logout_payload' ) : get_transient( 'defender_logout_payload' ) );
169
+
170
+ $login_url = add_query_arg( array(
171
+ 'redirect_to' => $logout_payload['redirect_to'],
172
+ 'defender_login_message' => $logout_payload['msg'],
173
+ ), $login_url );
174
+ wp_redirect( $login_url );
175
+ exit;
176
+ }
177
+ }
178
+
179
+
180
+ /**
181
+ * Handle the custom login message
182
+ *
183
+ */
184
+ function login_message( $message = '' ) {
185
+ $login_msg = HTTP_Helper::retrieve_get( 'defender_login_message', false );
186
+ if( $login_msg ) {
187
+ $logout_msg = strip_tags( $login_msg );
188
+ if ( $logout_msg == 'session_expired' ) {
189
+ $duration = $this->getService()->getDuration( false );
190
+ $msg = sprintf( __( 'Your session has expired because it has been over %d days since your last login. Please log back in to continue.', wp_defender()->domain ), $duration );
191
+ $msg = htmlspecialchars( $msg, ENT_QUOTES, 'UTF-8' );
192
+ $message .= '<p class="login message">'. $msg . '</p>';
193
+ }
194
+ }
195
+ return $message;
196
+ }
197
+
198
+ /**
199
+ * Cookie duration in days in seconds
200
+ *
201
+ * @param Integer $duration - default duration
202
+ * @param Integer $user_id - current user id
203
+ * @param Boolean $remember - remember me login
204
+ *
205
+ * @return Integer $duration
206
+ */
207
+ function cookie_duration( $duration, $user_id, $remember ) {
208
+ if ( $remember ) {
209
+ $duration = $this->getService()->getDuration( true );
210
+ }
211
+ return $duration;
212
+ }
213
+
214
+ }
215
+
216
+ ?>
app/module/hardener/component/prevent-php.php CHANGED
@@ -67,6 +67,7 @@ class Prevent_Php extends Rule {
67
  function addHooks() {
68
  $this->add_action( 'processingHardener' . self::$slug, 'process', 10, 2 );
69
  $this->add_action( 'processRevert' . self::$slug, 'revert' );
 
70
  }
71
 
72
  function process() {
@@ -100,6 +101,36 @@ class Prevent_Php extends Rule {
100
  }
101
  }
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  /**
104
  * @return Prevent_PHP_Service
105
  */
67
  function addHooks() {
68
  $this->add_action( 'processingHardener' . self::$slug, 'process', 10, 2 );
69
  $this->add_action( 'processRevert' . self::$slug, 'revert' );
70
+ $this->add_action( 'processUpdate' . self::$slug, 'update', 10, 2 );
71
  }
72
 
73
  function process() {
101
  }
102
  }
103
 
104
+ function update() {
105
+ if ( ! $this->verifyNonce() ) {
106
+ return;
107
+ }
108
+ $settings = Settings::instance();
109
+ $server = func_get_arg(0); //Get first param
110
+ $file_paths = func_get_arg(1); //Get second param
111
+ if ( in_array( $server, array( 'apache', 'litespeed' ) ) ) {
112
+ $service = $this->getApacheService();
113
+ $service->setHtConfig( $settings->getNewHtConfig() ); //Set the previous template
114
+ $service->unProtectContentDir(); //revert first
115
+ $service->setExcludeFilePaths( $file_paths ); //Set the paths
116
+ } else {
117
+ $service = $this->getService();
118
+ }
119
+ $ret = $service->process();
120
+ if ( ! is_wp_error( $ret ) ) {
121
+ if ( in_array( $server, array( 'apache', 'litespeed' ) ) ) {
122
+ $settings->saveExcludedFilePaths( $service->getExcludedFilePaths() );
123
+ $settings->saveNewHtConfig( $service->getNewHtConfig() );
124
+ }
125
+ $settings->setActiveServer( $server );
126
+ $settings->save();
127
+ } else {
128
+ wp_send_json_error( array(
129
+ 'message' => $ret->get_error_message()
130
+ ) );
131
+ }
132
+ }
133
+
134
  /**
135
  * @return Prevent_PHP_Service
136
  */
app/module/hardener/component/security-key.php CHANGED
@@ -16,14 +16,19 @@ class Security_Key extends Rule {
16
  static $service;
17
 
18
  function getDescription() {
19
- $time = Settings::instance()->getDValues( Security_Key_Service::CACHE_KEY );
 
 
 
 
 
20
  if ( $time ) {
21
  $daysAgo = ( time() - $time ) / ( 60 * 60 * 24 );
22
  } else {
23
  $daysAgo = null;
24
  }
25
  $this->renderPartial( 'rules/security-key', array(
26
- 'interval' => Security_Key_Service::DEFAULT_DAYS,
27
  'daysAgo' => $daysAgo
28
  ) );
29
  }
@@ -52,8 +57,8 @@ class Security_Key extends Rule {
52
  $reminder = HTTP_Helper::retrieve_post( 'remind_date', null );
53
  if ( $reminder ) {
54
  $settings = Settings::instance();
 
55
  $settings->setDValues( 'securityReminderDate', strtotime( '+' . $reminder, current_time( 'timestamp' ) ) );
56
- $settings->save();
57
  die;
58
  }
59
  }
16
  static $service;
17
 
18
  function getDescription() {
19
+ $settings = Settings::instance();
20
+ $time = $settings->getDValues( Security_Key_Service::CACHE_KEY );
21
+ $interval = $settings->getDValues( 'securityReminderDuration' );
22
+ if ( !$interval ) {
23
+ $interval = Security_Key_Service::DEFAULT_DAYS;
24
+ }
25
  if ( $time ) {
26
  $daysAgo = ( time() - $time ) / ( 60 * 60 * 24 );
27
  } else {
28
  $daysAgo = null;
29
  }
30
  $this->renderPartial( 'rules/security-key', array(
31
+ 'interval' => $interval,
32
  'daysAgo' => $daysAgo
33
  ) );
34
  }
57
  $reminder = HTTP_Helper::retrieve_post( 'remind_date', null );
58
  if ( $reminder ) {
59
  $settings = Settings::instance();
60
+ $settings->setDValues( 'securityReminderDuration', $reminder );
61
  $settings->setDValues( 'securityReminderDate', strtotime( '+' . $reminder, current_time( 'timestamp' ) ) );
 
62
  die;
63
  }
64
  }
app/module/hardener/component/servers/apache-service.php CHANGED
@@ -171,7 +171,13 @@ class Apache_Service extends Rule_Service implements IRule_Service {
171
  $default = $this->new_htconfig;
172
  }
173
 
174
- $htConfig = str_replace( implode( '', $default ), '', $htConfig );
 
 
 
 
 
 
175
  $htConfig = trim( $htConfig );
176
  file_put_contents( $htPath, $htConfig, LOCK_EX );
177
  }
171
  $default = $this->new_htconfig;
172
  }
173
 
174
+ //Introduced regex
175
+ preg_match_all('/## WP Defender(.*?)## WP Defender - End ##/s', $htConfig, $matches);
176
+ if ( is_array( $matches ) && count( $matches ) > 0 ) {
177
+ $htConfig = str_replace( implode( '', $matches[0] ), '', $htConfig );
178
+ } else {
179
+ $htConfig = str_replace( implode( '', $default ), '', $htConfig );
180
+ }
181
  $htConfig = trim( $htConfig );
182
  file_put_contents( $htPath, $htConfig, LOCK_EX );
183
  }
app/module/hardener/controller/main.php CHANGED
@@ -42,6 +42,7 @@ class Main extends Controller {
42
  $this->add_ajax_action( 'processRevert', 'processRevert' );
43
  $this->add_ajax_action( 'ignoreHardener', 'ignoreHardener' );
44
  $this->add_ajax_action( 'restoreHardener', 'restoreHardener' );
 
45
  }
46
 
47
  public function restoreHardener() {
@@ -121,6 +122,35 @@ class Main extends Controller {
121
  ) );
122
  }
123
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  /**
125
  * Add submit admin page
126
  */
42
  $this->add_ajax_action( 'processRevert', 'processRevert' );
43
  $this->add_ajax_action( 'ignoreHardener', 'ignoreHardener' );
44
  $this->add_ajax_action( 'restoreHardener', 'restoreHardener' );
45
+ $this->add_ajax_action( 'updateHardener', 'updateHardener' );
46
  }
47
 
48
  public function restoreHardener() {
122
  ) );
123
  }
124
 
125
+ /**
126
+ * Update Hardener
127
+ * Update existing rules
128
+ */
129
+ public function updateHardener() {
130
+ if ( ! $this->checkPermission() ) {
131
+ return;
132
+ }
133
+
134
+ $slug = HTTP_Helper::retrieve_post( 'slug' );
135
+ $file_paths = HTTP_Helper::retrieve_post( 'file_paths' ); //File paths to ignore. Apache and litespeed mainly
136
+ if ( $file_paths ) {
137
+ $file_paths = sanitize_textarea_field( $file_paths );
138
+ } else {
139
+ $file_paths = '';
140
+ }
141
+
142
+ $server = HTTP_Helper::retrieve_post( 'current_server' ); //Current server
143
+ do_action( "processUpdate" . $slug , $server, $file_paths );
144
+ //fall back
145
+ wp_send_json_success( array(
146
+ 'message' => __( "Security tweak successfully updated.", wp_defender()->domain ),
147
+ 'issues' => $this->getCount( 'issues' ),
148
+ 'fixed' => $this->getCount( 'fixed' ),
149
+ 'ignore' => $this->getCount( 'ignore' ),
150
+ 'update' => false
151
+ ) );
152
+ }
153
+
154
  /**
155
  * Add submit admin page
156
  */
app/module/hardener/js/scripts.js CHANGED
@@ -37,6 +37,9 @@ jQuery(function ($) {
37
  });
38
  $('span.hardener-nginx-extra-instructions').html(newRule);
39
  }
 
 
 
40
  });
41
 
42
  /**
@@ -50,6 +53,13 @@ jQuery(function ($) {
50
  }
51
  });
52
 
 
 
 
 
 
 
 
53
  /**
54
  * Server select
55
  */
@@ -66,6 +76,11 @@ jQuery(function ($) {
66
  });
67
  $('.hardener-instructions-'+selected).removeClass('wd-hide');
68
  }
 
 
 
 
 
69
 
70
  });
71
 
@@ -96,14 +111,20 @@ jQuery(function ($) {
96
  } else {
97
  $('.count-resolved').addClass('wd-hide');
98
  }
99
- form.closest('.rule').slideUp(500, function () {
100
- $(this).remove();
101
- if ($('.rule').size() == 0) {
102
- setTimeout(function () {
103
- location.reload();
104
- }, 500)
105
- }
106
- })
 
 
 
 
 
 
107
  } else {
108
  Defender.showNotification('error', data.data.message);
109
  }
37
  });
38
  $('span.hardener-nginx-extra-instructions').html(newRule);
39
  }
40
+ if ( $('.hardener-instructions-apache-litespeed').length ) {
41
+ $('.hardener-update-frm [name="file_paths"]').val(text_val);
42
+ }
43
  });
44
 
45
  /**
53
  }
54
  });
55
 
56
+ /**
57
+ * Toggle text area
58
+ */
59
+ $(document).on('click','button.hardener-php-excuted-execption', function(){
60
+ $('.hardener-instructions textarea.hardener-php-excuted-ignore').toggle('fast');
61
+ });
62
+
63
  /**
64
  * Server select
65
  */
76
  });
77
  $('.hardener-instructions-'+selected).removeClass('wd-hide');
78
  }
79
+ if( selected == 'apache' || selected == 'litespeed' || selected == 'nginx'){
80
+ $('.hardener-instructions-extra-exceptions').removeClass('wd-hide');
81
+ }else{
82
+ $('.hardener-instructions-extra-exceptions').addClass('wd-hide');
83
+ }
84
 
85
  });
86
 
111
  } else {
112
  $('.count-resolved').addClass('wd-hide');
113
  }
114
+ var update_rules = true;
115
+ if ( typeof data.data.update !== "undefined" ) {
116
+ update_rules = false;
117
+ }
118
+ if ( update_rules ) {
119
+ form.closest('.rule').slideUp(500, function () {
120
+ $(this).remove();
121
+ if ($('.rule').size() == 0) {
122
+ setTimeout(function () {
123
+ location.reload();
124
+ }, 500)
125
+ }
126
+ });
127
+ }
128
  } else {
129
  Defender.showNotification('error', data.data.message);
130
  }
app/module/hardener/model/settings.php CHANGED
@@ -8,22 +8,16 @@ namespace WP_Defender\Module\Hardener\Model;
8
  use Hammer\Helper\WP_Helper;
9
  use WP_Defender\Behavior\Utils;
10
  use WP_Defender\Module\Hardener\Component\Change_Admin;
11
- use WP_Defender\Module\Hardener\Component\Change_Admin_Service;
12
  use WP_Defender\Module\Hardener\Component\DB_Prefix;
13
- use WP_Defender\Module\Hardener\Component\DB_Prefix_Service;
14
  use WP_Defender\Module\Hardener\Component\Disable_File_Editor;
15
- use WP_Defender\Module\Hardener\Component\Disable_File_Editor_Service;
16
  use WP_Defender\Module\Hardener\Component\Disable_Trackback;
17
- use WP_Defender\Module\Hardener\Component\Disable_Trackback_Service;
18
  use WP_Defender\Module\Hardener\Component\Hide_Error;
19
- use WP_Defender\Module\Hardener\Component\Hide_Error_Service;
20
  use WP_Defender\Module\Hardener\Component\PHP_Version;
21
  use WP_Defender\Module\Hardener\Component\Prevent_Php;
22
  use WP_Defender\Module\Hardener\Component\Protect_Information;
23
  use WP_Defender\Module\Hardener\Component\Security_Key;
24
- use WP_Defender\Module\Hardener\Component\Security_Key_Service;
25
  use WP_Defender\Module\Hardener\Component\WP_Version;
26
- use WP_Defender\Module\Hardener\Component\WP_Version_Service;
27
  use WP_Defender\Module\Hardener\Rule;
28
  use WP_Defender\Module\Hardener\Rule_Service;
29
 
@@ -269,7 +263,8 @@ class Settings extends \Hammer\WP\Settings {
269
  Hide_Error::$slug => $init == true ? new Hide_Error() : Hide_Error::getClassName(),
270
  Security_Key::$slug => $init == true ? new Security_Key() : Security_Key::getClassName(),
271
  Protect_Information::$slug => $init == true ? new Protect_Information() : Protect_Information::getClassName(),
272
- Prevent_Php::$slug => $init == true ? new Prevent_Php() : Prevent_Php::getClassName()
 
273
  );
274
  }
275
 
8
  use Hammer\Helper\WP_Helper;
9
  use WP_Defender\Behavior\Utils;
10
  use WP_Defender\Module\Hardener\Component\Change_Admin;
 
11
  use WP_Defender\Module\Hardener\Component\DB_Prefix;
 
12
  use WP_Defender\Module\Hardener\Component\Disable_File_Editor;
 
13
  use WP_Defender\Module\Hardener\Component\Disable_Trackback;
 
14
  use WP_Defender\Module\Hardener\Component\Hide_Error;
15
+ use WP_Defender\Module\Hardener\Component\Login_Duration;
16
  use WP_Defender\Module\Hardener\Component\PHP_Version;
17
  use WP_Defender\Module\Hardener\Component\Prevent_Php;
18
  use WP_Defender\Module\Hardener\Component\Protect_Information;
19
  use WP_Defender\Module\Hardener\Component\Security_Key;
 
20
  use WP_Defender\Module\Hardener\Component\WP_Version;
 
21
  use WP_Defender\Module\Hardener\Rule;
22
  use WP_Defender\Module\Hardener\Rule_Service;
23
 
263
  Hide_Error::$slug => $init == true ? new Hide_Error() : Hide_Error::getClassName(),
264
  Security_Key::$slug => $init == true ? new Security_Key() : Security_Key::getClassName(),
265
  Protect_Information::$slug => $init == true ? new Protect_Information() : Protect_Information::getClassName(),
266
+ Prevent_Php::$slug => $init == true ? new Prevent_Php() : Prevent_Php::getClassName(),
267
+ Login_Duration::$slug => $init == true ? new Login_Duration() : Login_Duration::getClassName()
268
  );
269
  }
270
 
app/module/hardener/view/rules/change-admin.php CHANGED
@@ -28,7 +28,7 @@
28
  <?php $controller->createNonceField(); ?>
29
  <input type="hidden" name="action" value="processHardener"/>
30
  <input type="text" placeholder="<?php esc_attr_e( "Enter new username", wp_defender()->domain ) ?>"
31
- name="username" class="block">
32
  <input type="hidden" name="slug" value="<?php echo $controller::$slug ?>"/>
33
  <button class="button float-r"
34
  type="submit"><?php _e( "Update", wp_defender()->domain ) ?></button>
28
  <?php $controller->createNonceField(); ?>
29
  <input type="hidden" name="action" value="processHardener"/>
30
  <input type="text" placeholder="<?php esc_attr_e( "Enter new username", wp_defender()->domain ) ?>"
31
+ name="username" class="block" />
32
  <input type="hidden" name="slug" value="<?php echo $controller::$slug ?>"/>
33
  <button class="button float-r"
34
  type="submit"><?php _e( "Update", wp_defender()->domain ) ?></button>
app/module/hardener/view/rules/login-duration.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="rule closed" id="login-duration">
2
+ <div class="rule-title">
3
+ <?php if ( $controller->check() == false ): ?>
4
+ <i class="def-icon icon-warning"></i>
5
+ <?php else: ?>
6
+ <i class="def-icon icon-tick"></i>
7
+ <?php endif; ?>
8
+ <?php echo $controller->getTitle() ?>
9
+ </div>
10
+ <div class="rule-content">
11
+ <h3><?php _e( "Overview", wp_defender()->domain ) ?></h3>
12
+ <div class="line end">
13
+ <?php _e( "By default, users who select the 'remember me' option stay logged in for 14 days", wp_defender()->domain ) ?>
14
+ </div>
15
+ <h3>
16
+ <?php _e( "How to fix", wp_defender()->domain ) ?>
17
+ </h3>
18
+ <div class="well">
19
+ <?php
20
+ $setting = \WP_Defender\Module\Hardener\Model\Settings::instance();
21
+
22
+ if ( $controller->check() ):
23
+ ?>
24
+ <p class="line"><?php esc_attr_e( sprintf( __('Login Duration is locked down. Current duration is %d days', wp_defender()->domain ), $controller->getService()->getDuration() ) ); ?></p>
25
+ <form method="post" class="hardener-frm rule-process">
26
+ <?php $controller->createNonceField(); ?>
27
+ <input type="hidden" name="action" value="processRevert"/>
28
+ <input type="hidden" name="slug" value="<?php echo $controller::$slug ?>"/>
29
+ <button class="button button-small button-grey" type="submit"><?php _e( "Revert", wp_defender()->domain ) ?></button>
30
+ </form>
31
+ <?php
32
+ else:
33
+ ?>
34
+ <div class="line">
35
+ <p><?php _e( "Please change the number of days a user can stay logged in", wp_defender()->domain ) ?></p>
36
+ </div>
37
+ <form method="post" class="hardener-frm rule-process">
38
+ <?php $controller->createNonceField(); ?>
39
+ <input type="hidden" name="action" value="processHardener"/>
40
+ <input type="text" placeholder="<?php esc_attr_e( "Enter number of days", wp_defender()->domain ) ?>"
41
+ name="duration" class="block" />
42
+ <input type="hidden" name="slug" value="<?php echo $controller::$slug ?>"/>
43
+ <button class="button float-r"
44
+ type="submit"><?php _e( "Update", wp_defender()->domain ) ?></button>
45
+ </form>
46
+ <?php $controller->showIgnoreForm() ?>
47
+ <div class="clear"></div>
48
+ <?php
49
+ endif;
50
+ ?>
51
+ </div>
52
+ </div>
53
+ </div>
app/module/hardener/view/rules/prevent-php-executed.php CHANGED
@@ -16,8 +16,34 @@
16
  <?php _e( "How to fix", wp_defender()->domain ) ?>
17
  </h3>
18
  <div class="well">
19
- <?php if ( $controller->check() ): ?>
20
- <p class="line"><?php _e( "PHP execution is locked down.", wp_defender()->domain ) ?></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  <form method="post" class="hardener-frm rule-process">
22
  <?php $controller->createNonceField(); ?>
23
  <input type="hidden" name="action" value="processRevert"/>
@@ -26,8 +52,8 @@
26
  type="submit"><?php _e( "Revert", wp_defender()->domain ) ?></button>
27
  </form>
28
  <?php else:
29
- $servers = \WP_Defender\Behavior\Utils::instance()->serverTypes();
30
- $setting = \WP_Defender\Module\Hardener\Model\Settings::instance();
31
  if ( DIRECTORY_SEPARATOR == '\\' ) {
32
  //Windows
33
  $wp_includes = str_replace( ABSPATH, '', WPINC );
@@ -64,10 +90,6 @@
64
  <div class="line">
65
  <p><?php _e( "We will place <strong>.htaccess</strong> file into the root folder to lock down the files and folders inside.", wp_defender()->domain ) ?></p>
66
  </div>
67
- <div class="line">
68
- <p><?php _e( "File paths to ignore in the /wp-content directory (each in a new line). The file index.php is not allowed", wp_defender()->domain ) ?></p>
69
- <textarea class="hardener-php-excuted-ignore"></textarea>
70
- </div>
71
  <form method="post" class="hardener-frm hardener-apache-frm rule-process">
72
  <?php $controller->createNonceField(); ?>
73
  <input type="hidden" name="action" value="processHardener"/>
@@ -82,10 +104,6 @@
82
  <div class="line">
83
  <p><?php _e( "We will place <strong>.htaccess</strong> file into the root folder to lock down the files and folders inside.", wp_defender()->domain ) ?></p>
84
  </div>
85
- <div class="line">
86
- <p><?php _e( "File paths to ignore in the /wp-content directory (each in a new line). The file index.php is not allowed", wp_defender()->domain ) ?></p>
87
- <textarea class="hardener-php-excuted-ignore"></textarea>
88
- </div>
89
  <form method="post" class="hardener-frm hardener-litespeed-frm rule-process">
90
  <?php $controller->createNonceField(); ?>
91
  <input type="hidden" name="action" value="processHardener"/>
@@ -119,10 +137,6 @@ location ~* ^$wp_content/.*\.php$ {
119
 
120
  <p><?php esc_html_e( "For NGINX servers:", wp_defender()->domain ) ?></p>
121
  <ol>
122
- <li>
123
- <p><?php _e( "Input the file paths to ignore in the /wp-content directory (each in a new line). The file index.php is not allowed", wp_defender()->domain ) ?></p>
124
- <textarea class="hardener-php-excuted-ignore"></textarea>
125
- </li>
126
  <li>
127
  <?php esc_html_e( "Copy the generated code into your site specific .conf file usually located in a subdirectory under /etc/nginx/... or /usr/local/nginx/conf/...", wp_defender()->domain ) ?>
128
  </li>
@@ -164,8 +178,25 @@ location ~* ^$wp_content/.*\.php$ {
164
  </form>
165
 
166
  </div>
167
- <?php $controller->showIgnoreForm() ?>
168
- <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  </div>
170
  </div>
171
  </div>
16
  <?php _e( "How to fix", wp_defender()->domain ) ?>
17
  </h3>
18
  <div class="well">
19
+ <?php
20
+ $setting = \WP_Defender\Module\Hardener\Model\Settings::instance();
21
+
22
+ if ( $controller->check() ): ?>
23
+ <p class="line"><?php _e( "PHP execution is locked down.", wp_defender()->domain ) ?>
24
+ <?php
25
+ if ( in_array( $setting->active_server, array( 'apache', 'litespeed' ) ) ) {
26
+ $file_paths = $setting->getExcludedFilePaths();
27
+ if ( !empty( $file_paths ) && is_array( $file_paths ) && count( $file_paths ) > 0 ) {
28
+ _e(" The following file paths have been allowed in the /wp-content directory :", wp_defender()->domain );
29
+ ?>
30
+ <div class="hardener-instructions hardener-instructions-apache-litespeed">
31
+ <textarea class="hardener-php-excuted-ignore"><?php echo implode( "\n", $file_paths ); ?></textarea>
32
+ <form method="post" class="hardener-frm hardener-update-frm rule-process">
33
+ <?php $controller->createNonceField(); ?>
34
+ <input type="hidden" name="action" value="updateHardener"/>
35
+ <input type="hidden" name="file_paths" value="<?php echo implode( "\n", $file_paths ); ?>"/>
36
+ <input type="hidden" name="current_server" value="<?php echo $setting->active_server; ?>"/>
37
+ <input type="hidden" name="slug" value="<?php echo $controller::$slug ?>"/>
38
+ <button class="button button-small float-r"
39
+ type="submit"><?php _e( "Update .htaccess file", wp_defender()->domain ) ?></button>
40
+ </form>
41
+ </div>
42
+ <?php
43
+ }
44
+ }
45
+ ?>
46
+ </p>
47
  <form method="post" class="hardener-frm rule-process">
48
  <?php $controller->createNonceField(); ?>
49
  <input type="hidden" name="action" value="processRevert"/>
52
  type="submit"><?php _e( "Revert", wp_defender()->domain ) ?></button>
53
  </form>
54
  <?php else:
55
+ $servers = \WP_Defender\Behavior\Utils::instance()->serverTypes();
56
+
57
  if ( DIRECTORY_SEPARATOR == '\\' ) {
58
  //Windows
59
  $wp_includes = str_replace( ABSPATH, '', WPINC );
90
  <div class="line">
91
  <p><?php _e( "We will place <strong>.htaccess</strong> file into the root folder to lock down the files and folders inside.", wp_defender()->domain ) ?></p>
92
  </div>
 
 
 
 
93
  <form method="post" class="hardener-frm hardener-apache-frm rule-process">
94
  <?php $controller->createNonceField(); ?>
95
  <input type="hidden" name="action" value="processHardener"/>
104
  <div class="line">
105
  <p><?php _e( "We will place <strong>.htaccess</strong> file into the root folder to lock down the files and folders inside.", wp_defender()->domain ) ?></p>
106
  </div>
 
 
 
 
107
  <form method="post" class="hardener-frm hardener-litespeed-frm rule-process">
108
  <?php $controller->createNonceField(); ?>
109
  <input type="hidden" name="action" value="processHardener"/>
137
 
138
  <p><?php esc_html_e( "For NGINX servers:", wp_defender()->domain ) ?></p>
139
  <ol>
 
 
 
 
140
  <li>
141
  <?php esc_html_e( "Copy the generated code into your site specific .conf file usually located in a subdirectory under /etc/nginx/... or /usr/local/nginx/conf/...", wp_defender()->domain ) ?>
142
  </li>
178
  </form>
179
 
180
  </div>
181
+ <?php $controller->showIgnoreForm();
182
+ $prevent_php_style = "style='display:none'";
183
+ if ( in_array( $setting->active_server, array( 'apache', 'litespeed', 'nginx' ) ) ) {
184
+ $prevent_php_style = "style='display:block'";
185
+ }
186
+ ?>
187
+ <div <?php echo $prevent_php_style; ?> class="hardener-instructions hardener-instructions-extra-exceptions">
188
+ <h3>
189
+ <?php _e( "Exceptions", wp_defender()->domain ) ?>
190
+ </h3>
191
+ <div class="line">
192
+ <p><?php _e( "By default Defender will lock down directories WordPress doesn't need to allow PHP execution for. However, if you have specific files you need to allow PHP execution for you can add exceptions. Add file name one per line", wp_defender()->domain ) ?></p>
193
+ <button class="button button-grey hardener-php-excuted-execption" type="button"><?php _e( "Add Exception", wp_defender()->domain ) ?></button>
194
+ </div>
195
+ <div class="line">
196
+ <textarea class="hardener-php-excuted-ignore" style='display:none'></textarea>
197
+ </div>
198
+ </div>
199
+ <?php endif; ?>
200
  </div>
201
  </div>
202
  </div>
app/module/ip-lockout/component/login-protection-api.php CHANGED
@@ -40,15 +40,13 @@ class Login_Protection_Api extends Component {
40
  }
41
  }
42
 
43
- $logs = Log_Model::findAll( array(
44
  'ip' => $log->ip,
45
  'type' => Log_Model::AUTH_FAIL,
46
  'blog_id' => get_current_blog_id(),
47
  'date' => array( 'compare' => '>=', 'value' => $after )
48
  ) );
49
 
50
-
51
- $attempt = count( $logs );
52
  if ( ! is_object( $model ) ) {
53
  //no record, create one
54
  $model = new IP_Model();
@@ -173,6 +171,7 @@ class Login_Protection_Api extends Component {
173
 
174
  /**
175
  * @param null $time - unix timestamp
 
176
  * @deprecated
177
  * @return int
178
  */
@@ -190,6 +189,7 @@ class Login_Protection_Api extends Component {
190
 
191
  /**
192
  * @param null $time - unix timestamp
 
193
  * @deprecated
194
  * @return int
195
  */
@@ -283,7 +283,7 @@ class Login_Protection_Api extends Component {
283
  $data[] = $line;
284
 
285
  }
286
- fclose( $file );
287
 
288
  return $data;
289
  }
@@ -385,4 +385,55 @@ class Login_Protection_Api extends Component {
385
 
386
  return false;
387
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  }
40
  }
41
  }
42
 
43
+ $attempt = Log_Model::count( array(
44
  'ip' => $log->ip,
45
  'type' => Log_Model::AUTH_FAIL,
46
  'blog_id' => get_current_blog_id(),
47
  'date' => array( 'compare' => '>=', 'value' => $after )
48
  ) );
49
 
 
 
50
  if ( ! is_object( $model ) ) {
51
  //no record, create one
52
  $model = new IP_Model();
171
 
172
  /**
173
  * @param null $time - unix timestamp
174
+ *
175
  * @deprecated
176
  * @return int
177
  */
189
 
190
  /**
191
  * @param null $time - unix timestamp
192
+ *
193
  * @deprecated
194
  * @return int
195
  */
283
  $data[] = $line;
284
 
285
  }
286
+ fclose( $fp );
287
 
288
  return $data;
289
  }
385
 
386
  return false;
387
  }
388
+
389
+ /**
390
+ *
391
+ */
392
+ public static function createTables() {
393
+ global $wpdb;
394
+
395
+ $charsetCollate = $wpdb->get_charset_collate();
396
+ $tableName1 = $wpdb->base_prefix . 'defender_lockout';
397
+ $tableName2 = $wpdb->base_prefix . 'defender_lockout_log';
398
+ $sql = "CREATE TABLE IF NOT EXISTS `{$tableName1}` (
399
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
400
+ `ip` varchar(255) DEFAULT NULL,
401
+ `status` varchar(16) DEFAULT NULL,
402
+ `lockout_message` text,
403
+ `release_time` int(11) DEFAULT NULL,
404
+ `lock_time` int(11) DEFAULT NULL,
405
+ `lock_time_404` int(11) DEFAULT NULL,
406
+ `attempt` int(11) DEFAULT NULL,
407
+ `attempt_404` int(11) DEFAULT NULL,
408
+ PRIMARY KEY (`id`)
409
+ ) $charsetCollate;
410
+ CREATE TABLE `{$tableName2}` (
411
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
412
+ `log` text,
413
+ `ip` varchar(255) DEFAULT NULL,
414
+ `date` int(11) DEFAULT NULL,
415
+ `type` varchar(16) DEFAULT NULL,
416
+ `user_agent` varchar(255) DEFAULT NULL,
417
+ `blog_id` int(11) DEFAULT NULL,
418
+ PRIMARY KEY (`id`)
419
+ ) $charsetCollate;
420
+ ";
421
+ require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
422
+ dbDelta( $sql );
423
+ }
424
+
425
+ /**
426
+ * @return bool
427
+ */
428
+ public static function checkIfTableExists() {
429
+ global $wpdb;
430
+ $tableName1 = $wpdb->base_prefix . 'defender_lockout';
431
+ $tableName2 = $wpdb->base_prefix . 'defender_lockout_log';
432
+ if ( $wpdb->get_var( "SHOW TABLES LIKE '$tableName1'" ) != $tableName1 ||
433
+ $wpdb->get_var( "SHOW TABLES LIKE '$tableName2'" ) != $tableName2 ) {
434
+ return false;
435
+ }
436
+
437
+ return true;
438
+ }
439
  }
app/module/ip-lockout/controller/main.php CHANGED
@@ -8,13 +8,16 @@ namespace WP_Defender\Module\IP_Lockout\Controller;
8
  use Hammer\Helper\HTTP_Helper;
9
  use Hammer\Helper\Log_Helper;
10
  use Hammer\Helper\WP_Helper;
 
11
  use WP_Defender\Controller;
12
  use WP_Defender\Module\Audit\Component\Audit_API;
13
  use WP_Defender\Module\IP_Lockout\Behavior\IP_Lockout;
14
  use WP_Defender\Module\IP_Lockout\Component\Login_Protection_Api;
15
  use WP_Defender\Module\IP_Lockout\Component\Logs_Table;
16
  use WP_Defender\Module\IP_Lockout\Model\IP_Model;
 
17
  use WP_Defender\Module\IP_Lockout\Model\Log_Model;
 
18
  use WP_Defender\Module\IP_Lockout\Model\Settings;
19
  use WP_Defender\Vendor\Email_Search;
20
 
@@ -58,6 +61,7 @@ class Main extends Controller {
58
  $this->add_ajax_action( 'lockoutIPAction', 'lockoutIPAction' );
59
  $this->add_ajax_action( 'lockoutEmptyLogs', 'lockoutEmptyLogs' );
60
  $this->add_ajax_action( 'lockoutSummaryData', 'lockoutSummaryData' );
 
61
 
62
  $this->handleIpAction();
63
  $this->handleUserSearch();
@@ -72,8 +76,6 @@ class Main extends Controller {
72
  return;
73
  }
74
 
75
- $setting = Settings::instance();
76
-
77
  $lockouts = Log_Model::findAll( array(
78
  'type' => array(
79
  Log_Model::LOCKOUT_404,
@@ -81,9 +83,9 @@ class Main extends Controller {
81
  ),
82
  'date' => array(
83
  'compare' => '>=',
84
- 'value' => strtotime( 'first day of this month', current_time( 'timestamp' ) )
85
  )
86
- ), 'ID', 'DESC' );
87
 
88
  if ( count( $lockouts ) == 0 ) {
89
  $data = array(
@@ -105,7 +107,7 @@ class Main extends Controller {
105
  $lockout404ThisWeek = 0;
106
  //time
107
  $todayMidnight = strtotime( '-24 hours', current_time( 'timestamp' ) );
108
- $firstThisWeek = strtotime( 'monday this week', current_time( 'timestamp' ) );
109
  foreach ( $lockouts as $k => $log ) {
110
  //the other as DESC, so first will be last lockout
111
  if ( $k == 0 ) {
@@ -142,14 +144,9 @@ class Main extends Controller {
142
  return;
143
  }
144
 
145
- $perPage = 50;
146
-
147
- $logs = Log_Model::findAll( array(), 'ID', 'ASC', '0,' . $perPage );
148
- if ( count( $logs ) ) {
149
- foreach ( $logs as $log ) {
150
- $log->delete();
151
- }
152
- } else {
153
  wp_send_json_success( array(
154
  'message' => __( "Your logs have been successfully deleted.", wp_defender()->domain )
155
  ) );
@@ -243,24 +240,17 @@ class Main extends Controller {
243
  //if current user can logged in, and no blacklisted we don't need to check the ip
244
  return;
245
  }
246
- global $wpdb;
247
- //use raw queries here for faster
248
- if ( $this->isActivatedSingle() == false ) {
249
- switch_to_blog( 1 );
250
- }
251
- $sql = "SELECT ID FROM " . $wpdb->posts . " as t0," . $wpdb->postmeta . " as t1 WHERE t0.ID = t1.post_id AND t1.meta_key=%s and t1.meta_value=%s and t0.post_type=%s";
252
- $sql = $wpdb->prepare( $sql, "ip", $ip, "wd_ip_lockout" );
253
- $ID = $wpdb->get_var( $sql );
254
- if ( $this->isActivatedSingle() == false ) {
255
- restore_current_blog();
256
- }
257
- if ( $ID && is_object( ( $model = IP_Model::findByID( $ID ) ) ) ) {
258
- if ( $model->is_locked() ) {
259
- $this->renderPartial( 'locked', array(
260
- 'message' => $model->lockout_message
261
- ) );
262
- die;
263
- }
264
  }
265
  }
266
  }
@@ -302,6 +292,16 @@ class Main extends Controller {
302
  * Handle the logic here
303
  */
304
  private function handleIpAction() {
 
 
 
 
 
 
 
 
 
 
305
  $ip = $this->getUserIp();
306
  $settings = Settings::instance();
307
  if ( $settings->report ) {
@@ -315,6 +315,7 @@ class Main extends Controller {
315
  wp_clear_scheduled_hook( 'cleanUpOldLog' );
316
  wp_schedule_event( time(), 'hourly', 'cleanUpOldLog' );
317
  }
 
318
  $this->add_action( 'cleanUpOldLog', 'cleanUpOldLog' );
319
 
320
  if ( $settings->isWhitelist( $ip ) ) {
@@ -330,7 +331,7 @@ class Main extends Controller {
330
  '54.197.28.242',
331
  '54.221.174.186',
332
  '54.236.233.244',
333
- array_key_exists( 'SERVER_ADDR', $_SERVER ) ? $_SERVER['SERVER_ADDR'] : $_SERVER['LOCAL_ADDR']
334
  ) );
335
 
336
  if ( in_array( $ip, $arr ) ) {
@@ -365,18 +366,13 @@ class Main extends Controller {
365
  * cron for delete old log
366
  */
367
  public function cleanUpOldLog() {
368
- $logs = Log_Model::findAll( array(
 
369
  'date' => array(
370
  'compare' => '<=',
371
- 'value' => strtotime( apply_filters( 'ip_lockout_logs_store_backward', '-' . Settings::instance()->storage_days . ' days' ), current_time( 'timestamp' ) )
372
  ),
373
- ), null, null, 500 );
374
-
375
- if ( count( $logs ) ) {
376
- foreach ( $logs as $log ) {
377
- $log->delete();
378
- }
379
- }
380
  }
381
 
382
  /**
@@ -693,10 +689,14 @@ class Main extends Controller {
693
  * Add submit admin page
694
  */
695
  public function adminMenu() {
696
- $cap = is_multisite() ? 'manage_network_options' : 'manage_options';
 
 
 
 
697
  add_submenu_page( 'wp-defender', esc_html__( "IP Lockouts", wp_defender()->domain ), esc_html__( "IP Lockouts", wp_defender()->domain ), $cap, $this->slug, array(
698
  &$this,
699
- 'actionIndex'
700
  ) );
701
  }
702
 
@@ -785,6 +785,14 @@ class Main extends Controller {
785
  }
786
  }
787
 
 
 
 
 
 
 
 
 
788
  private function _renderSettings() {
789
  $this->render( 'settings', array(
790
  'settings' => Settings::instance()
@@ -838,4 +846,71 @@ class Main extends Controller {
838
  'email_search' => $this->email_search
839
  ) );
840
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
841
  }
8
  use Hammer\Helper\HTTP_Helper;
9
  use Hammer\Helper\Log_Helper;
10
  use Hammer\Helper\WP_Helper;
11
+ use WP_Defender\Behavior\Utils;
12
  use WP_Defender\Controller;
13
  use WP_Defender\Module\Audit\Component\Audit_API;
14
  use WP_Defender\Module\IP_Lockout\Behavior\IP_Lockout;
15
  use WP_Defender\Module\IP_Lockout\Component\Login_Protection_Api;
16
  use WP_Defender\Module\IP_Lockout\Component\Logs_Table;
17
  use WP_Defender\Module\IP_Lockout\Model\IP_Model;
18
+ use WP_Defender\Module\IP_Lockout\Model\IP_Model_Legacy;
19
  use WP_Defender\Module\IP_Lockout\Model\Log_Model;
20
+ use WP_Defender\Module\IP_Lockout\Model\Log_Model_Legacy;
21
  use WP_Defender\Module\IP_Lockout\Model\Settings;
22
  use WP_Defender\Vendor\Email_Search;
23
 
61
  $this->add_ajax_action( 'lockoutIPAction', 'lockoutIPAction' );
62
  $this->add_ajax_action( 'lockoutEmptyLogs', 'lockoutEmptyLogs' );
63
  $this->add_ajax_action( 'lockoutSummaryData', 'lockoutSummaryData' );
64
+ $this->add_ajax_action( 'migrateData', 'movingDataToTable' );
65
 
66
  $this->handleIpAction();
67
  $this->handleUserSearch();
76
  return;
77
  }
78
 
 
 
79
  $lockouts = Log_Model::findAll( array(
80
  'type' => array(
81
  Log_Model::LOCKOUT_404,
83
  ),
84
  'date' => array(
85
  'compare' => '>=',
86
+ 'value' => strtotime( '-30 days', current_time( 'timestamp' ) )
87
  )
88
+ ), 'id', 'DESC' );
89
 
90
  if ( count( $lockouts ) == 0 ) {
91
  $data = array(
107
  $lockout404ThisWeek = 0;
108
  //time
109
  $todayMidnight = strtotime( '-24 hours', current_time( 'timestamp' ) );
110
+ $firstThisWeek = strtotime( '-7 days', current_time( 'timestamp' ) );
111
  foreach ( $lockouts as $k => $log ) {
112
  //the other as DESC, so first will be last lockout
113
  if ( $k == 0 ) {
144
  return;
145
  }
146
 
147
+ $perPage = 500;
148
+ $count = Log_Model::deleteAll( array(), '0,' . $perPage );
149
+ if ( $count == 0 ) {
 
 
 
 
 
150
  wp_send_json_success( array(
151
  'message' => __( "Your logs have been successfully deleted.", wp_defender()->domain )
152
  ) );
240
  //if current user can logged in, and no blacklisted we don't need to check the ip
241
  return;
242
  }
243
+
244
+ $model = IP_Model::findOne( array(
245
+ 'ip' => $ip
246
+ ) );
247
+ if ( is_object( $model ) && $model->is_locked() ) {
248
+ header('HTTP/1.0 403 Forbidden');
249
+ header( 'Cache-Control: private' );
250
+ $this->renderPartial( 'locked', array(
251
+ 'message' => $model->lockout_message
252
+ ) );
253
+ die;
 
 
 
 
 
 
 
254
  }
255
  }
256
  }
292
  * Handle the logic here
293
  */
294
  private function handleIpAction() {
295
+ if ( get_site_option( 'defenderLockoutNeedUpdateLog' ) == 1 ) {
296
+ //we are migratng, so no record
297
+ return;
298
+ }
299
+
300
+ if ( ! Login_Protection_Api::checkIfTableExists() ) {
301
+ //no table logs, omething happen
302
+ return;
303
+ }
304
+
305
  $ip = $this->getUserIp();
306
  $settings = Settings::instance();
307
  if ( $settings->report ) {
315
  wp_clear_scheduled_hook( 'cleanUpOldLog' );
316
  wp_schedule_event( time(), 'hourly', 'cleanUpOldLog' );
317
  }
318
+
319
  $this->add_action( 'cleanUpOldLog', 'cleanUpOldLog' );
320
 
321
  if ( $settings->isWhitelist( $ip ) ) {
331
  '54.197.28.242',
332
  '54.221.174.186',
333
  '54.236.233.244',
334
+ array_key_exists( 'SERVER_ADDR', $_SERVER ) ? $_SERVER['SERVER_ADDR'] : ( isset( $_SERVER['LOCAL_ADDR'] ) ? $_SERVER['LOCAL_ADDR'] : null )
335
  ) );
336
 
337
  if ( in_array( $ip, $arr ) ) {
366
  * cron for delete old log
367
  */
368
  public function cleanUpOldLog() {
369
+ $timestamp = Utils::instance()->localToUtc( apply_filters( 'ip_lockout_logs_store_backward', '-' . Settings::instance()->storage_days . ' days' ) );
370
+ Log_Model::deleteAll( array(
371
  'date' => array(
372
  'compare' => '<=',
373
+ 'value' => $timestamp
374
  ),
375
+ ), '0,1000' );
 
 
 
 
 
 
376
  }
377
 
378
  /**
689
  * Add submit admin page
690
  */
691
  public function adminMenu() {
692
+ $cap = is_multisite() ? 'manage_network_options' : 'manage_options';
693
+ $action = "actionIndex";
694
+ if ( get_site_option( 'defenderLockoutNeedUpdateLog' ) == 1 ) {
695
+ $action = "actionMigration";
696
+ }
697
  add_submenu_page( 'wp-defender', esc_html__( "IP Lockouts", wp_defender()->domain ), esc_html__( "IP Lockouts", wp_defender()->domain ), $cap, $this->slug, array(
698
  &$this,
699
+ $action
700
  ) );
701
  }
702
 
785
  }
786
  }
787
 
788
+ /**
789
+ * Show the updating screen
790
+ */
791
+ public function actionMigration() {
792
+ $this->layout = null;
793
+ $this->render( 'migration' );
794
+ }
795
+
796
  private function _renderSettings() {
797
  $this->render( 'settings', array(
798
  'settings' => Settings::instance()
846
  'email_search' => $this->email_search
847
  ) );
848
  }
849
+
850
+ public function movingDataToTable() {
851
+ if ( ! $this->checkPermission() ) {
852
+ return;
853
+ }
854
+ $totalItems = get_site_option( 'defenderLogsTotal' );
855
+ $params = array(
856
+ 'date' => array(
857
+ 'compare' => '>=',
858
+ 'value' => strtotime( '-30 days' )
859
+ )
860
+ );
861
+ if ( $totalItems === false ) {
862
+ //get the total
863
+ $totalLogs = Log_Model_Legacy::count( $params );
864
+ $totalsIPs = IP_Model_Legacy::count();
865
+ //get the 200 items and import each time
866
+ update_site_option( 'defenderLogsTotal', $totalLogs + $totalsIPs );
867
+ //prevent timeout so we end here at the first time
868
+ wp_send_json_error( array(
869
+ 'progress' => 0
870
+ ) );
871
+ }
872
+
873
+ $logs = Log_Model_Legacy::findAll( $params, 'id', 'DESC', '0,50' );
874
+ $logs = array_filter( $logs );
875
+ $ips = IP_Model_Legacy::findAll( array(), 'id', 'DESC', '0,50' );
876
+ $ips = array_filter( $ips );
877
+ if ( is_array( $logs ) && count( $logs ) ) {
878
+ foreach ( $logs as $item ) {
879
+ $model = new Log_Model();
880
+ $data = $item->export();
881
+ unset( $data['id'] );
882
+ $model->import( $data );
883
+ $model->save();
884
+ $item->delete();
885
+ }
886
+ }
887
+
888
+ if ( is_array( $ips ) && count( $ips ) ) {
889
+ foreach ( $ips as $item ) {
890
+ $model = new IP_Model();
891
+ $data = $item->export();
892
+ unset( $data['id'] );
893
+ $model->import( $data );
894
+ $model->save();
895
+ $item->delete();
896
+ }
897
+ }
898
+
899
+ if ( empty( $logs ) && empty( $ips ) ) {
900
+ //all moved
901
+ delete_site_option( 'defenderLogsTotal' );
902
+ delete_site_option( 'defenderLogsMovedCount' );
903
+ delete_site_option( 'defenderLockoutNeedUpdateLog' );
904
+ wp_send_json_success( array(
905
+ 'message' => __( "Thanks for your patience. All sets!", wp_defender()->domain )
906
+ ) );
907
+ }
908
+
909
+ $count = get_site_option( 'defenderLogsMovedCount', 0 );
910
+ $count += 200;
911
+ update_site_option( 'defenderLogsMovedCount', $count );
912
+ wp_send_json_error( array(
913
+ 'progress' => round( ( $count / $totalItems ) * 200, 2 ) > 100 ? 100 : round( ( $count / $totalItems ) * 200, 2 )
914
+ ) );
915
+ }
916
  }
app/module/ip-lockout/js/script.js CHANGED
@@ -14,6 +14,27 @@ jQuery(function ($) {
14
  Defender.showNotification('error', data.data.message);
15
  }
16
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  //media uploader
18
  var mediaUploader;
19
  $('.file-picker').click(function () {
@@ -102,6 +123,13 @@ jQuery(function ($) {
102
  var that = $(this);
103
  cleaningLog(that);
104
  });
 
 
 
 
 
 
 
105
 
106
  function cleaningLog(button) {
107
  $.ajax({
@@ -161,7 +189,10 @@ WDIP.formHandler = function () {
161
  } else if (data.data != undefined && data.data.url != undefined) {
162
  location.href = data.data.url;
163
  } else {
164
- that.find('.button').removeAttr('disabled');
 
 
 
165
  jq('div.iplockout').trigger('form-submitted', [data, that])
166
  }
167
  }
@@ -186,6 +217,7 @@ WDIP.listenFilter = function () {
186
  inputs.on('click', function () {
187
  clearTimeout(typingTimer);
188
  });
 
189
  //user is "finished typing," do something
190
  function doneTyping() {
191
  //build query
14
  Defender.showNotification('error', data.data.message);
15
  }
16
  });
17
+ setTimeout(function () {
18
+ if ($('#moving-data').size() > 0) {
19
+ $('#moving-data').submit();
20
+ }
21
+ }, 1000);
22
+ $('div.iplockout').on('form-submitted', function (e, data, form) {
23
+ if (form.attr('id') != 'moving-data') {
24
+ return;
25
+ }
26
+ if (data.success == true) {
27
+ location.reload();
28
+ Defender.showNotification('success', data.data.message);
29
+ } else {
30
+ var progress = data.data.progress;
31
+ $('.scan-progress-text span').text(progress + '%');
32
+ $('.scan-progress-bar span').css('width', progress + '%');
33
+ setTimeout(function () {
34
+ $('#moving-data').submit();
35
+ }, 1000);
36
+ }
37
+ });
38
  //media uploader
39
  var mediaUploader;
40
  $('.file-picker').click(function () {
123
  var that = $(this);
124
  cleaningLog(that);
125
  });
126
+ if ($('#defLockoutUpgrade').size() > 0) {
127
+ $('body').addClass('wpmud');
128
+ WDP.showOverlay("#defLockoutUpgrade", {
129
+ title: 'Updating...',
130
+ class: 'no-close wp-defender'
131
+ });
132
+ }
133
 
134
  function cleaningLog(button) {
135
  $.ajax({
189
  } else if (data.data != undefined && data.data.url != undefined) {
190
  location.href = data.data.url;
191
  } else {
192
+ var buttons = that.find('.button');
193
+ if (buttons.size() > 0) {
194
+ buttons.removeAttr('disabled');
195
+ }
196
  jq('div.iplockout').trigger('form-submitted', [data, that])
197
  }
198
  }
217
  inputs.on('click', function () {
218
  clearTimeout(typingTimer);
219
  });
220
+
221
  //user is "finished typing," do something
222
  function doneTyping() {
223
  //build query
app/module/ip-lockout/model/ip-model-legacy.php ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Author: Hoang Ngo
5
+ */
6
+
7
+ namespace WP_Defender\Module\IP_Lockout\Model;
8
+
9
+ use Hammer\WP\Model;
10
+ use WP_Defender\Behavior\Utils;
11
+
12
+ /**
13
+ * Class IP_Model
14
+ * @package WP_Defender\Module\IP_Lockout\Model
15
+ * @deprecated 1.7
16
+ */
17
+ class IP_Model_Legacy extends Model {
18
+ const STATUS_BLOCKED = 'blocked', STATUS_NORMAL = 'normal';
19
+
20
+ static $post_type = 'wd_ip_lockout';
21
+
22
+ public $id;
23
+ public $ip;
24
+ public $status;
25
+ public $lockout_message;
26
+ public $release_time;
27
+ public $lock_time;
28
+ public $lock_time_404;
29
+ public $attempt;
30
+ public $attempt_404;
31
+
32
+ protected static function maps() {
33
+ return array(
34
+ 'id' => array(
35
+ 'type' => 'wp',
36
+ 'map' => 'ID'
37
+ ),
38
+ 'ip' => array(
39
+ 'type' => 'meta',
40
+ 'map' => 'ip'
41
+ ),
42
+ 'status' => array(
43
+ 'type' => 'meta',
44
+ 'map' => 'status'
45
+ ),
46
+ 'lockout_message' => array(
47
+ 'type' => 'meta',
48
+ 'map' => 'lockout_message'
49
+ ),
50
+ 'release_time' => array(
51
+ 'type' => 'meta',
52
+ 'map' => 'release_time'
53
+ ),
54
+ 'lock_time' => array(
55
+ 'type' => 'meta',
56
+ 'map' => 'lock_time'
57
+ ),
58
+ 'lock_time_404' => array(
59
+ 'type' => 'meta',
60
+ 'map' => 'lock_time_404'
61
+ ),
62
+ 'attempt' => array(
63
+ 'type' => 'meta',
64
+ 'map' => 'attempt'
65
+ ),
66
+ );
67
+ }
68
+
69
+
70
+ /**
71
+ * @return bool
72
+ */
73
+ public function is_locked() {
74
+ if ( $this->status == self::STATUS_BLOCKED ) {
75
+ if ( $this->release_time < time() ) {
76
+ //unlock it
77
+ $this->attempt = 0;
78
+ $this->status = self::STATUS_NORMAL;
79
+ $this->save();
80
+
81
+ return false;
82
+ } else {
83
+ return true;
84
+ }
85
+ }
86
+
87
+ return false;
88
+ }
89
+
90
+
91
+ /**
92
+ * @return array
93
+ */
94
+ public function events() {
95
+ $that = $this;
96
+
97
+ //becase we store all the logs in main blog, so in multisite we need to force to main when saving
98
+ return array(
99
+ self::EVENT_BEFORE_INSERT => array(
100
+ array(
101
+ function () use ( $that ) {
102
+ if ( Utils::instance()->isActivatedSingle() == false ) {
103
+ wp_defender()->global['oldBlog'] = get_current_blog_id();
104
+ switch_to_blog( 1 );
105
+ }
106
+ }
107
+ )
108
+ ),
109
+ self::EVENT_BEFORE_UPDATE => array(
110
+ array(
111
+ function () use ( $that ) {
112
+ if ( Utils::instance()->isActivatedSingle() == false ) {
113
+ wp_defender()->global['oldBlog'] = get_current_blog_id();
114
+ switch_to_blog( 1 );
115
+ }
116
+ }
117
+ )
118
+ ),
119
+ self::EVENT_AFTER_INSERT => array(
120
+ array(
121
+ function () use ( $that ) {
122
+ if ( Utils::instance()->isActivatedSingle() == false ) {
123
+ if ( isset( wp_defender()->global['oldBlog'] ) ) {
124
+ switch_to_blog( wp_defender()->global['oldBlog'] );
125
+ unset( wp_defender()->global['oldBlog'] );
126
+ }
127
+ }
128
+ }
129
+ )
130
+ ),
131
+ self::EVENT_AFTER_UPDATE => array(
132
+ array(
133
+ function () use ( $that ) {
134
+ if ( Utils::instance()->isActivatedSingle() == false ) {
135
+ if ( isset( wp_defender()->global['oldBlog'] ) ) {
136
+ switch_to_blog( wp_defender()->global['oldBlog'] );
137
+ unset( wp_defender()->global['oldBlog'] );
138
+ }
139
+ }
140
+ }
141
+ )
142
+ ),
143
+ self::EVENT_BEFORE_DELELTE => array(
144
+ array(
145
+ function () use ( $that ) {
146
+ if ( Utils::instance()->isActivatedSingle() == false ) {
147
+ wp_defender()->global['oldBlog'] = get_current_blog_id();
148
+ switch_to_blog( 1 );
149
+ }
150
+ }
151
+ )
152
+ ),
153
+ self::EVENT_AFTER_DELETE => array(
154
+ array(
155
+ function () use ( $that ) {
156
+ if ( Utils::instance()->isActivatedSingle() == false ) {
157
+ if ( isset( wp_defender()->global['oldBlog'] ) ) {
158
+ switch_to_blog( wp_defender()->global['oldBlog'] );
159
+ unset( wp_defender()->global['oldBlog'] );
160
+ }
161
+ }
162
+ }
163
+ )
164
+ ),
165
+ );
166
+ }
167
+ }
app/module/ip-lockout/model/ip-model.php CHANGED
@@ -6,13 +6,12 @@
6
 
7
  namespace WP_Defender\Module\IP_Lockout\Model;
8
 
9
- use Hammer\WP\Model;
10
- use WP_Defender\Behavior\Utils;
11
 
12
- class IP_Model extends Model {
13
  const STATUS_BLOCKED = 'blocked', STATUS_NORMAL = 'normal';
14
 
15
- static $post_type = 'wd_ip_lockout';
16
 
17
  public $id;
18
  public $ip;
@@ -24,44 +23,6 @@ class IP_Model extends Model {
24
  public $attempt;
25
  public $attempt_404;
26
 
27
- protected static function maps() {
28
- return array(
29
- 'id' => array(
30
- 'type' => 'wp',
31
- 'map' => 'ID'
32
- ),
33
- 'ip' => array(
34
- 'type' => 'meta',
35
- 'map' => 'ip'
36
- ),
37
- 'status' => array(
38
- 'type' => 'meta',
39
- 'map' => 'status'
40
- ),
41
- 'lockout_message' => array(
42
- 'type' => 'meta',
43
- 'map' => 'lockout_message'
44
- ),
45
- 'release_time' => array(
46
- 'type' => 'meta',
47
- 'map' => 'release_time'
48
- ),
49
- 'lock_time' => array(
50
- 'type' => 'meta',
51
- 'map' => 'lock_time'
52
- ),
53
- 'lock_time_404' => array(
54
- 'type' => 'meta',
55
- 'map' => 'lock_time_404'
56
- ),
57
- 'attempt' => array(
58
- 'type' => 'meta',
59
- 'map' => 'attempt'
60
- ),
61
- );
62
- }
63
-
64
-
65
  /**
66
  * @return bool
67
  */
@@ -81,82 +42,4 @@ class IP_Model extends Model {
81
 
82
  return false;
83
  }
84
-
85
-
86
- /**
87
- * @return array
88
- */
89
- public function events() {
90
- $that = $this;
91
-
92
- //becase we store all the logs in main blog, so in multisite we need to force to main when saving
93
- return array(
94
- self::EVENT_BEFORE_INSERT => array(
95
- array(
96
- function () use ( $that ) {
97
- if ( Utils::instance()->isActivatedSingle() == false ) {
98
- wp_defender()->global['oldBlog'] = get_current_blog_id();
99
- switch_to_blog( 1 );
100
- }
101
- }
102
- )
103
- ),
104
- self::EVENT_BEFORE_UPDATE => array(
105
- array(
106
- function () use ( $that ) {
107
- if ( Utils::instance()->isActivatedSingle() == false ) {
108
- wp_defender()->global['oldBlog'] = get_current_blog_id();
109
- switch_to_blog( 1 );
110
- }
111
- }
112
- )
113
- ),
114
- self::EVENT_AFTER_INSERT => array(
115
- array(
116
- function () use ( $that ) {
117
- if ( Utils::instance()->isActivatedSingle() == false ) {
118
- if ( isset( wp_defender()->global['oldBlog'] ) ) {
119
- switch_to_blog( wp_defender()->global['oldBlog'] );
120
- unset( wp_defender()->global['oldBlog'] );
121
- }
122
- }
123
- }
124
- )
125
- ),
126
- self::EVENT_AFTER_UPDATE => array(
127
- array(
128
- function () use ( $that ) {
129
- if ( Utils::instance()->isActivatedSingle() == false ) {
130
- if ( isset( wp_defender()->global['oldBlog'] ) ) {
131
- switch_to_blog( wp_defender()->global['oldBlog'] );
132
- unset( wp_defender()->global['oldBlog'] );
133
- }
134
- }
135
- }
136
- )
137
- ),
138
- self::EVENT_BEFORE_DELELTE => array(
139
- array(
140
- function () use ( $that ) {
141
- if ( Utils::instance()->isActivatedSingle() == false ) {
142
- wp_defender()->global['oldBlog'] = get_current_blog_id();
143
- switch_to_blog( 1 );
144
- }
145
- }
146
- )
147
- ),
148
- self::EVENT_AFTER_DELETE => array(
149
- array(
150
- function () use ( $that ) {
151
- if ( Utils::instance()->isActivatedSingle() == false ) {
152
- if ( isset( wp_defender()->global['oldBlog'] ) ) {
153
- switch_to_blog( wp_defender()->global['oldBlog'] );
154
- unset( wp_defender()->global['oldBlog'] );
155
- }
156
- }
157
- }
158
- )
159
- ),
160
- );
161
- }
162
  }
6
 
7
  namespace WP_Defender\Module\IP_Lockout\Model;
8
 
9
+ use Hammer\Base\DB_Model;
 
10
 
11
+ class IP_Model extends DB_Model {
12
  const STATUS_BLOCKED = 'blocked', STATUS_NORMAL = 'normal';
13
 
14
+ protected static $tableName = 'defender_lockout';
15
 
16
  public $id;
17
  public $ip;
23
  public $attempt;
24
  public $attempt_404;
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  /**
27
  * @return bool
28
  */
42
 
43
  return false;
44
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  }
app/module/ip-lockout/model/log-model-legacy.php ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Author: Hoang Ngo
5
+ */
6
+
7
+ namespace WP_Defender\Module\IP_Lockout\Model;
8
+
9
+ use Hammer\Helper\WP_Helper;
10
+ use Hammer\WP\Model;
11
+ use WP_Defender\Behavior\Utils;
12
+ use WP_Defender\Module\IP_Lockout\Component\Login_Protection_Api;
13
+ use WP_Defender\Module\IP_Lockout\Component\Logs_Table;
14
+
15
+ /**
16
+ * Class Log_Model_Legacy
17
+ * @package WP_Defender\Module\IP_Lockout\Model
18
+ * @deprecated 1.7
19
+ */
20
+ class Log_Model_Legacy extends Model {
21
+ const AUTH_FAIL = 'auth_fail', AUTH_LOCK = 'auth_lock', ERROR_404 = '404_error', LOCKOUT_404 = '404_lockout', ERROR_404_IGNORE = '404_error_ignore';
22
+ static $post_type = 'wd_iplockout_log';
23
+
24
+ public $id;
25
+ public $log;
26
+ public $ip;
27
+ public $date;
28
+ public $user_agent;
29
+ public $type;
30
+ public $blog_id;
31
+
32
+ protected static function maps() {
33
+ return array(
34
+ 'id' => array(
35
+ 'type' => 'wp',
36
+ 'map' => 'ID'
37
+ ),
38
+ 'log' => array(
39
+ 'type' => 'meta',
40
+ 'map' => 'log'
41
+ ),
42
+ 'ip' => array(
43
+ 'type' => 'meta',
44
+ 'map' => 'ip'
45
+ ),
46
+ 'date' => array(
47
+ 'type' => 'meta',
48
+ 'map' => 'date'
49
+ ),
50
+ 'type' => array(
51
+ 'type' => 'meta',
52
+ 'map' => 'type'
53
+ ),
54
+ 'user_agent' => array(
55
+ 'type' => 'meta',
56
+ 'map' => 'user_agent'
57
+ ),
58
+ 'blog_id' => array(
59
+ 'type' => 'meta',
60
+ 'map' => 'blog_id'
61
+ ),
62
+ );
63
+ }
64
+
65
+ /**
66
+ * @return string
67
+ */
68
+ public function get_ip() {
69
+ return esc_html( $this->ip );
70
+ }
71
+
72
+ /**
73
+ * @return string
74
+ */
75
+ public function get_log_text( $format = false ) {
76
+ if ( ! $format ) {
77
+ return esc_html( $this->log );
78
+ } else {
79
+ $text = sprintf( __( "Request for file <span class='log-text-table' tooltip='%s'>%s</span> which doesn't exist", wp_defender()->domain ), esc_attr( $this->log ), pathinfo( $this->log, PATHINFO_BASENAME ) );
80
+
81
+ return $text;
82
+ }
83
+ }
84
+
85
+ public function before_update() {
86
+ $this->blog_id = get_current_blog_id();
87
+ if ( Utils::instance()->isActivatedSingle() == false ) {
88
+ switch_to_blog( 1 );
89
+ }
90
+ }
91
+
92
+ public function before_insert() {
93
+ $this->blog_id = get_current_blog_id();
94
+ if ( Utils::instance()->isActivatedSingle() == false ) {
95
+ switch_to_blog( 1 );
96
+ }
97
+ }
98
+
99
+ /**
100
+ * @return string
101
+ */
102
+ public function get_date() {
103
+ return Utils::instance()->formatDateTime( date( 'Y-m-d H:i:s', $this->date ) );
104
+ }
105
+
106
+ /**
107
+ * @return mixed|null
108
+ */
109
+ public function get_type() {
110
+ $types = array(
111
+ 'auth_fail' => __( "Failed login attempts", wp_defender()->domain ),
112
+ 'auth_lock' => __( "Login lockout", wp_defender()->domain ),
113
+ '404_error' => __( "404 error", wp_defender()->domain ),
114
+ '404_error_ignore' => __( "404 error", wp_defender()->domain ),
115
+ '404_lockout' => __( "404 lockout", wp_defender()->domain )
116
+ );
117
+
118
+ if ( isset( $types[ $this->type ] ) ) {
119
+ return $types[ $this->type ];
120
+ }
121
+
122
+ return null;
123
+ }
124
+
125
+ /**
126
+ * @return array
127
+ */
128
+ public function events() {
129
+ $that = $this;
130
+
131
+ return array(
132
+ self::EVENT_BEFORE_INSERT => array(
133
+ array(
134
+ function () use ( $that ) {
135
+ $that->before_insert();
136
+ }
137
+ )
138
+ ),
139
+ self::EVENT_BEFORE_UPDATE => array(
140
+ array(
141
+ function () use ( $that ) {
142
+ $that->before_update();
143
+ }
144
+ )
145
+ ),
146
+ self::EVENT_AFTER_INSERT => array(
147
+ array(
148
+ function () use ( $that ) {
149
+ if ( Utils::instance()->isActivatedSingle() == false ) {
150
+ switch_to_blog( $that->blog_id );
151
+ }
152
+ }
153
+ )
154
+ ),
155
+ self::EVENT_AFTER_UPDATE => array(
156
+ array(
157
+ function () use ( $that ) {
158
+ if ( Utils::instance()->isActivatedSingle() == false ) {
159
+ switch_to_blog( $that->blog_id );
160
+ }
161
+ }
162
+ )
163
+ )
164
+ );
165
+ }
166
+ }
app/module/ip-lockout/model/log-model.php CHANGED
@@ -6,15 +6,12 @@
6
 
7
  namespace WP_Defender\Module\IP_Lockout\Model;
8
 
9
- use Hammer\Helper\WP_Helper;
10
- use Hammer\WP\Model;
11
  use WP_Defender\Behavior\Utils;
12
- use WP_Defender\Module\IP_Lockout\Component\Login_Protection_Api;
13
- use WP_Defender\Module\IP_Lockout\Component\Logs_Table;
14
 
15
- class Log_Model extends Model {
16
  const AUTH_FAIL = 'auth_fail', AUTH_LOCK = 'auth_lock', ERROR_404 = '404_error', LOCKOUT_404 = '404_lockout', ERROR_404_IGNORE = '404_error_ignore';
17
- static $post_type = 'wd_iplockout_log';
18
 
19
  public $id;
20
  public $log;
@@ -24,39 +21,6 @@ class Log_Model extends Model {
24
  public $type;
25
  public $blog_id;
26
 
27
- protected static function maps() {
28
- return array(
29
- 'id' => array(
30
- 'type' => 'wp',
31
- 'map' => 'ID'
32
- ),
33
- 'log' => array(
34
- 'type' => 'meta',
35
- 'map' => 'log'
36
- ),
37
- 'ip' => array(
38
- 'type' => 'meta',
39
- 'map' => 'ip'
40
- ),
41
- 'date' => array(
42
- 'type' => 'meta',
43
- 'map' => 'date'
44
- ),
45
- 'type' => array(
46
- 'type' => 'meta',
47
- 'map' => 'type'
48
- ),
49
- 'user_agent' => array(
50
- 'type' => 'meta',
51
- 'map' => 'user_agent'
52
- ),
53
- 'blog_id' => array(
54
- 'type' => 'meta',
55
- 'map' => 'blog_id'
56
- ),
57
- );
58
- }
59
-
60
  /**
61
  * @return string
62
  */
@@ -83,9 +47,6 @@ class Log_Model extends Model {
83
 
84
  public function before_insert() {
85
  $this->blog_id = get_current_blog_id();
86
- //update cache total
87
- $cache = WP_Helper::getCache();
88
- $cache->increase( Login_Protection_Api::COUNT_TOTAL, 1 );
89
  }
90
 
91
  /**
6
 
7
  namespace WP_Defender\Module\IP_Lockout\Model;
8
 
9
+ use Hammer\Base\DB_Model;
 
10
  use WP_Defender\Behavior\Utils;
 
 
11
 
12
+ class Log_Model extends DB_Model {
13
  const AUTH_FAIL = 'auth_fail', AUTH_LOCK = 'auth_lock', ERROR_404 = '404_error', LOCKOUT_404 = '404_lockout', ERROR_404_IGNORE = '404_error_ignore';
14
+ protected static $tableName = 'defender_lockout_log';
15
 
16
  public $id;
17
  public $log;
21
  public $type;
22
  public $blog_id;
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  /**
25
  * @return string
26
  */
47
 
48
  public function before_insert() {
49
  $this->blog_id = get_current_blog_id();
 
 
 
50
  }
51
 
52
  /**
app/module/ip-lockout/model/settings.php CHANGED
@@ -302,7 +302,7 @@ class Settings extends \Hammer\WP\Settings {
302
  } elseif ( stristr( $ip, '-' ) ) {
303
  $ips = explode( '-', $ip );
304
  foreach ( $ips as $ip ) {
305
- if ( ! filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) || ! filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
306
  return false;
307
  }
308
  }
302
  } elseif ( stristr( $ip, '-' ) ) {
303
  $ips = explode( '-', $ip );
304
  foreach ( $ips as $ip ) {
305
+ if ( ! filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) && ! filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
306
  return false;
307
  }
308
  }
app/module/ip-lockout/view/layouts/layout.php CHANGED
@@ -18,7 +18,7 @@
18
  <div class="clear"></div>
19
  <span class="sub"><?php _e( "Lockouts in the past 24 hours", wp_defender()->domain ) ?></span>
20
  <h6 class="lockoutThisMonth">.</h6>
21
- <span class="sub"><?php _e( "Total lockouts this month", wp_defender()->domain ) ?></span>
22
  </div>
23
  </div>
24
  <div class="column is-5">
@@ -31,13 +31,13 @@
31
  </li>
32
  <li>
33
  <div>
34
- <span class="list-label"><?php _e( "Login lockouts this week", wp_defender()->domain ) ?></span>
35
  <span class="list-detail loginLockoutThisWeek">.</span>
36
  </div>
37
  </li>
38
  <li>
39
  <div>
40
- <span class="list-label"><?php _e( "404 lockouts this week", wp_defender()->domain ) ?></span>
41
  <span class="list-detail lockout404ThisWeek">.</span>
42
  </div>
43
  </li>
18
  <div class="clear"></div>
19
  <span class="sub"><?php _e( "Lockouts in the past 24 hours", wp_defender()->domain ) ?></span>
20
  <h6 class="lockoutThisMonth">.</h6>
21
+ <span class="sub"><?php _e( "Total lockouts in the past 30 days", wp_defender()->domain ) ?></span>
22
  </div>
23
  </div>
24
  <div class="column is-5">
31
  </li>
32
  <li>
33
  <div>
34
+ <span class="list-label"><?php _e( "Login lockouts in the past 7 days", wp_defender()->domain ) ?></span>
35
  <span class="list-detail loginLockoutThisWeek">.</span>
36
  </div>
37
  </li>
38
  <li>
39
  <div>
40
+ <span class="list-label"><?php _e( "404 lockouts in the past 7 days", wp_defender()->domain ) ?></span>
41
  <span class="list-detail lockout404ThisWeek">.</span>
42
  </div>
43
  </li>
app/module/ip-lockout/view/locked.php CHANGED
@@ -1,77 +1,78 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title><?php esc_html_e( "WP Defender", wp_defender()->domain ) ?></title>
7
- <link rel="stylesheet"
8
- href="https://fonts.googleapis.com/css?family=Roboto+Condensed:400,700|Roboto:400,500,300,300italic">
9
- <style type="text/css">
10
- html, body {
11
- margin: 0;
12
- padding: 0;
 
13
 
14
- min-width: 100%;
15
- width: 100%;
16
- max-width: 100%;
17
 
18
- min-height: 100%;
19
- height: 100%;
20
- max-height: 100%;
21
- }
22
 
23
- .wp-defender {
24
- height: 100%;
25
- display: flex;
26
- align-items: center;
27
- font-family: Roboto;
28
- color: #000;
29
- font-size: 13px;
30
- line-height: 18px;
31
- }
32
 
33
- .container {
34
- margin: 0 auto;
35
- text-align: center;
36
- }
37
 
38
- .image {
39
- width: 128px;
40
- height: 128px;
41
- background-color: #F2F2F2;
42
- margin: 0 auto;
43
- border-radius: 50%;
44
- background-image: url("<?php echo wp_defender()->getPluginUrl().'assets/img/def-stand.svg' ?>");
45
- background-repeat: no-repeat;
46
- background-size: contain;
47
- margin-bottom: 30px;
48
- }
49
 
50
- .powered {
51
- position: absolute;
52
- bottom: 20px;
53
- display: block;
54
- text-align: center;
55
- width: 100%;
56
- font-size: 10px;
57
- color: #C0C0C0;
58
- }
59
 
60
- .powered strong {
61
- color: #8A8A8A;
62
- font-weight: normal;
63
- }
64
- </style>
65
  </head>
66
  <body>
67
  <div class="wp-defender">
68
- <div class="container">
69
- <div class="image">
70
- </div>
71
- <p><?php echo $message ?></p>
72
- </div>
73
- <div class="powered"><?php esc_html_e( "Powered by", wp_defender()->domain ) ?>
74
- <strong><?php esc_html_e( "Defender", wp_defender()->domain ) ?></strong></div>
75
  </div>
76
  </body>
77
  </html>
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta http-equiv="Cache-control" content="max-age=0">
7
+ <title><?php esc_html_e( "WP Defender", wp_defender()->domain ) ?></title>
8
+ <link rel="stylesheet"
9
+ href="https://fonts.googleapis.com/css?family=Roboto+Condensed:400,700|Roboto:400,500,300,300italic">
10
+ <style type="text/css">
11
+ html, body {
12
+ margin: 0;
13
+ padding: 0;
14
 
15
+ min-width: 100%;
16
+ width: 100%;
17
+ max-width: 100%;
18
 
19
+ min-height: 100%;
20
+ height: 100%;
21
+ max-height: 100%;
22
+ }
23
 
24
+ .wp-defender {
25
+ height: 100%;
26
+ display: flex;
27
+ align-items: center;
28
+ font-family: Roboto;
29
+ color: #000;
30
+ font-size: 13px;
31
+ line-height: 18px;
32
+ }
33
 
34
+ .container {
35
+ margin: 0 auto;
36
+ text-align: center;
37
+ }
38
 
39
+ .image {
40
+ width: 128px;
41
+ height: 128px;
42
+ background-color: #F2F2F2;
43
+ margin: 0 auto;
44
+ border-radius: 50%;
45
+ background-image: url("<?php echo wp_defender()->getPluginUrl().'assets/img/def-stand.svg' ?>");
46
+ background-repeat: no-repeat;
47
+ background-size: contain;
48
+ margin-bottom: 30px;
49
+ }
50
 
51
+ .powered {
52
+ position: absolute;
53
+ bottom: 20px;
54
+ display: block;
55
+ text-align: center;
56
+ width: 100%;
57
+ font-size: 10px;
58
+ color: #C0C0C0;
59
+ }
60
 
61
+ .powered strong {
62
+ color: #8A8A8A;
63
+ font-weight: normal;
64
+ }
65
+ </style>
66
  </head>
67
  <body>
68
  <div class="wp-defender">
69
+ <div class="container">
70
+ <div class="image">
71
+ </div>
72
+ <p><?php echo $message ?></p>
73
+ </div>
74
+ <div class="powered"><?php esc_html_e( "Powered by", wp_defender()->domain ) ?>
75
+ <strong><?php esc_html_e( "Defender", wp_defender()->domain ) ?></strong></div>
76
  </div>
77
  </body>
78
  </html>
app/module/ip-lockout/view/migration.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wrap">
2
+ <div id="wp-defender" class="wp-defender">
3
+ <div class="iplockout">
4
+ <div class="advanced-tools">
5
+ <h2 class="title">
6
+ <?php _e( "Migration", wp_defender()->domain ) ?>
7
+ </h2>
8
+ </div>
9
+ </div>
10
+ </div>
11
+ </div>
12
+
13
+ <dialog id="defLockoutUpgrade">
14
+ <div class="line">
15
+ <?php _e( "Please hold on, we are updating your data, please don't close this tab...", wp_defender()->domain ) ?>
16
+ </div>
17
+ <div class="well mline">
18
+ <div class="scan-progress">
19
+ <div class="scan-progress-text">
20
+ <img src="<?php echo wp_defender()->getPluginUrl() ?>assets/img/loading.gif" width="18"
21
+ height="18"/>
22
+ <span>0%</span>
23
+ </div>
24
+ <div class="scan-progress-bar">
25
+ <span style="width: 0%"></span>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ <form method="post" id="moving-data" class="ip-frm">
30
+ <input type="hidden" name="action" value="migrateData"/>
31
+ <?php
32
+ wp_nonce_field( 'processScan' );
33
+ ?>
34
+ </form>
35
+ </dialog>
app/module/ip-lockout/view/notification/report-free.php CHANGED
@@ -76,7 +76,7 @@
76
  </form>
77
  <div class="presale-text">
78
  <div>
79
- <?php printf( __( "Schedule automated file scanning and email reporting for all your websites. This feature is included in a WPMU DEV membership along with 100+ plugins & themes, 24/7 support and lots of handy site management tools – <a href=\"%s\">Try it all FREE today!</a>", wp_defender()->domain ), "https://premium.wpmudev.org/project/wp-defender/" ) ?>
80
  </div>
81
  </div>
82
  </div>
76
  </form>
77
  <div class="presale-text">
78
  <div>
79
+ <?php printf( __( "Schedule automated file scanning and email reporting for all your websites. This feature is included in a WPMU DEV membership along with 100+ plugins & themes, 24/7 support and lots of handy site management tools – <a href=\"%s\">Try it all FREE today!</a>", wp_defender()->domain ), "https://premium.wpmudev.org/project/wp-defender/?utm_source=defender&utm_medium=plugin&utm_campaign=defender_modal_upgrade" ) ?>
80
  </div>
81
  </div>
82
  </div>
app/module/ip-lockout/view/pro-feature.php CHANGED
@@ -32,7 +32,7 @@
32
  </p>
33
  </div>
34
  <div class="tc">
35
- <a class="button button-green mline" href="https://premium.wpmudev.org/project/wp-defender/"><?php _e( "Get Defender Pro for Free", wp_defender()->domain ) ?></a>
36
  <p class="is-marginless"><?php _e( "As part part of a WPMU DEV free trial.", wp_defender()->domain ) ?></p>
37
  </div>
38
  </div>
32
  </p>
33
  </div>
34
  <div class="tc">
35
+ <a class="button button-green mline" href="https://premium.wpmudev.org/project/wp-defender/?utm_source=defender&utm_medium=plugin&utm_campaign=defender_modal_upgrade"><?php _e( "Get Defender Pro for Free", wp_defender()->domain ) ?></a>
36
  <p class="is-marginless"><?php _e( "As part part of a WPMU DEV free trial.", wp_defender()->domain ) ?></p>
37
  </div>
38
  </div>
app/module/scan/behavior/core-result.php CHANGED
@@ -70,14 +70,20 @@ class Core_Result extends Behavior {
70
  //remove the file first
71
  $raw = $this->getRaw();
72
  if ( $raw['type'] == 'unknown' ) {
73
- @unlink( $raw['file'] );
 
 
 
74
  $this->getOwner()->delete();
75
 
76
  return true;
77
  } elseif ( $raw['type'] == 'modified' ) {
78
  return new \WP_Error( Error_Code::INVALID, __( "This file can't not remove", wp_defender()->domain ) );
79
  } elseif ( $raw['type'] == 'dir' ) {
80
- $this->deleteFolder( $raw['file'] );
 
 
 
81
  $this->getOwner()->delete();
82
 
83
  return true;
@@ -90,7 +96,7 @@ class Core_Result extends Behavior {
90
  */
91
  public function resolve() {
92
  $originSrc = $this->getOriginalSource();
93
- $raw = $this->getRaw();
94
  if ( $raw['type'] != 'modified' ) {
95
  return new \WP_Error( Error_Code::INVALID, __( "This file is not resolvable", wp_defender()->domain ) );
96
  }
@@ -391,11 +397,19 @@ class Core_Result extends Behavior {
391
  \RecursiveIteratorIterator::CHILD_FIRST );
392
  foreach ( $files as $file ) {
393
  if ( $file->isDir() ) {
394
- @rmdir( $file->getRealPath() );
395
  } else {
396
- @unlink( $file->getRealPath() );
 
 
 
397
  }
398
  }
399
- @rmdir( $dir );
 
 
 
 
 
400
  }
401
  }
70
  //remove the file first
71
  $raw = $this->getRaw();
72
  if ( $raw['type'] == 'unknown' ) {
73
+ $res = unlink( $raw['file'] );
74
+ if ( $res == false ) {
75
+ return new \WP_Error( Error_Code::NOT_WRITEABLE, __( "Defender doesn't have enough permission to remove this file", wp_defender()->domain ) );
76
+ }
77
  $this->getOwner()->delete();
78
 
79
  return true;
80
  } elseif ( $raw['type'] == 'modified' ) {
81
  return new \WP_Error( Error_Code::INVALID, __( "This file can't not remove", wp_defender()->domain ) );
82
  } elseif ( $raw['type'] == 'dir' ) {
83
+ $res = $this->deleteFolder( $raw['file'] );
84
+ if ( is_wp_error( $res ) ) {
85
+ return $res;
86
+ }
87
  $this->getOwner()->delete();
88
 
89
  return true;
96
  */
97
  public function resolve() {
98
  $originSrc = $this->getOriginalSource();
99
+ $raw = $this->getRaw();
100
  if ( $raw['type'] != 'modified' ) {
101
  return new \WP_Error( Error_Code::INVALID, __( "This file is not resolvable", wp_defender()->domain ) );
102
  }
397
  \RecursiveIteratorIterator::CHILD_FIRST );
398
  foreach ( $files as $file ) {
399
  if ( $file->isDir() ) {
400
+ $res = @rmdir( $file->getRealPath() );
401
  } else {
402
+ $res = @unlink( $file->getRealPath() );
403
+ }
404
+ if ( $res == false ) {
405
+ return new \WP_Error( Error_Code::NOT_WRITEABLE, __( "Defender doesn't have enough permission to remove this file", wp_defender()->domain ) );
406
  }
407
  }
408
+ $res = @rmdir( $dir );
409
+ if ( $res == false ) {
410
+ return new \WP_Error( Error_Code::NOT_WRITEABLE, __( "Defender doesn't have enough permission to remove this file", wp_defender()->domain ) );
411
+ }
412
+
413
+ return true;
414
  }
415
  }
app/module/scan/component/scan-api.php CHANGED
@@ -323,8 +323,16 @@ class Scan_Api extends Component {
323
  if ( is_array( self::$ignoreList ) ) {
324
  return self::$ignoreList;
325
  }
326
- $cache = Container::instance()->get( 'cache' );
327
- $ids = $cache->get( self::IGNORE_LIST, array() );
 
 
 
 
 
 
 
 
328
  if ( empty( $ids ) ) {
329
  self::$ignoreList = array();
330
 
@@ -337,6 +345,7 @@ class Scan_Api extends Component {
337
 
338
  self::$ignoreList = $ignoreList;
339
 
 
340
  return $ignoreList;
341
  }
342
 
@@ -364,10 +373,18 @@ class Scan_Api extends Component {
364
  * @param $id
365
  */
366
  public static function indexIgnore( $id ) {
367
- $cache = Container::instance()->get( 'cache' );
368
- $ids = $cache->get( self::IGNORE_LIST, array() );
 
 
 
 
 
 
 
 
369
  $ids[] = $id;
370
- $cache->set( self::IGNORE_LIST, $ids );
371
  }
372
 
373
  /**
@@ -376,10 +393,18 @@ class Scan_Api extends Component {
376
  * @param $id
377
  */
378
  public static function unIndexIgnore( $id ) {
379
- $cache = Container::instance()->get( 'cache' );
380
- $ids = $cache->get( self::IGNORE_LIST, array() );
 
 
 
 
 
 
 
 
381
  unset( $ids[ array_search( $id, $ids ) ] );
382
- $cache->set( self::IGNORE_LIST, $ids );
383
  }
384
 
385
  /**
323
  if ( is_array( self::$ignoreList ) ) {
324
  return self::$ignoreList;
325
  }
326
+
327
+ $ids = get_site_option( self::IGNORE_LIST );
328
+ if ( $ids == false ) {
329
+ $cache = Container::instance()->get( 'cache' );
330
+ $ids = $cache->get( self::IGNORE_LIST, array() );
331
+ update_site_option( self::IGNORE_LIST, $ids );
332
+ } elseif ( ! is_array( $ids ) ) {
333
+ $ids = unserialize( $ids );
334
+ }
335
+
336
  if ( empty( $ids ) ) {
337
  self::$ignoreList = array();
338
 
345
 
346
  self::$ignoreList = $ignoreList;
347
 
348
+
349
  return $ignoreList;
350
  }
351
 
373
  * @param $id
374
  */
375
  public static function indexIgnore( $id ) {
376
+ $ids = get_site_option( self::IGNORE_LIST );
377
+ if ( $ids == false ) {
378
+ $cache = Container::instance()->get( 'cache' );
379
+ $ids = $cache->get( self::IGNORE_LIST, array() );
380
+ } elseif ( ! is_array( $ids ) ) {
381
+ $ids = unserialize( $ids );
382
+ }
383
+ if ( ! is_array( $ids ) ) {
384
+ $ids = array();
385
+ }
386
  $ids[] = $id;
387
+ update_site_option( self::IGNORE_LIST, $ids );
388
  }
389
 
390
  /**
393
  * @param $id
394
  */
395
  public static function unIndexIgnore( $id ) {
396
+ $ids = get_site_option( self::IGNORE_LIST );
397
+ if ( $ids == false ) {
398
+ $cache = Container::instance()->get( 'cache' );
399
+ $ids = $cache->get( self::IGNORE_LIST, array() );
400
+ } elseif ( ! is_array( $ids ) ) {
401
+ $ids = unserialize( $ids );
402
+ }
403
+ if ( ! is_array( $ids ) ) {
404
+ $ids = array();
405
+ }
406
  unset( $ids[ array_search( $id, $ids ) ] );
407
+ update_site_option( self::IGNORE_LIST, $ids );
408
  }
409
 
410
  /**
app/module/scan/controller/main.php CHANGED
@@ -53,7 +53,6 @@ class Main extends \WP_Defender\Controller {
53
  $this->add_ajax_action( 'ignoreItem', 'ignoreItem' );
54
  $this->add_ajax_action( 'unIgnoreItem', 'unIgnoreItem' );
55
  $this->add_ajax_action( 'deleteItem', 'deleteItem' );
56
- $this->add_ajax_action( 'deleteItem', 'deleteItem' );
57
  $this->add_ajax_action( 'resolveItem', 'resolveItem' );
58
  $this->add_ajax_action( 'saveScanSettings', 'saveScanSettings' );
59
  $this->add_ajax_action( 'scanBulkAction', 'scanBulkAction' );
53
  $this->add_ajax_action( 'ignoreItem', 'ignoreItem' );
54
  $this->add_ajax_action( 'unIgnoreItem', 'unIgnoreItem' );
55
  $this->add_ajax_action( 'deleteItem', 'deleteItem' );
 
56
  $this->add_ajax_action( 'resolveItem', 'resolveItem' );
57
  $this->add_ajax_action( 'saveScanSettings', 'saveScanSettings' );
58
  $this->add_ajax_action( 'scanBulkAction', 'scanBulkAction' );
app/module/scan/view/automation-free.php CHANGED
@@ -60,7 +60,7 @@
60
  </form>
61
  <div class="presale-text">
62
  <div>
63
- <?php printf( __( "Schedule automated file scanning and email reporting for all your websites. This feature is included in a WPMU DEV membership along with 100+ plugins & themes, 24/7 support and lots of handy site management tools – <a href=\"%s\">Try it all FREE today!</a>", wp_defender()->domain ), "https://premium.wpmudev.org/project/wp-defender/" ) ?>
64
  </div>
65
  </div>
66
  </div>
60
  </form>
61
  <div class="presale-text">
62
  <div>
63
+ <?php printf( __( "Schedule automated file scanning and email reporting for all your websites. This feature is included in a WPMU DEV membership along with 100+ plugins & themes, 24/7 support and lots of handy site management tools – <a href=\"%s\">Try it all FREE today!</a>", wp_defender()->domain ), "https://premium.wpmudev.org/project/wp-defender/?utm_source=defender&utm_medium=plugin&utm_campaign=defender_modal_upgrade" ) ?>
64
  </div>
65
  </div>
66
  </div>
app/module/scan/view/pro-feature.php CHANGED
@@ -32,7 +32,7 @@
32
  </p>
33
  </div>
34
  <div class="tc">
35
- <a class="button button-green mline" href="https://premium.wpmudev.org/project/wp-defender/"><?php _e( "Get Defender Pro for Free", wp_defender()->domain ) ?></a>
36
  <p class="is-marginless"><?php _e( "As part part of a WPMU DEV free trial.", wp_defender()->domain ) ?></p>
37
  </div>
38
  </div>
32
  </p>
33
  </div>
34
  <div class="tc">
35
+ <a class="button button-green mline" href="https://premium.wpmudev.org/project/wp-defender/?utm_source=defender&utm_medium=plugin&utm_campaign=defender_modal_upgrade"><?php _e( "Get Defender Pro for Free", wp_defender()->domain ) ?></a>
36
  <p class="is-marginless"><?php _e( "As part part of a WPMU DEV free trial.", wp_defender()->domain ) ?></p>
37
  </div>
38
  </div>
app/module/scan/view/setting-free.php CHANGED
@@ -59,7 +59,7 @@
59
  <div class="presale-text">
60
  <div>
61
  <?php printf( __( "Defenders scans through every line of code on your website, searching for anything suspicious. This feature is included when you join WPMU DEV, along with 100+ plugins and themes, 24/7 support and lots of handy site management tools. – <a href=\"%s\">Try it all FREE today!
62
- </a>", wp_defender()->domain ), "https://premium.wpmudev.org/project/wp-defender/" ) ?>
63
  </div>
64
  </div>
65
  </div>
59
  <div class="presale-text">
60
  <div>
61
  <?php printf( __( "Defenders scans through every line of code on your website, searching for anything suspicious. This feature is included when you join WPMU DEV, along with 100+ plugins and themes, 24/7 support and lots of handy site management tools. – <a href=\"%s\">Try it all FREE today!
62
+ </a>", wp_defender()->domain ), "https://premium.wpmudev.org/project/wp-defender/?utm_source=defender&utm_medium=plugin&utm_campaign=defender_modal_upgrade" ) ?>
63
  </div>
64
  </div>
65
  </div>
app/view/pro-feature.php CHANGED
@@ -32,7 +32,7 @@
32
  </p>
33
  </div>
34
  <div class="tc">
35
- <a class="button button-green mline" href="https://premium.wpmudev.org/project/wp-defender/"><?php _e( "Get Defender Pro for Free", wp_defender()->domain ) ?></a>
36
  <p class="is-marginless"><?php _e( "As part part of a WPMU DEV free trial.", wp_defender()->domain ) ?></p>
37
  </div>
38
  </div>
32
  </p>
33
  </div>
34
  <div class="tc">
35
+ <a class="button button-green mline" href="https://premium.wpmudev.org/project/wp-defender/?utm_source=defender&utm_medium=plugin&utm_campaign=defender_modal_upgrade"><?php _e( "Get Defender Pro for Free", wp_defender()->domain ) ?></a>
36
  <p class="is-marginless"><?php _e( "As part part of a WPMU DEV free trial.", wp_defender()->domain ) ?></p>
37
  </div>
38
  </div>
assets/css/defender-icon.css CHANGED
@@ -1,3 +1,17 @@
1
  #toplevel_page_wp-defender > ul > li.wp-first-item > a > span {
2
  display: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  }
1
  #toplevel_page_wp-defender > ul > li.wp-first-item > a > span {
2
  display: none;
3
+ }
4
+
5
+ .def-oval {
6
+ -webkit-border-radius: 5px;
7
+ -moz-border-radius: 5px;
8
+ border-radius: 5px;
9
+ width: 10px;
10
+ height: 10px;
11
+ background-color: #E6E6E6;
12
+ display: block;
13
+ }
14
+
15
+ .def-oval.oval-green {
16
+ background-color: #1ABC9C;
17
  }
assets/css/styles.css CHANGED
@@ -2287,6 +2287,16 @@
2287
  font-family: Roboto, sans-serif; }
2288
  .wp-defender .wpmudev-register div label span {
2289
  font-weight: 400; }
 
 
 
 
 
 
 
 
 
 
2290
  .wp-defender .toggle-row {
2291
  display: none; }
2292
  @media screen and (min-width: 769px) and (max-width: 979px) {
2287
  font-family: Roboto, sans-serif; }
2288
  .wp-defender .wpmudev-register div label span {
2289
  font-weight: 400; }
2290
+ .wp-defender .advanced-tools .row > .col-third {
2291
+ width: 25%; }
2292
+ .wp-defender .advanced-tools .row > .col-two-third {
2293
+ width: 75%; }
2294
+ .wp-defender .advanced-tools i.icon-warning:not(.fill-red) {
2295
+ background: url("../img/wpmud-icon-warning-yellow.svg") no-repeat;
2296
+ mask: none;
2297
+ -webkit-mask: none; }
2298
+ .wp-defender .advanced-tools .toggle .toggle-label:after {
2299
+ left: 0; }
2300
  .wp-defender .toggle-row {
2301
  display: none; }
2302
  @media screen and (min-width: 769px) and (max-width: 979px) {
assets/img/2factor-disabled.svg ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg width="128px" height="128px" viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
+ <!-- Generator: Sketch 45.1 (43504) - http://www.bohemiancoding.com/sketch -->
4
+ <title>graphic-defender-2factor-disabled</title>
5
+ <desc>Created with Sketch.</desc>
6
+ <defs>
7
+ <circle id="path-1" cx="64" cy="64" r="64"></circle>
8
+ <polygon id="path-3" points="0.327466846 0.3500558 3.88734603 0.3500558 3.88734603 21.3428699 0.327466846 21.3428699 0.327466846 0.3500558"></polygon>
9
+ <polygon id="path-5" points="51.1257801 0.184853857 51.1257801 49.0738103 0.330536413 49.0738103 0.330536413 0.184853857"></polygon>
10
+ </defs>
11
+ <g id="Security-Plugin" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
12
+ <g id="Advanced-Tools---2-Factor---Disabled" transform="translate(-726.000000, -223.000000)">
13
+ <g id="graphic-defender-2factor-disabled" transform="translate(726.000000, 223.000000)">
14
+ <mask id="mask-2" fill="white">
15
+ <use xlink:href="#path-1"></use>
16
+ </mask>
17
+ <use id="mask" fill="#333333" xlink:href="#path-1"></use>
18
+ <g id="graphic" mask="url(#mask-2)">
19
+ <g transform="translate(-6.000000, 10.000000)">
20
+ <path d="M39.4062404,173.10829 C44.5020972,174.081424 53.4377494,173.063861 54.0267519,168.804431 C53.575243,166.584784 53.2010742,166.272707 53.2010742,166.272707 C53.2010742,166.272707 66.6772379,143.156842 65.7953453,123.921688 C64.9134527,104.686534 45.3095141,107.332196 45.3095141,107.332196 C45.3095141,107.332196 37.373913,118.626064 34.904757,136.272889 C32.4359591,153.919715 37.417954,162.29669 37.417954,162.29669 C37.417954,162.29669 35.7354476,166.837383 34.6032737,173.249817 C34.7436317,172.456549 34.891867,171.690869 35.044399,170.959585 C35.3802558,171.617418 36.4050128,172.535016 39.4062404,173.10829" id="Fill-19" fill="#9F5622"></path>
21
+ <path d="M98.7215192,173.10829 C93.6256624,174.081424 84.6900102,173.063861 84.1006496,168.804431 C84.5525166,166.584784 84.9266854,166.272707 84.9266854,166.272707 C84.9266854,166.272707 71.4505217,143.156842 72.3324143,123.921688 C73.2143069,104.686534 92.8182455,107.332196 92.8182455,107.332196 C92.8182455,107.332196 100.753847,118.626064 103.223003,136.272889 C105.691801,153.919715 100.709806,162.29669 100.709806,162.29669 C100.709806,162.29669 102.392312,166.837383 103.524486,173.249817 C103.384128,172.456549 103.235893,171.690869 103.083361,170.959585 C102.747504,171.617418 101.722747,172.535016 98.7215192,173.10829" id="Fill-77" fill="#9F5622"></path>
22
+ <path d="M45.5730793,111.169696 C44.4412634,111.145332 43.5396777,111.197643 42.9821841,111.245655 C42.9291918,111.344187 42.8747673,111.447376 42.8207008,111.549132 C45.055688,112.721121 54.9878107,118.292633 62.1181432,128.225332 C63.6098056,130.696504 64.5615192,132.467564 65.1673504,133.735218 C65.5007008,131.627717 65.7244859,129.513409 65.8032583,127.424898 C60.5981944,123.105273 50.4301125,115.602542 45.5730793,111.169696" id="Fill-123" fill="#98480C"></path>
23
+ <path d="M95.3429003,111.617065 C95.2684246,111.475897 95.1939488,111.334728 95.1216215,111.200725 C91.5313913,110.649665 73.9902148,108.978569 72.3789616,128.537265 C72.495688,130.435162 72.7262762,132.348825 73.0445882,134.254963 C74.7668389,130.825706 78.878399,123.432255 86.114,117.877224 C91.3011611,113.894757 94.0055601,112.275973 95.3429003,111.617065" id="Fill-125" fill="#98480C"></path>
24
+ <path d="M100.613739,76.4418678 C106.021821,71.862837 111.178547,67.119348 111.178547,67.119348 L111.178547,70.2465609 C119.016399,59.9806461 122.406118,48.4047988 122.238905,47.40121 C122.0409,46.2105903 119.117013,44.801768 115.563662,39.7637592 C102.081412,32.6214743 69.0639693,25.4283113 69.0639693,25.4283113 C69.0639693,25.4283113 38.0946087,33.1162819 24.6123581,40.2589251 C19.0610537,41.4491865 16.0870384,46.2105903 15.8886752,47.40121 C15.7228951,48.3961997 19.056399,59.7882408 26.7553248,69.9896623 L28.2978312,69.1609222 L36.5098517,74.7177445 L31.6094936,75.5826725 C31.6728696,75.6457327 31.7355294,75.7095095 31.7996215,75.7722115 C34.3769105,77.9549545 35.7650946,78.1530925 35.7650946,78.1530925 C35.7650946,78.1530925 39.7799795,83.113351 42.1592634,84.5021087 C49.0983939,85.69237 69.0639693,85.2437827 69.0639693,85.2437827 C69.0639693,85.2437827 89.0291867,85.69237 95.9686752,84.5021087 C98.3479591,83.113351 102.362844,78.1530925 102.362844,78.1530925 C102.362844,78.1530925 102.51645,78.1298032 102.810414,78.0230308 C100.344123,78.2670308 98.7471918,78.0223142 100.613739,76.4418678" id="Fill-127" fill="#9F5622"></path>
25
+ <path d="M82.4067212,34.5627971 L69.0637545,31.4660394 L55.7211458,34.5627971 L55.499509,37.0296693 C55.499509,37.0296693 60.1549565,40.9662743 62.0845217,42.1733756 C64.014087,43.3804769 65.8169003,45.3865797 65.8169003,45.3865797 L66.623601,45.9931759 L69.0637545,45.9931759 L71.504266,45.9931759 L72.3109668,45.3865797 C72.3109668,45.3865797 74.1137801,43.3804769 76.0433453,42.1733756 C77.9729105,40.9662743 82.6283581,37.0296693 82.6283581,37.0296693 L82.4067212,34.5627971 Z" id="Fill-129" fill="#98480C"></path>
26
+ <path d="M68.0702916,21.3509674 C67.9360205,19.1470849 67.4053811,10.2917838 67.2954578,6.37237709 C67.2199079,3.67010396 67.526046,1.65253568 67.7824143,0.467290455 C66.6745882,0.59090279 64.8008798,0.851026138 61.97689,1.39993656 C56.8996522,2.38740206 54.2400102,7.87149016 54.2400102,10.2297985 C54.2400102,10.8908558 54.3234373,13.0567589 54.4491151,15.8432317 C54.0899847,16.1409762 53.6216471,16.6067618 53.5629258,17.0546326 C53.5396522,17.2334226 53.5503939,17.6859512 53.5840512,18.2839483 C54.0459437,18.8876781 54.4791918,19.419032 54.620624,19.4867501 C54.9657903,19.6515665 57.1918261,24.4624153 59.2427724,26.2796957 C60.7566343,27.6215166 62.5981176,28.5348147 63.6006752,28.9748029 C63.6364808,28.837217 63.6726445,28.6996311 63.7095243,28.5631201 C64.6053811,25.2481598 66.7372481,22.5136399 68.0702916,21.3509674" id="Fill-131" fill="#FF5B0C"></path>
27
+ <path d="M60.4257545,37.7939518 C61.9381841,38.0959959 62.4806394,33.2980458 63.6006394,28.9748388 C62.5980818,28.5348505 60.7565985,27.6215524 59.2427366,26.2797316 C57.1917903,24.4624511 54.9657545,19.6516023 54.6205882,19.4867859 C54.479156,19.4190678 54.0459079,18.8873557 53.5843734,18.2839841 C53.6896419,20.1528593 54.0201279,23.4516963 54.2399744,24.3241486 C54.4308184,25.0815877 54.7480563,25.5523894 54.943555,25.7877903 C55.1963427,30.4553204 55.4437596,34.4015994 55.5458056,34.6309093 C55.6782864,34.9297286 60.6420205,37.9225803 60.4257545,37.7939518" id="Fill-133" fill="#FFBC00"></path>
28
+ <path d="M70.0574322,21.3509674 C70.1917033,19.1470849 70.7223427,10.2917838 70.832266,6.37237709 C70.9078159,3.67010396 70.6016777,1.65253568 70.3453095,0.467290455 C71.4531355,0.59090279 73.326844,0.851026138 76.1508338,1.39993656 C81.2280716,2.38740206 83.8877136,7.87149016 83.8877136,10.2297985 C83.8877136,10.8908558 83.8042864,13.0567589 83.6786087,15.8432317 C84.0377391,16.1409762 84.5060767,16.6067618 84.564798,17.0546326 C84.5880716,17.2334226 84.5773299,17.6859512 84.5436726,18.2839483 C84.0817801,18.8876781 83.648532,19.419032 83.5070997,19.4867501 C83.1619335,19.6515665 80.9358977,24.4624153 78.8849514,26.2796957 C77.3710895,27.6215166 75.5296061,28.5348147 74.5270486,28.9748029 C74.491243,28.837217 74.4550793,28.6996311 74.4181995,28.5631201 C73.5223427,25.2481598 71.3904757,22.5136399 70.0574322,21.3509674" id="Fill-135" fill="#FF5B0C"></path>
29
+ <g id="Group-139" stroke-width="1" fill="none" transform="translate(66.956522, 0.008241)">
30
+ <mask id="mask-4" fill="white">
31
+ <use xlink:href="#path-3"></use>
32
+ </mask>
33
+ <g id="Clip-138"></g>
34
+ <path d="M3.38871611,0.459192952 C2.50431714,0.361019677 2.10723274,0.349912482 2.10723274,0.349912482 C2.10723274,0.349912482 1.71050639,0.361019677 0.826107417,0.459192952 C0.569381074,1.64443818 0.263601023,3.66200646 0.339150895,6.36392129 C0.449074169,10.2836863 0.979713555,19.1386291 1.1136266,21.3428699 C1.55976471,20.9537598 1.91638875,20.7405733 2.10723274,20.7405733 C2.29843478,20.7405733 2.65505882,20.9537598 3.10083887,21.3428699 C3.23510997,19.1386291 3.76574936,10.2836863 3.87567263,6.36392129 C3.95122251,3.66200646 3.6450844,1.64443818 3.38871611,0.459192952" id="Fill-137" fill="#FFBC00" mask="url(#mask-4)"></path>
35
+ </g>
36
+ <path d="M63.7094527,29.1566743 C64.6053095,25.841714 66.7371765,23.1071941 68.0702199,21.9445216 C68.5163581,21.5554115 68.8729821,21.342225 69.0638261,21.342225 C69.2546701,21.342225 69.6112941,21.5554115 70.0574322,21.9445216 C71.3904757,23.1071941 73.5223427,25.841714 74.4181995,29.1566743 C74.4550793,29.2931853 74.491243,29.4304129 74.5270486,29.5683571 C75.471601,33.2143836 76.0054629,37.1982837 77.0567161,38.1753586 C77.2002967,38.0908006 77.3413708,38.0080341 77.4860256,37.9224012 C77.5579949,37.8797639 77.6299642,37.8367683 77.7019335,37.7937727 C76.1895038,38.096175 75.6470486,33.2978667 74.5270486,28.9746596 C74.491243,28.8370737 74.4550793,28.6998461 74.4181995,28.5629768 C73.5223427,25.2480164 71.3904757,22.5134966 70.0574322,21.3508241 C69.6112941,20.9620722 69.2546701,20.7488858 69.0638261,20.7488858 C68.8729821,20.7488858 68.5163581,20.9620722 68.0702199,21.3508241 C66.7371765,22.5134966 64.6053095,25.2480164 63.7094527,28.5629768 C63.6725729,28.6998461 63.6364092,28.8370737 63.6006036,28.9746596 C62.4806036,33.2978667 61.9381483,38.096175 60.4257187,37.7937727 C60.497688,37.8367683 60.5696573,37.8797639 60.6419847,37.9224012 C60.7862813,38.0080341 60.9273555,38.0908006 61.0709361,38.1753586 C62.1221893,37.1982837 62.6560512,33.2143836 63.6006036,29.5683571 C63.6364092,29.4304129 63.6725729,29.2931853 63.7094527,29.1566743" id="Fill-140" fill="#98480C"></path>
37
+ <path d="M62.1412379,38.8049932 C62.167734,38.8204 62.1938721,38.8358068 62.2207263,38.8512135 C62.3263529,38.9128405 62.4305473,38.973751 62.5336675,39.0339448 C62.5648184,39.0518596 62.5959693,39.0701327 62.6267621,39.0880476 C62.7220051,39.1432253 62.8154578,39.1976863 62.9078363,39.2514308 C62.9414936,39.2707789 62.975867,39.2904852 63.0091662,39.3098332 C63.249422,39.4492106 63.4789361,39.5817803 63.6941279,39.7053927 C63.7188338,39.7197245 63.7424655,39.7329815 63.7668133,39.7469551 C63.8502404,39.7949668 63.9318772,39.8419037 64.0106496,39.8866907 C64.0378619,39.9024558 64.0647161,39.9175043 64.0912123,39.932911 C64.1606752,39.9723236 64.2272737,40.0103031 64.2920818,40.0475659 C64.3232327,40.0651225 64.3550997,40.0830373 64.3851765,40.1002355 C64.4507008,40.1374984 64.5126445,40.1726115 64.573156,40.2070079 C64.5928491,40.2181151 64.6146905,40.2306555 64.6340256,40.2414044 C64.713156,40.2861915 64.7876317,40.3277539 64.8563785,40.3664499 C64.8678363,40.3728993 64.8775038,40.3782737 64.8886036,40.3843648 C64.9430281,40.41482 64.9938721,40.4434837 65.0407775,40.4692811 C65.0608286,40.4803883 65.0787315,40.4904206 65.0973504,40.5004529 C65.1320818,40.5198009 65.1639488,40.5373574 65.1936675,40.5534808 C65.2108542,40.5627965 65.2273248,40.5717539 65.2427212,40.5799947 C65.2695754,40.5946849 65.2928491,40.6072253 65.3143325,40.6183325 C65.3250742,40.6240652 65.3372481,40.6305145 65.3469156,40.6355307 C65.3741279,40.6495043 65.3966854,40.6609698 65.4102916,40.6674191 C65.8940256,40.8866966 69.0638977,40.9963354 69.0638977,40.9963354 C69.0638977,40.9963354 72.2337698,40.8866966 72.7175038,40.6674191 C72.73111,40.6609698 72.7536675,40.6495043 72.7808798,40.6355307 C72.7905473,40.6305145 72.8027212,40.6240652 72.8134629,40.6183325 C72.8349463,40.6072253 72.8582199,40.5946849 72.8850742,40.5799947 C72.9004706,40.5717539 72.9169412,40.5627965 72.9341279,40.5534808 C72.9638465,40.5373574 72.9957136,40.5198009 73.030445,40.5004529 C73.0490639,40.4904206 73.0669668,40.4803883 73.0870179,40.4692811 C73.1339233,40.4434837 73.1847673,40.41482 73.2391918,40.3843648 C73.2502916,40.3782737 73.2599591,40.3728993 73.2714169,40.3664499 C73.3401637,40.3277539 73.4146394,40.2861915 73.4937698,40.2414044 C73.5131049,40.2306555 73.5345882,40.2181151 73.5546394,40.2070079 C73.6151509,40.1726115 73.6770946,40.1374984 73.7426189,40.1002355 C73.7726957,40.0830373 73.8045627,40.0651225 73.8357136,40.0475659 C73.9005217,40.0103031 73.9671202,39.9723236 74.0365831,39.932911 C74.0630793,39.9175043 74.0899335,39.9024558 74.1171458,39.8866907 C74.1959182,39.8419037 74.277555,39.7949668 74.3609821,39.7469551 C74.3853299,39.7329815 74.4089616,39.7197245 74.4336675,39.7053927 C74.6488593,39.5817803 74.8783734,39.4492106 75.1186292,39.3098332 C75.1519284,39.2904852 75.1863018,39.2707789 75.2199591,39.2514308 C75.3123376,39.1976863 75.4057903,39.1432253 75.5010332,39.0880476 C75.5318261,39.0701327 75.562977,39.0518596 75.5941279,39.0339448 C75.6972481,38.973751 75.8014425,38.9128405 75.9070691,38.8512135 C75.9339233,38.8358068 75.9600614,38.8204 75.9865575,38.8049932 C76.1265575,38.7229433 76.2687059,38.6401768 76.4119284,38.5559771 C76.6231816,38.4320065 76.8408798,38.3030197 77.0567877,38.1754661 C76.0055345,37.1983912 75.4716726,33.214491 74.5271202,29.5684646 C74.4913146,29.4305204 74.4551509,29.2932928 74.4182711,29.1567818 C73.5224143,25.8418214 71.3905473,23.1073016 70.0575038,21.9446291 C69.6113657,21.5555189 69.2547417,21.3423325 69.0638977,21.3423325 C68.8730537,21.3423325 68.5164297,21.5555189 68.0702916,21.9446291 C66.7372481,23.1073016 64.6053811,25.8418214 63.7095243,29.1567818 C63.6726445,29.2932928 63.6364808,29.4305204 63.6006752,29.5684646 C62.6561228,33.214491 62.1222609,37.1983912 61.0710077,38.1754661 C61.2869156,38.3030197 61.5046138,38.4320065 61.715867,38.5559771 C61.8590895,38.6401768 62.0012379,38.7229433 62.1412379,38.8049932" id="Fill-142" fill="#9F5622"></path>
38
+ <path d="M77.7019693,37.7939518 C76.1895396,38.0959959 75.6470844,33.2980458 74.5270844,28.9748388 C75.5296419,28.5348505 77.3711253,27.6215524 78.8849872,26.2797316 C80.9359335,24.4624511 83.1619693,19.6516023 83.5071355,19.4867859 C83.6485678,19.4190678 84.0818159,18.8873557 84.5433504,18.2839841 C84.4380818,20.1528593 84.1075959,23.4516963 83.8877494,24.3241486 C83.6969054,25.0815877 83.3796675,25.5523894 83.1841688,25.7877903 C82.9313811,30.4553204 82.6839642,34.4015994 82.5819182,34.6309093 C82.4494373,34.9297286 77.4857033,37.9225803 77.7019693,37.7939518" id="Fill-144" fill="#FFBC00"></path>
39
+ <path d="M69.0638619,21.8109128 C68.2421228,21.7654091 66.4196164,23.9409862 66.6924552,24.9556822 C67.0827366,25.1900082 69.2282097,25.7364106 69.9690281,25.7364106 C70.7102046,25.7364106 72.3092839,25.1423548 72.1921995,24.6196 C72.0751151,24.0968452 70.07,21.866807 69.0638619,21.8109128" id="Fill-146" fill="#98480C"></path>
40
+ <path d="M64.7448082,30.6150849 C64.6058824,31.069405 64.9764706,29.5201304 65.1325831,28.9748029 C65.2883376,28.4294755 67.8713555,27.6487471 69.9538107,27.6487471 C72.036266,27.6487471 73.3231202,26.9987971 73.7914578,28.0457398 C74.2594373,29.0926825 74.2984655,29.4832258 74.2984655,29.4832258 C74.2984655,29.4832258 73.442711,28.7806062 73.3829156,28.5853345 C73.3231202,28.3904211 72.9722251,28.8153609 70.4758568,29.0321304 C67.9798465,29.2488999 66.0295141,28.7763066 65.8343734,29.0321304 C65.6395908,29.2879542 64.864399,30.2248999 64.7448082,30.6150849" id="Fill-148" fill="#98480C"></path>
41
+ <path d="M69.5063836,31.2004341 C70.2028031,30.4981727 70.5533402,29.6393357 71.7431611,29.795553 C72.9333402,29.951412 73.7135448,31.9030537 73.0890946,31.7858907 C72.4653606,31.6687278 71.5598363,31.1613797 71.4080205,31.1613797 C71.2562046,31.1613797 69.5063836,31.2004341 69.5063836,31.2004341" id="Fill-150" fill="#98480C"></path>
42
+ <path d="M57.8664041,17.6369721 C57.6744859,17.2525198 63.2447673,17.2084493 63.8488082,17.2084493 C64.452491,17.2084493 66.2810844,16.8429868 66.3372992,17.4502996 C66.3935141,18.057254 64.961289,20.6258825 64.2179642,20.8125551 C63.4746394,20.9995859 59.2184246,20.3456946 57.8664041,17.6369721" id="Fill-152" fill="#1F191A"></path>
43
+ <path d="M80.294046,17.7116769 C80.4859642,17.3272247 75.1308747,17.0724758 74.5271918,17.0724758 C73.923509,17.0724758 71.8739949,16.8159354 71.8181381,17.4232482 C71.7619233,18.0302026 73.1937903,20.5988311 73.9374731,20.785862 C74.680798,20.9725345 78.9416675,20.4203994 80.294046,17.7116769" id="Fill-154" fill="#1F191A"></path>
44
+ <path d="M94.7082813,75.6808458 L100.201223,76.8281116 C100.313652,76.7091571 100.449355,76.5808869 100.613703,76.4418678 C106.021785,71.862837 111.178512,67.119348 111.178512,67.119348 L111.178512,70.2465609 C113.456465,67.263025 115.355954,64.1702085 116.904189,61.2568987 L113.182194,53.8505492 C113.182194,53.8505492 102.36424,53.9677122 100.094164,55.6234009 C97.824445,57.2787313 100.595801,60.469721 100.410685,62.0906549 C99.873243,66.7954479 98.0990742,68.495207 98.0990742,68.495207 C98.0990742,68.495207 99.141376,69.1168517 99.186133,71.0294391 C99.23089,72.9416681 97.5168747,73.5661791 94.7082813,75.6808458" id="Fill-156" fill="#98480C"></path>
45
+ <path d="M41.3225575,68.7320053 C40.1828645,67.469368 38.6013299,59.9103841 38.6013299,59.9103841 C38.3517647,55.955506 39.2884399,55.7545016 38.5798465,55.100252 C37.8712532,54.4456441 34.6555499,56.6817733 34.6555499,56.6817733 L28.4719182,69.2784076 L36.5099233,74.718067 L31.6095652,75.5826367 C31.6729412,75.6456969 31.735601,75.7094737 31.7996931,75.7721756 C32.8820972,76.6890567 33.7518159,77.2526573 34.4002558,77.6016382 C36.4322251,77.7782784 46.7392327,78.5643812 44.5751407,76.1523283 C42.1772379,73.4801521 41.0565217,70.5345956 41.3225575,68.7320053" id="Fill-158" fill="#98480C"></path>
46
+ <path d="M35.7649872,78.1532358 C35.7649872,78.1532358 40.873734,79.3065927 45.099156,79.6104282 C49.3249361,79.914622 55.3284655,73.2814767 69.0638619,73.2814767 L69.0638619,74.2209304 C69.0638619,74.2209304 58.0801279,76.5702814 48.5239642,81.1858584 C47.5575703,81.7383518 37.5058568,80.2886837 35.7649872,78.1532358" id="Fill-160" fill="#98480C"></path>
47
+ <path d="M39.5202097,79.7762479 C39.5202097,79.7762479 40.3763223,82.7332699 41.895555,83.1481774 C40.6248133,83.8113844 37.0517698,81.6279248 36.5096726,78.4494755 C39.503023,79.3061627 39.5202097,79.7762479 39.5202097,79.7762479" id="Fill-162" fill="#98480C"></path>
48
+ <path d="M66.0684706,45.7797028 C66.2947621,45.9380699 59.2184962,42.6288423 38.4469361,41.7442079 C35.2981893,41.9100993 37.1761944,40.6940405 39.2203376,40.1963665 C41.2644808,39.6986925 51.6499028,36.547832 52.9206445,35.884625 C54.1913862,35.2210596 55.9036113,34.9448129 54.578087,36.4926543 C53.2522046,38.0404957 45.6284706,40.4174355 44.523509,40.8043959 C43.4189054,41.1913562 61.0965013,42.2970596 66.0684706,45.7797028" id="Fill-164" fill="#98480C"></path>
49
+ <path d="M30.8233811,67.6705874 C36.5096726,68.1127254 57.8924348,69.0525374 67.1732532,66.399351 C64.5218465,68.0575477 60.2677801,69.3291424 50.0477801,69.3291424 C39.8277801,69.3291424 31.5412839,68.7762907 30.8233811,67.6705874" id="Fill-166" fill="#98480C"></path>
50
+ <path d="M102.362772,78.1532358 C102.362772,78.1532358 97.2540256,79.3065927 93.0286036,79.6104282 C88.8028235,79.914622 82.7992941,73.2814767 69.0638977,73.2814767 L69.0638977,74.2209304 C69.0638977,74.2209304 80.0476317,76.5702814 89.6037954,81.1858584 C90.5701893,81.7383518 100.621903,80.2886837 102.362772,78.1532358" id="Fill-168" fill="#98480C"></path>
51
+ <path d="M98.6075499,79.7762479 C98.6075499,79.7762479 97.7514373,82.7332699 96.2322046,83.1481774 C97.5029463,83.8113844 101.07599,81.6279248 101.618087,78.4494755 C98.6247366,79.3061627 98.6075499,79.7762479 98.6075499,79.7762479" id="Fill-170" fill="#98480C"></path>
52
+ <path d="M72.059289,45.7797028 C71.8329974,45.9380699 78.9092634,42.6288423 99.6808235,41.7442079 C102.829928,41.9100993 100.951565,40.6940405 98.907422,40.1963665 C96.8632788,39.6986925 86.4778568,36.547832 85.2071151,35.884625 C83.9363734,35.2210596 82.2241483,34.9448129 83.5496726,36.4926543 C84.875555,38.0404957 92.499289,40.4174355 93.6042506,40.8043959 C94.7088542,41.1913562 77.0312583,42.2970596 72.059289,45.7797028" id="Fill-172" fill="#98480C"></path>
53
+ <path d="M107.304414,67.6705874 C101.618123,68.1127254 80.2353606,69.0525374 70.9541841,66.399351 C73.6059488,68.0575477 77.8600153,69.3291424 88.0800153,69.3291424 C98.3000153,69.3291424 106.586153,68.7762907 107.304414,67.6705874" id="Fill-174" fill="#98480C"></path>
54
+ <path d="M69.2970997,45.2821363 C69.2970997,43.7894725 69.0640051,43.3473345 69.0640051,43.3473345 C69.0640051,43.3473345 68.8305524,43.7894725 68.8305524,45.2821363 C68.8305524,46.7748 68.1122916,62.6401744 68.0571509,63.3033815 C68.0020102,63.9669468 68.5788389,64.3539072 69.0640051,64.3539072 C69.5488133,64.3539072 70.1256419,63.9669468 70.0705013,63.3033815 C70.0153606,62.6401744 69.2970997,46.7748 69.2970997,45.2821363" id="Fill-176" fill="#98480C"></path>
55
+ <path d="M93.986046,104.143571 L69.0638977,104.143571 L44.1417494,104.143571 L42.3571969,111.286214 C55.8394476,115.253991 65.4145882,130.614526 65.4145882,130.614526 C65.4145882,130.614526 66.9416982,131.919442 69.0638977,131.919442 C71.1860972,131.919442 72.7132072,130.614526 72.7132072,130.614526 C72.7132072,130.614526 82.2883478,115.253991 95.7702404,111.286214 L93.986046,104.143571 Z" id="Fill-178" fill="#1F191A"></path>
56
+ <path d="M96.7585115,83.8684969 L95.9686394,84.5019653 C95.9686394,84.5019653 90.2730384,85.0311695 69.0639335,85.0311695 C47.8548286,85.0311695 42.1592276,84.5019653 42.1592276,84.5019653 L41.3693555,83.8684969 C41.3693555,83.8684969 40.0373862,84.4679272 40.4076164,86.8384176 C40.7015806,88.7241327 42.2261841,89.3593927 42.2261841,89.3593927 C42.2261841,89.3593927 42.8588696,98.5156628 42.7707877,99.2655777 C41.8455703,99.7062825 41.4048031,103.939199 44.1417852,104.143428 C52.4304297,104.480227 69.0639335,104.732826 69.0639335,104.732826 C69.0639335,104.732826 85.6970793,104.480227 93.9860818,104.143428 C96.7227059,103.939199 96.2822967,99.7062825 95.3567212,99.2655777 C95.2686394,98.5156628 95.9013248,89.3593927 95.9013248,89.3593927 C95.9013248,89.3593927 97.4259284,88.7241327 97.7202506,86.8384176 C98.0901228,84.4679272 96.7585115,83.8684969 96.7585115,83.8684969" id="Fill-180" fill="#FFBC00"></path>
57
+ <path d="M97.7202864,86.8382385 C98.0901586,84.4681063 96.7585473,83.8683178 96.7585473,83.8683178 L95.9686752,84.5017862 C95.9686752,84.5017862 90.2730742,85.0309903 69.0639693,85.0309903 C47.8548645,85.0309903 42.1592634,84.5017862 42.1592634,84.5017862 L41.3693913,83.8683178 C41.3693913,83.8683178 40.037422,84.4681063 40.4076522,86.8382385 C40.7016164,88.7239536 42.2262199,89.3595718 42.2262199,89.3595718 C42.2262199,89.3595718 42.4038159,91.9317833 42.5577801,94.4609991 C45.7312327,93.6591313 47.6615141,93.0145557 47.6615141,93.0145557 C47.6615141,93.0145557 53.1952737,93.8920241 54.7030486,93.7666203 C56.2111816,93.6412164 58.7168593,94.3932811 62.7260153,94.3932811 C66.7348133,94.3932811 68.5587519,92.3875366 68.5587519,92.3875366 C68.5587519,92.3875366 70.914046,92.2266614 70.9545064,90.8654925 C70.9759898,90.1331342 71.0651458,89.4874837 71.1761432,88.9102678 C71.0533299,90.2700035 71.8961944,89.7744793 72.5739949,90.3961239 C73.2528696,91.0188435 73.7000818,92.7748552 77.0260665,93.1779389 C80.3520512,93.5813809 83.7786496,91.7662502 85.0887775,91.6652106 C86.3989054,91.5645292 91.640133,92.1696922 92.696757,92.1696922 C92.9681637,92.1696922 94.0430486,92.4563295 95.6679079,92.8902267 C95.7903632,90.967607 95.9013606,89.3595718 95.9013606,89.3595718 C95.9013606,89.3595718 97.4259642,88.7239536 97.7202864,86.8382385" id="Fill-182" fill="#FF9000"></path>
58
+ <polygon id="Fill-184" fill="#98480C" points="70.36289 71.8627295 75.0011509 71.8627295 75.0011509 85.0161568 70.954399 85.0161568 70.0742967 78.0616194"></polygon>
59
+ <path d="M71.5167621,76.4331254 C71.5751253,74.6670814 69.7175294,74.374353 69.7483223,73.2815483 C69.7791151,72.1883853 71.3585013,72.839052 71.2346138,71.1969786 C71.1107263,69.5549051 68.8710844,67.5366203 67.1735396,67.8641034 C66.80689,67.4789345 66.6210588,66.1464294 66.2186036,65.7745175 C65.8161483,65.4029639 64.1440256,65.3409786 63.3079642,65.6817186 C62.4719028,66.0224587 62.1005985,66.6423119 60.7378363,66.983052 C59.3757903,67.3237921 58.7255601,67.2929786 57.9202916,68.3463706 C57.1153811,69.3997627 54.7930281,74.9770079 51.9446905,75.1317921 C49.0959949,75.2865762 48.2910844,75.1317921 42.841468,74.7290667 C37.3918517,74.3263413 32.716711,73.5689022 31.5089872,73.2815483 C30.3016215,72.9938361 29.3105217,72.4051548 29.3105217,72.4051548 C29.3105217,72.4051548 23.7735396,74.049378 19.9262251,79.3206379 C17.4305729,82.7402209 16.7538465,88.1261357 16.5855601,91.4901827 C11.0596777,90.9860593 8.00581586,89.5378244 6.5137954,88.647099 C8.57870588,89.8817891 13.6409054,92.1906526 24.138757,91.5664999 C36.7924655,90.8144352 47.6616215,87.1787994 47.6616215,87.1787994 C47.6616215,87.1787994 53.1953811,88.0562678 54.703156,87.930864 C56.211289,87.8054602 58.7169668,88.5578831 62.7257647,88.5578831 C66.7349207,88.5578831 68.5588593,86.5517803 68.5588593,86.5517803 C68.5588593,86.5517803 70.9141535,86.3909051 70.9542558,85.0297363 C70.9947161,83.6685674 71.2654066,82.5986937 71.4823887,81.7316159 C71.6990128,80.8638214 70.8321586,80.8018361 70.6151765,79.1285909 C70.3985524,77.455704 71.458399,78.1991695 71.5167621,76.4331254" id="Fill-192" fill="#FF5B0C"></path>
60
+ <path d="M18.2097391,67.119348 C18.2097391,67.119348 22.3531662,69.7255977 23.7144962,70.0810279 C25.0758261,70.4360999 29.3105575,72.4052981 29.3105575,72.4052981 C29.3105575,72.4052981 32.5617084,72.0025727 35.5342916,68.160558 C38.5068747,64.3185433 40.6741893,59.9806461 40.6741893,59.9806461 C40.6741893,59.9806461 40.9216061,61.3131512 41.7576675,63.0791953 C42.5937289,64.8452394 45.814087,67.8642467 45.814087,67.8642467 L48.4458005,51.4599941 L24.6125013,40.2589251 C24.6125013,40.2589251 15.0216061,40.4731865 11.3970026,53.8505492 C-0.254506394,61.8738855 3.60354987,65.5292276 2.24293606,69.1609222 C2.06140153,69.6446226 -0.416705882,78.6031131 0.460531969,83.2670602 C1.21209207,88.0564112 4.46932992,87.3039883 5.5968491,88.0564112 C4.99961125,67.1773921 18.2097391,67.119348 18.2097391,67.119348" id="Fill-196" fill="#9F5622"></path>
61
+ <path d="M19.9262609,79.3206737 C23.7735754,74.0494138 29.3105575,72.4051906 29.3105575,72.4051906 C29.3105575,72.4051906 25.0758261,70.4363507 23.7144962,70.0809204 C22.3531662,69.7254902 18.2097391,67.1192405 18.2097391,67.1192405 C18.2097391,67.1192405 4.99961125,67.1772846 5.5968491,88.0563037 C5.64053197,88.0853257 5.6910179,88.1193639 5.74544246,88.1562684 C5.76262916,88.1677339 5.78089003,88.179916 5.79879284,88.1920981 C5.82493095,88.2096546 5.85214322,88.2279278 5.88042967,88.2469175 C5.89833248,88.2587413 5.91766752,88.2712816 5.93628645,88.283822 C6.04119693,88.3529733 6.16042967,88.4303653 6.29577494,88.5145651 C6.30938107,88.5231642 6.32298721,88.531405 6.33730946,88.5400041 C6.38421483,88.5690261 6.43291049,88.5987648 6.48375448,88.62922 C6.49342199,88.635311 6.50380563,88.6414021 6.5138312,88.6471348 C8.00585166,89.5378602 11.0597136,90.9860952 16.5855959,91.4902185 C16.7538824,88.1261715 17.4306087,82.7402567 19.9262609,79.3206737" id="Fill-206" fill="#FFAD00"></path>
62
+ <path d="M120.61734,86.0000752 C120.437238,85.4146185 120.830384,82.7951119 120.109974,80.0928388 C118.219795,73.3371559 109.964092,71.469714 109.964092,71.469714 C108.012685,72.4600458 106.509207,72.8452147 104.303223,73.0150473 C102.097596,73.1845216 96.0457289,73.863852 91.973555,73.665714 C87.9013811,73.4675759 87.2507928,72.1092734 86.6571355,70.5248858 C86.0631202,68.9401398 84.5925831,66.5345363 83.5463427,65.9652029 C82.5001023,65.3958696 79.361023,64.1575965 78.2864962,63.3654026 C77.2119693,62.5728505 75.1474169,64.6670943 73.9880307,65.9652029 C72.9135038,65.6219548 71.3115601,66.4976317 70.4529412,67.864175 C69.5946803,69.2307184 71.5181586,71.1189416 71.5181586,71.1189416 C71.5181586,71.1189416 70.4529412,72.2224952 70.3684399,73.5524922 C70.2835806,74.8824893 71.6692583,75.2504599 71.7258312,76.12757 C71.7824041,77.0050385 70.6513043,77.4009562 70.5864962,78.701573 C70.522046,80.002548 71.8672634,80.3156993 71.838977,80.8581604 C71.8103325,81.4009797 71.3015345,81.7023072 71.1762148,83.0692088 C71.0508951,84.4361104 71.8955499,83.9380781 72.5740665,84.5604394 C73.2529412,85.1831589 73.7001535,86.9391706 77.0257801,87.3426126 C80.3517647,87.7460546 83.7787212,85.9305656 85.0888491,85.829526 C86.398977,85.7288446 91.6398465,86.3340076 92.6964706,86.3340076 C93.7534527,86.3340076 106.959284,90.6704717 117.541637,91.1749533 C118.268491,91.2097081 118.952737,91.2240399 119.604041,91.2236816 C120.32445,90.3411971 120.797442,86.5851736 120.61734,86.0000752" id="Fill-208" fill="#FF5B0C"></path>
63
+ <path d="M120.61734,86.0000752 C120.437238,85.4146185 120.830384,82.7951119 120.109974,80.0928388 C118.219795,73.3371559 109.964092,71.469714 109.964092,71.469714 C108.012685,72.4600458 106.509207,72.8452147 104.303223,73.0150473 C102.097596,73.1845216 96.0457289,73.863852 91.973555,73.665714 C87.9013811,73.4675759 87.2507928,72.1092734 86.6571355,70.5248858 C86.0631202,68.9401398 84.5925831,66.5345363 83.5463427,65.9652029 C82.5001023,65.3958696 79.361023,64.1575965 78.2864962,63.3654026 C77.2119693,62.5728505 75.1474169,64.6670943 73.9880307,65.9652029 C72.9135038,65.6219548 71.3115601,66.4976317 70.4529412,67.864175 C69.5946803,69.2307184 71.5181586,71.1189416 71.5181586,71.1189416 C71.5181586,71.1189416 70.4529412,72.2224952 70.3684399,73.5524922 C70.2835806,74.8824893 71.6692583,75.2504599 71.7258312,76.12757 C71.7824041,77.0050385 70.6513043,77.4009562 70.5864962,78.701573 C70.522046,80.002548 71.8672634,80.3156993 71.838977,80.8581604 C71.8103325,81.4009797 71.3015345,81.7023072 71.1762148,83.0692088 C71.0508951,84.4361104 71.8955499,83.9380781 72.5740665,84.5604394 C73.2529412,85.1831589 73.7001535,86.9391706 77.0257801,87.3426126 C80.3517647,87.7460546 83.7787212,85.9305656 85.0888491,85.829526 C86.398977,85.7288446 91.6398465,86.3340076 92.6964706,86.3340076 C93.7534527,86.3340076 106.959284,90.6704717 117.541637,91.1749533 C118.268491,91.2097081 118.952737,91.2240399 119.604041,91.2236816 C120.32445,90.3411971 120.797442,86.5851736 120.61734,86.0000752" id="Fill-210" fill="#FF5B0C"></path>
64
+ <g id="Group-222" stroke-width="1" fill="none" transform="translate(88.797954, 39.420869)">
65
+ <mask id="mask-6" fill="white">
66
+ <use xlink:href="#path-5"></use>
67
+ </mask>
68
+ <g id="Clip-221"></g>
69
+ <path d="M49.9089258,32.9952493 C48.1451407,26.1080717 47.9159847,22.6809645 46.842532,20.1868617 C44.3651407,14.4297515 37.9154731,12.160659 36.5043734,9.44584552 C33.7831458,2.68872952 26.765601,0.342961527 26.765601,0.342961527 C20.9217647,-1.75199883 0.178132992,17.6623037 0.331381074,17.7755254 C0.484987212,17.8887471 6.62565217,26.4061744 6.62565217,26.4061744 C6.62565217,26.4061744 8.32248082,24.5953433 9.11414322,22.4727941 C9.90616368,20.3506032 10.1270844,18.0868852 10.1270844,18.0868852 C10.1270844,18.0868852 10.1324552,17.945358 11.5177749,20.4355195 C12.9034527,22.9256811 16.952711,30.9454344 21.1659591,32.048988 C21.1659591,32.048988 24.7687212,30.7526708 24.9037084,30.7075254 C25.0386957,30.6627383 26.7938875,30.1220687 27.5314834,29.7168352 C28.2687212,29.3116018 31.8346036,27.4197956 31.8346036,27.4197956 C31.8346036,27.4197956 36.6157289,26.2273844 41.9167519,36.0672846 C44.8836061,41.574662 43.616087,47.3636605 43.1348593,49.0738103 C44.080844,48.7230379 45.016087,48.4432082 46.079156,48.3249703 C50.6146547,47.8204887 51.017468,44.39159 51.1184399,43.8462626 C51.2190537,43.3009351 50.2734271,34.4176869 49.9089258,32.9952493" id="Fill-220" fill="#9F5622" mask="url(#mask-6)"></path>
70
+ </g>
71
+ <path d="M130.714598,75.4880464 C125.413575,65.6481463 120.632808,66.8405574 120.632808,66.8405574 C120.632808,66.8405574 117.066926,68.7323636 116.32933,69.1375971 C115.592092,69.5428305 113.836542,70.0835001 113.701555,70.1286455 C113.566568,70.1734326 109.963806,71.4697498 109.963806,71.4697498 C109.963806,71.4697498 118.219867,73.3371918 120.110046,80.0928746 C120.830455,82.7951477 120.437309,85.4146543 120.617412,86.000111 C120.797514,86.5852094 120.324164,90.3412329 119.604113,91.2237175 C126.214189,91.2212094 129.120174,89.5393651 131.932706,88.4949304 C132.413934,86.7844223 133.681453,80.9954238 130.714598,75.4880464" id="Fill-223" fill="#FFAD00"></path>
72
+ <path d="M62.0177801,68.6410338 C61.1788542,68.6009046 61.4982404,69.1609222 61.4982404,69.1609222 C61.4982404,69.1609222 64.5349156,68.5210044 65.0941995,68.6808047 C65.5084706,68.7994009 66.930312,68.0688341 67.8462199,67.8491982 C67.6170639,67.8198179 67.3907724,67.822326 67.1734322,67.8642467 C67.1734322,67.8642467 62.8567059,68.6808047 62.0177801,68.6410338" id="Fill-225" fill="#E43500"></path>
73
+ <path d="M69.5144041,79.6354015 C70.5277033,79.9553604 70.9018721,80.1954191 70.9541483,80.2953838 C70.8130742,80.0137627 70.6827417,79.649375 70.6154271,79.12877 C70.398445,77.4558831 71.4582916,78.1993486 71.5166547,76.4329463 C71.5750179,74.6669022 70.3275499,74.3945968 70.3583427,73.3014338 C70.3894936,72.2082708 71.6419744,72.7611225 71.518087,71.119049 C71.4539949,70.2720358 70.5427417,69.4056746 69.7177801,68.7320769 C69.9938414,69.460494 70.5201841,71.0778449 70.074046,71.8392253 C69.4889821,72.8388728 69.4492379,73.0388023 69.5688286,73.4784323 C69.6887775,73.9180623 70.8979335,75.0294984 71.1668338,75.397469 C71.4360921,75.7657979 71.2423836,77.6937921 70.7253504,78.0449228 C70.2079591,78.3960535 68.5011049,79.3154426 69.5144041,79.6354015" id="Fill-227" fill="#E43500"></path>
74
+ <path d="M70.9543274,85.0296288 C70.9944297,83.6684599 71.2654783,82.5989445 71.4824604,81.7315084 C71.6317698,81.1338696 71.2669105,80.918175 70.9543274,80.2954555 C71.0066036,80.3954203 70.5676266,81.4344805 70.5676266,82.7537286 C70.5676266,84.0650943 71.0961176,85.0127888 70.6628696,85.7347565 C70.8322302,85.5452176 70.9460921,85.3151912 70.9543274,85.0296288" id="Fill-229" fill="#FF3500"></path>
75
+ <path d="M84.2314476,85.592262 C82.9130844,85.6721621 79.7167161,86.4718802 78.1985575,86.1519213 C76.680399,85.8319624 75.2023427,84.3127847 75.2023427,84.3127847 C75.2023427,84.3127847 73.0446957,84.2730138 72.8449003,84.1931137 C72.6451049,84.1132135 71.2698107,83.1135659 71.5183018,82.6338068 C71.7664348,82.1540476 72.4127263,81.7495307 72.1259233,81.3038097 C71.8387621,80.858447 71.6296573,79.7953809 71.5183018,79.2357216 C71.4065882,78.675704 71.6464859,78.1959448 71.7664348,77.5563853 C71.8860256,76.9168258 72.3257187,75.9573075 71.9261279,75.4374191 C71.5265371,74.917889 70.5279182,73.798212 70.5676624,73.3188112 C70.6077647,72.8386937 72.6053606,71.1998449 72.6053606,71.1998449 C72.6053606,71.1998449 71.1419847,70.0987994 70.2371765,68.7225821 C70.2873043,69.9071107 71.5183018,71.1188699 71.5183018,71.1188699 C71.5183018,71.1188699 70.4530844,72.2227818 70.3682251,73.5524206 C70.2833657,74.8824176 71.6694015,75.2503883 71.7256164,76.1274984 C71.7574834,76.6208728 71.4137494,76.9623295 71.0950793,77.3976599 C71.0027008,77.6964793 70.8788133,77.9404793 70.7255652,78.0447436 C70.6507315,78.2371489 70.5988133,78.4524852 70.5866394,78.7018596 C70.5221893,80.0024764 71.8670486,80.3156276 71.8387621,80.858447 C71.8104757,81.4009081 71.3016777,81.7025938 71.1763581,83.0691372 C71.0510384,84.4360388 71.895335,83.9380065 72.5742097,84.560726 C73.2527263,85.1830872 73.6999386,86.939099 77.0259233,87.342541 C80.3519079,87.745983 83.7785064,85.930494 85.0889923,85.8298126 C85.2007059,85.8212135 85.3428542,85.8179888 85.5064859,85.8187054 C85.2379437,85.6764617 84.8301176,85.556074 84.2314476,85.592262" id="Fill-231" fill="#E43500"></path>
76
+ <path d="M45.1709821,99.3815941 C46.4009054,99.526346 58.6414169,99.7434737 71.0423376,99.8158496 C83.4432583,99.8885838 93.7889361,99.5987219 93.7889361,99.5987219 C93.7889361,99.5987219 87.6393197,99.3815941 68.5395243,98.9473386 C49.4393708,98.5130831 45.1709821,99.3815941 45.1709821,99.3815941" id="Fill-233" fill="#F9D400"></path>
77
+ <path d="M44.4475294,89.2460634 C44.4475294,89.2460634 62.4208798,90.0425568 70.0743325,89.6803189 C77.7274271,89.3184394 93.4994476,89.2460634 93.4994476,89.2460634 C93.4994476,89.2460634 84.6303939,89.1736875 70.3629258,89.2460634 C56.0954578,89.3184394 44.4475294,89.2460634 44.4475294,89.2460634" id="Fill-235" fill="#FF7E00"></path>
78
+ <path d="M28.6531662,40.2588176 C26.7139335,40.2606091 26.462578,40.6927148 28.4719898,41.4390467 C30.4810435,42.1850203 35.3151611,47.8891025 40.4622199,48.6590819 C45.6092788,49.4294197 34.4056982,43.2129733 38.3457494,41.4630526 C44.1179744,38.8997985 32.8141381,41.1982714 32.2609412,41.0778837 C31.7077442,40.957496 29.5429361,40.258101 28.6531662,40.2588176" id="Fill-237" fill="#98480C"></path>
79
+ <path d="M100.438578,45.1806667 C101.692133,45.8399325 103.048092,44.966047 106.193616,42.8198502 C109.339499,40.6736535 111.877402,40.2085844 109.267887,39.4575947 C106.658373,38.7062467 105.292389,41.8047959 99.719601,40.4343113 C94.1471714,39.064185 95.2553555,40.3515448 95.2553555,40.3515448 C95.2553555,40.3515448 102.118578,42.3193098 101.153616,43.5353686 C100.188297,44.7514273 98.3292685,44.0717386 100.438578,45.1806667" id="Fill-239" fill="#98480C"></path>
80
+ </g>
81
+ </g>
82
+ </g>
83
+ </g>
84
+ </g>
85
+ </svg>
assets/img/android-download.svg ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg width="122px" height="40px" viewBox="0 0 122 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
+ <!-- Generator: Sketch 45.1 (43504) - http://www.bohemiancoding.com/sketch -->
4
+ <title>graphic-defender-download-android</title>
5
+ <desc>Created with Sketch.</desc>
6
+ <defs>
7
+ <path d="M17.2892223,9.4886212 L11.789266,6.30733698 C11.789266,6.30733698 1.76950676,0.510781483 1.18045284,0.170074664 C0.591418798,-0.170632155 0.00453103111,0.0357989049 0.00453103111,0.747794923 L0.00453103111,25.7515381 C0.00453103111,26.2852962 0.423989249,26.5153808 0.935757289,26.2195918 C1.44728685,25.923325 11.789266,19.940886 11.789266,19.940886 L17.2889839,16.7598208 C17.2889839,16.7598208 21.955469,14.0607068 22.5757234,13.7020607 C23.1960176,13.3429567 23.1363988,12.8507715 22.6129454,12.5683823 C22.0897306,12.2857143 17.2892223,9.4886212 17.2892223,9.4886212 L17.2892223,9.4886212 Z" id="path-1"></path>
8
+ <linearGradient x1="49.9998541%" y1="0.000147098194%" x2="49.9998541%" y2="100.000147%" id="linearGradient-3">
9
+ <stop stop-color="#257CB0" offset="0%"></stop>
10
+ <stop stop-color="#4A93B5" offset="28.6%"></stop>
11
+ <stop stop-color="#78BCBB" offset="76.7%"></stop>
12
+ <stop stop-color="#89CFBD" offset="100%"></stop>
13
+ </linearGradient>
14
+ <path d="M17.2892223,9.4886212 L11.789266,6.30733698 C11.789266,6.30733698 1.76950676,0.510781483 1.18045284,0.170074664 C0.591418798,-0.170632155 0.00453103111,0.0357989049 0.00453103111,0.747794923 L0.00453103111,25.7515381 C0.00453103111,26.2852962 0.423989249,26.5153808 0.935757289,26.2195918 C1.44728685,25.923325 11.789266,19.940886 11.789266,19.940886 L17.2889839,16.7598208 C17.2889839,16.7598208 21.955469,14.0607068 22.5757234,13.7020607 C23.1960176,13.3429567 23.1363988,12.8507715 22.6129454,12.5683823 C22.0897306,12.2857143 17.2892223,9.4886212 17.2892223,9.4886212 L17.2892223,9.4886212 Z" id="path-4"></path>
15
+ <linearGradient x1="0.00126473415%" y1="49.9985397%" x2="100.001265%" y2="49.9985397%" id="linearGradient-6">
16
+ <stop stop-color="#52C1AD" offset="0%"></stop>
17
+ <stop stop-color="#DEE89A" offset="100%"></stop>
18
+ </linearGradient>
19
+ <path d="M17.2892223,9.4886212 L11.789266,6.30733698 C11.789266,6.30733698 1.76950676,0.510781483 1.18045284,0.170074664 C0.591418798,-0.170632155 0.00453103111,0.0357989049 0.00453103111,0.747794923 L0.00453103111,25.7515381 C0.00453103111,26.2852962 0.423989249,26.5153808 0.935757289,26.2195918 C1.44728685,25.923325 11.789266,19.940886 11.789266,19.940886 L17.2889839,16.7598208 C17.2889839,16.7598208 21.955469,14.0607068 22.5757234,13.7020607 C23.1960176,13.3429567 23.1363988,12.8507715 22.6129454,12.5683823 C22.0897306,12.2857143 17.2892223,9.4886212 17.2892223,9.4886212 L17.2892223,9.4886212 Z" id="path-7"></path>
20
+ <linearGradient x1="49.999885%" y1="0.000292074841%" x2="49.999885%" y2="100.000292%" id="linearGradient-9">
21
+ <stop stop-color="#EC413D" offset="0%"></stop>
22
+ <stop stop-color="#DA4452" offset="16.7%"></stop>
23
+ <stop stop-color="#B0487A" offset="57.5%"></stop>
24
+ <stop stop-color="#954A92" offset="86.2%"></stop>
25
+ <stop stop-color="#8A4A9D" offset="100%"></stop>
26
+ </linearGradient>
27
+ <path d="M17.2892223,9.4886212 L11.789266,6.30733698 C11.789266,6.30733698 1.76950676,0.510781483 1.18045284,0.170074664 C0.591418798,-0.170632155 0.00453103111,0.0357989049 0.00453103111,0.747794923 L0.00453103111,25.7515381 C0.00453103111,26.2852962 0.423989249,26.5153808 0.935757289,26.2195918 C1.44728685,25.923325 11.789266,19.940886 11.789266,19.940886 L17.2889839,16.7598208 C17.2889839,16.7598208 21.955469,14.0607068 22.5757234,13.7020607 C23.1960176,13.3429567 23.1363988,12.8507715 22.6129454,12.5683823 C22.0897306,12.2857143 17.2892223,9.4886212 17.2892223,9.4886212 L17.2892223,9.4886212 Z" id="path-10"></path>
28
+ <linearGradient x1="50.0010991%" y1="0.000547669119%" x2="50.0010991%" y2="99.9972617%" id="linearGradient-12">
29
+ <stop stop-color="#F58879" offset="0%"></stop>
30
+ <stop stop-color="#F69079" offset="11.9%"></stop>
31
+ <stop stop-color="#FCB877" offset="71.3%"></stop>
32
+ <stop stop-color="#FEC874" offset="100%"></stop>
33
+ </linearGradient>
34
+ </defs>
35
+ <g id="Security-Plugin" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
36
+ <g id="Advanced-Tools---2-Factor---New" transform="translate(-822.000000, -978.000000)">
37
+ <g id="graphic-defender-download-android" transform="translate(822.000000, 978.000000)">
38
+ <g>
39
+ <path d="M121.992468,34.5883922 C121.992468,37.5716078 119.57884,39.9909607 116.601714,39.9909607 L5.40901776,39.9909607 C2.43165336,39.9911996 0.0170907314,37.5718467 0.0170907314,34.5883922 L0.0170907314,5.41829766 C0.0170907314,2.43532106 2.43165336,0.0162070682 5.40901776,0.0162070682 L116.601475,0.0162070682 C119.578601,0.0162070682 121.99223,2.43532106 121.99223,5.41829766 L121.99223,34.5883922 L121.992468,34.5883922 Z" id="Shape" fill="#000000" fill-rule="nonzero"></path>
40
+ <g id="Clipped" transform="translate(9.161427, 8.123444)">
41
+ <mask id="mask-2" fill="white">
42
+ <use xlink:href="#path-1"></use>
43
+ </mask>
44
+ <g id="a"></g>
45
+ <polygon id="Shape" fill="url(#linearGradient-3)" fill-rule="nonzero" mask="url(#mask-2)" points="0.00476950643 -0.411229467 0.00476950643 26.6596715 13.6298185 13.1243405"></polygon>
46
+ </g>
47
+ <g id="Clipped" transform="translate(9.161427, 8.123444)">
48
+ <mask id="mask-5" fill="white">
49
+ <use xlink:href="#path-4"></use>
50
+ </mask>
51
+ <g id="d"></g>
52
+ <polygon id="Shape" fill="url(#linearGradient-6)" fill-rule="nonzero" mask="url(#mask-5)" points="17.2892223 9.4886212 11.789266 6.30733698 0.00476950643 -0.509666501 0.00476950643 -0.411229467 13.6298185 13.1243405"></polygon>
53
+ </g>
54
+ <g id="Clipped" transform="translate(9.161427, 8.123444)">
55
+ <mask id="mask-8" fill="white">
56
+ <use xlink:href="#path-7"></use>
57
+ </mask>
58
+ <g id="g"></g>
59
+ <polygon id="Shape" fill="url(#linearGradient-9)" fill-rule="nonzero" mask="url(#mask-8)" points="0.00476950643 26.6596715 0.00476950643 26.7581085 11.789266 19.9408661 17.2889839 16.7595819 13.6298185 13.1243405"></polygon>
60
+ </g>
61
+ <g id="Clipped" transform="translate(9.161427, 8.123444)">
62
+ <mask id="mask-11" fill="white">
63
+ <use xlink:href="#path-10"></use>
64
+ </mask>
65
+ <g id="j"></g>
66
+ <polygon id="Shape" fill="url(#linearGradient-12)" fill-rule="nonzero" mask="url(#mask-11)" points="17.2892223 9.4886212 13.6298185 13.1243405 17.2889839 16.7595819 23.5744581 13.1241015"></polygon>
67
+ </g>
68
+ <path d="M94.9441003,26.5394923 C94.4323323,26.5394923 93.9653976,26.444878 93.5425809,26.2558885 C93.1197641,26.06666 92.7644558,25.7756496 92.4775501,25.383335 L92.3917188,25.383335 C92.4489331,25.8430264 92.4775501,26.2788452 92.4775501,26.6904928 L92.4775501,29.9300747 L91.2880352,29.9300747 L91.2880352,18.5230861 L92.255768,18.5230861 L92.420316,19.6006371 L92.4775501,19.6006371 C92.7837325,19.1693778 93.1400345,18.8585366 93.5461381,18.6669189 C93.9522815,18.4753011 94.4184809,18.3794923 94.943842,18.3794923 C95.9859791,18.3794923 96.7903564,18.736446 97.3564968,19.4498756 C97.9228757,20.1633051 98.2061844,21.1644002 98.2061844,22.4522051 C98.2061844,23.7452663 97.9181062,24.7494674 97.3426653,25.466003 C96.7667672,26.1818019 95.9673979,26.5394923 94.9441003,26.5394923 L94.9441003,26.5394923 Z M94.7719212,19.3922947 C93.9689748,19.3922947 93.3882873,19.6152115 93.0298589,20.0603484 C92.6714305,20.5056844 92.4873276,21.2145943 92.4775501,22.1867795 L92.4775501,22.452225 C92.4775501,23.558666 92.661653,24.3499851 93.0298589,24.82666 C93.3980648,25.303335 93.9885297,25.5410453 94.8005382,25.5410453 C95.4797159,25.5410453 96.0115358,25.2660428 96.3964349,24.7153211 C96.7808571,24.1648382 96.9732869,23.405774 96.9732869,22.4378895 C96.9732869,21.4566252 96.7808373,20.7030363 96.3964349,20.1788352 C96.0117544,19.6541563 95.4699384,19.3922947 94.7719212,19.3922947 L94.7719212,19.3922947 Z M100.962025,26.3956595 L99.7720134,26.3956595 L99.7720134,15.2187556 L100.962025,15.2187556 L100.962025,26.3956595 Z M107.804597,26.3956595 L107.567791,25.275122 L107.510557,25.275122 C107.118484,25.7687208 106.727862,26.1029766 106.338213,26.2771528 C105.948783,26.4522847 105.462293,26.5395122 104.879459,26.5395122 C104.10038,26.5395122 103.489863,26.3383375 103.047492,25.9362071 C102.60512,25.5341165 102.384292,24.9621105 102.384292,24.2195321 C102.384292,22.6299652 103.653458,21.7965953 106.191292,21.7196615 L107.525343,21.6764161 L107.525343,21.1880538 C107.525343,20.5701941 107.392492,20.1138477 107.127069,19.8197312 C106.862123,19.524878 106.43716,19.3777203 105.854585,19.3777203 C105.199473,19.3777203 104.45855,19.578895 103.631975,19.9810055 L103.266174,19.0687904 C103.653696,18.8580587 104.077467,18.6929816 104.539155,18.5732603 C105.000366,18.453559 105.462531,18.3936088 105.926366,18.3936088 C106.863117,18.3936088 107.557299,18.6017123 108.009229,19.0183972 C108.460663,19.4350821 108.686499,20.1030961 108.686499,21.0227377 L108.686499,26.3954405 L107.804617,26.3954405 L107.804617,26.3956595 L107.804597,26.3956595 Z M105.116027,25.5555998 C105.856493,25.5555998 106.438372,25.3520159 106.861666,24.9451468 C107.284264,24.5382379 107.496269,23.9681832 107.496269,23.2351618 L107.496269,22.5241215 L106.305561,22.5740567 C105.359291,22.608223 104.677471,22.7549228 104.258728,23.0165455 C103.840681,23.2774515 103.631518,23.6833848 103.631518,24.2341065 C103.631518,24.664888 103.761487,24.9931707 104.022399,25.2177402 C104.283032,25.4430662 104.647184,25.5555998 105.116027,25.5555998 Z M109.377342,18.5230861 L110.653185,18.5230861 L112.374043,23.0127028 C112.751549,24.0376904 112.985951,24.7774216 113.077048,25.2325535 L113.134302,25.2325535 C113.196525,24.9878945 113.326971,24.5704928 113.524905,23.9784569 C113.723317,23.386879 114.372426,21.56888 115.471341,18.5230861 L116.748137,18.5230861 L113.37085,27.487785 C113.036508,28.3737183 112.645666,29.0023096 112.198267,29.3740767 C111.751603,29.744888 111.202871,29.9300747 110.553503,29.9300747 C110.190066,29.9300747 109.831638,29.8894574 109.477502,29.808223 L109.477502,28.8529816 C109.740282,28.9103235 110.03456,28.9392334 110.359622,28.9392334 C111.177115,28.9392334 111.759711,28.4795421 112.109077,27.5599403 L112.546202,26.4396018 L109.377342,18.5230861 L109.377342,18.5230861 Z M72.8972755,19.254674 C73.2750402,19.5678845 74.0639166,20.2258835 74.0639166,21.4781085 C74.0639166,22.6959084 73.3735305,23.2733897 72.6831445,23.8159881 C72.4694706,24.0298059 72.2228871,24.2610851 72.2228871,24.623773 C72.2228871,24.9852663 72.4692321,25.183116 72.6507118,25.3314883 L73.2426076,25.7916376 C73.9656648,26.4011349 74.6224258,26.9614136 74.6224258,28.0979791 C74.6224258,29.6457342 73.1267086,31.2094973 70.3002991,31.2094973 C67.9167581,31.2094973 66.7668301,30.0736486 66.7668301,28.8544151 C66.7668301,28.2618815 67.0613273,27.4225386 68.0324186,26.8455351 C69.0507083,26.2197909 70.4321958,26.1383176 71.1714494,26.0876854 C70.9406252,25.7916575 70.6783023,25.478666 70.6783023,24.9690393 C70.6783023,24.6894973 70.7608148,24.5246391 70.8426317,24.3260926 C70.6611321,24.3428173 70.4806063,24.3593031 70.3160782,24.3593031 C68.574473,24.3593031 67.5883975,23.0583574 67.5883975,21.7746142 C67.5883975,21.0169836 67.9339482,20.1766849 68.6398352,19.5681434 C69.5770233,18.7942857 70.6945187,18.6621404 71.5828591,18.6621404 L74.9677778,18.6621404 L73.9158433,19.2549129 L72.8972953,19.2549129 L72.8972953,19.254674 L72.8972755,19.254674 Z M71.7299388,26.5662519 C71.5985587,26.5490493 71.5160264,26.5490493 71.3524323,26.5490493 C71.2045975,26.5490493 70.3158,26.5827377 69.6263678,26.813778 C69.2648591,26.9444699 68.2126662,27.3396516 68.2126662,28.5094276 C68.2126662,29.678009 69.3473517,30.5190443 71.1061072,30.5190443 C72.682906,30.5190443 73.5220808,29.7599801 73.5220808,28.73999 C73.5221007,27.8984968 72.9795693,27.455769 71.7299388,26.5662519 Z M72.2068894,23.4370533 C72.5843958,23.0578795 72.6168483,22.5315281 72.6168483,22.2347835 C72.6168483,21.0494774 71.9104646,19.2052165 70.5466441,19.2052165 C70.1187995,19.2052165 69.6590389,19.4190543 69.3960007,19.7487705 C69.1169647,20.0944948 69.0339752,20.538656 69.0339752,20.9672872 C69.0339752,22.0704032 69.6749969,23.8984171 71.0891556,23.8984171 C71.5000684,23.8984171 71.9429171,23.7008263 72.2068894,23.4370533 L72.2068894,23.4370533 Z M62.5500896,26.3027178 C59.941408,26.3027178 58.5465858,24.2639721 58.5465858,22.4223395 C58.5465858,20.2684121 60.3020026,18.427994 62.7971699,18.427994 C65.2081355,18.427994 66.7179427,20.3178895 66.7179427,22.3076356 C66.7181613,24.2467695 65.2255442,26.3027178 62.5500896,26.3027178 Z M64.6009972,24.9711896 C64.9954354,24.4445993 65.0939058,23.7873171 65.0939058,23.1455849 C65.0939058,21.6983972 64.4047122,18.9369238 62.3698022,18.9369238 C61.8284831,18.9369238 61.2871442,19.1510005 60.8934214,19.4969637 C60.2533338,20.071558 60.1379316,20.7952812 60.1379316,21.5029766 C60.1379316,23.129338 60.9420505,25.8083823 62.928073,25.8083823 C63.5679023,25.8083823 64.224405,25.4965854 64.6009972,24.9711896 L64.6009972,24.9711896 Z M53.6561525,26.3027178 C51.0469741,26.3027178 49.6519133,24.2639721 49.6519133,22.4223395 C49.6519133,20.2684121 51.4080257,18.427994 53.9024975,18.427994 C56.3141984,18.427994 57.8237273,20.3178895 57.8237273,22.3076356 C57.8239857,24.2467695 56.3311302,26.3027178 53.6561525,26.3027178 Z M55.7075172,24.9711896 C56.1012399,24.4445993 56.1999687,23.7873171 56.1999687,23.1455849 C56.1999687,21.6983972 55.5102782,18.9369238 53.4753683,18.9369238 C52.9342678,18.9369238 52.3924717,19.1510005 51.9989676,19.4969637 C51.3588998,20.071558 51.2441932,20.7952812 51.2441932,21.5029766 C51.2441932,23.129338 52.047855,25.8083823 54.0341359,25.8083823 C54.6742036,25.8083823 55.3302691,25.4965854 55.7075172,24.9711896 L55.7075172,24.9711896 Z M48.3984871,26.0449179 L46.0389923,26.5903833 C45.0817524,26.7394724 44.224215,26.8706421 43.3172934,26.8706421 C38.7633686,26.8706421 37.0317993,23.5151817 37.0317993,20.8870085 C37.0317993,17.680896 39.489526,14.7065007 43.6969461,14.7065007 C44.5881284,14.7065007 45.4452285,14.8383873 46.2204919,15.0534196 C47.4577019,15.4005973 48.0350705,15.8299253 48.3982486,16.0781882 L47.0284463,17.3838925 L46.451336,17.5155401 L46.8636599,16.8541961 C46.3030044,16.3092086 45.2792298,15.3011847 43.3332712,15.3011847 C40.7264975,15.3011847 38.7629115,17.2854555 38.7629115,20.1776406 C38.7629115,23.2841414 41.0069643,26.209776 44.6026754,26.209776 C45.659598,26.209776 46.2028646,25.9952414 46.698158,25.796436 L46.698158,23.136008 L44.2075217,23.2681334 L45.5267672,22.5566351 L49.0244848,22.5566351 L48.5959446,22.9697362 C48.4795885,23.0693678 48.4636107,23.1028173 48.4307011,23.2337481 C48.4135309,23.3828372 48.39803,23.8625983 48.39803,24.0276954 L48.39803,26.0449378 L48.3984871,26.0449378 L48.3984871,26.0449179 Z" id="Shape" fill="#F9F9F9" fill-rule="nonzero"></path>
69
+ <path d="M78.1115582,25.5689796 C77.5668806,25.5192832 77.4528695,25.4206073 77.4528695,24.7752713 L77.4528695,15.4204082 C77.4562082,15.3848084 77.4583545,15.3482529 77.4616732,15.3138278 C77.5282277,14.7356297 77.6930142,14.6364759 78.2050008,14.3385565 L75.8450888,14.3385565 L74.6074217,14.9337183 L75.8687177,14.9337183 L75.8687177,14.9411249 L75.8677638,14.9351518 L75.8677638,25.1393927 C75.8677638,25.4693479 75.80266,25.5195222 75.422749,26.0148133 L78.3431376,26.0148133 L78.9536146,25.6521254 C78.6734061,25.6179592 78.3924822,25.6019512 78.1115582,25.5689796 L78.1115582,25.5689796 Z M84.8246187,25.7209358 C84.6450666,25.8196117 84.4647793,25.9350124 84.2851875,26.0164858 C83.74361,26.2625784 83.18679,26.3285217 82.6943186,26.3285217 C82.1713422,26.3285217 81.3514641,26.2945943 80.5151311,25.6879642 C79.3528223,24.8665406 78.8448698,23.4549925 78.8448698,22.2242708 C78.8448698,19.680438 80.9090924,18.4330114 82.5965437,18.4330114 C83.1865317,18.4330114 83.7934712,18.5804281 84.284949,18.8929617 C85.1034162,19.4336287 85.3163349,20.1394326 85.430346,20.5171528 L81.5811357,22.077113 L80.3193628,22.1755301 C80.7283479,24.2601493 82.13728,25.4738875 83.6942655,25.4738875 C84.5296446,25.4738875 85.1360873,25.1790543 85.6929272,24.9004679 L84.8246187,25.7209358 L84.8246187,25.7209358 Z M83.2850419,20.8287108 C83.5957752,20.7142658 83.7595879,20.6153509 83.7595879,20.3857442 C83.7595879,19.7296565 83.0226991,18.9741762 82.1372403,18.9741762 C81.4811748,18.9741762 80.2532852,19.483325 80.2532852,21.2556894 C80.2532852,21.5347536 80.2861948,21.8300647 80.3031266,22.1265505 L83.2850419,20.8287108 L83.2850419,20.8287108 Z M86.4059485,18.5453061 L86.4059485,19.6283524 L86.2745685,19.6283524 L86.2745685,18.5453061 L85.9168555,18.5453061 L85.9168555,18.4329915 L86.7634429,18.4329915 L86.7634429,18.5453061 L86.4059485,18.5453061 L86.4059485,18.5453061 Z M87.8797459,19.6283524 L87.8797459,18.5352713 L87.873784,18.5352713 L87.5408725,19.6283524 L87.4380896,19.6283524 L87.1023163,18.5352713 L87.0980039,18.5352713 L87.0980039,19.6283524 L86.9787662,19.6283524 L86.9787662,18.4330114 L87.1831396,18.4330114 L87.4869572,19.3992235 L87.4912497,19.3992235 L87.7905362,18.4330114 L87.9977912,18.4330114 L87.9977912,19.6283524 L87.8797459,19.6283524 L87.8797459,19.6283524 Z" id="Shape" fill="#F9F9F9" fill-rule="nonzero"></path>
70
+ <path d="M40.3084502,11.4881832 L39.4885721,11.4881832 C39.4885721,11.3751717 39.4108291,11.0552514 39.2553432,10.5281832 L38.0717703,10.5281832 C37.9112963,11.0466501 37.8309301,11.3665505 37.8309301,11.4881832 L37.0599394,11.4881832 C37.0599394,11.4215032 37.2593048,10.8738875 37.6580355,9.84557491 C38.0567464,8.81724241 38.2561316,8.25073171 38.2561316,8.14658039 L39.2245799,8.14658039 C39.2245799,8.24406172 39.4051057,8.80219014 39.7663958,9.82120458 C40.1276859,10.840219 40.3084502,11.3957193 40.3084502,11.4881832 L40.3084502,11.4881832 Z M39.1248773,10.0379094 C38.8327649,9.15506222 38.686818,8.6777103 38.686818,8.60577402 L38.6458003,8.60577402 C38.6458003,8.67245396 38.4946069,9.14980587 38.1924587,10.0379094 L39.1248773,10.0379094 L39.1248773,10.0379094 Z M43.6118104,11.4881832 L42.9791354,11.4881832 C42.9791354,11.4179393 42.744257,11.0476058 42.2746793,10.3769438 C41.7829432,9.67020408 41.5027346,9.18709806 41.4345506,8.92692882 L41.3935328,8.92692882 C41.4362199,9.30154306 41.4577026,9.64033848 41.4577026,9.94331508 C41.4577026,10.3659731 41.4696263,10.8810951 41.4934739,11.488442 L40.8631836,11.488442 C40.8886806,10.9580289 40.9015781,10.3755301 40.9015781,9.74070682 C40.9015781,9.1161772 40.8887004,8.58478845 40.8631836,8.14683922 L41.6239,8.14683922 C41.6239,8.23763066 41.8347122,8.59960179 42.256575,9.23251369 C42.7056439,9.90484818 42.9636543,10.3609557 43.0302088,10.6005973 L43.0686034,10.6005973 C43.0276055,10.2190343 43.0070767,9.87687407 43.0070767,9.57393728 C43.0070767,9.11044301 42.9951331,8.63448482 42.9713054,8.14683922 L43.6118501,8.14683922 C43.5877443,8.57116974 43.576059,9.10253858 43.576059,9.74070682 C43.5758006,10.3836336 43.5877244,10.9661324 43.6118104,11.4881832 L43.6118104,11.4881832 Z M47.3246327,9.70176207 C47.3246327,10.1877153 47.1691666,10.6120657 46.8584134,10.9747536 C46.5474416,11.3376804 46.1119658,11.5187855 45.5518071,11.5187855 C45.2990233,11.5187855 44.9506108,11.5084918 44.5065698,11.4879443 C44.5287281,10.9711697 44.5399563,10.3884121 44.5399563,9.74022897 C44.5399563,9.11759084 44.528748,8.586222 44.5065698,8.14634146 L44.9549233,8.14634146 C45.0283538,8.14634146 45.1375755,8.14371329 45.2828268,8.13869587 C45.4278,8.13367845 45.5227131,8.13105027 45.5670696,8.13105027 C46.1835481,8.13105027 46.6304509,8.28515679 46.9082548,8.59313091 C47.18584,8.90110503 47.3246327,9.27048283 47.3246327,9.70176207 L47.3246327,9.70176207 Z M46.6254032,9.81210553 C46.6254032,9.48358387 46.5297746,9.20690891 46.3385173,8.98160279 C46.1472601,8.75677451 45.8551279,8.64426083 45.462359,8.64426083 C45.3889285,8.64426083 45.288272,8.65190642 45.1599723,8.66743654 C45.1769041,9.00979592 45.1854892,9.36722748 45.1854892,9.74020906 C45.1854892,10.1492484 45.1940743,10.5547038 45.2109862,10.9568143 C45.3205841,10.9789365 45.4320977,10.9901409 45.5438977,10.9902638 C45.9111497,10.9902638 46.1830116,10.8758387 46.3597417,10.6474067 C46.5364717,10.4189945 46.6254032,10.1406272 46.6254032,9.81210553 L46.6254032,9.81210553 Z M50.7484229,11.4881832 L49.9900713,11.4881832 C49.7918984,10.8825087 49.6400094,10.5085913 49.5341264,10.36667 C49.4282434,10.2245097 49.257495,10.153549 49.0218814,10.153549 C48.9226757,10.153549 48.8279811,10.1545047 48.7376188,10.1561772 C48.7376188,10.5960577 48.7452302,11.0399602 48.7607509,11.4881832 L48.0486636,11.4881832 C48.070822,10.9713888 48.0820502,10.3886511 48.0820502,9.74044798 C48.0820502,9.11782977 48.0708418,8.58644102 48.0486636,8.14658039 L48.4917309,8.14658039 C48.5430031,8.14658039 48.6500984,8.14395222 48.8132155,8.13893479 C48.9763326,8.13391737 49.127049,8.13126929 49.2653647,8.13126929 C50.0492331,8.13126929 50.4412865,8.39982081 50.4412865,8.93718268 C50.4412865,9.36318566 50.2175967,9.65993031 49.770217,9.82789447 L49.770217,9.86636137 C49.9426346,9.91414634 50.093828,10.0491389 50.2235586,10.2703833 C50.3530308,10.4918666 50.5280717,10.8977999 50.7484229,11.4881832 L50.7484229,11.4881832 Z M49.7878443,9.12686909 C49.7878443,8.78640119 49.5691624,8.6160677 49.1320371,8.6160677 C48.9715432,8.6160677 48.8296306,8.62801394 48.7068356,8.65190642 C48.7256752,8.91711299 48.7349757,9.26283723 48.7349757,9.68884022 C48.8289549,9.69242409 48.9083672,9.69385764 48.9732126,9.69385764 C49.5162209,9.69409657 49.7878443,9.50510702 49.7878443,9.12686909 L49.7878443,9.12686909 Z M54.420446,9.75571926 C54.420446,10.280896 54.2599521,10.716436 53.9387457,11.0621603 C53.6175195,11.4076655 53.2204581,11.5806272 52.7475615,11.5806272 C52.2966245,11.5806272 51.9190982,11.4219811 51.6152807,11.10445 C51.3112246,10.7871578 51.1593158,10.3836336 51.1593158,9.89453459 C51.1593158,9.3693778 51.3198097,8.93381782 51.641036,8.58809358 C51.9620238,8.24260826 52.3590852,8.06962668 52.8322004,8.06962668 C53.2831572,8.06962668 53.660445,8.22779492 53.9645011,8.54437033 C54.2685571,8.86096565 54.420446,9.26450971 54.420446,9.75571926 L54.420446,9.75571926 Z M53.713625,9.8300448 C53.713625,9.47237432 53.6222691,9.18231956 53.4396169,8.95988054 C53.2567063,8.73744151 53.0313471,8.62634146 52.7633009,8.62634146 C52.5138557,8.62634146 52.3020896,8.73839721 52.1280026,8.96250871 C51.9539156,9.18662021 51.8663952,9.46976605 51.8663952,9.81212544 C51.8663952,10.1678845 51.9582082,10.4574614 52.1418143,10.6808761 C52.3254403,10.9042708 52.5503424,11.0158487 52.8169578,11.0158487 C53.0661645,11.0158487 53.2781691,10.9033151 53.4522561,10.678228 C53.6263431,10.4533997 53.713625,10.1704928 53.713625,9.8300448 L53.713625,9.8300448 Z M55.868965,11.4881832 L55.144,11.4881832 C55.1661782,10.95777 55.1773865,10.3752713 55.1773865,9.74044798 C55.1773865,9.11589846 55.1661981,8.58452962 55.144,8.14658039 L55.868965,8.14658039 C55.8467868,8.57783972 55.8355784,9.10896964 55.8355784,9.74044798 C55.8355784,10.3853061 55.8467868,10.9680438 55.868965,11.4881832 Z M59.5820257,9.70176207 C59.5820257,10.1877153 59.4265398,10.6120657 59.1158065,10.9747536 C58.8048545,11.3376804 58.3693787,11.5187855 57.8092002,11.5187855 C57.5564164,11.5187855 57.2080039,11.5084918 56.763943,11.4879443 C56.7861411,10.9711697 56.7973494,10.3884121 56.7973494,9.74022897 C56.7973494,9.11759084 56.7861609,8.586222 56.763943,8.14634146 L57.2122965,8.14634146 C57.2857469,8.14634146 57.3949686,8.14371329 57.5402,8.13869587 C57.6852129,8.13367845 57.7801062,8.13105027 57.8244825,8.13105027 C58.4409412,8.13105027 58.8878439,8.28515679 59.1656478,8.59313091 C59.4432331,8.90110503 59.5820257,9.27048283 59.5820257,9.70176207 L59.5820257,9.70176207 Z M58.8828161,9.81210553 C58.8828161,9.48358387 58.7871875,9.20690891 58.5959104,8.98160279 C58.4046532,8.75677451 58.1125408,8.64426083 57.7197521,8.64426083 C57.6463017,8.64426083 57.5456651,8.65190642 57.4173654,8.66743654 C57.4342971,9.00979592 57.4428624,9.36722748 57.4428624,9.74020906 C57.4428624,10.1492484 57.4514673,10.5547038 57.4683792,10.9568143 C57.5779773,10.9789356 57.6894908,10.99014 57.8012908,10.9902638 C58.1685229,10.9902638 58.4404046,10.8758387 58.6171148,10.6474067 C58.7938648,10.4189945 58.8828161,10.1406272 58.8828161,9.81210553 Z M64.507972,11.4881832 L63.6880938,11.4881832 C63.6880938,11.3751717 63.6103509,11.0552514 63.4546265,10.5281832 L62.2710735,10.5281832 C62.1105796,11.0466501 62.0301935,11.3665505 62.0301935,11.4881832 L61.2594612,11.4881832 C61.2594612,11.4215032 61.4588066,10.8738875 61.8575573,9.84557491 C62.256288,8.81724241 62.4556534,8.25073171 62.4556534,8.14658039 L63.4241016,8.14658039 C63.4241016,8.24406172 63.6048659,8.80219014 63.9659176,9.82120458 C64.3269692,10.840219 64.507972,11.3957193 64.507972,11.4881832 Z M63.324419,10.0379094 C63.0322867,9.15506222 62.8860814,8.6777103 62.8860814,8.60577402 L62.8450637,8.60577402 C62.8450637,8.67245396 62.6941088,9.14980587 62.3919805,10.0379094 L63.324419,10.0379094 L63.324419,10.0379094 Z M67.4960678,9.02152315 C67.4960678,9.43056247 67.3443776,9.73256346 67.0412755,9.92752613 C66.7381733,10.1224888 66.3663903,10.2201891 65.925668,10.2201891 C65.8453217,10.2201891 65.7883261,10.2185167 65.7539857,10.2151717 C65.7539857,10.5370035 65.7632663,10.961115 65.7821258,11.4881832 L65.0621489,11.4881832 C65.0843072,10.9938477 65.0955354,10.4110901 65.0955354,9.74044798 C65.0955354,9.12449975 65.084347,8.59313091 65.0621489,8.14658039 L65.5078593,8.14658039 C65.5710552,8.14658039 65.6921808,8.14395222 65.8715341,8.13893479 C66.0508874,8.13391737 66.2061349,8.13126929 66.3377534,8.13126929 C66.6620798,8.13126929 66.9363264,8.20485814 67.1600163,8.35203584 C67.383726,8.49923345 67.4960678,8.72215032 67.4960678,9.02152315 L67.4960678,9.02152315 Z M66.8352526,9.16272773 C66.8352526,8.79667496 66.5927034,8.61343952 66.1076644,8.61343952 C65.9862805,8.61343952 65.8582193,8.62632155 65.7234807,8.65190642 C65.7423202,8.97541065 65.7516208,9.3414435 65.7516208,9.75048283 C65.794288,9.7540667 65.8439107,9.75550025 65.9001909,9.75550025 C66.5235654,9.75571926 66.8352526,9.55814833 66.8352526,9.16272773 L66.8352526,9.16272773 Z M70.5685838,9.02152315 C70.5685838,9.43056247 70.4169135,9.73256346 70.1140498,9.92752613 C69.8109477,10.1224888 69.4389262,10.2201891 68.9982437,10.2201891 C68.9178576,10.2201891 68.8608819,10.2185167 68.8265216,10.2151717 C68.8265216,10.5370035 68.835842,10.961115 68.8546617,11.4881832 L68.1347047,11.4881832 C68.1568829,10.9938477 68.1681111,10.4110901 68.1681111,9.74044798 C68.1681111,9.12449975 68.1569028,8.59313091 68.1347047,8.14658039 L68.5804151,8.14658039 C68.6436309,8.14658039 68.7647565,8.14395222 68.9440899,8.13893479 C69.1234234,8.13391737 69.2786708,8.13126929 69.4103092,8.13126929 C69.7346157,8.13126929 70.0088822,8.20485814 70.2325721,8.35203584 C70.4562421,8.49923345 70.5685838,8.72215032 70.5685838,9.02152315 L70.5685838,9.02152315 Z M69.9077687,9.16272773 C69.9077687,8.79667496 69.6652393,8.61343952 69.1802004,8.61343952 C69.0588164,8.61343952 68.9307353,8.62632155 68.7960166,8.65190642 C68.8148363,8.97541065 68.8241567,9.3414435 68.8241567,9.75048283 C68.8668239,9.7540667 68.9164467,9.75550025 68.9727268,9.75550025 C69.5960814,9.75571926 69.9077687,9.55814833 69.9077687,9.16272773 L69.9077687,9.16272773 Z M75.5920665,9.75571926 C75.5920665,10.280896 75.4315726,10.716436 75.1103463,11.0621603 C74.7891399,11.4078845 74.3920586,11.5806272 73.9191621,11.5806272 C73.4682251,11.5806272 73.0906988,11.4219811 72.7869011,11.10445 C72.4830637,10.7871578 72.3309363,10.3836336 72.3309363,9.89453459 C72.3309363,9.3693778 72.4914302,8.93381782 72.8126366,8.58809358 C73.1338628,8.24236934 73.5309441,8.06962668 74.0038208,8.06962668 C74.4547777,8.06962668 74.8322841,8.22779492 75.1361016,8.54437033 C75.4399192,8.86096565 75.5920665,9.26450971 75.5920665,9.75571926 L75.5920665,9.75571926 Z M74.8849871,9.8300448 C74.8849871,9.47237432 74.7936312,9.18231956 74.610979,8.95988054 C74.4283268,8.73744151 74.2027092,8.62634146 73.9346828,8.62634146 C73.6852178,8.62634146 73.4734517,8.73839721 73.2993647,8.96250871 C73.1252777,9.18662021 73.0379958,9.46976605 73.0379958,9.81212544 C73.0379958,10.1678845 73.1298286,10.4574614 73.3134348,10.6808761 C73.4970409,10.9042708 73.721943,11.0158487 73.9883199,11.0158487 C74.2377651,11.0158487 74.4495312,10.9033151 74.6236182,10.6782479 C74.7979436,10.4533997 74.8849871,10.1704928 74.8849871,9.8300448 L74.8849871,9.8300448 Z M79.0642671,11.4881832 L78.4315921,11.4881832 C78.4315921,11.4179393 78.1969125,11.0476058 77.727136,10.3769438 C77.2353999,9.67020408 76.9551715,9.18709806 76.8869875,8.92692882 L76.8459697,8.92692882 C76.8886568,9.30154306 76.9101394,9.64033848 76.9101394,9.94331508 C76.9101394,10.3659731 76.9220632,10.8810951 76.9459306,11.488442 L76.3156205,11.488442 C76.3411373,10.9580289 76.354015,10.3755301 76.354015,9.74070682 C76.354015,9.1161772 76.3411771,8.58478845 76.3156205,8.14683922 L77.0763567,8.14683922 C77.0763567,8.23763066 77.2874074,8.59960179 77.7090318,9.23251369 C78.1583193,9.90484818 78.4161111,10.3609557 78.4826656,10.6005973 L78.5210601,10.6005973 C78.4800424,10.2190343 78.4595335,9.87687407 78.4595335,9.57393728 C78.4595335,9.11044301 78.4476097,8.63448482 78.4237423,8.14683922 L79.064287,8.14683922 C79.040201,8.57116974 79.0285157,9.10253858 79.0285157,9.74070682 C79.0284958,10.3836336 79.0404196,10.9661324 79.0642671,11.4881832 L79.0642671,11.4881832 Z" id="Shape" fill="#F9F9FA" fill-rule="nonzero"></path>
71
+ </g>
72
+ </g>
73
+ </g>
74
+ </g>
75
+ </svg>
assets/img/ios-download.svg ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg width="122px" height="40px" viewBox="0 0 122 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
+ <!-- Generator: Sketch 45.1 (43504) - http://www.bohemiancoding.com/sketch -->
4
+ <title>graphic-defender-download-ios</title>
5
+ <desc>Created with Sketch.</desc>
6
+ <defs></defs>
7
+ <g id="Security-Plugin" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
8
+ <g id="Advanced-Tools---2-Factor---New" transform="translate(-690.000000, -978.000000)">
9
+ <g id="graphic-defender-download-ios" transform="translate(690.000000, 978.000000)">
10
+ <g>
11
+ <path d="M121.876094,34.4521429 C121.876094,37.425 119.464449,39.8359524 116.489746,39.8359524 L5.38753906,39.8359524 C2.41259766,39.8361905 0,37.4252381 0,34.4521429 L0,5.38333333 C0,2.41071429 2.41259766,0 5.38753906,0 L116.489508,0 C119.464211,0 121.875855,2.41071429 121.875855,5.38333333 L121.875855,34.4521429 L121.876094,34.4521429 Z" id="path6" fill="#000000" fill-rule="nonzero"></path>
12
+ <g id="g3447" transform="translate(8.450693, 5.437730)" fill-rule="nonzero" fill="#FFFFFF">
13
+ <g id="g3449">
14
+ <path d="M19.6864359,14.9573036 C19.6549428,11.4599596 22.5523066,9.75849037 22.6847948,9.67927656 C21.0438965,7.28875568 18.5005584,6.96213435 17.6068063,6.93609145 C15.4707064,6.71147147 13.3986786,8.21327851 12.3105382,8.21327851 C11.2006785,8.21327851 9.5250292,6.95779387 7.71906368,6.99468797 C5.39509121,7.03049695 3.2209824,8.37496149 2.02858905,10.4627337 C-0.43221544,14.7196622 1.40307123,20.9753829 3.76070871,24.4163007 C4.94007044,26.1014931 6.31816439,27.9830924 8.12195797,27.9169 C9.88665669,27.8441969 10.5458395,26.792715 12.6754236,26.792715 C14.7854603,26.792715 15.4044623,27.9169 17.2440929,27.8745803 C19.1380218,27.8441969 20.3304152,26.181792 21.4685101,24.4814079 C22.8314005,22.5498931 23.3787286,20.6476765 23.400448,20.5500156 C23.3559233,20.5348239 19.7222729,19.1491248 19.6864359,14.9573036 Z" id="path3451"></path>
15
+ <path d="M16.2113369,4.67252969 C17.1604733,3.48649278 17.8098824,1.87291831 17.6296117,0.23547119 C16.2558616,0.296237948 14.5378595,1.18495179 13.5485423,2.34494581 C12.6732517,3.3671295 11.8913544,5.04255585 12.0933446,6.61815109 C13.6365057,6.73317388 15.2209337,5.84011956 16.2113369,4.67252969 L16.2113369,4.67252969 Z" id="path3453"></path>
16
+ </g>
17
+ </g>
18
+ <g id="g3455" transform="translate(35.993230, 14.542779)" fill-rule="nonzero" fill="#FFFFFF">
19
+ <path d="M10.6202177,12.3060081 L8.54907005,12.3060081 L7.41454443,8.74379054 L3.47106471,8.74379054 L2.39034698,12.3060081 L0.373919215,12.3060081 L4.28091901,0.178612084 L6.69406595,0.178612084 L10.6202177,12.3060081 L10.6202177,12.3060081 Z M7.07254515,7.24928127 L6.0465473,4.08256192 C5.93801953,3.75905534 5.73464396,2.99722012 5.43459659,1.79796756 L5.39811667,1.79796756 C5.27864492,2.31375552 5.08621332,3.07559073 4.82173388,4.08256192 L3.81397599,7.24928127 L7.07254515,7.24928127 L7.07254515,7.24928127 Z" id="path3457"></path>
20
+ <path d="M20.6677006,7.82612539 C20.6677006,9.31334438 20.2655095,10.4889035 19.4611271,11.3518915 C18.7406487,12.1201057 17.8459785,12.5037572 16.7780288,12.5037572 C15.6252632,12.5037572 14.7971689,12.0900333 14.292834,11.2625854 L14.2563541,11.2625854 L14.2563541,15.8691369 L12.3119741,15.8691369 L12.3119741,6.44005917 C12.3119741,5.50507959 12.2873502,4.54549528 12.2399263,3.56130625 L13.9499227,3.56130625 L14.0584505,4.94737247 L14.0949304,4.94737247 C14.743361,3.90303855 15.727407,3.38178288 17.0479802,3.38178288 C18.080362,3.38178288 18.9422002,3.78912778 19.6316708,4.60472888 C20.3229653,5.42124126 20.6677006,6.49473634 20.6677006,7.82612539 L20.6677006,7.82612539 Z M18.6868408,7.89720571 C18.6868408,7.04606446 18.4953212,6.34437413 18.110458,5.79213472 C17.6900269,5.21620188 17.1255,4.92823546 16.4177895,4.92823546 C15.9380785,4.92823546 15.5021435,5.08862182 15.1127203,5.40483811 C14.7223851,5.72378826 14.4670256,6.14024603 14.3475539,6.65603399 C14.287362,6.89661353 14.2572661,7.09345134 14.2572661,7.24836998 L14.2572661,8.70642781 C14.2572661,9.34250554 14.4524337,9.87925307 14.8427688,10.3175817 C15.233104,10.7559103 15.740175,10.974619 16.3639816,10.974619 C17.0963161,10.974619 17.6663149,10.6921203 18.0739781,10.1289455 C18.4825532,9.56485936 18.6868408,8.82124986 18.6868408,7.89720571 L18.6868408,7.89720571 Z" id="path3459"></path>
21
+ <path d="M30.7334235,7.82612539 C30.7334235,9.31334438 30.3312323,10.4889035 29.525938,11.3518915 C28.8063715,12.1201057 27.9117014,12.5037572 26.8437516,12.5037572 C25.6909861,12.5037572 24.8628918,12.0900333 24.3594689,11.2625854 L24.3229889,11.2625854 L24.3229889,15.8691369 L22.378609,15.8691369 L22.378609,6.44005917 C22.378609,5.50507959 22.3539851,4.54549528 22.3065612,3.56130625 L24.0165576,3.56130625 L24.1250853,4.94737247 L24.1615653,4.94737247 C24.8090839,3.90303855 25.7931298,3.38178288 27.1146151,3.38178288 C28.1460849,3.38178288 29.0079231,3.78912778 29.6992176,4.60472888 C30.3877762,5.42124126 30.7334235,6.49473634 30.7334235,7.82612539 L30.7334235,7.82612539 Z M28.7525636,7.89720571 C28.7525636,7.04606446 28.560132,6.34437413 28.1752688,5.79213472 C27.7548377,5.21620188 27.1921349,4.92823546 26.4835124,4.92823546 C26.0028894,4.92823546 25.5678663,5.08862182 25.1775311,5.40483811 C24.787196,5.72378826 24.5327485,6.14024603 24.4132767,6.65603399 C24.3539969,6.89661353 24.3229889,7.09345134 24.3229889,7.24836998 L24.3229889,8.70642781 C24.3229889,9.34250554 24.5181565,9.87925307 24.9066677,10.3175817 C25.2970029,10.7549991 25.8040738,10.974619 26.4297045,10.974619 C27.162039,10.974619 27.7320378,10.6921203 28.1397009,10.1289455 C28.5482761,9.56485936 28.7525636,8.82124986 28.7525636,7.89720571 L28.7525636,7.89720571 Z" id="path3461"></path>
22
+ <path d="M41.9874798,8.90508819 C41.9874798,9.9366641 41.6290646,10.7759586 40.9094981,11.4238831 C40.1187958,12.1319524 39.0180141,12.4855314 37.603505,12.4855314 C36.2975238,12.4855314 35.25055,12.2340165 34.4580237,11.7300752 L34.9085507,10.1107198 C35.7621809,10.6265077 36.6988029,10.885313 37.7193288,10.885313 C38.4516633,10.885313 39.0216621,10.7194589 39.4311492,10.3895733 C39.8388124,10.0596877 40.0421879,9.61680267 40.0421879,9.06456326 C40.0421879,8.57246875 39.8743803,8.15783355 39.537853,7.82156896 C39.2031497,7.48530438 38.6440949,7.17273323 37.8634245,6.88385552 C35.738469,6.09194786 34.6769032,4.93188061 34.6769032,3.4063876 C34.6769032,2.40944056 35.0489984,1.59201689 35.7941008,0.955939164 C36.5364673,0.31895015 37.5268972,0.000911286143 38.7653906,0.000911286143 C39.8698203,0.000911286143 40.7872904,0.193192662 41.5196248,0.576844128 L41.0335298,2.16065944 C40.3495313,1.7888547 39.5761569,1.60295233 38.7106707,1.60295233 C38.0266722,1.60295233 37.4922413,1.77154026 37.1092021,2.10689356 C36.7854428,2.4067067 36.6231071,2.77213245 36.6231071,3.20499336 C36.6231071,3.68432988 36.8082427,4.08073935 37.1803379,4.39239921 C37.5040973,4.68036563 38.092336,4.99202549 38.9459662,5.32829008 C39.990204,5.74839299 40.7571944,6.23957622 41.2505854,6.80275106 C41.7421524,7.36410332 41.9874798,8.06670494 41.9874798,8.90508819 L41.9874798,8.90508819 Z" id="path3463"></path>
23
+ <path d="M48.4161543,5.01936407 L46.2729588,5.01936407 L46.2729588,9.26504621 C46.2729588,10.3449203 46.6505261,10.8844017 47.4074845,10.8844017 C47.7549557,10.8844017 48.0431471,10.8543292 48.2711466,10.7941844 L48.3249545,12.2695566 C47.9419153,12.4126286 47.4375804,12.4846202 46.8128617,12.4846202 C46.0449593,12.4846202 45.4448646,12.2504196 45.0116655,11.7829298 C44.5802904,11.3145287 44.3632349,10.5290001 44.3632349,9.42543258 L44.3632349,5.0175415 L43.0864375,5.0175415 L43.0864375,3.55948367 L44.3632349,3.55948367 L44.3632349,1.95835392 L46.2729588,1.38242108 L46.2729588,3.55948367 L48.4161543,3.55948367 L48.4161543,5.01936407 L48.4161543,5.01936407 Z" id="path3465"></path>
24
+ <path d="M58.08607,7.86166555 C58.08607,9.20581262 57.7012068,10.3093801 56.9333045,11.1723681 C56.1280102,12.0608721 55.0591484,12.5037572 53.7267192,12.5037572 C52.4426259,12.5037572 51.420276,12.0781865 50.6578456,11.2270453 C49.8954152,10.375904 49.5142,9.30149766 49.5142,8.00656005 C49.5142,6.65147756 49.9063592,5.54153103 50.6934136,4.67854306 C51.4786439,3.81464379 52.5383857,3.38269416 53.8708149,3.38269416 C55.1549082,3.38269416 56.188202,3.80826479 56.9679604,4.66031733 C57.7139748,5.48685387 58.08607,6.55396994 58.08607,7.86166555 L58.08607,7.86166555 Z M56.0687303,7.9245443 C56.0687303,7.11805606 55.8963626,6.42638988 55.5470674,5.84954575 C55.1394042,5.15150057 54.5566375,4.80338926 53.801503,4.80338926 C53.0199207,4.80338926 52.4262099,5.15241185 52.0185468,5.84954575 C51.6692515,6.42730117 51.4968839,7.12990278 51.4968839,7.96099574 C51.4968839,8.76748398 51.6692515,9.45915016 52.0185468,10.035083 C52.4389779,10.7331282 53.0263047,11.0812395 53.7841751,11.0812395 C54.5265415,11.0812395 55.1093083,10.7258379 55.5297394,10.0168573 C55.8881547,9.42907772 56.0687303,8.73012125 56.0687303,7.9245443 L56.0687303,7.9245443 Z" id="path3467"></path>
25
+ <path d="M64.4062168,5.26996776 C64.2137852,5.2344276 64.0085856,5.21620188 63.7933541,5.21620188 C63.1093555,5.21620188 62.5803966,5.47409586 62.2083014,5.9907951 C61.8845421,6.44643817 61.7222064,7.02237102 61.7222064,7.71768234 L61.7222064,12.3060081 L59.7787385,12.3060081 L59.7969784,6.31521297 C59.7969784,5.3073305 59.7723545,4.38966535 59.7240186,3.56221753 L61.417599,3.56221753 L61.4887349,5.23533889 L61.5425428,5.23533889 C61.7477424,4.66031733 62.0715017,4.19738397 62.5147327,3.85018395 C62.9479318,3.53761281 63.4157869,3.38178288 63.9201218,3.38178288 C64.0997854,3.38178288 64.2621211,3.39454088 64.4062168,3.41732304 L64.4062168,5.26996776 Z" id="path3469"></path>
26
+ <path d="M73.1021185,7.51993325 C73.1021185,7.86804456 73.0793186,8.1614787 73.0309827,8.40114695 L67.1978429,8.40114695 C67.2206429,9.26504621 67.5024503,9.92572867 68.0441771,10.3813717 C68.5357441,10.7887166 69.1714068,10.9928447 69.9520771,10.9928447 C70.8157393,10.9928447 71.6037057,10.8552405 72.3123282,10.5791208 L72.6169355,11.9278243 C71.7888413,12.2886936 70.8111793,12.468217 69.6830377,12.468217 C68.3259845,12.468217 67.2607708,12.0690737 66.4855724,11.2716983 C65.712198,10.4743229 65.3245988,9.40356171 65.3245988,8.06032593 C65.3245988,6.74169488 65.6848381,5.64359508 66.4062286,4.7678491 C67.161363,3.83286952 68.1818888,3.36537973 69.4659821,3.36537973 C70.7272755,3.36537973 71.6821375,3.83286952 72.3305681,4.7678491 C72.8440231,5.51054731 73.1021185,6.42912374 73.1021185,7.51993325 L73.1021185,7.51993325 Z M71.2480264,7.01599201 C71.2607944,6.44005917 71.1340266,5.94249694 70.8704592,5.52239403 C70.5339319,4.98200134 70.016829,4.71226064 69.3209745,4.71226064 C68.6853118,4.71226064 68.1682089,4.97562234 67.7733137,5.5041683 C67.4495544,5.92427121 67.2571228,6.42821245 67.1978429,7.01508073 L71.2480264,7.01508073 L71.2480264,7.01599201 Z" id="path3471"></path>
27
+ </g>
28
+ <g id="g3473" transform="translate(36.661984, 7.639426)" fill-rule="nonzero" fill="#FFFFFF">
29
+ <g id="g3475">
30
+ <path d="M3.09476983,2.04913172 C3.09476983,2.65073512 2.91419896,3.10359885 2.55356876,3.40772292 C2.21953823,3.68833487 1.74483635,3.82889641 1.12997464,3.82889641 C0.825101444,3.82889641 0.56422002,3.81560696 0.34579577,3.78902805 L0.34579577,0.501932489 C0.630719207,0.45593053 0.937638529,0.432418417 1.2691114,0.432418417 C1.85481577,0.432418417 2.29626806,0.559690505 2.5939798,0.814234679 C2.9274988,1.10200249 3.09476983,1.51346446 3.09476983,2.04913172 Z M2.52952675,2.06395457 C2.52952675,1.67396019 2.42619724,1.37494745 2.21953823,1.16640523 C2.01287922,0.958374152 1.71107522,0.854103044 1.3136147,0.854103044 C1.14480907,0.854103044 1.00106852,0.865347967 0.881881519,0.88886008 L0.881881519,3.38778873 C0.947869173,3.39801139 1.06859077,3.40261159 1.24404632,3.40261159 C1.65429515,3.40261159 1.97093358,3.28862896 2.19396162,3.06066369 C2.41698966,2.83269843 2.52952675,2.50046205 2.52952675,2.06395457 L2.52952675,2.06395457 Z" id="path3477"></path>
31
+ <path d="M6.09183701,2.57457632 C6.09183701,2.94514766 5.98594985,3.24876059 5.77417551,3.48694851 C5.55217054,3.73178116 5.25803952,3.85394192 4.8907594,3.85394192 C4.53677911,3.85394192 4.25492487,3.73689249 4.04468513,3.50177137 C3.83495693,3.26716138 3.73009283,2.97121544 3.73009283,2.61444469 C3.73009283,2.24131768 3.83802612,1.93514909 4.05491578,1.6974723 C4.27180543,1.45979551 4.56337879,1.34070155 4.93065891,1.34070155 C5.28463919,1.34070155 5.5690511,1.45775098 5.78440616,1.69236097 C5.98901904,1.92032623 6.09183701,2.21473877 6.09183701,2.57457632 L6.09183701,2.57457632 Z M5.53580151,2.59195484 C5.53580151,2.36961204 5.48771748,2.17895947 5.39206096,2.01999715 C5.27952387,1.82781118 5.11941429,1.7317182 4.91122069,1.7317182 C4.69586563,1.7317182 4.53217532,1.82781118 4.41963824,2.01999715 C4.32347018,2.17895947 4.27589769,2.37267883 4.27589769,2.60166636 C4.27589769,2.82400917 4.32398172,3.01466173 4.41963824,3.17362406 C4.53575605,3.36581002 4.69740022,3.461903 4.90610536,3.461903 C5.11071825,3.461903 5.27133936,3.36427662 5.38694564,3.16851273 C5.48618288,3.00648361 5.53580151,2.81429764 5.53580151,2.59195484 Z" id="path3479"></path>
32
+ <path d="M10.110434,1.3897703 L9.355924,3.7992507 L8.86485309,3.7992507 L8.55230691,2.7529617 C8.47301942,2.49177279 8.40856636,2.23211729 8.35843621,1.97450632 L8.34871709,1.97450632 C8.30216766,2.23927315 8.23771461,2.49841752 8.15484639,2.7529617 L7.82286199,3.7992507 L7.32616422,3.7992507 L6.61666905,1.3897703 L7.16758924,1.3897703 L7.4402359,2.53521909 C7.50622355,2.80611952 7.56044597,3.06424162 7.60392621,3.30856314 L7.61364532,3.30856314 C7.65354483,3.10717678 7.71953248,2.85058808 7.81263134,2.54033042 L8.15484639,1.39028144 L8.59169489,1.39028144 L8.91958703,2.51579604 C8.99887452,2.7902744 9.06332758,3.0545301 9.11294621,3.30907427 L9.12778064,3.30907427 C9.16409943,3.06117482 9.21883337,2.79691912 9.29147094,2.51579604 L9.58406737,1.39028144 L10.110434,1.39028144 L10.110434,1.3897703 Z" id="path3481"></path>
33
+ <path d="M12.8895885,3.7992507 L12.3535027,3.7992507 L12.3535027,2.41919193 C12.3535027,1.99392937 12.1918585,1.78129809 11.8675471,1.78129809 C11.7084606,1.78129809 11.580066,1.83956724 11.4803172,1.95661667 C11.3815915,2.0736661 11.3314614,2.21167198 11.3314614,2.36961204 L11.3314614,3.79873957 L10.7953756,3.79873957 L10.7953756,2.07826629 C10.7953756,1.86665728 10.7887257,1.63715862 10.7759374,1.38874804 L11.2470586,1.38874804 L11.2721236,1.76545297 L11.2869581,1.76545297 C11.349365,1.64840354 11.4424639,1.55179943 11.5647201,1.47461836 C11.7099952,1.38465897 11.8726624,1.33916815 12.0506757,1.33916815 C12.2757498,1.33916815 12.4629706,1.41174902 12.6118265,1.55742189 C12.7970011,1.73580726 12.8895885,2.00210749 12.8895885,2.35581145 L12.8895885,3.7992507 L12.8895885,3.7992507 Z" id="path3483"></path>
34
+ <polygon id="path3485" points="14.3679165 3.7992507 13.8323423 3.7992507 13.8323423 0.284189882 14.3679165 0.284189882"></polygon>
35
+ <path d="M17.5240702,2.57457632 C17.5240702,2.94514766 17.4181831,3.24876059 17.2064087,3.48694851 C16.9844038,3.73178116 16.6897612,3.85394192 16.3229926,3.85394192 C15.9685008,3.85394192 15.6866466,3.73689249 15.4769183,3.50177137 C15.2671901,3.26716138 15.162326,2.97121544 15.162326,2.61444469 C15.162326,2.24131768 15.2702593,1.93514909 15.487149,1.6974723 C15.7040386,1.45979551 15.995612,1.34070155 16.3623806,1.34070155 C16.7168724,1.34070155 17.0007728,1.45775098 17.2166394,1.69236097 C17.4212523,1.92032623 17.5240702,2.21473877 17.5240702,2.57457632 L17.5240702,2.57457632 Z M16.9675232,2.59195484 C16.9675232,2.36961204 16.9194392,2.17895947 16.8237826,2.01999715 C16.7117571,1.82781118 16.551136,1.7317182 16.3434539,1.7317182 C16.1275873,1.7317182 15.963897,1.82781118 15.8518715,2.01999715 C15.7557034,2.17895947 15.7081309,2.37267883 15.7081309,2.60166636 C15.7081309,2.82400917 15.7562149,3.01466173 15.8518715,3.17362406 C15.9679893,3.36581002 16.1296334,3.461903 16.3383386,3.461903 C16.5429515,3.461903 16.703061,3.36427662 16.8186673,3.16851273 C16.9184161,3.00648361 16.9675232,2.81429764 16.9675232,2.59195484 L16.9675232,2.59195484 Z" id="path3487"></path>
36
+ <path d="M20.1185616,3.7992507 L19.6372098,3.7992507 L19.5973102,3.52170555 L19.5824758,3.52170555 C19.4177624,3.74302609 19.1829692,3.85394192 18.878096,3.85394192 C18.6504641,3.85394192 18.4663125,3.78084992 18.3276873,3.63568818 C18.2018504,3.5038159 18.1389319,3.33974224 18.1389319,3.14500062 C18.1389319,2.85058808 18.2616997,2.62620074 18.5087697,2.47081635 C18.7553282,2.31543195 19.1021471,2.23927315 19.5487147,2.24285108 L19.5487147,2.19787139 C19.5487147,1.88045787 19.3819552,1.72200668 19.0479247,1.72200668 C18.8100622,1.72200668 18.600334,1.78180922 18.4192516,1.90039205 L18.3102952,1.54873263 C18.5343463,1.41021562 18.8110853,1.34070155 19.1374428,1.34070155 C19.7676505,1.34070155 20.0837774,1.67293792 20.0837774,2.33741066 L20.0837774,3.22473735 C20.0837774,3.46548093 20.0955426,3.65715576 20.1185616,3.7992507 Z M19.5620145,2.97121544 L19.5620145,2.59962183 C18.9706833,2.58939917 18.6750177,2.7514283 18.6750177,3.08519807 C18.6750177,3.21093676 18.7087788,3.30498521 18.7778357,3.36785455 C18.8468925,3.4307239 18.934876,3.461903 19.0397401,3.461903 C19.1573926,3.461903 19.267372,3.4245903 19.3676323,3.35047603 C19.4684041,3.27585063 19.5302995,3.18129105 19.5533185,3.06526389 C19.5589453,3.03919611 19.5620145,3.00750587 19.5620145,2.97121544 Z" id="path3489"></path>
37
+ <path d="M23.1647358,3.7992507 L22.6890109,3.7992507 L22.6639458,3.41232311 L22.6491114,3.41232311 C22.4971863,3.70673565 22.238351,3.85394192 21.8746516,3.85394192 C21.5841013,3.85394192 21.3421466,3.73995929 21.150322,3.51199403 C20.9584974,3.28402876 20.8628409,2.98808282 20.8628409,2.62466734 C20.8628409,2.23467296 20.966682,1.91879284 21.1753871,1.67753812 C21.3774423,1.45263965 21.6250239,1.34019041 21.9196665,1.34019041 C22.2434663,1.34019041 22.4700751,1.44906172 22.5989812,1.66731546 L22.6092119,1.66731546 L22.6092119,0.284189882 L23.1458091,0.284189882 L23.1458091,3.15011195 C23.1458091,3.38472194 23.1519475,3.60093115 23.1647358,3.7992507 L23.1647358,3.7992507 Z M22.6092119,2.78311854 L22.6092119,2.38136809 C22.6092119,2.31185402 22.6040965,2.2556294 22.5943774,2.21269424 C22.564197,2.08388876 22.4992324,1.97552858 22.4005067,1.88812486 C22.3007579,1.80072114 22.1805479,1.75676371 22.0419226,1.75676371 C21.8419136,1.75676371 21.6853847,1.83598931 21.57029,1.99495163 C21.4562183,2.15391396 21.3984151,2.35683371 21.3984151,2.60473316 C21.3984151,2.84292108 21.4531491,3.03612931 21.5631285,3.18486898 C21.6792463,3.34332017 21.8357752,3.42254577 22.031692,3.42254577 C22.2076591,3.42254577 22.3483304,3.35660963 22.4552407,3.22422621 C22.5585702,3.10206545 22.6092119,2.95485918 22.6092119,2.78311854 L22.6092119,2.78311854 Z" id="path3491"></path>
38
+ <path d="M27.749599,2.57457632 C27.749599,2.94514766 27.6437118,3.24876059 27.4319375,3.48694851 C27.2099325,3.73178116 26.916313,3.85394192 26.5485214,3.85394192 C26.1950526,3.85394192 25.9131984,3.73689249 25.7024471,3.50177137 C25.4927189,3.26716138 25.3878548,2.97121544 25.3878548,2.61444469 C25.3878548,2.24131768 25.4957881,1.93514909 25.7126777,1.6974723 C25.9295674,1.45979551 26.2211408,1.34070155 26.5889324,1.34070155 C26.9424012,1.34070155 27.2273246,1.45775098 27.4421681,1.69236097 C27.646781,1.92032623 27.749599,2.21473877 27.749599,2.57457632 L27.749599,2.57457632 Z M27.194075,2.59195484 C27.194075,2.36961204 27.145991,2.17895947 27.0503345,2.01999715 C26.9372858,1.82781118 26.7776878,1.7317182 26.5689827,1.7317182 C26.3541391,1.7317182 26.1904488,1.82781118 26.0774002,2.01999715 C25.9812321,2.17895947 25.9336597,2.37267883 25.9336597,2.60166636 C25.9336597,2.82400917 25.9817437,3.01466173 26.0774002,3.17362406 C26.193518,3.36581002 26.3551622,3.461903 26.5638673,3.461903 C26.7684802,3.461903 26.9296129,3.36427662 27.0452191,3.16851273 C27.1439448,3.00648361 27.194075,2.81429764 27.194075,2.59195484 L27.194075,2.59195484 Z" id="path3493"></path>
39
+ <path d="M30.6320829,3.7992507 L30.0965087,3.7992507 L30.0965087,2.41919193 C30.0965087,1.99392937 29.9348645,1.78129809 29.6100416,1.78129809 C29.4509551,1.78129809 29.3225605,1.83956724 29.2233233,1.95661667 C29.124086,2.0736661 29.0744674,2.21167198 29.0744674,2.36961204 L29.0744674,3.79873957 L28.5378701,3.79873957 L28.5378701,2.07826629 C28.5378701,1.86665728 28.5317317,1.63715862 28.5189434,1.38874804 L28.989553,1.38874804 L29.0146181,1.76545297 L29.0294525,1.76545297 C29.092371,1.64840354 29.1854699,1.55179943 29.3072145,1.47461836 C29.4530012,1.38465897 29.6151569,1.33916815 29.7936817,1.33916815 C30.0182443,1.33916815 30.2054651,1.41174902 30.354321,1.55742189 C30.5400071,1.73580726 30.6320829,2.00210749 30.6320829,2.35581145 L30.6320829,3.7992507 L30.6320829,3.7992507 Z" id="path3495"></path>
40
+ <path d="M34.2399196,1.79100961 L33.6496114,1.79100961 L33.6496114,2.96150391 C33.6496114,3.25898325 33.7544755,3.40772292 33.9621576,3.40772292 C34.0583256,3.40772292 34.1381247,3.39954479 34.2010431,3.38267741 L34.2148545,3.78902805 C34.1089673,3.82889641 33.9698306,3.84883059 33.7984673,3.84883059 C33.586693,3.84883059 33.4219796,3.78442785 33.3027926,3.65562236 C33.183094,3.52681688 33.1237563,3.31009654 33.1237563,3.00597247 L33.1237563,1.79100961 L32.7713106,1.79100961 L32.7713106,1.3897703 L33.1237563,1.3897703 L33.1237563,0.948151494 L33.6490999,0.789700301 L33.6490999,1.38925917 L34.239408,1.38925917 L34.239408,1.79100961 L34.2399196,1.79100961 Z" id="path3497"></path>
41
+ <path d="M37.0779002,3.7992507 L36.541303,3.7992507 L36.541303,2.42941458 C36.541303,1.9975073 36.3796588,1.78129809 36.0558589,1.78129809 C35.8072542,1.78129809 35.6374256,1.90652565 35.5443267,2.15698076 C35.5284692,2.20962744 35.5192616,2.27403019 35.5192616,2.34967785 L35.5192616,3.79873957 L34.9836874,3.79873957 L34.9836874,0.284189882 L35.5192616,0.284189882 L35.5192616,1.7363184 L35.5294923,1.7363184 C35.6982979,1.4720627 35.9402526,1.34019041 36.2538219,1.34019041 C36.4758268,1.34019041 36.6594669,1.41277128 36.8052536,1.55844415 C36.9868475,1.73989633 37.0779002,2.00977449 37.0779002,2.36654524 L37.0779002,3.7992507 Z" id="path3499"></path>
42
+ <path d="M40.005399,2.48052787 C40.005399,2.57662085 39.9982376,2.65737985 39.9854493,2.72331599 L38.3777036,2.72331599 C38.384865,2.96150391 38.4615949,3.14295608 38.6104507,3.26869477 C38.7465183,3.38114401 38.9219738,3.43736862 39.1368174,3.43736862 C39.3746798,3.43736862 39.5915695,3.39954479 39.7869748,3.32338599 L39.8708661,3.69549073 C39.6422112,3.79465051 39.3731452,3.8442304 39.0616221,3.8442304 C38.6882036,3.8442304 38.3940726,3.73433683 38.1812752,3.51454969 C37.9674547,3.29476255 37.8615676,2.99983888 37.8615676,2.62977867 C37.8615676,2.26636319 37.9602933,1.96377253 38.1592793,1.72251781 C38.3669614,1.46490684 38.6477926,1.33610135 39.0022844,1.33610135 C39.3491032,1.33610135 39.6125423,1.46490684 39.7905555,1.72251781 C39.9342961,1.92697096 40.005399,2.17998174 40.005399,2.48052787 L40.005399,2.48052787 Z M39.4938668,2.34201086 C39.4979591,2.18304853 39.4626634,2.04606492 39.3900258,1.93054889 C39.2969269,1.78180922 39.1552325,1.70718382 38.9634079,1.70718382 C38.7884639,1.70718382 38.6457464,1.77976469 38.5367901,1.92543756 C38.4477835,2.04146473 38.3950957,2.17998174 38.3777036,2.34201086 L39.4938668,2.34201086 L39.4938668,2.34201086 Z" id="path3501"></path>
43
+ </g>
44
+ </g>
45
+ </g>
46
+ </g>
47
+ </g>
48
+ </g>
49
+ </svg>
changelog.txt CHANGED
@@ -1,12 +1,22 @@
1
  Plugin Name: WP Defender
2
  Author: Hoang Ngo, Aaron Edwards
3
- Tested up to: 4.7.4
4
 
5
  Change Log:
6
 
 
 
 
 
 
 
 
 
7
  1.6.2 - 2017-05-07
8
  ----------------------------------------------------------------------
 
9
  - Improvement: Email reports now have unsubscribe link, and link to Reports where email reports can be turned off.
 
10
  - Other minor enhancements/fixes
11
 
12
  1.6.1 - 2017-21-06
1
  Plugin Name: WP Defender
2
  Author: Hoang Ngo, Aaron Edwards
3
+ Tested up to: 4.8.1
4
 
5
  Change Log:
6
 
7
+ 1.7 - 2017-15-08
8
+ ----------------------------------------------------------------------
9
+ - New: Now you can enable 2 factors authentication with Defender and Google Authenticator app, support for iOS and Android
10
+ - New: We can define how long the "Remember me" can take affect, via a new Security Tweak, called "Manage Login Duration"
11
+ - Improvement: IP Lockout logs now have separate tables, better for performance.
12
+ - Fix: Ignore a file in Scanning section sometimes coming back after couple of scans.
13
+ - Other minor enhancements/fixes
14
+
15
  1.6.2 - 2017-05-07
16
  ----------------------------------------------------------------------
17
+ - New: CSV export for Audit Logging.
18
  - Improvement: Email reports now have unsubscribe link, and link to Reports where email reports can be turned off.
19
+ - Fix: Typo in Audit email.
20
  - Other minor enhancements/fixes
21
 
22
  1.6.1 - 2017-21-06
languages/wpdef-default.pot CHANGED
@@ -2,9 +2,9 @@
2
  # This file is distributed under the GNU General Public License (Version 2 - GPLv2).
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: WP Defender Pro 1.7-beta1\n"
6
  "Report-Msgid-Bugs-To: https://wpmudev.org\n"
7
- "POT-Creation-Date: 2017-07-07 08:16:30+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
@@ -152,17 +152,17 @@ msgid "Lockout reports are active scheduled to send %s"
152
  msgstr ""
153
 
154
  #: app/behavior/report-free.php:129 app/behavior/report.php:224
155
- #: app/behavior/utils.php:588 free/utils.php:591
156
  msgid "daily"
157
  msgstr ""
158
 
159
  #: app/behavior/report-free.php:132 app/behavior/report.php:227
160
- #: app/behavior/utils.php:591 free/utils.php:594
161
  msgid "weekly"
162
  msgstr ""
163
 
164
  #: app/behavior/report-free.php:135 app/behavior/report.php:230
165
- #: app/behavior/utils.php:594 free/utils.php:597
166
  msgid "monthly"
167
  msgstr ""
168
 
@@ -204,67 +204,72 @@ msgstr ""
204
  msgid "To activate this report you must first enable the Audit Logging module."
205
  msgstr ""
206
 
207
- #: app/behavior/utils.php:75 free/utils.php:77
208
  msgid ""
209
  "WPMU DEV Dashboard will be required for this action. Please visit <a "
210
  "href=\"%s\">here</a> and install the WPMU DEV Dashboard"
211
  msgstr ""
212
 
213
- #: app/behavior/utils.php:172 app/behavior/utils.php:181
214
  #: app/module/audit/view/table.php:86 app/module/audit/view/table.php:144
215
  #: free/utils.php:174 free/utils.php:183
216
  msgid "Guest"
217
  msgstr ""
218
 
219
- #: app/behavior/utils.php:523 free/utils.php:525
220
  msgid "WordPress Core Integrity"
221
  msgstr ""
222
 
223
- #: app/behavior/utils.php:524 free/utils.php:526
224
  msgid "Plugins & Themes vulnerability"
225
  msgstr ""
226
 
227
- #: app/behavior/utils.php:525 app/module/scan/behavior/scan.php:145
228
  #: app/module/scan/view/layouts/layout.php:70
229
  #: app/module/scan/view/setting-free.php:52 app/module/scan/view/setting.php:43
230
- #: app/view/settings.php:98 free/utils.php:527
231
  msgid "Suspicious Code"
232
  msgstr ""
233
 
234
- #: app/behavior/utils.php:571 free/utils.php:574
 
 
 
 
 
235
  msgid "Please upgrade to 5.3 or later"
236
  msgstr ""
237
 
238
- #: app/controller/dashboard.php:59 app/view/dashboard.php:4
239
  msgid "Dashboard"
240
  msgstr ""
241
 
242
- #: app/controller/dashboard.php:186 app/controller/dashboard.php:188
243
- #: app/controller/requirement.php:69 app/module/ip-lockout/view/locked.php:74
244
  msgid "Defender"
245
  msgstr ""
246
 
247
- #: app/controller/dashboard.php:220
248
  msgid "QUICK SETUP"
249
  msgstr ""
250
 
251
- #: app/controller/dashboard.php:220
252
  msgid "Skip"
253
  msgstr ""
254
 
255
- #: app/controller/dashboard.php:221
256
  msgid "Activating File Scanning..."
257
  msgstr ""
258
 
259
- #: app/controller/dashboard.php:222
260
  msgid "Activating Audit Module..."
261
  msgstr ""
262
 
263
- #: app/controller/dashboard.php:223
264
  msgid "Activating IP Lockouts Module..."
265
  msgstr ""
266
 
267
- #: app/controller/dashboard.php:224
268
  msgid "Activating Blacklist Monitoring..."
269
  msgstr ""
270
 
@@ -304,6 +309,244 @@ msgstr ""
304
  msgid "Defender%s"
305
  msgstr ""
306
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  #: app/module/audit/behavior/audit-free.php:25
308
  #: app/module/audit/behavior/audit.php:38 app/view/activator.php:35
309
  msgid ""
@@ -324,11 +567,6 @@ msgstr ""
324
  msgid "Please hold on, Defender will update Audit information soon..."
325
  msgstr ""
326
 
327
- #: app/module/audit/behavior/audit.php:43 app/module/audit/view/new.php:15
328
- #: app/module/ip-lockout/behavior/widget.php:37
329
- msgid "Activate"
330
- msgstr ""
331
-
332
  #: app/module/audit/component/audit-api.php:57
333
  #: app/module/audit/component/audit-api.php:89
334
  msgid ""
@@ -873,7 +1111,7 @@ msgstr ""
873
  #: app/module/scan/view/layouts/layout.php:131
874
  #: app/module/scan/view/layouts/layout.php:146
875
  #: app/module/scan/view/setting-free.php:3 app/module/scan/view/setting.php:3
876
- #: app/view/settings.php:6 free/main-activator.php:139 main-activator.php:81
877
  msgid "Settings"
878
  msgstr ""
879
 
@@ -1015,17 +1253,6 @@ msgstr ""
1015
  msgid "User"
1016
  msgstr ""
1017
 
1018
- #: app/module/audit/controller/main.php:143
1019
- #: app/module/ip-lockout/controller/main.php:90
1020
- msgid "Never"
1021
- msgstr ""
1022
-
1023
- #: app/module/audit/controller/main.php:196
1024
- #: app/module/ip-lockout/controller/main.php:656
1025
- #: app/module/scan/controller/main.php:306
1026
- msgid "Your settings have been updated."
1027
- msgstr ""
1028
-
1029
  #: app/module/audit/controller/main.php:331
1030
  msgid "Hi {USER_NAME},"
1031
  msgstr ""
@@ -1132,7 +1359,7 @@ msgstr ""
1132
  msgid "<a href=\"%s\">Configure reporting preferences</a>"
1133
  msgstr ""
1134
 
1135
- #: app/module/audit/view/free.php:9 free/main-activator.php:99
1136
  msgid "Upgrade"
1137
  msgstr ""
1138
 
@@ -1345,14 +1572,6 @@ msgstr ""
1345
  msgid "Update Settings"
1346
  msgstr ""
1347
 
1348
- #: app/module/audit/view/report.php:68 app/module/scan/controller/main.php:531
1349
- msgid "Cancel"
1350
- msgstr ""
1351
-
1352
- #: app/module/audit/view/settings.php:10
1353
- msgid "Deactivate"
1354
- msgstr ""
1355
-
1356
  #: app/module/audit/view/settings.php:13
1357
  msgid "If you no longer want to use this feature you can turn it off at any time."
1358
  msgstr ""
@@ -1431,14 +1650,14 @@ msgid "Audit log reports are disabled"
1431
  msgstr ""
1432
 
1433
  #: app/module/hardener/behavior/widget.php:19
1434
- #: app/module/hardener/controller/main.php:129
1435
  #: app/module/hardener/view/layouts/layout.php:3
1436
  msgid "Security Tweaks"
1437
  msgstr ""
1438
 
1439
  #: app/module/hardener/behavior/widget.php:34
1440
  msgid ""
1441
- " Defender checks for security tweaks you can make to enhance your website’s\n"
1442
  " defense against hackers and bots."
1443
  msgstr ""
1444
 
@@ -1485,7 +1704,7 @@ msgstr ""
1485
  #: app/module/hardener/component/servers/apache-service.php:104
1486
  #: app/module/hardener/component/servers/apache-service.php:108
1487
  #: app/module/hardener/component/servers/apache-service.php:158
1488
- #: app/module/hardener/component/servers/apache-service.php:183
1489
  msgid "The file %s is not writeable"
1490
  msgstr ""
1491
 
@@ -1538,6 +1757,14 @@ msgstr ""
1538
  msgid "Disable the file editor"
1539
  msgstr ""
1540
 
 
 
 
 
 
 
 
 
1541
  #: app/module/hardener/component/disable-trackback.php:28
1542
  #: app/module/hardener/view/rules/disable-trackback.php:8
1543
  msgid "Disable trackbacks and pingbacks"
@@ -1552,6 +1779,20 @@ msgstr ""
1552
  msgid "Hide error reporting"
1553
  msgstr ""
1554
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1555
  #: app/module/hardener/component/php-version.php:30
1556
  #: app/module/hardener/view/rules/php-version.php:8
1557
  msgid "Update PHP to latest version"
@@ -1576,12 +1817,12 @@ msgstr ""
1576
  msgid "Prevent Information Disclosure"
1577
  msgstr ""
1578
 
1579
- #: app/module/hardener/component/security-key.php:35
1580
  #: app/module/hardener/view/rules/security-key.php:8
1581
  msgid "Update old security keys"
1582
  msgstr ""
1583
 
1584
- #: app/module/hardener/component/security-key.php:77
1585
  msgid ""
1586
  "All key salts have been regenerated. You will now need to <a "
1587
  "href=\"%s\"><strong>re-login</strong></a>.<br/>This will auto reload after "
@@ -1597,25 +1838,29 @@ msgstr ""
1597
  msgid "Update WordPress to latest version"
1598
  msgstr ""
1599
 
1600
- #: app/module/hardener/controller/main.php:57
1601
  msgid "Security tweak successfully restored."
1602
  msgstr ""
1603
 
1604
- #: app/module/hardener/controller/main.php:75
1605
  msgid "Security tweak successfully ignored."
1606
  msgstr ""
1607
 
1608
- #: app/module/hardener/controller/main.php:91
1609
  msgid "Security tweak successfully reverted."
1610
  msgstr ""
1611
 
1612
- #: app/module/hardener/controller/main.php:117
1613
  msgid "Security tweak successfully resolved."
1614
  msgstr ""
1615
 
 
 
 
 
1616
  #: app/module/hardener/rule.php:111
1617
- #: app/module/scan/behavior/core-result.php:183
1618
- #: app/module/scan/behavior/pro/content-result.php:105
1619
  #: app/module/scan/behavior/pro/vuln-result.php:156
1620
  #: app/module/scan/component/result-table.php:199
1621
  msgid "Ignore"
@@ -1705,6 +1950,7 @@ msgstr ""
1705
  #: app/module/hardener/view/rules/disable-file-editor.php:11
1706
  #: app/module/hardener/view/rules/disable-trackback.php:11
1707
  #: app/module/hardener/view/rules/hide-error.php:11
 
1708
  #: app/module/hardener/view/rules/php-version.php:11
1709
  #: app/module/hardener/view/rules/prevent-php-executed.php:11
1710
  #: app/module/hardener/view/rules/protect-information.php:11
@@ -1728,6 +1974,7 @@ msgstr ""
1728
  #: app/module/hardener/view/rules/disable-file-editor.php:16
1729
  #: app/module/hardener/view/rules/disable-trackback.php:16
1730
  #: app/module/hardener/view/rules/hide-error.php:16
 
1731
  #: app/module/hardener/view/rules/php-version.php:34
1732
  #: app/module/hardener/view/rules/prevent-php-executed.php:16
1733
  #: app/module/hardener/view/rules/protect-information.php:16
@@ -1750,6 +1997,7 @@ msgstr ""
1750
 
1751
  #: app/module/hardener/view/rules/change-admin.php:34
1752
  #: app/module/hardener/view/rules/db-prefix.php:37
 
1753
  #: app/module/hardener/view/rules/security-key.php:31
1754
  #: app/module/scan/behavior/pro/vuln-result.php:162
1755
  #: app/module/scan/behavior/pro/vuln-result.php:166
@@ -1793,7 +2041,8 @@ msgstr ""
1793
 
1794
  #: app/module/hardener/view/rules/disable-file-editor.php:26
1795
  #: app/module/hardener/view/rules/disable-trackback.php:26
1796
- #: app/module/hardener/view/rules/prevent-php-executed.php:26
 
1797
  #: app/module/hardener/view/rules/protect-information.php:26
1798
  msgid "Revert"
1799
  msgstr ""
@@ -1864,6 +2113,20 @@ msgid ""
1864
  "your hosting provider and ask them to set WP_DEBUG to false."
1865
  msgstr ""
1866
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1867
  #: app/module/hardener/view/rules/php-version.php:14
1868
  msgid ""
1869
  "PHP versions older than 5.6 are no longer supported. For security and "
@@ -1903,17 +2166,25 @@ msgid ""
1903
  "direct PHP execution in directories that don't require it."
1904
  msgstr ""
1905
 
1906
- #: app/module/hardener/view/rules/prevent-php-executed.php:20
1907
  msgid "PHP execution is locked down."
1908
  msgstr ""
1909
 
1910
- #: app/module/hardener/view/rules/prevent-php-executed.php:51
 
 
 
 
 
 
 
 
1911
  #: app/module/hardener/view/rules/protect-information.php:42
1912
  msgid "Server Type:"
1913
  msgstr ""
1914
 
1915
- #: app/module/hardener/view/rules/prevent-php-executed.php:65
1916
- #: app/module/hardener/view/rules/prevent-php-executed.php:83
1917
  #: app/module/hardener/view/rules/protect-information.php:54
1918
  #: app/module/hardener/view/rules/protect-information.php:66
1919
  msgid ""
@@ -1921,76 +2192,78 @@ msgid ""
1921
  "down the files and folders inside."
1922
  msgstr ""
1923
 
1924
- #: app/module/hardener/view/rules/prevent-php-executed.php:68
1925
- #: app/module/hardener/view/rules/prevent-php-executed.php:86
1926
- msgid ""
1927
- "File paths to ignore in the /wp-content directory (each in a new line). The "
1928
- "file index.php is not allowed"
1929
- msgstr ""
1930
-
1931
- #: app/module/hardener/view/rules/prevent-php-executed.php:78
1932
- #: app/module/hardener/view/rules/prevent-php-executed.php:96
1933
  #: app/module/hardener/view/rules/protect-information.php:61
1934
  #: app/module/hardener/view/rules/protect-information.php:73
1935
  msgid "Add .htaccess file"
1936
  msgstr ""
1937
 
1938
- #: app/module/hardener/view/rules/prevent-php-executed.php:120
1939
  #: app/module/hardener/view/rules/protect-information.php:105
1940
  msgid "For NGINX servers:"
1941
  msgstr ""
1942
 
1943
- #: app/module/hardener/view/rules/prevent-php-executed.php:123
1944
- msgid ""
1945
- "Input the file paths to ignore in the /wp-content directory (each in a new "
1946
- "line). The file index.php is not allowed"
1947
- msgstr ""
1948
-
1949
- #: app/module/hardener/view/rules/prevent-php-executed.php:127
1950
  #: app/module/hardener/view/rules/protect-information.php:108
1951
  msgid ""
1952
  "Copy the generated code into your site specific .conf file usually located "
1953
  "in a subdirectory under /etc/nginx/... or /usr/local/nginx/conf/..."
1954
  msgstr ""
1955
 
1956
- #: app/module/hardener/view/rules/prevent-php-executed.php:130
1957
  #: app/module/hardener/view/rules/protect-information.php:111
1958
  msgid ""
1959
  "Add the code above inside the <strong>server</strong> section in the file, "
1960
  "right before the php location block. Looks something like:"
1961
  msgstr ""
1962
 
1963
- #: app/module/hardener/view/rules/prevent-php-executed.php:134
1964
  #: app/module/hardener/view/rules/protect-information.php:115
1965
  msgid "Reload NGINX."
1966
  msgstr ""
1967
 
1968
- #: app/module/hardener/view/rules/prevent-php-executed.php:137
1969
  #: app/module/hardener/view/rules/protect-information.php:118
1970
  msgid ""
1971
  "Still having trouble? <a target='_blank' href=\"%s\">Open a support "
1972
  "ticket</a>."
1973
  msgstr ""
1974
 
1975
- #: app/module/hardener/view/rules/prevent-php-executed.php:147
1976
  #: app/module/hardener/view/rules/protect-information.php:124
1977
  msgid "For IIS servers, <a href=\"%s\">visit Microsoft TechNet</a>"
1978
  msgstr ""
1979
 
1980
- #: app/module/hardener/view/rules/prevent-php-executed.php:152
1981
  msgid ""
1982
  "We will place <strong>web.config</strong> file into the uploads folder to "
1983
  "lock down the files and folders inside."
1984
  msgstr ""
1985
 
1986
- #: app/module/hardener/view/rules/prevent-php-executed.php:155
1987
  msgid "For more information, please <a href=\"%s\">visit Microsoft TechNet</a>"
1988
  msgstr ""
1989
 
1990
- #: app/module/hardener/view/rules/prevent-php-executed.php:163
1991
  msgid "Add web.config file"
1992
  msgstr ""
1993
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1994
  #: app/module/hardener/view/rules/protect-information.php:13
1995
  msgid ""
1996
  "Often servers are incorrectly configured, and can allow an attacker to get "
@@ -2093,12 +2366,10 @@ msgid "Last lockout"
2093
  msgstr ""
2094
 
2095
  #: app/module/ip-lockout/behavior/widget.php:51
2096
- #: app/module/ip-lockout/view/layouts/layout.php:34
2097
  msgid "Login lockouts this week"
2098
  msgstr ""
2099
 
2100
  #: app/module/ip-lockout/behavior/widget.php:57
2101
- #: app/module/ip-lockout/view/layouts/layout.php:40
2102
  msgid "404 lockouts this week"
2103
  msgstr ""
2104
 
@@ -2114,23 +2385,23 @@ msgstr ""
2114
  msgid "Lockout notifications are disabled"
2115
  msgstr ""
2116
 
2117
- #: app/module/ip-lockout/component/login-protection-api.php:64
2118
- #: app/module/ip-lockout/controller/main.php:551
2119
- #: app/module/ip-lockout/controller/main.php:560
2120
  msgid ""
2121
  "You have been locked out by the administrator for attempting to login with "
2122
  "a banned username"
2123
  msgstr ""
2124
 
2125
- #: app/module/ip-lockout/component/login-protection-api.php:77
2126
  msgid "Lockout occurred: Attempting to login with a banned username."
2127
  msgstr ""
2128
 
2129
- #: app/module/ip-lockout/component/login-protection-api.php:79
2130
  msgid "Lockout occurred: Too many failed login attempts"
2131
  msgstr ""
2132
 
2133
- #: app/module/ip-lockout/component/login-protection-api.php:146
2134
  msgid "Lockout occurred: Too many 404 requests for %s"
2135
  msgstr ""
2136
 
@@ -2186,23 +2457,28 @@ msgid "All"
2186
  msgstr ""
2187
 
2188
  #: app/module/ip-lockout/component/logs-table.php:164
2189
- #: app/module/ip-lockout/model/log-model.php:103
 
2190
  msgid "Failed login attempts"
2191
  msgstr ""
2192
 
2193
  #: app/module/ip-lockout/component/logs-table.php:166
2194
- #: app/module/ip-lockout/model/log-model.php:104
 
2195
  msgid "Login lockout"
2196
  msgstr ""
2197
 
2198
  #: app/module/ip-lockout/component/logs-table.php:168
2199
- #: app/module/ip-lockout/model/log-model.php:105
2200
- #: app/module/ip-lockout/model/log-model.php:106
 
 
2201
  msgid "404 error"
2202
  msgstr ""
2203
 
2204
  #: app/module/ip-lockout/component/logs-table.php:170
2205
- #: app/module/ip-lockout/model/log-model.php:107
 
2206
  msgid "404 lockout"
2207
  msgstr ""
2208
 
@@ -2224,60 +2500,60 @@ msgstr ""
2224
  msgid "%s results"
2225
  msgstr ""
2226
 
2227
- #: app/module/ip-lockout/controller/main.php:154
2228
  msgid "Your logs have been successfully deleted."
2229
  msgstr ""
2230
 
2231
- #: app/module/ip-lockout/controller/main.php:194
2232
  msgid ""
2233
  "IP %s has been added to your blacklist. You can control your blacklist in "
2234
  "<a href=\"%s\">IP Lockouts.</a>"
2235
  msgstr ""
2236
 
2237
- #: app/module/ip-lockout/controller/main.php:199
2238
  msgid "No record found"
2239
  msgstr ""
2240
 
2241
- #: app/module/ip-lockout/controller/main.php:224
2242
  msgid "Demo"
2243
  msgstr ""
2244
 
2245
- #: app/module/ip-lockout/controller/main.php:403
2246
  msgid "404 lockout alert for %s"
2247
  msgstr ""
2248
 
2249
- #: app/module/ip-lockout/controller/main.php:426
2250
  msgid "Login lockout alert for %s"
2251
  msgstr ""
2252
 
2253
- #: app/module/ip-lockout/controller/main.php:491
2254
  msgid "Failed login attempt with username %s"
2255
  msgstr ""
2256
 
2257
- #: app/module/ip-lockout/controller/main.php:553
2258
- #: app/module/ip-lockout/controller/main.php:563
2259
  msgid "%d login attempts remaining"
2260
  msgstr ""
2261
 
2262
- #: app/module/ip-lockout/controller/main.php:652
2263
  msgid ""
2264
  "Your settings have been updated, however some IPs were removed because "
2265
  "invalid format, or you blacklist yourself"
2266
  msgstr ""
2267
 
2268
- #: app/module/ip-lockout/controller/main.php:663
2269
  msgid "Login Protection has been activated."
2270
  msgstr ""
2271
 
2272
- #: app/module/ip-lockout/controller/main.php:665
2273
  msgid "Login Protection has been deactivated."
2274
  msgstr ""
2275
 
2276
- #: app/module/ip-lockout/controller/main.php:670
2277
  msgid "404 Detection has been activated."
2278
  msgstr ""
2279
 
2280
- #: app/module/ip-lockout/controller/main.php:672
2281
  msgid "404 Detection has been deactivated."
2282
  msgstr ""
2283
 
@@ -2299,7 +2575,12 @@ msgstr ""
2299
  msgid "Your whitelist/blacklist has been successfully imported."
2300
  msgstr ""
2301
 
2302
- #: app/module/ip-lockout/model/log-model.php:74
 
 
 
 
 
2303
  msgid ""
2304
  "Request for file <span class='log-text-table' tooltip='%s'>%s</span> which "
2305
  "doesn't exist"
@@ -2399,11 +2680,6 @@ msgid ""
2399
  "temporarily block them from accessing your site."
2400
  msgstr ""
2401
 
2402
- #: app/module/ip-lockout/view/detect-404/disabled.php:16
2403
- #: app/module/ip-lockout/view/login-lockouts/disabled.php:18
2404
- msgid "Enable"
2405
- msgstr ""
2406
-
2407
  #: app/module/ip-lockout/view/detect-404/enabled.php:7
2408
  msgid "Deactivate 404 Detection"
2409
  msgstr ""
@@ -2543,7 +2819,7 @@ msgstr ""
2543
  #: app/module/ip-lockout/view/emails/login-lockout.php:482
2544
  #: app/module/ip-lockout/view/emails/login-username-ban.php:481
2545
  #: app/module/ip-lockout/view/emails/report.php:515
2546
- #: app/module/ip-lockout/view/locked.php:6
2547
  msgid "WP Defender"
2548
  msgstr ""
2549
 
@@ -2632,7 +2908,15 @@ msgid "Lockouts in the past 24 hours"
2632
  msgstr ""
2633
 
2634
  #: app/module/ip-lockout/view/layouts/layout.php:21
2635
- msgid "Total lockouts this month"
 
 
 
 
 
 
 
 
2636
  msgstr ""
2637
 
2638
  #: app/module/ip-lockout/view/layouts/layout.php:54
@@ -2672,7 +2956,7 @@ msgstr ""
2672
  msgid "IP Blacklist"
2673
  msgstr ""
2674
 
2675
- #: app/module/ip-lockout/view/locked.php:73
2676
  msgid "Powered by"
2677
  msgstr ""
2678
 
@@ -2732,6 +3016,14 @@ msgid ""
2732
  "these are common for bots to try logging in with. One username per line"
2733
  msgstr ""
2734
 
 
 
 
 
 
 
 
 
2735
  #: app/module/ip-lockout/view/notification/enabled.php:10
2736
  msgid "Send email notifications"
2737
  msgstr ""
@@ -2880,66 +3172,75 @@ msgstr ""
2880
  msgid "This WordPress core file appears modified"
2881
  msgstr ""
2882
 
2883
- #: app/module/scan/behavior/core-result.php:78
 
 
 
 
 
 
 
 
 
2884
  msgid "This file can't not remove"
2885
  msgstr ""
2886
 
2887
- #: app/module/scan/behavior/core-result.php:95
2888
  msgid "This file is not resolvable"
2889
  msgstr ""
2890
 
2891
- #: app/module/scan/behavior/core-result.php:99
2892
  msgid ""
2893
  "It seems the %s file is currently using by another process or isn't "
2894
  "writeable."
2895
  msgstr ""
2896
 
2897
- #: app/module/scan/behavior/core-result.php:116
2898
- #: app/module/scan/behavior/pro/content-result.php:55
2899
  #: app/module/scan/behavior/pro/vuln-result.php:109
2900
  msgid "Issue Details"
2901
  msgstr ""
2902
 
2903
- #: app/module/scan/behavior/core-result.php:126
2904
- #: app/module/scan/behavior/pro/content-result.php:64
2905
  msgid "Location"
2906
  msgstr ""
2907
 
2908
- #: app/module/scan/behavior/core-result.php:136
2909
  msgid "Size"
2910
  msgstr ""
2911
 
2912
- #: app/module/scan/behavior/core-result.php:153
2913
- #: app/module/scan/behavior/pro/content-result.php:72
2914
  msgid "Date Added"
2915
  msgstr ""
2916
 
2917
- #: app/module/scan/behavior/core-result.php:191
2918
- #: app/module/scan/behavior/pro/content-result.php:126
2919
  msgid "Delete"
2920
  msgstr ""
2921
 
2922
- #: app/module/scan/behavior/core-result.php:193
2923
  msgid ""
2924
  "This will permanent remove the file/folder with all content, do you want to "
2925
  "do this?"
2926
  msgstr ""
2927
 
2928
- #: app/module/scan/behavior/core-result.php:196
2929
- #: app/module/scan/behavior/pro/content-result.php:131
2930
  msgid "Yes"
2931
  msgstr ""
2932
 
2933
- #: app/module/scan/behavior/core-result.php:199
2934
- #: app/module/scan/behavior/pro/content-result.php:134
2935
  msgid "No"
2936
  msgstr ""
2937
 
2938
- #: app/module/scan/behavior/core-result.php:209
2939
  msgid "Restore to Original"
2940
  msgstr ""
2941
 
2942
- #: app/module/scan/behavior/core-result.php:258
2943
  msgid ""
2944
  "A stray file has been found in your site directory, which your version of "
2945
  "WordPress doesn't need. As far as we can tell, the file is harmless (and "
@@ -2948,21 +3249,21 @@ msgid ""
2948
  "beforehand"
2949
  msgstr ""
2950
 
2951
- #: app/module/scan/behavior/core-result.php:274
2952
- #: app/module/scan/behavior/core-result.php:296
2953
- #: app/module/scan/behavior/core-result.php:318
2954
- #: app/module/scan/behavior/pro/content-result.php:92
2955
  msgid "Pulling source file..."
2956
  msgstr ""
2957
 
2958
- #: app/module/scan/behavior/core-result.php:291
2959
  msgid ""
2960
  "Compare your file with the original file in the WordPress repository. "
2961
  "Pieces highlighted in red will be removed when you patch the file, and "
2962
  "pieces highlighted in green will be added."
2963
  msgstr ""
2964
 
2965
- #: app/module/scan/behavior/core-result.php:313
2966
  msgid ""
2967
  "We found this folder in your WordPress file list. Your current version of "
2968
  "WordPress doesn’t use this folder so it might belong to another "
@@ -2971,11 +3272,11 @@ msgid ""
2971
  "support team for more information."
2972
  msgstr ""
2973
 
2974
- #: app/module/scan/behavior/pro/content-result.php:45
2975
  msgid "Suspicious function found"
2976
  msgstr ""
2977
 
2978
- #: app/module/scan/behavior/pro/content-result.php:87
2979
  msgid ""
2980
  " There’s some suspicious looking code in the file %s. If you know the code "
2981
  "is harmless you can ignore this warning. Otherwise, you can choose to "
@@ -2983,19 +3284,19 @@ msgid ""
2983
  "recommend backing up your website."
2984
  msgstr ""
2985
 
2986
- #: app/module/scan/behavior/pro/content-result.php:112
2987
  msgid ""
2988
  "This will permanent delete the whole plugin containing this file, do you "
2989
  "want to do this?"
2990
  msgstr ""
2991
 
2992
- #: app/module/scan/behavior/pro/content-result.php:115
2993
  msgid ""
2994
  "This will permanent delete the whole theme containing this file, do you "
2995
  "want to do this?"
2996
  msgstr ""
2997
 
2998
- #: app/module/scan/behavior/pro/content-result.php:118
2999
  msgid "This will permanent delete this file, do you want to do this?"
3000
  msgstr ""
3001
 
@@ -3121,7 +3422,7 @@ msgid "Suspicious File"
3121
  msgstr ""
3122
 
3123
  #: app/module/scan/component/result-table.php:35
3124
- #: app/module/scan/controller/main.php:808
3125
  msgid "Issue"
3126
  msgstr ""
3127
 
@@ -3182,81 +3483,81 @@ msgstr ""
3182
  msgid "Update Theme"
3183
  msgstr ""
3184
 
3185
- #: app/module/scan/controller/main.php:179
3186
- #: app/module/scan/controller/main.php:440
3187
  msgid "The suspicious file has been successfully ignored."
3188
  msgid_plural "The suspicious files have been successfully ignored."
3189
  msgstr[0] ""
3190
  msgstr[1] ""
3191
 
3192
- #: app/module/scan/controller/main.php:194
3193
- #: app/module/scan/controller/main.php:411
3194
  msgid "The suspicious file has been successfully restored."
3195
  msgid_plural "The suspicious files have been successfully restored."
3196
  msgstr[0] ""
3197
  msgstr[1] ""
3198
 
3199
- #: app/module/scan/controller/main.php:213
3200
  msgid "The suspicious files has been successfully deleted."
3201
  msgid_plural "The suspicious files have been successfully deleted."
3202
  msgstr[0] ""
3203
  msgstr[1] ""
3204
 
3205
- #: app/module/scan/controller/main.php:219
3206
  msgid "No item has been deleted"
3207
  msgstr ""
3208
 
3209
- #: app/module/scan/controller/main.php:236
3210
  msgid "The suspicious files has been successfully resolved."
3211
  msgid_plural "The suspicious files have been successfully resolved."
3212
  msgstr[0] ""
3213
  msgstr[1] ""
3214
 
3215
- #: app/module/scan/controller/main.php:242
3216
  msgid "No item has been resolved"
3217
  msgstr ""
3218
 
3219
- #: app/module/scan/controller/main.php:336
3220
  msgid "This item has been resolved."
3221
  msgstr ""
3222
 
3223
- #: app/module/scan/controller/main.php:340
3224
  msgid "Please try again!"
3225
  msgstr ""
3226
 
3227
- #: app/module/scan/controller/main.php:351
3228
- #: app/module/scan/controller/main.php:387
3229
- #: app/module/scan/controller/main.php:416
3230
- #: app/module/scan/controller/main.php:445
3231
  msgid "The item doesn't exist!"
3232
  msgstr ""
3233
 
3234
- #: app/module/scan/controller/main.php:381
3235
  msgid "This item has been permanent removed."
3236
  msgstr ""
3237
 
3238
- #: app/module/scan/controller/main.php:520
3239
  #: app/module/scan/view/layouts/layout.php:5
3240
  #: app/module/scan/view/scanning.php:6 app/view/activator-free.php:13
3241
  #: app/view/activator.php:13
3242
  msgid "File Scanning"
3243
  msgstr ""
3244
 
3245
- #: app/module/scan/controller/main.php:531
3246
  msgid "Scan In Progress"
3247
  msgstr ""
3248
 
3249
- #: app/module/scan/controller/main.php:532 app/module/scan/view/issues.php:37
3250
  msgid ""
3251
  "Your code is currently clean! There were no issues found during the last "
3252
  "scan, though you can always perform a new scan anytime."
3253
  msgstr ""
3254
 
3255
- #: app/module/scan/controller/main.php:806
3256
  msgid "File"
3257
  msgstr ""
3258
 
3259
- #: app/module/scan/controller/main.php:842
3260
  msgid "Let’s get your site patched up."
3261
  msgstr ""
3262
 
@@ -3738,18 +4039,18 @@ msgid ""
3738
  "this email."
3739
  msgstr ""
3740
 
3741
- #: free/main-activator.php:53
3742
  msgid "Get Members!"
3743
  msgstr ""
3744
 
3745
- #: free/main-activator.php:97
3746
  msgid ""
3747
  "%s, you now have access to Defender's pro features but you still have the "
3748
  "free version installed. Let's upgrade Defender and unlock all those juicy "
3749
  "features! &nbsp; %s"
3750
  msgstr ""
3751
 
3752
- #: free/main-activator.php:127
3753
  msgid "<br/>Something went wrong. Please try again later!"
3754
  msgstr ""
3755
 
@@ -3789,7 +4090,7 @@ msgstr ""
3789
  msgid "Rate %s"
3790
  msgstr ""
3791
 
3792
- #: main-activator.php:70
3793
  msgid ""
3794
  "We noticed you have both the free and pro versions of Defender installed, "
3795
  "so we've automatically deactivated the free version for you."
@@ -3820,4 +4121,10 @@ msgstr ""
3820
 
3821
  #. Author URI of the plugin/theme
3822
  msgid "http://premium.wpmudev.org/"
 
 
 
 
 
 
3823
  msgstr ""
2
  # This file is distributed under the GNU General Public License (Version 2 - GPLv2).
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: WP Defender Pro 1.7\n"
6
  "Report-Msgid-Bugs-To: https://wpmudev.org\n"
7
+ "POT-Creation-Date: 2017-08-17 04:38:03+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
152
  msgstr ""
153
 
154
  #: app/behavior/report-free.php:129 app/behavior/report.php:224
155
+ #: app/behavior/utils.php:663 free/utils.php:516
156
  msgid "daily"
157
  msgstr ""
158
 
159
  #: app/behavior/report-free.php:132 app/behavior/report.php:227
160
+ #: app/behavior/utils.php:666 free/utils.php:519
161
  msgid "weekly"
162
  msgstr ""
163
 
164
  #: app/behavior/report-free.php:135 app/behavior/report.php:230
165
+ #: app/behavior/utils.php:669 free/utils.php:522
166
  msgid "monthly"
167
  msgstr ""
168
 
204
  msgid "To activate this report you must first enable the Audit Logging module."
205
  msgstr ""
206
 
207
+ #: app/behavior/utils.php:76 free/utils.php:77
208
  msgid ""
209
  "WPMU DEV Dashboard will be required for this action. Please visit <a "
210
  "href=\"%s\">here</a> and install the WPMU DEV Dashboard"
211
  msgstr ""
212
 
213
+ #: app/behavior/utils.php:173 app/behavior/utils.php:182
214
  #: app/module/audit/view/table.php:86 app/module/audit/view/table.php:144
215
  #: free/utils.php:174 free/utils.php:183
216
  msgid "Guest"
217
  msgstr ""
218
 
219
+ #: app/behavior/utils.php:550
220
  msgid "WordPress Core Integrity"
221
  msgstr ""
222
 
223
+ #: app/behavior/utils.php:551
224
  msgid "Plugins & Themes vulnerability"
225
  msgstr ""
226
 
227
+ #: app/behavior/utils.php:552 app/module/scan/behavior/scan.php:145
228
  #: app/module/scan/view/layouts/layout.php:70
229
  #: app/module/scan/view/setting-free.php:52 app/module/scan/view/setting.php:43
230
+ #: app/view/settings.php:98
231
  msgid "Suspicious Code"
232
  msgstr ""
233
 
234
+ #: app/behavior/utils.php:557 app/module/audit/controller/main.php:143
235
+ #: app/module/ip-lockout/controller/main.php:92
236
+ msgid "Never"
237
+ msgstr ""
238
+
239
+ #: app/behavior/utils.php:646 free/utils.php:499
240
  msgid "Please upgrade to 5.3 or later"
241
  msgstr ""
242
 
243
+ #: app/controller/dashboard.php:60 app/view/dashboard.php:4
244
  msgid "Dashboard"
245
  msgstr ""
246
 
247
+ #: app/controller/dashboard.php:306 app/controller/dashboard.php:308
248
+ #: app/controller/requirement.php:69 app/module/ip-lockout/view/locked.php:75
249
  msgid "Defender"
250
  msgstr ""
251
 
252
+ #: app/controller/dashboard.php:340
253
  msgid "QUICK SETUP"
254
  msgstr ""
255
 
256
+ #: app/controller/dashboard.php:340
257
  msgid "Skip"
258
  msgstr ""
259
 
260
+ #: app/controller/dashboard.php:341
261
  msgid "Activating File Scanning..."
262
  msgstr ""
263
 
264
+ #: app/controller/dashboard.php:342
265
  msgid "Activating Audit Module..."
266
  msgstr ""
267
 
268
+ #: app/controller/dashboard.php:343
269
  msgid "Activating IP Lockouts Module..."
270
  msgstr ""
271
 
272
+ #: app/controller/dashboard.php:344
273
  msgid "Activating Blacklist Monitoring..."
274
  msgstr ""
275
 
309
  msgid "Defender%s"
310
  msgstr ""
311
 
312
+ #: app/module/advanced-tools/controller/main.php:58
313
+ msgid ""
314
+ "You enabled Jetpack WordPress.com login, so Defender will disable the 2 "
315
+ "factors login for avoiding conflict"
316
+ msgstr ""
317
+
318
+ #: app/module/advanced-tools/controller/main.php:61
319
+ msgid ""
320
+ "You enabled the plugin Theme My Login, so Defender will disable the 2 "
321
+ "factors login for avoiding conflict"
322
+ msgstr ""
323
+
324
+ #: app/module/advanced-tools/controller/main.php:135
325
+ msgid "2 Factor"
326
+ msgstr ""
327
+
328
+ #: app/module/advanced-tools/controller/main.php:158
329
+ msgid "Your token is invalid"
330
+ msgstr ""
331
+
332
+ #: app/module/advanced-tools/controller/main.php:170
333
+ msgid "Your code has been sent to your email."
334
+ msgstr ""
335
+
336
+ #: app/module/advanced-tools/controller/main.php:214
337
+ msgid "Please input a valid OTP code"
338
+ msgstr ""
339
+
340
+ #: app/module/advanced-tools/controller/main.php:228
341
+ msgid "Your OTP code is incorrect. Please try again."
342
+ msgstr ""
343
+
344
+ #: app/module/advanced-tools/controller/main.php:289
345
+ msgid "Some error happen"
346
+ msgstr ""
347
+
348
+ #: app/module/advanced-tools/controller/main.php:326
349
+ msgid "Whoops, the passcode you entered was incorrect or expired."
350
+ msgstr ""
351
+
352
+ #: app/module/advanced-tools/controller/main.php:392
353
+ #: app/module/advanced-tools/view/layouts/layout.php:5
354
+ msgid "Advanced Tools"
355
+ msgstr ""
356
+
357
+ #: app/module/advanced-tools/controller/main.php:455
358
+ #: app/module/audit/controller/main.php:196
359
+ #: app/module/ip-lockout/controller/main.php:652
360
+ #: app/module/scan/controller/main.php:305
361
+ msgid "Your settings have been updated."
362
+ msgstr ""
363
+
364
+ #: app/module/advanced-tools/view/disabled.php:4
365
+ #: app/module/advanced-tools/view/layouts/layout.php:13
366
+ #: app/module/advanced-tools/view/layouts/layout.php:20
367
+ #: app/module/advanced-tools/view/login/disabled.php:6
368
+ #: app/module/advanced-tools/view/login/enabled.php:6
369
+ #: app/module/advanced-tools/view/main.php:4
370
+ msgid "2 Factor Authentication"
371
+ msgstr ""
372
+
373
+ #: app/module/advanced-tools/view/disabled.php:10
374
+ msgid ""
375
+ "Beef up your website’s security with 2-Step verification. Protect your user "
376
+ "accounts by requiring a second passcode sent to users phones in order to "
377
+ "get past your login screen - the best protection against brute force "
378
+ "attacks."
379
+ msgstr ""
380
+
381
+ #: app/module/advanced-tools/view/disabled.php:19
382
+ #: app/module/audit/behavior/audit.php:43 app/module/audit/view/new.php:15
383
+ #: app/module/ip-lockout/behavior/widget.php:37
384
+ msgid "Activate"
385
+ msgstr ""
386
+
387
+ #: app/module/advanced-tools/view/login/disabled.php:2
388
+ #: app/module/advanced-tools/view/login/enabled.php:2
389
+ msgid "Security"
390
+ msgstr ""
391
+
392
+ #: app/module/advanced-tools/view/login/disabled.php:11
393
+ #: app/module/ip-lockout/view/detect-404/disabled.php:16
394
+ #: app/module/ip-lockout/view/login-lockouts/disabled.php:18
395
+ msgid "Enable"
396
+ msgstr ""
397
+
398
+ #: app/module/advanced-tools/view/login/disabled.php:15
399
+ #: app/module/advanced-tools/view/login/disabled.php:21
400
+ msgid "Use the Google Authenticator app to sign in with a separate passcode."
401
+ msgstr ""
402
+
403
+ #: app/module/advanced-tools/view/login/disabled.php:20
404
+ #: app/module/audit/view/report.php:68 app/module/scan/controller/main.php:530
405
+ msgid "Cancel"
406
+ msgstr ""
407
+
408
+ #: app/module/advanced-tools/view/login/disabled.php:24
409
+ msgid "1. Install the Verification app"
410
+ msgstr ""
411
+
412
+ #: app/module/advanced-tools/view/login/disabled.php:27
413
+ msgid ""
414
+ "Download and install the Google Authenticator app on your device using the "
415
+ "links below."
416
+ msgstr ""
417
+
418
+ #: app/module/advanced-tools/view/login/disabled.php:36
419
+ msgid "2. Scan the barcode"
420
+ msgstr ""
421
+
422
+ #: app/module/advanced-tools/view/login/disabled.php:37
423
+ msgid ""
424
+ "Open the Google Authenticator app you just downloaded, tap the “+” symbol "
425
+ "and then use your phone’s camera to scan the barcode below."
426
+ msgstr ""
427
+
428
+ #: app/module/advanced-tools/view/login/disabled.php:41
429
+ msgid "3. Enter passcode"
430
+ msgstr ""
431
+
432
+ #: app/module/advanced-tools/view/login/disabled.php:43
433
+ msgid ""
434
+ "Enter the 6 digit passcode that is shown on your device into the input "
435
+ "field below and hit “Verify”."
436
+ msgstr ""
437
+
438
+ #: app/module/advanced-tools/view/login/disabled.php:49
439
+ msgid "Verify"
440
+ msgstr ""
441
+
442
+ #: app/module/advanced-tools/view/login/enabled.php:9
443
+ msgid "2 factor authentication is active."
444
+ msgstr ""
445
+
446
+ #: app/module/advanced-tools/view/login/enabled.php:12
447
+ msgid "Disabled"
448
+ msgstr ""
449
+
450
+ #: app/module/advanced-tools/view/login/enabled.php:17
451
+ msgid "Fallback email address"
452
+ msgstr ""
453
+
454
+ #: app/module/advanced-tools/view/login/enabled.php:21
455
+ msgid ""
456
+ "If you ever lose your device, you can send a fallback passcode to this "
457
+ "email address."
458
+ msgstr ""
459
+
460
+ #: app/module/advanced-tools/view/login/otp.php:98
461
+ msgid "https://wordpress.org/"
462
+ msgstr ""
463
+
464
+ #: app/module/advanced-tools/view/login/otp.php:99
465
+ msgid "Powered by WordPress"
466
+ msgstr ""
467
+
468
+ #: app/module/advanced-tools/view/login/otp.php:224
469
+ msgid "Enter 6 digit passcode"
470
+ msgstr ""
471
+
472
+ #: app/module/advanced-tools/view/login/otp.php:227
473
+ msgid "Authenticate"
474
+ msgstr ""
475
+
476
+ #: app/module/advanced-tools/view/login/otp.php:236
477
+ msgid "Lost your device?"
478
+ msgstr ""
479
+
480
+ #: app/module/advanced-tools/view/main.php:9
481
+ msgid ""
482
+ "Configure your 2 factor authentication settings, our recommendations are on "
483
+ "by default."
484
+ msgstr ""
485
+
486
+ #: app/module/advanced-tools/view/main.php:18
487
+ msgid "User Roles"
488
+ msgstr ""
489
+
490
+ #: app/module/advanced-tools/view/main.php:20
491
+ msgid ""
492
+ "Choose what user roles you want to enable 2 factor authentication for. They "
493
+ "must then use the Google Authenticator app to login."
494
+ msgstr ""
495
+
496
+ #: app/module/advanced-tools/view/main.php:27
497
+ msgid "User role"
498
+ msgstr ""
499
+
500
+ #: app/module/advanced-tools/view/main.php:59
501
+ msgid "Lost Phone"
502
+ msgstr ""
503
+
504
+ #: app/module/advanced-tools/view/main.php:61
505
+ msgid ""
506
+ "If a user is unable to access their phone, you can allow an option to send "
507
+ "the one time password to their registered email."
508
+ msgstr ""
509
+
510
+ #: app/module/advanced-tools/view/main.php:71
511
+ msgid "Enable lost phone option"
512
+ msgstr ""
513
+
514
+ #: app/module/advanced-tools/view/main.php:76
515
+ msgid "App Download"
516
+ msgstr ""
517
+
518
+ #: app/module/advanced-tools/view/main.php:78
519
+ msgid "Need the app? Here’s links to the official Google Authenticator apps."
520
+ msgstr ""
521
+
522
+ #: app/module/advanced-tools/view/main.php:92
523
+ msgid "Active Users"
524
+ msgstr ""
525
+
526
+ #: app/module/advanced-tools/view/main.php:94
527
+ msgid ""
528
+ "Here’s a quick link to see which of your users have enabled 2 step "
529
+ "verification."
530
+ msgstr ""
531
+
532
+ #: app/module/advanced-tools/view/main.php:98
533
+ msgid "<a href=\"%s\">View users</a> who have enabled this feature."
534
+ msgstr ""
535
+
536
+ #: app/module/advanced-tools/view/main.php:103
537
+ #: app/module/advanced-tools/view/main.php:110
538
+ #: app/module/audit/view/settings.php:10
539
+ msgid "Deactivate"
540
+ msgstr ""
541
+
542
+ #: app/module/advanced-tools/view/main.php:105
543
+ msgid "Turn off the 2 factor authentication feature completely."
544
+ msgstr ""
545
+
546
+ #: app/module/advanced-tools/view/main.php:118
547
+ msgid "SAVE SETTINGS"
548
+ msgstr ""
549
+
550
  #: app/module/audit/behavior/audit-free.php:25
551
  #: app/module/audit/behavior/audit.php:38 app/view/activator.php:35
552
  msgid ""
567
  msgid "Please hold on, Defender will update Audit information soon..."
568
  msgstr ""
569
 
 
 
 
 
 
570
  #: app/module/audit/component/audit-api.php:57
571
  #: app/module/audit/component/audit-api.php:89
572
  msgid ""
1111
  #: app/module/scan/view/layouts/layout.php:131
1112
  #: app/module/scan/view/layouts/layout.php:146
1113
  #: app/module/scan/view/setting-free.php:3 app/module/scan/view/setting.php:3
1114
+ #: app/view/settings.php:6 free/main-activator.php:146 main-activator.php:89
1115
  msgid "Settings"
1116
  msgstr ""
1117
 
1253
  msgid "User"
1254
  msgstr ""
1255
 
 
 
 
 
 
 
 
 
 
 
 
1256
  #: app/module/audit/controller/main.php:331
1257
  msgid "Hi {USER_NAME},"
1258
  msgstr ""
1359
  msgid "<a href=\"%s\">Configure reporting preferences</a>"
1360
  msgstr ""
1361
 
1362
+ #: app/module/audit/view/free.php:9 free/main-activator.php:106
1363
  msgid "Upgrade"
1364
  msgstr ""
1365
 
1572
  msgid "Update Settings"
1573
  msgstr ""
1574
 
 
 
 
 
 
 
 
 
1575
  #: app/module/audit/view/settings.php:13
1576
  msgid "If you no longer want to use this feature you can turn it off at any time."
1577
  msgstr ""
1650
  msgstr ""
1651
 
1652
  #: app/module/hardener/behavior/widget.php:19
1653
+ #: app/module/hardener/controller/main.php:159
1654
  #: app/module/hardener/view/layouts/layout.php:3
1655
  msgid "Security Tweaks"
1656
  msgstr ""
1657
 
1658
  #: app/module/hardener/behavior/widget.php:34
1659
  msgid ""
1660
+ "Defender checks for security tweaks you can make to enhance your website’s\n"
1661
  " defense against hackers and bots."
1662
  msgstr ""
1663
 
1704
  #: app/module/hardener/component/servers/apache-service.php:104
1705
  #: app/module/hardener/component/servers/apache-service.php:108
1706
  #: app/module/hardener/component/servers/apache-service.php:158
1707
+ #: app/module/hardener/component/servers/apache-service.php:189
1708
  msgid "The file %s is not writeable"
1709
  msgstr ""
1710
 
1757
  msgid "Disable the file editor"
1758
  msgstr ""
1759
 
1760
+ #: app/module/hardener/component/disable-file-editor.php:91
1761
+ msgid "Sorry, you are not allowed to edit templates for this site."
1762
+ msgstr ""
1763
+
1764
+ #: app/module/hardener/component/disable-file-editor.php:94
1765
+ msgid "Sorry, you are not allowed to edit plugins for this site."
1766
+ msgstr ""
1767
+
1768
  #: app/module/hardener/component/disable-trackback.php:28
1769
  #: app/module/hardener/view/rules/disable-trackback.php:8
1770
  msgid "Disable trackbacks and pingbacks"
1779
  msgid "Hide error reporting"
1780
  msgstr ""
1781
 
1782
+ #: app/module/hardener/component/login-duration.php:38
1783
+ msgid "Manage Login Duration"
1784
+ msgstr ""
1785
+
1786
+ #: app/module/hardener/component/login-duration.php:94
1787
+ msgid "Duration can only be a number"
1788
+ msgstr ""
1789
+
1790
+ #: app/module/hardener/component/login-duration.php:190
1791
+ msgid ""
1792
+ "Your session has expired because it has been over %d days since your last "
1793
+ "login. Please log back in to continue."
1794
+ msgstr ""
1795
+
1796
  #: app/module/hardener/component/php-version.php:30
1797
  #: app/module/hardener/view/rules/php-version.php:8
1798
  msgid "Update PHP to latest version"
1817
  msgid "Prevent Information Disclosure"
1818
  msgstr ""
1819
 
1820
+ #: app/module/hardener/component/security-key.php:40
1821
  #: app/module/hardener/view/rules/security-key.php:8
1822
  msgid "Update old security keys"
1823
  msgstr ""
1824
 
1825
+ #: app/module/hardener/component/security-key.php:82
1826
  msgid ""
1827
  "All key salts have been regenerated. You will now need to <a "
1828
  "href=\"%s\"><strong>re-login</strong></a>.<br/>This will auto reload after "
1838
  msgid "Update WordPress to latest version"
1839
  msgstr ""
1840
 
1841
+ #: app/module/hardener/controller/main.php:58
1842
  msgid "Security tweak successfully restored."
1843
  msgstr ""
1844
 
1845
+ #: app/module/hardener/controller/main.php:76
1846
  msgid "Security tweak successfully ignored."
1847
  msgstr ""
1848
 
1849
+ #: app/module/hardener/controller/main.php:92
1850
  msgid "Security tweak successfully reverted."
1851
  msgstr ""
1852
 
1853
+ #: app/module/hardener/controller/main.php:118
1854
  msgid "Security tweak successfully resolved."
1855
  msgstr ""
1856
 
1857
+ #: app/module/hardener/controller/main.php:146
1858
+ msgid "Security tweak successfully updated."
1859
+ msgstr ""
1860
+
1861
  #: app/module/hardener/rule.php:111
1862
+ #: app/module/scan/behavior/core-result.php:189
1863
+ #: app/module/scan/behavior/pro/content-result.php:106
1864
  #: app/module/scan/behavior/pro/vuln-result.php:156
1865
  #: app/module/scan/component/result-table.php:199
1866
  msgid "Ignore"
1950
  #: app/module/hardener/view/rules/disable-file-editor.php:11
1951
  #: app/module/hardener/view/rules/disable-trackback.php:11
1952
  #: app/module/hardener/view/rules/hide-error.php:11
1953
+ #: app/module/hardener/view/rules/login-duration.php:11
1954
  #: app/module/hardener/view/rules/php-version.php:11
1955
  #: app/module/hardener/view/rules/prevent-php-executed.php:11
1956
  #: app/module/hardener/view/rules/protect-information.php:11
1974
  #: app/module/hardener/view/rules/disable-file-editor.php:16
1975
  #: app/module/hardener/view/rules/disable-trackback.php:16
1976
  #: app/module/hardener/view/rules/hide-error.php:16
1977
+ #: app/module/hardener/view/rules/login-duration.php:16
1978
  #: app/module/hardener/view/rules/php-version.php:34
1979
  #: app/module/hardener/view/rules/prevent-php-executed.php:16
1980
  #: app/module/hardener/view/rules/protect-information.php:16
1997
 
1998
  #: app/module/hardener/view/rules/change-admin.php:34
1999
  #: app/module/hardener/view/rules/db-prefix.php:37
2000
+ #: app/module/hardener/view/rules/login-duration.php:44
2001
  #: app/module/hardener/view/rules/security-key.php:31
2002
  #: app/module/scan/behavior/pro/vuln-result.php:162
2003
  #: app/module/scan/behavior/pro/vuln-result.php:166
2041
 
2042
  #: app/module/hardener/view/rules/disable-file-editor.php:26
2043
  #: app/module/hardener/view/rules/disable-trackback.php:26
2044
+ #: app/module/hardener/view/rules/login-duration.php:29
2045
+ #: app/module/hardener/view/rules/prevent-php-executed.php:52
2046
  #: app/module/hardener/view/rules/protect-information.php:26
2047
  msgid "Revert"
2048
  msgstr ""
2113
  "your hosting provider and ask them to set WP_DEBUG to false."
2114
  msgstr ""
2115
 
2116
+ #: app/module/hardener/view/rules/login-duration.php:13
2117
+ msgid ""
2118
+ "By default, users who select the 'remember me' option stay logged in for 14 "
2119
+ "days"
2120
+ msgstr ""
2121
+
2122
+ #: app/module/hardener/view/rules/login-duration.php:35
2123
+ msgid "Please change the number of days a user can stay logged in"
2124
+ msgstr ""
2125
+
2126
+ #: app/module/hardener/view/rules/login-duration.php:40
2127
+ msgid "Enter number of days"
2128
+ msgstr ""
2129
+
2130
  #: app/module/hardener/view/rules/php-version.php:14
2131
  msgid ""
2132
  "PHP versions older than 5.6 are no longer supported. For security and "
2166
  "direct PHP execution in directories that don't require it."
2167
  msgstr ""
2168
 
2169
+ #: app/module/hardener/view/rules/prevent-php-executed.php:23
2170
  msgid "PHP execution is locked down."
2171
  msgstr ""
2172
 
2173
+ #: app/module/hardener/view/rules/prevent-php-executed.php:28
2174
+ msgid " The following file paths have been allowed in the /wp-content directory :"
2175
+ msgstr ""
2176
+
2177
+ #: app/module/hardener/view/rules/prevent-php-executed.php:39
2178
+ msgid "Update .htaccess file"
2179
+ msgstr ""
2180
+
2181
+ #: app/module/hardener/view/rules/prevent-php-executed.php:77
2182
  #: app/module/hardener/view/rules/protect-information.php:42
2183
  msgid "Server Type:"
2184
  msgstr ""
2185
 
2186
+ #: app/module/hardener/view/rules/prevent-php-executed.php:91
2187
+ #: app/module/hardener/view/rules/prevent-php-executed.php:105
2188
  #: app/module/hardener/view/rules/protect-information.php:54
2189
  #: app/module/hardener/view/rules/protect-information.php:66
2190
  msgid ""
2192
  "down the files and folders inside."
2193
  msgstr ""
2194
 
2195
+ #: app/module/hardener/view/rules/prevent-php-executed.php:100
2196
+ #: app/module/hardener/view/rules/prevent-php-executed.php:114
 
 
 
 
 
 
 
2197
  #: app/module/hardener/view/rules/protect-information.php:61
2198
  #: app/module/hardener/view/rules/protect-information.php:73
2199
  msgid "Add .htaccess file"
2200
  msgstr ""
2201
 
2202
+ #: app/module/hardener/view/rules/prevent-php-executed.php:138
2203
  #: app/module/hardener/view/rules/protect-information.php:105
2204
  msgid "For NGINX servers:"
2205
  msgstr ""
2206
 
2207
+ #: app/module/hardener/view/rules/prevent-php-executed.php:141
 
 
 
 
 
 
2208
  #: app/module/hardener/view/rules/protect-information.php:108
2209
  msgid ""
2210
  "Copy the generated code into your site specific .conf file usually located "
2211
  "in a subdirectory under /etc/nginx/... or /usr/local/nginx/conf/..."
2212
  msgstr ""
2213
 
2214
+ #: app/module/hardener/view/rules/prevent-php-executed.php:144
2215
  #: app/module/hardener/view/rules/protect-information.php:111
2216
  msgid ""
2217
  "Add the code above inside the <strong>server</strong> section in the file, "
2218
  "right before the php location block. Looks something like:"
2219
  msgstr ""
2220
 
2221
+ #: app/module/hardener/view/rules/prevent-php-executed.php:148
2222
  #: app/module/hardener/view/rules/protect-information.php:115
2223
  msgid "Reload NGINX."
2224
  msgstr ""
2225
 
2226
+ #: app/module/hardener/view/rules/prevent-php-executed.php:151
2227
  #: app/module/hardener/view/rules/protect-information.php:118
2228
  msgid ""
2229
  "Still having trouble? <a target='_blank' href=\"%s\">Open a support "
2230
  "ticket</a>."
2231
  msgstr ""
2232
 
2233
+ #: app/module/hardener/view/rules/prevent-php-executed.php:161
2234
  #: app/module/hardener/view/rules/protect-information.php:124
2235
  msgid "For IIS servers, <a href=\"%s\">visit Microsoft TechNet</a>"
2236
  msgstr ""
2237
 
2238
+ #: app/module/hardener/view/rules/prevent-php-executed.php:166
2239
  msgid ""
2240
  "We will place <strong>web.config</strong> file into the uploads folder to "
2241
  "lock down the files and folders inside."
2242
  msgstr ""
2243
 
2244
+ #: app/module/hardener/view/rules/prevent-php-executed.php:169
2245
  msgid "For more information, please <a href=\"%s\">visit Microsoft TechNet</a>"
2246
  msgstr ""
2247
 
2248
+ #: app/module/hardener/view/rules/prevent-php-executed.php:177
2249
  msgid "Add web.config file"
2250
  msgstr ""
2251
 
2252
+ #: app/module/hardener/view/rules/prevent-php-executed.php:189
2253
+ msgid "Exceptions"
2254
+ msgstr ""
2255
+
2256
+ #: app/module/hardener/view/rules/prevent-php-executed.php:192
2257
+ msgid ""
2258
+ "By default Defender will lock down directories WordPress doesn't need to "
2259
+ "allow PHP execution for. However, if you have specific files you need to "
2260
+ "allow PHP execution for you can add exceptions. Add file name one per line"
2261
+ msgstr ""
2262
+
2263
+ #: app/module/hardener/view/rules/prevent-php-executed.php:193
2264
+ msgid "Add Exception"
2265
+ msgstr ""
2266
+
2267
  #: app/module/hardener/view/rules/protect-information.php:13
2268
  msgid ""
2269
  "Often servers are incorrectly configured, and can allow an attacker to get "
2366
  msgstr ""
2367
 
2368
  #: app/module/ip-lockout/behavior/widget.php:51
 
2369
  msgid "Login lockouts this week"
2370
  msgstr ""
2371
 
2372
  #: app/module/ip-lockout/behavior/widget.php:57
 
2373
  msgid "404 lockouts this week"
2374
  msgstr ""
2375
 
2385
  msgid "Lockout notifications are disabled"
2386
  msgstr ""
2387
 
2388
+ #: app/module/ip-lockout/component/login-protection-api.php:62
2389
+ #: app/module/ip-lockout/controller/main.php:547
2390
+ #: app/module/ip-lockout/controller/main.php:556
2391
  msgid ""
2392
  "You have been locked out by the administrator for attempting to login with "
2393
  "a banned username"
2394
  msgstr ""
2395
 
2396
+ #: app/module/ip-lockout/component/login-protection-api.php:75
2397
  msgid "Lockout occurred: Attempting to login with a banned username."
2398
  msgstr ""
2399
 
2400
+ #: app/module/ip-lockout/component/login-protection-api.php:77
2401
  msgid "Lockout occurred: Too many failed login attempts"
2402
  msgstr ""
2403
 
2404
+ #: app/module/ip-lockout/component/login-protection-api.php:144
2405
  msgid "Lockout occurred: Too many 404 requests for %s"
2406
  msgstr ""
2407
 
2457
  msgstr ""
2458
 
2459
  #: app/module/ip-lockout/component/logs-table.php:164
2460
+ #: app/module/ip-lockout/model/log-model-legacy.php:111
2461
+ #: app/module/ip-lockout/model/log-model.php:64
2462
  msgid "Failed login attempts"
2463
  msgstr ""
2464
 
2465
  #: app/module/ip-lockout/component/logs-table.php:166
2466
+ #: app/module/ip-lockout/model/log-model-legacy.php:112
2467
+ #: app/module/ip-lockout/model/log-model.php:65
2468
  msgid "Login lockout"
2469
  msgstr ""
2470
 
2471
  #: app/module/ip-lockout/component/logs-table.php:168
2472
+ #: app/module/ip-lockout/model/log-model-legacy.php:113
2473
+ #: app/module/ip-lockout/model/log-model-legacy.php:114
2474
+ #: app/module/ip-lockout/model/log-model.php:66
2475
+ #: app/module/ip-lockout/model/log-model.php:67
2476
  msgid "404 error"
2477
  msgstr ""
2478
 
2479
  #: app/module/ip-lockout/component/logs-table.php:170
2480
+ #: app/module/ip-lockout/model/log-model-legacy.php:115
2481
+ #: app/module/ip-lockout/model/log-model.php:68
2482
  msgid "404 lockout"
2483
  msgstr ""
2484
 
2500
  msgid "%s results"
2501
  msgstr ""
2502
 
2503
+ #: app/module/ip-lockout/controller/main.php:151
2504
  msgid "Your logs have been successfully deleted."
2505
  msgstr ""
2506
 
2507
+ #: app/module/ip-lockout/controller/main.php:191
2508
  msgid ""
2509
  "IP %s has been added to your blacklist. You can control your blacklist in "
2510
  "<a href=\"%s\">IP Lockouts.</a>"
2511
  msgstr ""
2512
 
2513
+ #: app/module/ip-lockout/controller/main.php:196
2514
  msgid "No record found"
2515
  msgstr ""
2516
 
2517
+ #: app/module/ip-lockout/controller/main.php:221
2518
  msgid "Demo"
2519
  msgstr ""
2520
 
2521
+ #: app/module/ip-lockout/controller/main.php:399
2522
  msgid "404 lockout alert for %s"
2523
  msgstr ""
2524
 
2525
+ #: app/module/ip-lockout/controller/main.php:422
2526
  msgid "Login lockout alert for %s"
2527
  msgstr ""
2528
 
2529
+ #: app/module/ip-lockout/controller/main.php:487
2530
  msgid "Failed login attempt with username %s"
2531
  msgstr ""
2532
 
2533
+ #: app/module/ip-lockout/controller/main.php:549
2534
+ #: app/module/ip-lockout/controller/main.php:559
2535
  msgid "%d login attempts remaining"
2536
  msgstr ""
2537
 
2538
+ #: app/module/ip-lockout/controller/main.php:648
2539
  msgid ""
2540
  "Your settings have been updated, however some IPs were removed because "
2541
  "invalid format, or you blacklist yourself"
2542
  msgstr ""
2543
 
2544
+ #: app/module/ip-lockout/controller/main.php:659
2545
  msgid "Login Protection has been activated."
2546
  msgstr ""
2547
 
2548
+ #: app/module/ip-lockout/controller/main.php:661
2549
  msgid "Login Protection has been deactivated."
2550
  msgstr ""
2551
 
2552
+ #: app/module/ip-lockout/controller/main.php:666
2553
  msgid "404 Detection has been activated."
2554
  msgstr ""
2555
 
2556
+ #: app/module/ip-lockout/controller/main.php:668
2557
  msgid "404 Detection has been deactivated."
2558
  msgstr ""
2559
 
2575
  msgid "Your whitelist/blacklist has been successfully imported."
2576
  msgstr ""
2577
 
2578
+ #: app/module/ip-lockout/controller/main.php:905
2579
+ msgid "Thanks for your patience. All sets!"
2580
+ msgstr ""
2581
+
2582
+ #: app/module/ip-lockout/model/log-model-legacy.php:79
2583
+ #: app/module/ip-lockout/model/log-model.php:38
2584
  msgid ""
2585
  "Request for file <span class='log-text-table' tooltip='%s'>%s</span> which "
2586
  "doesn't exist"
2680
  "temporarily block them from accessing your site."
2681
  msgstr ""
2682
 
 
 
 
 
 
2683
  #: app/module/ip-lockout/view/detect-404/enabled.php:7
2684
  msgid "Deactivate 404 Detection"
2685
  msgstr ""
2819
  #: app/module/ip-lockout/view/emails/login-lockout.php:482
2820
  #: app/module/ip-lockout/view/emails/login-username-ban.php:481
2821
  #: app/module/ip-lockout/view/emails/report.php:515
2822
+ #: app/module/ip-lockout/view/locked.php:7
2823
  msgid "WP Defender"
2824
  msgstr ""
2825
 
2908
  msgstr ""
2909
 
2910
  #: app/module/ip-lockout/view/layouts/layout.php:21
2911
+ msgid "Total lockouts in the past 30 days"
2912
+ msgstr ""
2913
+
2914
+ #: app/module/ip-lockout/view/layouts/layout.php:34
2915
+ msgid "Login lockouts in the past 7 days"
2916
+ msgstr ""
2917
+
2918
+ #: app/module/ip-lockout/view/layouts/layout.php:40
2919
+ msgid "404 lockouts in the past 7 days"
2920
  msgstr ""
2921
 
2922
  #: app/module/ip-lockout/view/layouts/layout.php:54
2956
  msgid "IP Blacklist"
2957
  msgstr ""
2958
 
2959
+ #: app/module/ip-lockout/view/locked.php:74
2960
  msgid "Powered by"
2961
  msgstr ""
2962
 
3016
  "these are common for bots to try logging in with. One username per line"
3017
  msgstr ""
3018
 
3019
+ #: app/module/ip-lockout/view/migration.php:6
3020
+ msgid "Migration"
3021
+ msgstr ""
3022
+
3023
+ #: app/module/ip-lockout/view/migration.php:15
3024
+ msgid "Please hold on, we are updating your data, please don't close this tab..."
3025
+ msgstr ""
3026
+
3027
  #: app/module/ip-lockout/view/notification/enabled.php:10
3028
  msgid "Send email notifications"
3029
  msgstr ""
3172
  msgid "This WordPress core file appears modified"
3173
  msgstr ""
3174
 
3175
+ #: app/module/scan/behavior/core-result.php:75
3176
+ #: app/module/scan/behavior/core-result.php:405
3177
+ #: app/module/scan/behavior/core-result.php:410
3178
+ #: app/module/scan/behavior/pro/content-result.php:206
3179
+ #: app/module/scan/behavior/pro/content-result.php:227
3180
+ #: app/module/scan/behavior/pro/content-result.php:232
3181
+ msgid "Defender doesn't have enough permission to remove this file"
3182
+ msgstr ""
3183
+
3184
+ #: app/module/scan/behavior/core-result.php:81
3185
  msgid "This file can't not remove"
3186
  msgstr ""
3187
 
3188
+ #: app/module/scan/behavior/core-result.php:101
3189
  msgid "This file is not resolvable"
3190
  msgstr ""
3191
 
3192
+ #: app/module/scan/behavior/core-result.php:105
3193
  msgid ""
3194
  "It seems the %s file is currently using by another process or isn't "
3195
  "writeable."
3196
  msgstr ""
3197
 
3198
+ #: app/module/scan/behavior/core-result.php:122
3199
+ #: app/module/scan/behavior/pro/content-result.php:56
3200
  #: app/module/scan/behavior/pro/vuln-result.php:109
3201
  msgid "Issue Details"
3202
  msgstr ""
3203
 
3204
+ #: app/module/scan/behavior/core-result.php:132
3205
+ #: app/module/scan/behavior/pro/content-result.php:65
3206
  msgid "Location"
3207
  msgstr ""
3208
 
3209
+ #: app/module/scan/behavior/core-result.php:142
3210
  msgid "Size"
3211
  msgstr ""
3212
 
3213
+ #: app/module/scan/behavior/core-result.php:159
3214
+ #: app/module/scan/behavior/pro/content-result.php:73
3215
  msgid "Date Added"
3216
  msgstr ""
3217
 
3218
+ #: app/module/scan/behavior/core-result.php:197
3219
+ #: app/module/scan/behavior/pro/content-result.php:127
3220
  msgid "Delete"
3221
  msgstr ""
3222
 
3223
+ #: app/module/scan/behavior/core-result.php:199
3224
  msgid ""
3225
  "This will permanent remove the file/folder with all content, do you want to "
3226
  "do this?"
3227
  msgstr ""
3228
 
3229
+ #: app/module/scan/behavior/core-result.php:202
3230
+ #: app/module/scan/behavior/pro/content-result.php:132
3231
  msgid "Yes"
3232
  msgstr ""
3233
 
3234
+ #: app/module/scan/behavior/core-result.php:205
3235
+ #: app/module/scan/behavior/pro/content-result.php:135
3236
  msgid "No"
3237
  msgstr ""
3238
 
3239
+ #: app/module/scan/behavior/core-result.php:215
3240
  msgid "Restore to Original"
3241
  msgstr ""
3242
 
3243
+ #: app/module/scan/behavior/core-result.php:264
3244
  msgid ""
3245
  "A stray file has been found in your site directory, which your version of "
3246
  "WordPress doesn't need. As far as we can tell, the file is harmless (and "
3249
  "beforehand"
3250
  msgstr ""
3251
 
3252
+ #: app/module/scan/behavior/core-result.php:280
3253
+ #: app/module/scan/behavior/core-result.php:302
3254
+ #: app/module/scan/behavior/core-result.php:324
3255
+ #: app/module/scan/behavior/pro/content-result.php:93
3256
  msgid "Pulling source file..."
3257
  msgstr ""
3258
 
3259
+ #: app/module/scan/behavior/core-result.php:297
3260
  msgid ""
3261
  "Compare your file with the original file in the WordPress repository. "
3262
  "Pieces highlighted in red will be removed when you patch the file, and "
3263
  "pieces highlighted in green will be added."
3264
  msgstr ""
3265
 
3266
+ #: app/module/scan/behavior/core-result.php:319
3267
  msgid ""
3268
  "We found this folder in your WordPress file list. Your current version of "
3269
  "WordPress doesn’t use this folder so it might belong to another "
3272
  "support team for more information."
3273
  msgstr ""
3274
 
3275
+ #: app/module/scan/behavior/pro/content-result.php:46
3276
  msgid "Suspicious function found"
3277
  msgstr ""
3278
 
3279
+ #: app/module/scan/behavior/pro/content-result.php:88
3280
  msgid ""
3281
  " There’s some suspicious looking code in the file %s. If you know the code "
3282
  "is harmless you can ignore this warning. Otherwise, you can choose to "
3284
  "recommend backing up your website."
3285
  msgstr ""
3286
 
3287
+ #: app/module/scan/behavior/pro/content-result.php:113
3288
  msgid ""
3289
  "This will permanent delete the whole plugin containing this file, do you "
3290
  "want to do this?"
3291
  msgstr ""
3292
 
3293
+ #: app/module/scan/behavior/pro/content-result.php:116
3294
  msgid ""
3295
  "This will permanent delete the whole theme containing this file, do you "
3296
  "want to do this?"
3297
  msgstr ""
3298
 
3299
+ #: app/module/scan/behavior/pro/content-result.php:119
3300
  msgid "This will permanent delete this file, do you want to do this?"
3301
  msgstr ""
3302
 
3422
  msgstr ""
3423
 
3424
  #: app/module/scan/component/result-table.php:35
3425
+ #: app/module/scan/controller/main.php:807
3426
  msgid "Issue"
3427
  msgstr ""
3428
 
3483
  msgid "Update Theme"
3484
  msgstr ""
3485
 
3486
+ #: app/module/scan/controller/main.php:178
3487
+ #: app/module/scan/controller/main.php:439
3488
  msgid "The suspicious file has been successfully ignored."
3489
  msgid_plural "The suspicious files have been successfully ignored."
3490
  msgstr[0] ""
3491
  msgstr[1] ""
3492
 
3493
+ #: app/module/scan/controller/main.php:193
3494
+ #: app/module/scan/controller/main.php:410
3495
  msgid "The suspicious file has been successfully restored."
3496
  msgid_plural "The suspicious files have been successfully restored."
3497
  msgstr[0] ""
3498
  msgstr[1] ""
3499
 
3500
+ #: app/module/scan/controller/main.php:212
3501
  msgid "The suspicious files has been successfully deleted."
3502
  msgid_plural "The suspicious files have been successfully deleted."
3503
  msgstr[0] ""
3504
  msgstr[1] ""
3505
 
3506
+ #: app/module/scan/controller/main.php:218
3507
  msgid "No item has been deleted"
3508
  msgstr ""
3509
 
3510
+ #: app/module/scan/controller/main.php:235
3511
  msgid "The suspicious files has been successfully resolved."
3512
  msgid_plural "The suspicious files have been successfully resolved."
3513
  msgstr[0] ""
3514
  msgstr[1] ""
3515
 
3516
+ #: app/module/scan/controller/main.php:241
3517
  msgid "No item has been resolved"
3518
  msgstr ""
3519
 
3520
+ #: app/module/scan/controller/main.php:335
3521
  msgid "This item has been resolved."
3522
  msgstr ""
3523
 
3524
+ #: app/module/scan/controller/main.php:339
3525
  msgid "Please try again!"
3526
  msgstr ""
3527
 
3528
+ #: app/module/scan/controller/main.php:350
3529
+ #: app/module/scan/controller/main.php:386
3530
+ #: app/module/scan/controller/main.php:415
3531
+ #: app/module/scan/controller/main.php:444
3532
  msgid "The item doesn't exist!"
3533
  msgstr ""
3534
 
3535
+ #: app/module/scan/controller/main.php:380
3536
  msgid "This item has been permanent removed."
3537
  msgstr ""
3538
 
3539
+ #: app/module/scan/controller/main.php:519
3540
  #: app/module/scan/view/layouts/layout.php:5
3541
  #: app/module/scan/view/scanning.php:6 app/view/activator-free.php:13
3542
  #: app/view/activator.php:13
3543
  msgid "File Scanning"
3544
  msgstr ""
3545
 
3546
+ #: app/module/scan/controller/main.php:530
3547
  msgid "Scan In Progress"
3548
  msgstr ""
3549
 
3550
+ #: app/module/scan/controller/main.php:531 app/module/scan/view/issues.php:37
3551
  msgid ""
3552
  "Your code is currently clean! There were no issues found during the last "
3553
  "scan, though you can always perform a new scan anytime."
3554
  msgstr ""
3555
 
3556
+ #: app/module/scan/controller/main.php:805
3557
  msgid "File"
3558
  msgstr ""
3559
 
3560
+ #: app/module/scan/controller/main.php:841
3561
  msgid "Let’s get your site patched up."
3562
  msgstr ""
3563
 
4039
  "this email."
4040
  msgstr ""
4041
 
4042
+ #: free/main-activator.php:60
4043
  msgid "Get Members!"
4044
  msgstr ""
4045
 
4046
+ #: free/main-activator.php:104
4047
  msgid ""
4048
  "%s, you now have access to Defender's pro features but you still have the "
4049
  "free version installed. Let's upgrade Defender and unlock all those juicy "
4050
  "features! &nbsp; %s"
4051
  msgstr ""
4052
 
4053
+ #: free/main-activator.php:134
4054
  msgid "<br/>Something went wrong. Please try again later!"
4055
  msgstr ""
4056
 
4090
  msgid "Rate %s"
4091
  msgstr ""
4092
 
4093
+ #: main-activator.php:78
4094
  msgid ""
4095
  "We noticed you have both the free and pro versions of Defender installed, "
4096
  "so we've automatically deactivated the free version for you."
4121
 
4122
  #. Author URI of the plugin/theme
4123
  msgid "http://premium.wpmudev.org/"
4124
+ msgstr ""
4125
+
4126
+ #: app/module/advanced-tools/view/login/otp.php:286
4127
+ #. translators: %s: site title
4128
+ msgctxt "site"
4129
+ msgid "&larr; Back to %s"
4130
  msgstr ""
main-activator.php CHANGED
@@ -28,6 +28,12 @@ class WD_Main_Activator {
28
  * Initial
29
  */
30
  public function init() {
 
 
 
 
 
 
31
  add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( &$this, 'addSettingsLink' ) );
32
  add_action( 'admin_enqueue_scripts', array( &$this, 'register_styles' ) );
33
  if ( ! \WP_Defender\Behavior\Utils::instance()->checkRequirement() ) {
@@ -40,6 +46,7 @@ class WD_Main_Activator {
40
  \Hammer\Base\Container::instance()->set( 'scan', new \WP_Defender\Module\Scan() );
41
  \Hammer\Base\Container::instance()->set( 'audit', new \WP_Defender\Module\Audit() );
42
  \Hammer\Base\Container::instance()->set( 'lockout', new \WP_Defender\Module\IP_Lockout() );
 
43
  //no need to set debug
44
  new \WP_Defender\Controller\Debug();
45
  require_once $this->wp_defender->getPluginPath() . 'free-dashboard/module.php';
28
  * Initial
29
  */
30
  public function init() {
31
+ $db_ver = get_site_option( 'wd_db_version' );
32
+ if ( version_compare( $db_ver, '1.7', '<' ) ) {
33
+ add_site_option( 'defenderLockoutNeedUpdateLog', 1 );
34
+ \WP_Defender\Module\IP_Lockout\Component\Login_Protection_Api::createTables();
35
+ update_site_option( 'wd_db_version', "1.7" );
36
+ }
37
  add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( &$this, 'addSettingsLink' ) );
38
  add_action( 'admin_enqueue_scripts', array( &$this, 'register_styles' ) );
39
  if ( ! \WP_Defender\Behavior\Utils::instance()->checkRequirement() ) {
46
  \Hammer\Base\Container::instance()->set( 'scan', new \WP_Defender\Module\Scan() );
47
  \Hammer\Base\Container::instance()->set( 'audit', new \WP_Defender\Module\Audit() );
48
  \Hammer\Base\Container::instance()->set( 'lockout', new \WP_Defender\Module\IP_Lockout() );
49
+ \Hammer\Base\Container::instance()->set( 'advanced_tool', new \WP_Defender\Module\Advanced_Tools() );
50
  //no need to set debug
51
  new \WP_Defender\Controller\Debug();
52
  require_once $this->wp_defender->getPluginPath() . 'free-dashboard/module.php';
phpunit.xml DELETED
@@ -1,14 +0,0 @@
1
- <phpunit
2
- bootstrap="tests/bootstrap.php"
3
- backupGlobals="false"
4
- colors="true"
5
- convertErrorsToExceptions="true"
6
- convertNoticesToExceptions="true"
7
- convertWarningsToExceptions="true"
8
- >
9
- <testsuites>
10
- <testsuite>
11
- <directory prefix="test-" suffix=".php">./tests/</directory>
12
- </testsuite>
13
- </testsuites>
14
- </phpunit>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
readme.txt CHANGED
@@ -1,13 +1,13 @@
1
  === Defender Security, Monitoring, and Hack Protection ===
2
  Plugin Name: Defender Security, Monitoring, and Hack Protection
3
- Version: 1.6.2
4
  Author: WPMU DEV
5
  Author URI: http://premium.wpmudev.org/
6
  Contributors: WPMUDEV
7
  Tags: Security, Security Tweaks, Hardening, IP lockout, Monitoring, Blacklist, Site Protection, Hacked, Security Scan
8
  Requires at least: 3.5
9
  Tested up to: 4.8
10
- Stable tag: 1.6.2
11
  License: GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
12
 
13
  Protect WordPress from hackers with security tweaks, code scans, IP lockouts, and monitoring.
@@ -103,6 +103,14 @@ Hackers and bot attacks are not the only threat to your site. No matter what se
103
 
104
  == Changelog ==
105
 
 
 
 
 
 
 
 
 
106
  = 1.6.2 =
107
  * New: CSV export for Audit Logging.
108
  * Improvement: Email reports now have unsubscribe link, and link to Reports where email reports can be turned off.
1
  === Defender Security, Monitoring, and Hack Protection ===
2
  Plugin Name: Defender Security, Monitoring, and Hack Protection
3
+ Version: 1.7
4
  Author: WPMU DEV
5
  Author URI: http://premium.wpmudev.org/
6
  Contributors: WPMUDEV
7
  Tags: Security, Security Tweaks, Hardening, IP lockout, Monitoring, Blacklist, Site Protection, Hacked, Security Scan
8
  Requires at least: 3.5
9
  Tested up to: 4.8
10
+ Stable tag: 1.7
11
  License: GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
12
 
13
  Protect WordPress from hackers with security tweaks, code scans, IP lockouts, and monitoring.
103
 
104
  == Changelog ==
105
 
106
+ = 1.7 =
107
+ * New: Now you can enable 2 factors authentication with Defender and Google Authenticator app, support for iOS and Android
108
+ * New: We can define how long the "Remember me" can take affect, via a new Security Tweak, called "Manage Login Duration"
109
+ * Improvement: IP Lockout logs now have separate tables, better for performance.
110
+ * Fix: Ignore a file in Scanning section sometimes coming back after couple of scans.
111
+ * Other minor enhancements/fixes
112
+
113
+
114
  = 1.6.2 =
115
  * New: CSV export for Audit Logging.
116
  * Improvement: Email reports now have unsubscribe link, and link to Reports where email reports can be turned off.
uninstall.php CHANGED
@@ -40,6 +40,7 @@ $cache->delete( 'cleanchecksum' );
40
  \WP_Defender\Module\Scan\Model\Settings::instance()->delete();
41
  \WP_Defender\Module\Hardener\Model\Settings::instance()->delete();
42
  \WP_Defender\Module\IP_Lockout\Model\Settings::instance()->delete();
 
43
 
44
  //clear old stuff
45
  delete_site_option( 'wp_defender' );
40
  \WP_Defender\Module\Scan\Model\Settings::instance()->delete();
41
  \WP_Defender\Module\Hardener\Model\Settings::instance()->delete();
42
  \WP_Defender\Module\IP_Lockout\Model\Settings::instance()->delete();
43
+ \WP_Defender\Module\Advanced_Tools\Model\Auth_Settings::instance()->delete();
44
 
45
  //clear old stuff
46
  delete_site_option( 'wp_defender' );
vendor/binary-to-text-php/Base2n.php ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Binary-to-text PHP Utilities
4
+ *
5
+ * @package binary-to-text-php
6
+ * @link https://github.com/ademarre/binary-to-text-php
7
+ * @author Andre DeMarre
8
+ * @copyright 2009-2013 Andre DeMarre
9
+ * @license http://opensource.org/licenses/MIT MIT
10
+ */
11
+
12
+ /**
13
+ * Class for binary-to-text encoding with a base of 2^n
14
+ *
15
+ * The Base2n class is for binary-to-text conversion. It employs a
16
+ * generalization of the algorithms used by many encoding schemes that
17
+ * use a fixed number of bits to encode each character. In other words,
18
+ * the base is a power of 2.
19
+ *
20
+ * Earlier versions of this class were named
21
+ * FixedBitNotation and FixedBitEncoding.
22
+ *
23
+ * @package binary-to-text-php
24
+ */
25
+ class Base2n
26
+ {
27
+ protected $_chars;
28
+ protected $_bitsPerCharacter;
29
+ protected $_radix;
30
+ protected $_rightPadFinalBits;
31
+ protected $_padFinalGroup;
32
+ protected $_padCharacter;
33
+ protected $_caseSensitive;
34
+ protected $_charmap;
35
+
36
+ /**
37
+ * Constructor
38
+ *
39
+ * @param integer $bitsPerCharacter Bits to use for each encoded character
40
+ * @param string $chars Base character alphabet
41
+ * @param boolean $caseSensitive To decode in a case-sensitive manner
42
+ * @param boolean $rightPadFinalBits How to encode last character
43
+ * @param boolean $padFinalGroup Add padding to end of encoded output
44
+ * @param string $padCharacter Character to use for padding
45
+ *
46
+ * @throws InvalidArgumentException for incompatible parameters
47
+ */
48
+ public function __construct(
49
+ $bitsPerCharacter,
50
+ $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_',
51
+ $caseSensitive = TRUE, $rightPadFinalBits = FALSE,
52
+ $padFinalGroup = FALSE, $padCharacter = '=')
53
+ {
54
+ // Ensure validity of $chars
55
+ if (!is_string($chars) || ($charLength = strlen($chars)) < 2) {
56
+ throw new InvalidArgumentException('$chars must be a string of at least two characters');
57
+ }
58
+
59
+ // Ensure validity of $padCharacter
60
+ if ($padFinalGroup) {
61
+ if (!is_string($padCharacter) || !isset($padCharacter[0])) {
62
+ throw new InvalidArgumentException('$padCharacter must be a string of one character');
63
+ }
64
+
65
+ if ($caseSensitive) {
66
+ $padCharFound = strpos($chars, $padCharacter[0]);
67
+ } else {
68
+ $padCharFound = stripos($chars, $padCharacter[0]);
69
+ }
70
+
71
+ if ($padCharFound !== FALSE) {
72
+ throw new InvalidArgumentException('$padCharacter can not be a member of $chars');
73
+ }
74
+ }
75
+
76
+ // Ensure validity of $bitsPerCharacter
77
+ if (!is_int($bitsPerCharacter)) {
78
+ throw new InvalidArgumentException('$bitsPerCharacter must be an integer');
79
+ }
80
+
81
+ if ($bitsPerCharacter < 1) {
82
+ // $bitsPerCharacter must be at least 1
83
+ throw new InvalidArgumentException('$bitsPerCharacter can not be less than 1');
84
+
85
+ } elseif ($charLength < 1 << $bitsPerCharacter) {
86
+ // Character length of $chars is too small for $bitsPerCharacter
87
+ // Find greatest acceptable value of $bitsPerCharacter
88
+ $bitsPerCharacter = 1;
89
+ $radix = 2;
90
+
91
+ while ($charLength >= ($radix <<= 1) && $bitsPerCharacter < 8) {
92
+ $bitsPerCharacter++;
93
+ }
94
+
95
+ $radix >>= 1;
96
+ throw new InvalidArgumentException(
97
+ '$bitsPerCharacter can not be more than ' . $bitsPerCharacter
98
+ . ' given $chars length of ' . $charLength
99
+ . ' (max radix ' . $radix . ')');
100
+
101
+ } elseif ($bitsPerCharacter > 8) {
102
+ // $bitsPerCharacter must not be greater than 8
103
+ throw new InvalidArgumentException('$bitsPerCharacter can not be greater than 8');
104
+
105
+ } else {
106
+ $radix = 1 << $bitsPerCharacter;
107
+ }
108
+
109
+ $this->_chars = $chars;
110
+ $this->_bitsPerCharacter = $bitsPerCharacter;
111
+ $this->_radix = $radix;
112
+ $this->_rightPadFinalBits = $rightPadFinalBits;
113
+ $this->_padFinalGroup = $padFinalGroup;
114
+ $this->_padCharacter = $padCharacter[0];
115
+ $this->_caseSensitive = $caseSensitive;
116
+ }
117
+
118
+ /**
119
+ * Encode a string
120
+ *
121
+ * @param string $rawString Binary data to encode
122
+ * @return string
123
+ */
124
+ public function encode($rawString)
125
+ {
126
+ // Unpack string into an array of bytes
127
+ $bytes = unpack('C*', $rawString);
128
+ $byteCount = count($bytes);
129
+
130
+ $encodedString = '';
131
+ $byte = array_shift($bytes);
132
+ $bitsRead = 0;
133
+ $oldBits = 0;
134
+
135
+ $chars = $this->_chars;
136
+ $bitsPerCharacter = $this->_bitsPerCharacter;
137
+ $rightPadFinalBits = $this->_rightPadFinalBits;
138
+ $padFinalGroup = $this->_padFinalGroup;
139
+ $padCharacter = $this->_padCharacter;
140
+
141
+ $charsPerByte = 8 / $bitsPerCharacter;
142
+ $encodedLength = $byteCount * $charsPerByte;
143
+
144
+ // Generate encoded output; each loop produces one encoded character
145
+ for ($c = 0; $c < $encodedLength; $c++) {
146
+
147
+ // Get the bits needed for this encoded character
148
+ if ($bitsRead + $bitsPerCharacter > 8) {
149
+ // Not enough bits remain in this byte for the current character
150
+ // Save the remaining bits before getting the next byte
151
+ $oldBitCount = 8 - $bitsRead;
152
+ $oldBits = $byte ^ ($byte >> $oldBitCount << $oldBitCount);
153
+ $newBitCount = $bitsPerCharacter - $oldBitCount;
154
+
155
+ if (!$bytes) {
156
+ // Last bits; match final character and exit loop
157
+ if ($rightPadFinalBits) $oldBits <<= $newBitCount;
158
+ $encodedString .= $chars[$oldBits];
159
+
160
+ if ($padFinalGroup) {
161
+ // Array of the lowest common multiples of $bitsPerCharacter and 8, divided by 8
162
+ $lcmMap = array(1 => 1, 2 => 1, 3 => 3, 4 => 1, 5 => 5, 6 => 3, 7 => 7, 8 => 1);
163
+ $bytesPerGroup = $lcmMap[$bitsPerCharacter];
164
+ $pads = $bytesPerGroup * $charsPerByte - ceil((strlen($rawString) % $bytesPerGroup) * $charsPerByte);
165
+ $encodedString .= str_repeat($padCharacter, $pads);
166
+ }
167
+
168
+ break;
169
+ }
170
+
171
+ // Get next byte
172
+ $byte = array_shift($bytes);
173
+ $bitsRead = 0;
174
+
175
+ } else {
176
+ $oldBitCount = 0;
177
+ $newBitCount = $bitsPerCharacter;
178
+ }
179
+
180
+ // Read only the needed bits from this byte
181
+ $bits = $byte >> 8 - ($bitsRead + ($newBitCount));
182
+ $bits ^= $bits >> $newBitCount << $newBitCount;
183
+ $bitsRead += $newBitCount;
184
+
185
+ if ($oldBitCount) {
186
+ // Bits come from seperate bytes, add $oldBits to $bits
187
+ $bits = ($oldBits << $newBitCount) | $bits;
188
+ }
189
+
190
+ $encodedString .= $chars[$bits];
191
+ }
192
+
193
+ return $encodedString;
194
+ }
195
+
196
+ /**
197
+ * Decode a string
198
+ *
199
+ * @param string $encodedString Data to decode
200
+ * @param boolean $strict Returns NULL if $encodedString contains an undecodable character
201
+ * @return string
202
+ */
203
+ public function decode($encodedString, $strict = FALSE)
204
+ {
205
+ if (!$encodedString || !is_string($encodedString)) {
206
+ // Empty string, nothing to decode
207
+ return '';
208
+ }
209
+
210
+ $chars = $this->_chars;
211
+ $bitsPerCharacter = $this->_bitsPerCharacter;
212
+ $radix = $this->_radix;
213
+ $rightPadFinalBits = $this->_rightPadFinalBits;
214
+ $padFinalGroup = $this->_padFinalGroup;
215
+ $padCharacter = $this->_padCharacter;
216
+ $caseSensitive = $this->_caseSensitive;
217
+
218
+ // Get index of encoded characters
219
+ if ($this->_charmap) {
220
+ $charmap = $this->_charmap;
221
+
222
+ } else {
223
+ $charmap = array();
224
+
225
+ for ($i = 0; $i < $radix; $i++) {
226
+ $charmap[$chars[$i]] = $i;
227
+ }
228
+
229
+ $this->_charmap = $charmap;
230
+ }
231
+
232
+ // The last encoded character is $encodedString[$lastNotatedIndex]
233
+ $lastNotatedIndex = strlen($encodedString) - 1;
234
+
235
+ // Remove trailing padding characters
236
+ if ($padFinalGroup) {
237
+ while ($encodedString[$lastNotatedIndex] === $padCharacter) {
238
+ $encodedString = substr($encodedString, 0, $lastNotatedIndex);
239
+ $lastNotatedIndex--;
240
+ }
241
+ }
242
+
243
+ $rawString = '';
244
+ $byte = 0;
245
+ $bitsWritten = 0;
246
+
247
+ // Convert each encoded character to a series of unencoded bits
248
+ for ($c = 0; $c <= $lastNotatedIndex; $c++) {
249
+
250
+ if (!$caseSensitive && !isset($charmap[$encodedString[$c]])) {
251
+ // Encoded character was not found; try other case
252
+ if (isset($charmap[$cUpper = strtoupper($encodedString[$c])])) {
253
+ $charmap[$encodedString[$c]] = $charmap[$cUpper];
254
+
255
+ } elseif (isset($charmap[$cLower = strtolower($encodedString[$c])])) {
256
+ $charmap[$encodedString[$c]] = $charmap[$cLower];
257
+ }
258
+ }
259
+
260
+ if (isset($charmap[$encodedString[$c]])) {
261
+ $bitsNeeded = 8 - $bitsWritten;
262
+ $unusedBitCount = $bitsPerCharacter - $bitsNeeded;
263
+
264
+ // Get the new bits ready
265
+ if ($bitsNeeded > $bitsPerCharacter) {
266
+ // New bits aren't enough to complete a byte; shift them left into position
267
+ $newBits = $charmap[$encodedString[$c]] << $bitsNeeded - $bitsPerCharacter;
268
+ $bitsWritten += $bitsPerCharacter;
269
+
270
+ } elseif ($c !== $lastNotatedIndex || $rightPadFinalBits) {
271
+ // Zero or more too many bits to complete a byte; shift right
272
+ $newBits = $charmap[$encodedString[$c]] >> $unusedBitCount;
273
+ $bitsWritten = 8; //$bitsWritten += $bitsNeeded;
274
+
275
+ } else {
276
+ // Final bits don't need to be shifted
277
+ $newBits = $charmap[$encodedString[$c]];
278
+ $bitsWritten = 8;
279
+ }
280
+
281
+ $byte |= $newBits;
282
+
283
+ if ($bitsWritten === 8 || $c === $lastNotatedIndex) {
284
+ // Byte is ready to be written
285
+ $rawString .= pack('C', $byte);
286
+
287
+ if ($c !== $lastNotatedIndex) {
288
+ // Start the next byte
289
+ $bitsWritten = $unusedBitCount;
290
+ $byte = ($charmap[$encodedString[$c]] ^ ($newBits << $unusedBitCount)) << 8 - $bitsWritten;
291
+ }
292
+ }
293
+
294
+ } elseif ($strict) {
295
+ // Unable to decode character; abort
296
+ return NULL;
297
+ }
298
+ }
299
+
300
+ return $rawString;
301
+ }
302
+ }
vendor/binary-to-text-php/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2009-2013 Andre DeMarre
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.
vendor/binary-to-text-php/README.md ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Binary-to-Text Utilities for PHP
2
+ =================================
3
+
4
+ For now, the only class in this repository is **Base2n**.
5
+
6
+ Base2n is for binary-to-text conversion with arbitrary encoding schemes that represent binary data in a base 2<sup>n</sup> notation. It can handle non-standard variants of many standard encoding schemes such as [Base64][rfc4648base64] and [Base32][rfc4648base32]. Many binary-to-text encoding schemes use a fixed number of bits of binary data to generate each encoded character. Such schemes generalize to a single algorithm, implemented here.
7
+
8
+ [rfc4648base64]: http://tools.ietf.org/html/rfc4648#section-4 "RFC 4648 Base64 Specification"
9
+ [rfc4648base32]: http://tools.ietf.org/html/rfc4648#section-6 "RFC 4648 Base32 Specification"
10
+
11
+ Binary-to-text encoding is usually used to represent data in a notation that is safe for transport over text-based protocols, and there are several other practical uses. See the examples below.
12
+
13
+
14
+
15
+ Basic Base2n Usage
16
+ ------------------
17
+
18
+ With Base2n, you define your encoding scheme parametrically. Let's instantiate a [Base32][rfc4648base32] encoder:
19
+
20
+ ```php
21
+ // RFC 4648 base32 alphabet; case-insensitive
22
+ $base32 = new Base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', FALSE, TRUE, TRUE);
23
+ $encoded = $base32->encode('encode this');
24
+ // MVXGG33EMUQHI2DJOM======
25
+ ```
26
+
27
+
28
+ ### Constructor Parameters
29
+
30
+ - <code>integer $bitsPerCharacter</code> **Required**. The number of bits to use for each encoded character; 1–8. The most practical range is 1–6. The encoding's radix is a power of 2: <code>2^$bitsPerCharacter</code>.
31
+ 1. [base-2, binary][binary]
32
+ 2. [base-4, quaternary][quaternary]
33
+ 3. [base-8, octal][octal]
34
+ 4. [base-16, hexadecimal][hexadecimal]
35
+ 5. [base-32][base32]
36
+ 6. [base-64][base64]
37
+ 7. base-128
38
+ 8. base-256
39
+
40
+ [binary]: http://en.wikipedia.org/wiki/Binary_numeral_system "Binary Notation"
41
+ [quaternary]: http://en.wikipedia.org/wiki/Quaternary_numeral_system "Base-2 Notation"
42
+ [octal]: http://en.wikipedia.org/wiki/Octal "Octal Notation"
43
+ [hexadecimal]: http://en.wikipedia.org/wiki/Base16 "Hexadecimal Notation"
44
+ [base32]: http://en.wikipedia.org/wiki/Base32 "Base32 Encoding"
45
+ [base64]: http://en.wikipedia.org/wiki/Base64 "Base64 Encoding"
46
+
47
+ - <code>string $chars</code> This string specifies the base alphabet. Must be <code>2^$bitsPerCharacter</code> long. Default: <code>0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_</code>
48
+
49
+ - <code>boolean $caseSensitive</code> To decode in a case-sensitive manner. Default: <code>FALSE</code>
50
+
51
+ - <code>boolean $rightPadFinalBits</code> How to encode the last character when the bits remaining are fewer than <code>$bitsPerCharacter</code>. When <code>TRUE</code>, the bits to encode are placed in the most significant position of the final group of bits, with the lower bits set to <code>0</code>. When <code>FALSE</code>, the final bits are placed in the least significant position. For [RFC 4648][rfc4648] encodings, <code>$rightPadFinalBits</code>should be <code>TRUE</code>. Default: <code>FALSE</code>
52
+
53
+ [rfc4648]: http://tools.ietf.org/html/rfc4648 "RFC 4648: Base16, Base32, Base64"
54
+
55
+ - <code>boolean $padFinalGroup</code> It's common to encode characters in groups. For example, Base64 (which is based on 6 bits per character) converts 3 raw bytes into 4 encoded characters. If insufficient bytes remain at the end, the final group will be padded with <code>=</code> to complete a group of 4 characters, and the encoded length is always a multiple of 4. Although the information provided by the padding is redundant, some programs rely on it for decoding; Base2n does not. Default: <code>FALSE</code>
56
+
57
+ - <code>string $padCharacter</code> When <code>$padFinalGroup</code> is <code>TRUE</code>, this is the pad character used. Default: <code>=</code>
58
+
59
+
60
+ ### <code>encode()</code> Parameters
61
+
62
+ - <code>string $rawString</code> **Required**. The data to be encoded.
63
+
64
+
65
+ ### <code>decode()</code> Parameters
66
+
67
+ - <code>string $encodedString</code> **Required**. The string to be decoded.
68
+ - <code>boolean $strict</code> When <code>TRUE</code>, <code>NULL</code> will be returned if <code>$encodedString</code> contains an undecodable character. When <code>FALSE</code>, unknown characters are simply ignored. Default: <code>FALSE</code>
69
+
70
+
71
+
72
+ Examples
73
+ --------
74
+
75
+ PHP does not provide any Base32 encoding functions. By setting <code>$bitsPerCharacter</code> to 5 and specifying your desired alphabet in <code>$chars</code>, you can handle any variant of Base32:
76
+
77
+ ```php
78
+ // RFC 4648 base32 alphabet; case-insensitive
79
+ $base32 = new Base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', FALSE, TRUE, TRUE);
80
+ $encoded = $base32->encode('encode this');
81
+ // MVXGG33EMUQHI2DJOM======
82
+ ```
83
+
84
+ ```php
85
+ // RFC 4648 base32hex alphabet
86
+ $base32hex = new Base2n(5, '0123456789ABCDEFGHIJKLMNOPQRSTUV', FALSE, TRUE, TRUE);
87
+ $encoded = $base32hex->encode('encode this');
88
+ // CLN66RR4CKG78Q39EC======
89
+ ```
90
+
91
+
92
+ Octal notation:
93
+
94
+ ```php
95
+ $octal = new Base2n(3);
96
+ $encoded = $octal->encode('encode this');
97
+ // 312671433366214510072150322711
98
+ ```
99
+
100
+
101
+ A convenient way to go back and forth between binary notation and its real binary representation:
102
+
103
+ ```php
104
+ $binary = new Base2n(1);
105
+ $encoded = $binary->encode('encode this');
106
+ // 0110010101101110011000110110111101100100011001010010000001110100011010000110100101110011
107
+ $decoded = $binary->decode($encoded);
108
+ // encode this
109
+ ```
110
+
111
+
112
+ PHP uses a proprietary binary-to-text encoding scheme to generate session identifiers from random hash digests. The most efficient way to store these session IDs in a database is to decode them back to their raw hash digests. PHP's encoding scheme is configured with the <code>[session.hash_bits_per_character][phphashbits]</code> php.ini setting. The decoded size depends on the hash function, set with <code>[session.hash_function][phphash]</code> in php.ini.
113
+
114
+ ```php
115
+ // session.hash_function = 0
116
+ // session.hash_bits_per_character = 5
117
+ // 128-bit session ID
118
+ $sessionId = 'q3c8n4vqpq11i0vr6ucmafg1h3';
119
+ // Decodes to 16 bytes
120
+ $phpBase32 = new Base2n(5, '0123456789abcdefghijklmnopqrstuv');
121
+ $rawSessionId = $phpBase32->decode($sessionId);
122
+ ```
123
+
124
+ ```php
125
+ // session.hash_function = 1
126
+ // session.hash_bits_per_character = 6
127
+ // 160-bit session ID
128
+ $sessionId = '7Hf91mVc,q-9W1VndNNh3evVN83';
129
+ // Decodes to 20 bytes
130
+ $phpBase64 = new Base2n(6, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,');
131
+ $rawSessionId = $phpBase64->decode($sessionId);
132
+ ```
133
+
134
+ [phphashbits]: http://php.net/manual/en/session.configuration.php#ini.session.hash-bits-per-character "PHP session.hash_bits_per_character"
135
+ [phphash]: http://php.net/manual/en/session.configuration.php#ini.session.hash-function "PHP session.hash_function"
136
+
137
+
138
+ Generate random security tokens:
139
+ ```php
140
+ $tokenEncoder = new Base2n(6, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,');
141
+ $binaryToken = openssl_random_pseudo_bytes(32); // PHP >= 5.3
142
+ $token = $tokenEncoder->encode($binaryToken);
143
+ // Example: U6M132v9FG-AHhBVaQWOg1gjyUi1IogNxuen0i3u3ep
144
+ ```
145
+
146
+
147
+ The rest of these examples are probably more fun than they are practical.
148
+
149
+
150
+ We can encode arbitrary data with a 7-bit encoding. (Note that this is not the same as the [7bit MIME content-transfer-encoding][7bit].)
151
+ ```php
152
+ // This uses all 7-bit ASCII characters
153
+ $base128chars = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
154
+ . "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
155
+ . "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F"
156
+ . "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F"
157
+ . "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F"
158
+ . "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F"
159
+ . "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F"
160
+ . "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x69\x7A\x7B\x7C\x7D\x7E\x7F";
161
+
162
+ $base128 = new Base2n(7, $base128chars);
163
+ $encoded = $base128->encode('encode this');
164
+ ```
165
+ [7bit]: http://msdn.microsoft.com/en-us/library/ms526290(v=exchg.10).aspx "7bit MIME Content-Transfer-Encoding"
166
+
167
+
168
+ The following encoding guarantees that the most significant bit is set for every byte:
169
+ ```php
170
+ // "High" base-128 encoding
171
+ $high128chars = "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F"
172
+ . "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F"
173
+ . "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF"
174
+ . "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF"
175
+ . "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF"
176
+ . "\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF"
177
+ . "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF"
178
+ . "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
179
+
180
+ $high128 = new Base2n(7, $high128chars);
181
+ $encoded = $high128->encode('encode this');
182
+ ```
183
+
184
+
185
+ Let's create an encoding using exclusively non-printable control characters!
186
+ ```php
187
+ // Base-32 non-printable character encoding
188
+ $noPrintChars = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
189
+ . "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
190
+
191
+ $nonPrintable32 = new Base2n(5, $noPrintChars);
192
+ $encoded = $nonPrintable32->encode('encode this');
193
+ ```
194
+
195
+
196
+ Why not encode data using only whitespace? Here's a base-4 encoding using space, tab, new line, and carriage return:
197
+ ```php
198
+ // Base-4 whitespace encoding
199
+ $whitespaceChars = " \t\n\r";
200
+
201
+ $whitespace = new Base2n(2, $whitespaceChars);
202
+ $encoded = $whitespace->encode('encode this');
203
+ // "\t\n\t\t\t\n\r\n\t\n \r\t\n\r\r\t\n\t \t\n\t\t \n \t\r\t \t\n\n \t\n\n\t\t\r \r"
204
+
205
+ $decoded = $whitespace->decode(
206
+ "\t\n\t\t\t\n\r\n\t\n \r\t\n\r\r\t\n\t \t\n\t\t \n \t\r\t \t\n\n \t\n\n\t\t\r \r"
207
+ );
208
+ // encode this
209
+ ```
210
+
211
+
212
+
213
+ Counterexamples
214
+ ----------------
215
+
216
+ Base2n is not slow, but it will never outperform an encoding function implemented in C. When one exists, use it instead.
217
+
218
+
219
+ PHP provides the <code>[base64_encode()][base64_encode]</code> and <code>[base64_decode()][base64_decode]</code> functions, and you should always use them for standard Base64. When you need to use a modified alphabet, you can translate the encoded output with <code>[strtr()][strtr]</code> or <code>[str_replace()][str_replace]</code>.
220
+
221
+ [base64_encode]: http://php.net/base64_encode "PHP base64_encode() Function"
222
+ [base64_decode]: http://php.net/base64_decode "PHP base64_decode() Function"
223
+ [strtr]: http://php.net/strtr "PHP strtr() Function"
224
+ [str_replace]: http://php.net/str_replace "PHP str_replace() Function"
225
+
226
+ A common variant of Base64 is [modified for URLs and filenames][rfc4648base64url], where <code>+</code> and <code>/</code> are replaced with <code>-</code> and <code>_</code>, and the <code>=</code> padding is omitted. It's better to handle this variant with native PHP functions:
227
+
228
+ ```php
229
+ // RFC 4648 base64url with Base2n...
230
+ $base64url = new Base2n(6, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', TRUE, TRUE, FALSE);
231
+ $encoded = $base64url->encode("encode this \xBF\xC2\xBF");
232
+ // ZW5jb2RlIHRoaXMgv8K_
233
+
234
+ // RFC 4648 base64url with native functions...
235
+ $encoded = str_replace(array('+', '/', '='), array('-', '_', ''), base64_encode("encode this \xBF\xC2\xBF"));
236
+ // ZW5jb2RlIHRoaXMgv8K_
237
+ ```
238
+
239
+ [rfc4648base64url]: http://tools.ietf.org/html/rfc4648#page-7 "Modified Base64 for URLs"
240
+
241
+
242
+ Native functions get slightly more cumbersome when every position in the alphabet has changed, as seen in this example of [decoding a Bcrypt hash][bmcf]:
243
+ ```php
244
+ // Decode the salt and digest from a Bcrypt hash
245
+
246
+ $hash = '$2y$14$i5btSOiulHhaPHPbgNUGdObga/GC.AVG/y5HHY1ra7L0C9dpCaw8u';
247
+ $encodedSalt = substr($hash, 7, 22);
248
+ $encodedDigest = substr($hash, 29, 31);
249
+
250
+ // Using Base2n...
251
+ $bcrypt64 = new Base2n(6, './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', TRUE, TRUE);
252
+ $rawSalt = $bcrypt64->decode($encodedSalt); // 16 bytes
253
+ $rawDigest = $bcrypt64->decode($encodedDigest); // 23 bytes
254
+
255
+ // Using native functions...
256
+ $bcrypt64alphabet = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
257
+ $base64alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
258
+ $rawSalt = base64_decode(strtr($encodedSalt, $bcrypt64alphabet, $base64alphabet)); // 16 bytes
259
+ $rawDigest = base64_decode(strtr($encodedDigest, $bcrypt64alphabet, $base64alphabet)); // 23 bytes
260
+ ```
261
+
262
+ [bmcf]: https://github.com/ademarre/binary-mcf "Binary Modular Crypt Format (BMCF)"
263
+
264
+ You can encode and decode hexadecimal with <code>[bin2hex()][bin2hex]</code> and <code>[pack()][pack]</code>:
265
+
266
+ ```php
267
+ // Hexadecimal with Base2n...
268
+ $hexadecimal = new Base2n(4);
269
+ $encoded = $hexadecimal->encode('encode this'); // 656e636f64652074686973
270
+ $decoded = $hexadecimal->decode($encoded); // encode this
271
+
272
+ // It's better to use native functions...
273
+ $encoded = bin2hex('encode this'); // 656e636f64652074686973
274
+ $decoded = pack('H*', $encoded); // encode this
275
+ // As of PHP 5.4 you can use hex2bin() instead of pack()
276
+ ```
277
+
278
+ [bin2hex]: http://php.net/bin2hex "PHP bin2hex() Function"
279
+ [pack]: http://php.net/pack "PHP pack() Function"
vendor/binary-to-text-php/composer.json ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "ademarre/binary-to-text-php",
3
+ "description": "Collection of binary-to-text encoding utilities for PHP. Includes Base32 support and much more.",
4
+ "keywords": ["rfc4648", "base32", "octal", "base-8", "base-4", "binary"],
5
+ "type": "library",
6
+ "homepage": "https://github.com/ademarre/binary-to-text-php",
7
+ "license": "MIT",
8
+ "authors": [
9
+ {
10
+ "name": "Andre DeMarre",
11
+ "role": "Developer"
12
+ }
13
+ ],
14
+ "require": {
15
+ "php": ">=5.2.14"
16
+ },
17
+ "autoload": {
18
+ "psr-0": { "Base2n": "" }
19
+ }
20
+ }
vendor/hammer/base/db-model.php ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Author: Hoang Ngo
4
+ */
5
+
6
+ namespace Hammer\Base;
7
+ class DB_Model extends Model {
8
+ const EVENT_BEFORE_INSERT = 'beforeInsert', EVENT_AFTER_INSERT = 'afterInsert',
9
+ EVENT_BEFORE_UPDATE = 'beforeUpdate', EVENT_AFTER_UPDATE = 'afterUpdate',
10
+ EVENT_BEFORE_DELELTE = 'beforeDelete', EVENT_AFTER_DELETE = 'afterDelete';
11
+
12
+ public $id;
13
+ protected static $tableName = '';
14
+
15
+ public function save() {
16
+ if ( $this->id ) {
17
+ $this->update();
18
+ } else {
19
+ $this->insert();
20
+ }
21
+ }
22
+
23
+ /**
24
+ * @return false|int|\WP_Error
25
+ */
26
+ private function insert() {
27
+ if ( static::$tableName == null ) {
28
+ return new \WP_Error( 'db_error', 'No table specific' );
29
+ }
30
+
31
+ $this->trigger( self::EVENT_BEFORE_INSERT );
32
+ $data = $this->export();
33
+ if ( isset( $data['id'] ) && ! empty( $data['id'] ) ) {
34
+ return new \WP_Error( 'db_error', "This id already exists!" );
35
+ }
36
+
37
+ $id = self::getWPDB()->insert( self::getTable(), $data );
38
+ if ( $id == false ) {
39
+ error_log( self::getWPDB()->last_error );
40
+
41
+ return new \WP_Error( 'db_error', self::getWPDB()->last_error );
42
+ }
43
+
44
+ $this->trigger( self::EVENT_BEFORE_UPDATE );
45
+
46
+ return self::getWPDB()->insert_id;
47
+ }
48
+
49
+ /**
50
+ * @return bool|\WP_Error
51
+ */
52
+ private function update() {
53
+ if ( static::$tableName == null ) {
54
+ return new \WP_Error( 'db_error', 'No table specific' );
55
+ }
56
+ $this->trigger( self::EVENT_BEFORE_UPDATE );
57
+ $data = $this->export();
58
+ $check = self::findByID( $data['id'] );
59
+ if ( is_null( $check ) ) {
60
+ return new \WP_Error( 'db_error', "This record doesn't exists" );
61
+ }
62
+ unset( $data['id'] );
63
+ $affected = self::getWPDB()->update( self::getTable(), $data, array(
64
+ 'id' => $check->id
65
+ ) );
66
+ if ( $affected == false ) {
67
+ error_log( self::getWPDB()->last_error );
68
+
69
+ return new \WP_Error( 'db_error', self::getWPDB()->last_error );
70
+ }
71
+ $this->trigger( self::EVENT_AFTER_UPDATE );
72
+
73
+ return true;
74
+ }
75
+
76
+ /**
77
+ * @param $id
78
+ *
79
+ * @return mixed|null
80
+ */
81
+ public static function findByID( $id ) {
82
+ if ( ! $id ) {
83
+ return null;
84
+ }
85
+ $sql = self::getWPDB()->prepare( "SELECT * FROM " . self::getTable() . " WHERE id = %d", $id );
86
+ $data = self::getWPDB()->get_row( $sql, ARRAY_A );
87
+ if ( is_array( $data ) && count( $data ) ) {
88
+ return self::bind( $data );
89
+ } else {
90
+ return null;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * @param array $attributes
96
+ * @param null $orderBy
97
+ * @param string $order
98
+ *
99
+ * @return mixed|null
100
+ */
101
+ public static function findOne( $attributes = array(), $orderBy = null, $order = 'ASC' ) {
102
+ $fields = self::buildFields();
103
+ $where = self::buildWhere( $attributes );
104
+ $sqlOrder = null;
105
+ if ( ! empty( $orderBy ) && in_array( $orderBy, $fields ) ) {
106
+ if ( ! in_array( strtolower( $order ), array( 'asc', 'desc' ) ) ) {
107
+ $order = 'ASC';
108
+ }
109
+ $sqlOrder = 'ORDER BY ' . $orderBy . ' ' . $order;
110
+ }
111
+
112
+ $sql = 'SELECT ' . implode( ', ', $fields ) . ' FROM ' . self::getTable() .
113
+ ' WHERE ' . implode( 'AND', $where ) . $sqlOrder . ' LIMIT 0,1';
114
+ $data = self::getWPDB()->get_row( $sql, ARRAY_A );
115
+ if ( is_array( $data ) && count( $data ) ) {
116
+ return self::bind( $data );
117
+ }
118
+
119
+ return null;
120
+ }
121
+
122
+ /**
123
+ * @param array $attributes
124
+ * @param null $orderBy
125
+ * @param string $order
126
+ * @param null $limit
127
+ *
128
+ * @return array
129
+ */
130
+ public static function findAll( $attributes = array(), $orderBy = null, $order = 'ASC', $limit = null ) {
131
+ $fields = self::buildFields();
132
+ $where = self::buildWhere( $attributes );
133
+ $sqlOrder = null;
134
+ if ( ! empty( $orderBy ) && in_array( $orderBy, $fields ) ) {
135
+ if ( ! in_array( strtolower( $order ), array( 'asc', 'desc' ) ) ) {
136
+ $order = 'ASC';
137
+ }
138
+ $sqlOrder = ' ORDER BY ' . $orderBy . ' ' . $order;
139
+ }
140
+
141
+ $sql = 'SELECT ' . implode( ', ', $fields ) . ' FROM ' . self::getTable() .
142
+ ' WHERE ' . implode( ' AND ', $where ) . $sqlOrder;
143
+ if ( $limit ) {
144
+ $sql = $sql . ' LIMIT ' . $limit;
145
+ }
146
+ $data = self::getWPDB()->get_results( $sql, ARRAY_A );
147
+ $results = array();
148
+ if ( is_array( $data ) && count( $data ) ) {
149
+ foreach ( $data as $row ) {
150
+ $results[] = self::bind( $row );
151
+ }
152
+ }
153
+
154
+ return $results;
155
+ }
156
+
157
+ /**
158
+ *
159
+ */
160
+ public function delete() {
161
+ global $wpdb;
162
+ $wpdb->delete( self::getTable(), array(
163
+ 'id' => $this->id
164
+ ) );
165
+ }
166
+
167
+ /**
168
+ * @param array $attributes
169
+ * @param bool $limit
170
+ *
171
+ * @return int
172
+ */
173
+ public static function deleteAll( $attributes = array(), $limit = false ) {
174
+ $where = self::buildWhere( $attributes );
175
+ $sql = "SELECT id from " . self::getTable() . " WHERE " . implode( ' AND ', $where );
176
+ if ( $limit != false ) {
177
+ $sql = $sql . ' LIMIT ' . $limit;
178
+ }
179
+
180
+ global $wpdb;
181
+ $ids = $wpdb->get_col( $sql );
182
+ if ( ! empty( $ids ) ) {
183
+ $sql = "DELETE from " . self::getTable() . " WHERE id";
184
+ $sql .= " IN (" . implode( ', ', array_fill( 0, count( $ids ), '%s' ) ) . ")";
185
+ $sql = call_user_func_array( array(
186
+ $wpdb,
187
+ 'prepare'
188
+ ), array_merge( array( $sql ), $ids ) );
189
+ $wpdb->query( $sql );
190
+ }
191
+
192
+ return count( $ids );
193
+ }
194
+
195
+ /**
196
+ * @param array $attributes
197
+ *
198
+ * @return null|string
199
+ */
200
+ public static function count( $attributes = array() ) {
201
+ $where = self::buildWhere( $attributes );
202
+ $sql = "SELECT count(id) FROM " . self::getTable() . " WHERE " . implode( ' AND ', $where );
203
+
204
+ return self::getWPDB()->get_var( $sql );
205
+ }
206
+
207
+ /**
208
+ * @return \wpdb
209
+ */
210
+ private static function getWPDB() {
211
+ global $wpdb;
212
+
213
+ return $wpdb;
214
+ }
215
+
216
+ /**
217
+ * @param $data
218
+ *
219
+ * @return mixed
220
+ */
221
+ private static function bind( $data ) {
222
+ $class = get_called_class();
223
+ $obj = new $class;
224
+
225
+ foreach ( $data as $key => $val ) {
226
+ $data[ $key ] = maybe_unserialize( $val );
227
+ }
228
+
229
+ $obj->import( $data );
230
+
231
+ return $obj;
232
+ }
233
+
234
+ private static function getTable() {
235
+ return self::getWPDB()->base_prefix . static::$tableName;
236
+ }
237
+
238
+ /**
239
+ * @return array
240
+ */
241
+ private static function buildFields() {
242
+ $class = get_called_class();
243
+ $obj = new $class;
244
+ $data = $obj->export();
245
+ $fields = array_keys( $data );
246
+
247
+ return $fields;
248
+ }
249
+
250
+ /**
251
+ * @param array $attributes
252
+ *
253
+ * @return array
254
+ */
255
+ private static function buildWhere( $attributes = array() ) {
256
+ if ( empty( $attributes ) ) {
257
+ return array( '1=1' );
258
+ }
259
+ $condition = array();
260
+ $fields = self::buildFields();
261
+ global $wpdb;
262
+ foreach ( $attributes as $key => $attribute ) {
263
+ if ( ! in_array( $key, $fields ) ) {
264
+ //this condition is not supported
265
+ continue;
266
+ }
267
+ if ( is_array( $attribute ) ) {
268
+ if ( isset( $attribute['compare'] ) ) {
269
+ $sql = $key . ' ' . $attribute['compare'] . ' %s';
270
+ $sql = $wpdb->prepare( $sql, $attribute['value'] );
271
+ $condition[] = $sql;
272
+ } elseif ( ! empty( $attribute ) ) {
273
+ $sql = $key . " IN (" . implode( ', ', array_fill( 0, count( $attribute ), '%s' ) ) . ")";
274
+
275
+ $sql = call_user_func_array( array(
276
+ $wpdb,
277
+ 'prepare'
278
+ ), array_merge( array( $sql ), $attribute ) );
279
+ $condition[] = $sql;
280
+ }
281
+ } elseif ( strpos( '%', $attribute ) === 0 ) {
282
+ $condition[] = $wpdb->prepare( $key . ' LIKE %s', $attribute );
283
+ } else {
284
+ $condition[] = $wpdb->prepare( $key . ' = %s', $attribute );
285
+ }
286
+ }
287
+
288
+ $condition = array_filter( $condition );
289
+
290
+ return $condition;
291
+ }
292
+ }
vendor/hammer/base/view.php CHANGED
@@ -53,7 +53,6 @@ class View extends Component {
53
  public function render( $view, $params = array() ) {
54
  $this->trigger( self::EVENT_BEFORE_RENDER );
55
  $view_file = $this->_base_path . DIRECTORY_SEPARATOR . $view . '.php';
56
-
57
  if ( is_file( $view_file ) ) {
58
  $content = $this->renderPHPFile( $view_file, $params );
59
  $this->trigger( self::EVENT_AFTER_RENDER );
53
  public function render( $view, $params = array() ) {
54
  $this->trigger( self::EVENT_BEFORE_RENDER );
55
  $view_file = $this->_base_path . DIRECTORY_SEPARATOR . $view . '.php';
 
56
  if ( is_file( $view_file ) ) {
57
  $content = $this->renderPHPFile( $view_file, $params );
58
  $this->trigger( self::EVENT_AFTER_RENDER );
vendor/hammer/vendor/psr/log/.gitignore DELETED
@@ -1 +0,0 @@
1
- vendor
 
vendor/hammer/vendor/wixel/gump/examples/basic_tags.php DELETED
@@ -1,24 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- require "../gump.class.php";
5
-
6
- $validator = new GUMP();
7
-
8
- $validator->validation_rules(array(
9
- 'comment' => 'required|max_len,500',
10
- ));
11
-
12
- $validator->filter_rules(array(
13
- 'comment' => 'basic_tags',
14
- ));
15
-
16
- // Valid Data
17
- $_POST = array(
18
- 'comment' => '<strong>this is freaking awesome</strong><script>alert(1);</script>'
19
- );
20
-
21
-
22
- $_POST = $validator->run($_POST);
23
-
24
- print_r($_POST);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/contains.php DELETED
@@ -1,48 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- require "../gump.class.php";
5
-
6
- $validator = new GUMP();
7
-
8
- $rules = array(
9
- 'account_type' => "required|contains,pro free basic premium",
10
- 'priority' => "required|contains,'low' 'medium' 'very high'",
11
- );
12
-
13
- echo "\nVALID DATA TEST:\n\n";
14
-
15
- // Valid Data
16
- $_POST_VALID = array(
17
- 'account_type' => 'pro',
18
- 'priority' => 'very high'
19
- );
20
-
21
- $valid = $validator->validate(
22
- $_POST_VALID, $rules
23
- );
24
-
25
- if($valid !== true) {
26
- echo $validator->get_readable_errors(true);
27
- } else {
28
- echo "Validation passed! \n";
29
- }
30
-
31
- echo "\nINVALID DATA TEST:\n\n";
32
-
33
- // Invalid
34
- $_POST_INVALID = array(
35
- 'account_type' => 'bad',
36
- 'priority' => 'unknown'
37
- );
38
-
39
- $invalid = $validator->validate(
40
- $_POST_INVALID, $rules
41
- );
42
-
43
- if($invalid !== true) {
44
- echo $validator->get_readable_errors(true);
45
- echo "\n\n";
46
- } else {
47
- echo "Validation passed!\n\n";
48
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/credit_card.php DELETED
@@ -1,16 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- require "../gump.class.php";
5
-
6
- $validator = new GUMP();
7
-
8
- $_POST = array(
9
- 'cc' => '987230234-2498234-24234-23' // This is not a valid credit card number
10
- );
11
-
12
- $rules = array(
13
- 'cc' => 'valid_cc'
14
- );
15
-
16
- print_r($validator->validate($_POST, $rules));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/custom_validator.php DELETED
@@ -1,44 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- require "../gump.class.php";
5
-
6
- // Add the custom validator
7
- GUMP::add_validator("is_object", function($field, $input, $param = NULL) {
8
- return is_object($input[$field]);
9
- });
10
-
11
- // Generic test data
12
- $input_data = array(
13
- 'not_object' => "asdasd",
14
- 'valid_object' => new stdClass()
15
- );
16
-
17
- $rules = array(
18
- 'not_object' => "is_object",
19
- 'valid_object' => "is_object"
20
- );
21
-
22
- // METHOD 1 (Long):
23
-
24
- $validator = new GUMP();
25
-
26
- $validated = $validator->validate(
27
- $input_data, $rules
28
- );
29
-
30
- if($validated === true) {
31
- echo "Validation passed!";
32
- } else {
33
- echo $validator->get_readable_errors(true);
34
- }
35
-
36
- // METHOD 2 (Short):
37
-
38
- $is_valid = GUMP::is_valid($input_data, $rules);
39
-
40
- if($is_valid === true) {
41
- echo "Validation passed!";
42
- } else {
43
- print_r($is_valid);
44
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/escaping_mysql_strings.php DELETED
@@ -1,38 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- require "../gump.class.php";
5
-
6
- $validator = new GUMP();
7
-
8
- $_POST = array(
9
- 'username' => "my username",
10
- 'password' => "' OR ''='"
11
- );
12
-
13
- $validator->sanitize($_POST);
14
-
15
- $filters = array(
16
- 'username' => 'noise_words',
17
- 'password' => 'trim|strtolower|addslashes'
18
- );
19
-
20
- print_r($validator->filter($_POST, $filters));
21
-
22
- // OR (If you have a mysql connection)
23
-
24
- $validator->sanitize($_POST);
25
-
26
- $_POST = array(
27
- 'username' => "my username",
28
- 'password' => "' OR ''='"
29
- );
30
-
31
- $filters = array(
32
- 'username' => 'noise_words',
33
- 'password' => 'trim|strtolower'
34
- );
35
-
36
- $validator->filter($_POST, $filters);
37
-
38
- echo mysql_real_escape_string($_POST['password']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/explicit_fields.php DELETED
@@ -1,26 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- error_reporting(-1);
5
-
6
- ini_set('display_errors', 1);
7
-
8
- require "../gump.class.php";
9
-
10
- $data = array(
11
- 'str' => null
12
- );
13
-
14
- $rules = array(
15
- 'str' => 'required'
16
- );
17
-
18
- GUMP::set_field_name("str", "Street");
19
-
20
- $validated = GUMP::is_valid($data, $rules);
21
-
22
- if($validated === true) {
23
- echo "Valid Street Address\n";
24
- } else {
25
- print_r($validated);
26
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/files.php DELETED
@@ -1,41 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- require "../gump.class.php";
5
-
6
- $_FILES = array(
7
- 'attachments' => array(
8
- 'name' => array("test1.png"),
9
- 'type' => array("image/png"),
10
- 'tmp_name' => array("/tmp/phpmFkEUe"),
11
- 'error' => array(0),
12
- 'size' => array(9855)
13
- )
14
- );
15
-
16
- $errors = array();
17
-
18
- $length = count($_FILES['attachments']['name']);
19
-
20
- for($i = 0; $i < $length; $i++) {
21
- $struct = array(
22
- 'name' => $_FILES['attachments']['name'][$i],
23
- 'type' => $_FILES['attachments']['type'][$i],
24
- 'tmp_name' => $_FILES['attachments']['tmp_name'][$i],
25
- 'error' => $_FILES['attachments']['error'][$i],
26
- 'size' => $_FILES['attachments']['size'][$i],
27
- );
28
-
29
- $validated = GUMP::is_valid($struct, array(
30
- 'name' => 'required',
31
- 'type' => 'required',
32
- 'tmp_name' => 'required',
33
- 'size' => 'required|numeric',
34
- ));
35
-
36
- if($validated !== true) {
37
- $errors[] = $validated;
38
- }
39
- }
40
-
41
- print_r($errors);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/full_example.php DELETED
@@ -1,62 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- require "../gump.class.php";
5
-
6
- $validator = new GUMP();
7
-
8
- // Set the data
9
-
10
- $_POST = array(
11
- 'username' => 'SeanNieuwoudt',
12
- 'password' => 'mypassword',
13
- 'email' => 'sean@wixel.net',
14
- 'gender' => 'm',
15
- 'credit_card' => '9872389-2424-234224-234', // Obviously an invalid credit card number,
16
- 'bio' => 'This is good! I think I will switch to another language'
17
- );
18
-
19
- $_POST = $validator->sanitize($_POST); // You don't have to sanitize, but it's safest to do so.
20
-
21
- // Let's define the rules and filters
22
-
23
- $rules = array(
24
- 'username' => 'required|alpha_numeric|max_len,100|min_len,6',
25
- 'password' => 'required|max_len,100|min_len,6',
26
- 'email' => 'required|valid_email',
27
- 'gender' => 'required|exact_len,1',
28
- 'credit_card' => 'required|valid_cc',
29
- 'bio' => 'required'
30
- );
31
-
32
- $filters = array(
33
- 'username' => 'trim|sanitize_string',
34
- 'password' => 'trim|base64_encode',
35
- 'email' => 'trim|sanitize_email',
36
- 'gender' => 'trim'
37
- );
38
-
39
- $_POST = $validator->filter($_POST, $filters);
40
-
41
- // You can run filter() or validate() first
42
-
43
- $validated = $validator->validate(
44
- $_POST, $rules
45
- );
46
-
47
- // Check if validation was successful
48
-
49
- if($validated === TRUE)
50
- {
51
- echo "Successful Validation\n\n";
52
-
53
- print_r($_POST); // You can now use POST data safely
54
-
55
- exit;
56
- }
57
- else
58
- {
59
- print_r($_POST);
60
-
61
- print_r($validated); // Shows all the rules that failed along with the data
62
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/guid.php DELETED
@@ -1,18 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- require "../gump.class.php";
5
-
6
- $data = array(
7
- 'guid' => "A98C5A1E-A742-4808-96FA-6F409E799937"
8
- );
9
-
10
- $is_valid = GUMP::is_valid($data, array(
11
- 'guid' => 'required|guidv4',
12
- ));
13
-
14
- if($is_valid === true) {
15
- // continue
16
- } else {
17
- print_r($is_valid);
18
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/handling_errors.php DELETED
@@ -1,74 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- require "../gump.class.php";
5
-
6
- $validator = new GUMP();
7
-
8
- // Set the data
9
-
10
- $_POST = array(
11
- 'username' => 'SeanNieuwoudt',
12
- 'password' => 'mypassword',
13
- 'email' => 'sean@wixel.net',
14
- 'gender' => 'm',
15
- 'credit_card' => '9872389-2424-234224-234', // Obviously an invalid credit card number,
16
- 'bio' => 'This is good! I think I will switch to another language'
17
- );
18
-
19
- $_POST = $validator->sanitize($_POST); // You don't have to sanitize, but it's safest to do so.
20
-
21
- // Let's define the rules and filters
22
-
23
- $rules = array(
24
- 'username' => 'required|alpha_numeric|max_len,100|min_len,40',
25
- 'password' => 'required|max_len,100|min_len,6',
26
- 'email' => 'required|valid_email',
27
- 'gender' => 'required|exact_len,1',
28
- 'credit_card' => 'required|valid_cc',
29
- 'bio' => 'required'
30
- );
31
-
32
- $filters = array(
33
- 'username' => 'trim|sanitize_string',
34
- 'password' => 'trim|base64_encode',
35
- 'email' => 'trim|sanitize_email',
36
- 'gender' => 'trim'
37
- );
38
-
39
- $_POST = $validator->filter($_POST, $filters);
40
-
41
- // You can run filter() or validate() first
42
-
43
- $validated = $validator->validate(
44
- $_POST, $rules
45
- );
46
-
47
- if($validated === TRUE)
48
- {
49
- echo "Successful Validation\n\n";
50
-
51
- print_r($_POST); // You can now use POST data safely
52
-
53
- exit;
54
- }
55
- else
56
- {
57
- // You should know what form fields to expect, so you can reference them here for custom messages
58
- echo "There were errors with the data you provided:\n";
59
-
60
- foreach($validated as $v) {
61
- switch($v['field']) {
62
- case 'credit_card':
63
- echo "- The credit card provided is not valid.\n";
64
- break;
65
- case 'username':
66
- echo "- The username provided is not valid.\n";
67
- break;
68
- }
69
- }
70
-
71
- // Or you can simply use the built in helper to generate the error messages for you
72
- // Passing a boolean true to is returns the errors as html, otherwise it returns an array
73
- echo $validator->get_readable_errors(true);
74
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/match.php DELETED
@@ -1,22 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- require "../gump.class.php";
5
-
6
- $data = array(
7
- 'username' => "myusername",
8
- 'password' => "mypassword",
9
- 'password_confirm' => "mypa33word",
10
- );
11
-
12
- $is_valid = GUMP::is_valid($data, array(
13
- 'username' => 'required|alpha_numeric',
14
- 'password' => 'required|max_len,100|min_len,6',
15
- 'password_confirm' => 'equalsfield,password',
16
- ));
17
-
18
- if($is_valid === true) {
19
- // continue
20
- } else {
21
- print_r($is_valid);
22
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/noise_words.php DELETED
@@ -1,18 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- require "../gump.class.php";
5
-
6
- $validator = new GUMP();
7
-
8
- // What are noise words? http://support.dtsearch.com/webhelp/dtsearch/noise_words.htm
9
-
10
- $_POST = array(
11
- 'words' => "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English"
12
- );
13
-
14
- $filters = array(
15
- 'words' => 'noise_words'
16
- );
17
-
18
- print_r($validator->filter($_POST, $filters));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/sanitize_string.php DELETED
@@ -1,16 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- require "../gump.class.php";
5
-
6
- $validator = new GUMP();
7
-
8
- $_POST = array(
9
- 'string' => '<script>alert(1); $("body").remove(); </script>'
10
- );
11
-
12
- $filters = array(
13
- 'string' => 'sanitize_string'
14
- );
15
-
16
- print_r($validator->filter($_POST, $filters));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/sanitize_whitelist.php DELETED
@@ -1,45 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- require "../gump.class.php";
5
-
6
- $validator = new GUMP();
7
-
8
- $_POST = array(
9
- 'first_name' => 'Joe',
10
- 'last_name' => 'Black',
11
- 'nickname' => 'blackjoe', // unexpected field
12
- );
13
-
14
- $rules = array(
15
- 'first_name' => 'required|valid_name',
16
- 'last_name' => 'required|valid_name'
17
- );
18
-
19
-
20
- /**
21
- * You can "whitelist" the submitted fileds: other fields will be ignored.
22
- * Pass an array of fields as 2nd argument in 'sanitize' method, e.g.:
23
- * $whitelist = array( 'first_name', 'last_name' );
24
- *
25
- * Tip: you can use the keys of rule/filter array as a whitelist
26
- */
27
- $whitelist = array_keys($rules);
28
- $_POST = $validator->sanitize( $_POST, $whitelist );
29
-
30
- $validated = $validator->validate($_POST, $rules);
31
-
32
- if( $validated === TRUE )
33
- {
34
- /**
35
- * Now you are sure that the $_POST array contains only the fields
36
- * included in whitelist.
37
- *
38
- * It's a good practice anyway, but it's very useful if you are
39
- * using an ORM/active-records library to store data into database
40
- * and you have to be sure that the fields match the table columns.
41
- *
42
- * E.g.: ... $db->table('products')->insert($_POST) ...
43
- */
44
- print_r($_POST);
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/street_address.php DELETED
@@ -1,22 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- error_reporting(-1);
5
-
6
- ini_set('display_errors', 1);
7
-
8
- require "../gump.class.php";
9
-
10
- $data = array(
11
- 'street' => '6 Avondans Road'
12
- );
13
-
14
- $validated = GUMP::is_valid($data, array(
15
- 'street' => 'required|street_address'
16
- ));
17
-
18
- if($validated === true) {
19
- echo "Valid Street Address\n";
20
- } else {
21
- print_r($validated);
22
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/url_exists.php DELETED
@@ -1,26 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- error_reporting(-1);
5
-
6
- ini_set('display_errors', 1);
7
-
8
- require "../gump.class.php";
9
-
10
- $validator = new GUMP();
11
-
12
- $_POST = array(
13
- 'url' => 'http://sudygausdjhasgdjasjhdasd987lkasjhdkasdkjs.com/' // This url obviously does not exist
14
- );
15
-
16
- $rules = array(
17
- 'url' => 'url_exists'
18
- );
19
-
20
- $is_valid = $validator->validate($_POST, $rules);
21
-
22
- if($is_valid === true) {
23
- echo "The URL provided is valid";
24
- } else {
25
- print_r($validator->get_readable_errors());
26
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/examples/utf-8.php DELETED
@@ -1,24 +0,0 @@
1
- #!/usr/bin/php -q
2
- <?php
3
-
4
- error_reporting(-1);
5
-
6
- ini_set('display_errors', 1);
7
-
8
- require "../gump.class.php";
9
-
10
- $data = array(
11
- 'one' => 'Freiheit, Mobilität und Unabhängigkeit lebt. ö, Ä, é, or ß',
12
- 'two' => 'ß'
13
- );
14
-
15
- $validated = GUMP::is_valid($data, array(
16
- 'one' => 'required|min_len,10',
17
- 'two' => 'required|min_len,1',
18
- ));
19
-
20
- if($validated === true) {
21
- echo "Valid Text\n";
22
- } else {
23
- print_r($validated);
24
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/hammer/vendor/wixel/gump/gump.class.php CHANGED
@@ -10,6 +10,7 @@
10
  *
11
  * @version 1.4
12
  */
 
13
  class GUMP
14
  {
15
  //Singleton instance of GUMP
@@ -2129,3 +2130,4 @@ class GUMP
2129
  }
2130
  }
2131
  } // EOC
 
10
  *
11
  * @version 1.4
12
  */
13
+ if (!class_exists('GUMP')) {
14
  class GUMP
15
  {
16
  //Singleton instance of GUMP
2130
  }
2131
  }
2132
  } // EOC
2133
+ }
vendor/hammer/wp/model.php CHANGED
@@ -118,6 +118,37 @@ abstract class Model extends \Hammer\Base\Model {
118
  $this->trigger( self::EVENT_AFTER_DELETE );
119
  }
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  /**
122
  *
123
  * @param $id
@@ -208,14 +239,6 @@ abstract class Model extends \Hammer\Base\Model {
208
  return $results;
209
  }
210
 
211
- private function cacheQuery() {
212
-
213
- }
214
-
215
- private function flushCacheQuery() {
216
-
217
- }
218
-
219
  /**
220
  * @param array $attributes
221
  *
@@ -330,6 +353,8 @@ abstract class Model extends \Hammer\Base\Model {
330
  $i ++;
331
  }
332
 
 
 
333
  return $where;
334
  }
335
 
@@ -342,10 +367,13 @@ abstract class Model extends \Hammer\Base\Model {
342
  if ( isset( $value['compare'] ) ) {
343
  $sql = 't' . $pos . '.' . $field . ' ' . $value['compare'] . ' %s';
344
  $sql = $wpdb->prepare( $sql, $value['value'] );
345
- } else {
346
  $sql = 't' . $pos . "." . $field . " IN (" . implode( ', ', array_fill( 0, count( $value ), '%s' ) ) . ")";
347
 
348
  $sql = call_user_func_array( array( $wpdb, 'prepare' ), array_merge( array( $sql ), $value ) );
 
 
 
349
  }
350
 
351
  return $sql;
118
  $this->trigger( self::EVENT_AFTER_DELETE );
119
  }
120
 
121
+ /**
122
+ * @param array $attributes
123
+ * @param null $orderBy
124
+ * @param null $order
125
+ * @param null $limit
126
+ */
127
+ public static function deleteAll( $attributes = array(), $orderBy = null, $order = null, $limit = null ) {
128
+ if ( ! empty( $attributes ) ) {
129
+ $join = static::buildJoins();
130
+ } else {
131
+ $join = array();
132
+ }
133
+ $where = static::buildWhere( $attributes );
134
+ $sql = "SELECT ID FROM " . self::getWPDB()->posts . ' AS t0 ' . implode( ' ', $join ) . ' ' . implode( ' AND ', $where );
135
+ if ( ! empty( $orderBy ) && static::buildOrderBy( $orderBy ) != false ) {
136
+ $sql = $sql . ' ORDER BY ' . static::buildOrderBy( $orderBy );
137
+ if ( ! empty( $order ) && in_array( strtolower( $order ), array( 'desc', 'asc' ) ) ) {
138
+ $sql = $sql . ' ' . $order;
139
+ }
140
+ }
141
+ if ( ! empty( $limit ) ) {
142
+ $sql .= ' LIMIT ' . $limit;
143
+ }
144
+
145
+ $ids = self::getWPDB()->get_col( $sql );
146
+
147
+ foreach ( $ids as $id ) {
148
+ wp_delete_post( $id );
149
+ }
150
+ }
151
+
152
  /**
153
  *
154
  * @param $id
239
  return $results;
240
  }
241
 
 
 
 
 
 
 
 
 
242
  /**
243
  * @param array $attributes
244
  *
353
  $i ++;
354
  }
355
 
356
+ $where = array_filter( $where );
357
+
358
  return $where;
359
  }
360
 
367
  if ( isset( $value['compare'] ) ) {
368
  $sql = 't' . $pos . '.' . $field . ' ' . $value['compare'] . ' %s';
369
  $sql = $wpdb->prepare( $sql, $value['value'] );
370
+ } elseif ( ! empty( $value ) ) {
371
  $sql = 't' . $pos . "." . $field . " IN (" . implode( ', ', array_fill( 0, count( $value ), '%s' ) ) . ")";
372
 
373
  $sql = call_user_func_array( array( $wpdb, 'prepare' ), array_merge( array( $sql ), $value ) );
374
+ } else {
375
+ //this case the in array is empty,
376
+ $sql = "";
377
  }
378
 
379
  return $sql;
vendor/hammer/wp/settings.php CHANGED
@@ -17,7 +17,7 @@ use Hammer\Helper\Log_Helper;
17
  class Settings extends Model {
18
  private static $_instance;
19
 
20
- const EVENT_BEFORE_SAVE = 'beforeSave', EVENT_AFTER_SAVE = 'afterSave';
21
  /**
22
  * Required, this will be the option name for storing
23
  * @var string
@@ -59,7 +59,9 @@ class Settings extends Model {
59
  }
60
 
61
  public function delete() {
 
62
  $ret = delete_option( $this->id );
63
  $ret = delete_site_option( $this->id );
 
64
  }
65
  }
17
  class Settings extends Model {
18
  private static $_instance;
19
 
20
+ const EVENT_BEFORE_SAVE = 'beforeSave', EVENT_AFTER_SAVE = 'afterSave', EVENT_BEFORE_DELETE = 'beforeDelete', EVENT_AFTER_DELETED = 'afterDeleted';
21
  /**
22
  * Required, this will be the option name for storing
23
  * @var string
59
  }
60
 
61
  public function delete() {
62
+ $this->trigger( self::EVENT_BEFORE_DELETE );
63
  $ret = delete_option( $this->id );
64
  $ret = delete_site_option( $this->id );
65
+ $this->trigger( self::EVENT_AFTER_DELETED );
66
  }
67
  }
wp-defender.php CHANGED
@@ -1,9 +1,8 @@
1
  <?php
2
-
3
  /**
4
  * Plugin Name: WP Defender
5
  * Plugin URI: https://premium.wpmudev.org/project/wp-defender/
6
- * Version: 1.6.2
7
  * Description: Get regular security scans, vulnerability reports, safety recommendations and customized hardening for your site in just a few clicks. Defender is the analyst and enforcer who never sleeps.
8
  * Author: WPMU DEV
9
  * Author URI: http://premium.wpmudev.org/
1
  <?php
 
2
  /**
3
  * Plugin Name: WP Defender
4
  * Plugin URI: https://premium.wpmudev.org/project/wp-defender/
5
+ * Version: 1.7
6
  * Description: Get regular security scans, vulnerability reports, safety recommendations and customized hardening for your site in just a few clicks. Defender is the analyst and enforcer who never sleeps.
7
  * Author: WPMU DEV
8
  * Author URI: http://premium.wpmudev.org/