Login Security Solution - Version 0.21.0

Version Description

  • Fix is_pw_outside_ascii() to permit spaces.
  • In multisite mode, send notifications to network admin, not blog admin.
  • Add "Notifiations To" setting for admins to specify the email addresses the failure and breach notifications get sent to. (Request #1560)
  • Clarify that the Change All Passwords link just goes to the UI.
  • Get all unit tests to pass when mbstring isn't enabled.
  • Internationalize the unit tests.
  • Rename admin.inc to admin.php.
  • Rename temporary files holding actual test results. (Bug #1552 redux)
  • Unit tests pass using PHP 5.4.5-dev, 5.3.16-dev, and 5.2.18-dev.
  • Tested under WordPress 3.4.1 using regular and multisite.
  • Also tested on Windows 7 using PHP 5.4.5 and WordPress 3.4.1.
Download this release

Release Info

Developer convissor
Plugin Icon wp plugin Login Security Solution
Version 0.21.0
Comparing to
See all releases

Code changes from version 0.20.2 to 0.21.0

admin.inc → admin.php RENAMED
@@ -123,7 +123,7 @@ class login_security_solution_admin extends login_security_solution {
123
 
124
  // NON-STANDARD: This is for the password change page.
125
  $this->option_pw_force_change_name = self::ID . '-pw-force-change-done';
126
- $this->text_pw_force_change = __('Change All Passwords', self::ID);
127
  $this->text_button_remind = __("Do not remind me about this", self::ID);
128
  $this->text_button_require = __("Require All Passwords Be Changed", self::ID);
129
  }
@@ -286,6 +286,12 @@ class login_security_solution_admin extends login_security_solution {
286
  'text' => sprintf(__("How many matching login failures should it take to get into this (%d - %d second) Delay Tier? Must be > Delay Tier 2.", self::ID), 25, 60),
287
  'type' => 'int',
288
  ),
 
 
 
 
 
 
289
  'login_fail_notify' => array(
290
  'group' => 'login',
291
  'label' => __("Failure Notification", self::ID),
@@ -480,7 +486,7 @@ class login_security_solution_admin extends login_security_solution {
480
  *
481
  * @uses login_security_solution_admin::input_radio() for rendering
482
  * radio buttons
483
- * @uses login_security_solution_admin::input_text() for rendering
484
  * text input boxes
485
  */
486
  public function __call($name, $params) {
@@ -492,7 +498,10 @@ class login_security_solution_admin extends login_security_solution {
492
  $this->input_radio($name);
493
  break;
494
  case 'int':
495
- $this->input_text($name);
 
 
 
496
  break;
497
  }
498
  }
@@ -517,10 +526,10 @@ class login_security_solution_admin extends login_security_solution {
517
  }
518
 
519
  /**
520
- * Renders the text input boxes
521
  * @return void
522
  */
523
- protected function input_text($name) {
524
  echo '<input type="text" size="3" name="'
525
  . $this->hsc_utf8($this->option_name)
526
  . '[' . $this->hsc_utf8($name) . ']"'
@@ -530,6 +539,21 @@ class login_security_solution_admin extends login_security_solution {
530
  . $this->options_default[$name] . '.');
531
  }
532
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
533
  /**
534
  * Validates the user input
535
  *
@@ -856,15 +880,20 @@ class login_security_solution_admin extends login_security_solution {
856
  echo '</strong></p>';
857
 
858
  echo '<p><strong>';
859
- echo $this->hsc_utf8(__("Speaking of which, do YOU have a strong password? Make sure by changing yours once you've submitted the Change All Passwords form.", self::ID));
 
 
 
 
860
  echo '</strong></p>';
861
 
862
- echo '<p><strong><a href="' . $this->hsc_utf8($this->page_options)
 
863
  . '?page=' . $this->hsc_utf8($this->option_pw_force_change_name)
864
- . '">' . $this->hsc_utf8($this->text_pw_force_change)
865
- . "</a></strong></p>\n";
866
 
867
- echo "</div>\n";
868
  }
869
 
870
  /**
123
 
124
  // NON-STANDARD: This is for the password change page.
125
  $this->option_pw_force_change_name = self::ID . '-pw-force-change-done';
126
+ $this->text_pw_force_change = __("Change All Passwords", self::ID);
127
  $this->text_button_remind = __("Do not remind me about this", self::ID);
128
  $this->text_button_require = __("Require All Passwords Be Changed", self::ID);
129
  }
286
  'text' => sprintf(__("How many matching login failures should it take to get into this (%d - %d second) Delay Tier? Must be > Delay Tier 2.", self::ID), 25, 60),
287
  'type' => 'int',
288
  ),
289
+ 'admin_email' => array(
290
+ 'group' => 'login',
291
+ 'label' => __("Notifications To", self::ID),
292
+ 'text' => __("The email address(es) the failure and breach notifications should be sent to. For multiple addresses, separate them with commas. WordPress' 'admin_email' setting is used if none is provided here.", self::ID),
293
+ 'type' => 'string',
294
+ ),
295
  'login_fail_notify' => array(
296
  'group' => 'login',
297
  'label' => __("Failure Notification", self::ID),
486
  *
487
  * @uses login_security_solution_admin::input_radio() for rendering
488
  * radio buttons
489
+ * @uses login_security_solution_admin::input_int() for rendering
490
  * text input boxes
491
  */
492
  public function __call($name, $params) {
498
  $this->input_radio($name);
499
  break;
500
  case 'int':
501
+ $this->input_int($name);
502
+ break;
503
+ case 'string':
504
+ $this->input_string($name);
505
  break;
506
  }
507
  }
526
  }
527
 
528
  /**
529
+ * Renders the text input boxes for editing integers
530
  * @return void
531
  */
532
+ protected function input_int($name) {
533
  echo '<input type="text" size="3" name="'
534
  . $this->hsc_utf8($this->option_name)
535
  . '[' . $this->hsc_utf8($name) . ']"'
539
  . $this->options_default[$name] . '.');
540
  }
541
 
542
+ /**
543
+ * Renders the text input boxes for editing strings
544
+ * @return void
545
+ */
546
+ protected function input_string($name) {
547
+ echo '<input type="text" size="75" name="'
548
+ . $this->hsc_utf8($this->option_name)
549
+ . '[' . $this->hsc_utf8($name) . ']"'
550
+ . ' value="' . $this->hsc_utf8($this->options[$name]) . '" /> ';
551
+ echo '<br />';
552
+ echo $this->hsc_utf8($this->fields[$name]['text']
553
+ . ' ' . __('Default:', self::ID) . ' '
554
+ . $this->options_default[$name] . '.');
555
+ }
556
+
557
  /**
558
  * Validates the user input
559
  *
880
  echo '</strong></p>';
881
 
882
  echo '<p><strong>';
883
+ echo $this->hsc_utf8(__("Speaking of which, do YOU have a strong password? Make sure by changing yours too.", self::ID));
884
+ echo '</strong></p>';
885
+
886
+ echo '<p><strong>';
887
+ echo $this->hsc_utf8(__("The following link leads to a user interface where you can either require all passwords to be reset or disable this notice.", self::ID));
888
  echo '</strong></p>';
889
 
890
+ echo '<p><strong>';
891
+ echo '<a href="' . $this->hsc_utf8($this->page_options)
892
  . '?page=' . $this->hsc_utf8($this->option_pw_force_change_name)
893
+ . '">' . $this->hsc_utf8($this->text_pw_force_change) . '</a>';
894
+ echo '</strong></p>';
895
 
896
+ echo "\n</div>\n";
897
  }
898
 
899
  /**
languages/login-security-solution.pot CHANGED
@@ -2,9 +2,9 @@
2
  # This file is distributed under the same license as the Login Security Solution package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Login Security Solution 0.20.1\n"
6
- "Report-Msgid-Bugs-To: http://wordpress.org/tag/login-security-solution\n"
7
- "POT-Creation-Date: 2012-07-12 13:02:17+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
@@ -12,108 +12,432 @@ msgstr ""
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
14
 
15
- #: login-security-solution.php:499
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  msgid "Invalid username or password."
17
  msgstr ""
18
 
19
- #: login-security-solution.php:505 tests/LoginErrorsTest.php:117
20
- #: tests/LoginErrorsTest.php:129
21
  msgid "Password reset is not allowed for this user"
22
  msgstr ""
23
 
24
- #: login-security-solution.php:530 tests/LoginMessageTest.php:66
25
  msgid "It has been over %d minutes since your last action."
26
  msgstr ""
27
 
28
- #: login-security-solution.php:531 tests/LoginMessageTest.php:67
29
  msgid "Please log back in."
30
  msgstr ""
31
 
32
- #: login-security-solution.php:534 tests/LoginMessageTest.php:77
33
  msgid "The grace period for changing your password has expired."
34
  msgstr ""
35
 
36
- #: login-security-solution.php:535 tests/LoginMessageTest.php:78
37
  msgid "Please submit this form to reset your password."
38
  msgstr ""
39
 
40
- #: login-security-solution.php:538 tests/LoginMessageTest.php:88
41
  msgid "Your password must be reset."
42
  msgstr ""
43
 
44
- #: login-security-solution.php:539 tests/LoginMessageTest.php:89
45
  msgid "Please submit this form to reset it."
46
  msgstr ""
47
 
48
- #: login-security-solution.php:542 tests/LoginMessageTest.php:104
49
  msgid "Your password has expired. Please log and change it."
50
  msgstr ""
51
 
52
- #: login-security-solution.php:543 tests/LoginMessageTest.php:105
53
  msgid "We provide a %d minute grace period to do so."
54
  msgstr ""
55
 
56
- #: login-security-solution.php:546 tests/LoginMessageTest.php:115
57
  msgid "The password you tried to create is not secure. Please try again."
58
  msgstr ""
59
 
60
- #: login-security-solution.php:552 tests/LoginMessageTest.php:129
61
  #: tests/LoginMessageTest.php:144
62
  msgid "The site is undergoing maintenance."
63
  msgstr ""
64
 
65
- #: login-security-solution.php:553 tests/LoginMessageTest.php:130
66
  #: tests/LoginMessageTest.php:145
67
  msgid "Please try again later."
68
  msgstr ""
69
 
70
- #: login-security-solution.php:624
71
  msgid ""
72
  "The password should either be: A) at least %d characters long and contain "
73
  "upper and lower case letters plus numbers and punctuation, or B) at least %d "
74
  "characters long."
75
  msgstr ""
76
 
77
- #: login-security-solution.php:658
78
  msgid "Passwords can not be reused."
79
  msgstr ""
80
 
81
- #: login-security-solution.php:833
82
  msgid "ERROR"
83
  msgstr ""
84
 
85
- #: login-security-solution.php:958
86
- msgid "Component Count Value from Current Attempt"
87
- msgstr ""
88
-
89
- #: login-security-solution.php:960
90
- msgid "Network IP %5d %s"
91
- msgstr ""
92
-
93
- #: login-security-solution.php:962
94
- msgid "Username %5d %s"
95
- msgstr ""
96
-
97
- #: login-security-solution.php:964
98
- msgid "Password MD5 %5d %s"
99
  msgstr ""
100
 
101
- #: login-security-solution.php:1761 login-security-solution.php:1798
102
  msgid "POTENTIAL INTRUSION AT %s"
103
  msgstr ""
104
 
105
- #: login-security-solution.php:1765
106
  msgid "Your website, %s, may have been broken in to."
107
  msgstr ""
108
 
109
- #: login-security-solution.php:1768
110
  msgid ""
111
  "Someone just logged in using the following components. Prior to that, some "
112
  "combination of those components were a part of %d failed attempts to log in "
113
  "during the past %d minutes:"
114
  msgstr ""
115
 
116
- #: login-security-solution.php:1774
117
  msgid ""
118
  "The user's current IP address is one they have verified with your site in "
119
  "the past. Therefore, the user will NOT be required to confirm their "
@@ -121,103 +445,105 @@ msgid ""
121
  "just in case this actually was a breach."
122
  msgstr ""
123
 
124
- #: login-security-solution.php:1776
125
  msgid ""
126
  "The user has been logged out and will be required to confirm their identity "
127
  "via the password reset functionality."
128
  msgstr ""
129
 
130
- #: login-security-solution.php:1802
131
  msgid ""
132
  "Someone just logged into your '%s' account at %s. Was it you that logged "
133
  "in? We are asking because the site is being attacked."
134
  msgstr ""
135
 
136
- #: login-security-solution.php:1803
137
  msgid "IF IT WAS NOT YOU, please do the following right away:"
138
  msgstr ""
139
 
140
- #: login-security-solution.php:1804
141
  msgid "1) Log into %s and change your password."
142
  msgstr ""
143
 
144
- #: login-security-solution.php:1805
145
  msgid "2) Send an email to %s letting them know it was not you who logged in."
146
  msgstr ""
147
 
148
- #: login-security-solution.php:1831
149
  msgid "ATTACK HAPPENING TO %s"
150
  msgstr ""
151
 
152
- #: login-security-solution.php:1835
153
  msgid "Your website, %s, is undergoing a brute force attack."
154
  msgstr ""
155
 
156
- #: login-security-solution.php:1838
157
  msgid ""
158
  "There have been at least %d failed attempts to log in during the past %d "
159
  "minutes that used one or more of the following components:"
160
  msgstr ""
161
 
162
- #: login-security-solution.php:1843
163
  msgid ""
164
  "The %s plugin for WordPress is repelling the attack by making their login "
165
  "failures take a very long time."
166
  msgstr ""
167
 
168
- #: login-security-solution.php:2194
169
  msgid "Password not set."
170
  msgstr ""
171
 
172
- #: login-security-solution.php:2209
173
  msgid "Passwords must be strings."
174
  msgstr ""
175
 
176
- #: login-security-solution.php:2227
177
  msgid "Passwords must use ASCII characters."
178
  msgstr ""
179
 
180
- #: login-security-solution.php:2246
 
181
  msgid "Password is too short."
182
  msgstr ""
183
 
184
- #: login-security-solution.php:2255
185
  msgid "Passwords must either contain numbers or be %d characters long."
186
  msgstr ""
187
 
188
- #: login-security-solution.php:2264
189
  msgid ""
190
  "Passwords must either contain punctuation marks / symbols or be %d "
191
  "characters long."
192
  msgstr ""
193
 
194
- #: login-security-solution.php:2273
195
  msgid ""
196
  "Passwords must either contain upper-case and lower-case letters or be %d "
197
  "characters long."
198
  msgstr ""
199
 
200
- #: login-security-solution.php:2283
201
  msgid "Passwords can't be sequential keys."
202
  msgstr ""
203
 
204
- #: login-security-solution.php:2292
205
  msgid "Passwords can't have that many sequential characters."
206
  msgstr ""
207
 
208
- #: login-security-solution.php:2308
 
209
  msgid "Passwords can't contain user data."
210
  msgstr ""
211
 
212
- #: login-security-solution.php:2319
213
  msgid "Passwords can't contain site info."
214
  msgstr ""
215
 
216
- #: login-security-solution.php:2328
217
  msgid "Password is too common."
218
  msgstr ""
219
 
220
- #: login-security-solution.php:2337
221
  msgid "Passwords can't be variations of dictionary words."
222
  msgstr ""
223
 
2
  # This file is distributed under the same license as the Login Security Solution package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Login Security Solution 0.21.0\n"
6
+ "Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/login-security-solution\n"
7
+ "POT-Creation-Date: 2012-08-07 15:10:37+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
14
 
15
+ #: admin.php:112 admin.php:362
16
+ msgid "Settings"
17
+ msgstr ""
18
+
19
+ #: admin.php:126
20
+ msgid "Change All Passwords"
21
+ msgstr ""
22
+
23
+ #: admin.php:127
24
+ msgid "Do not remind me about this"
25
+ msgstr ""
26
+
27
+ #: admin.php:128
28
+ msgid "Require All Passwords Be Changed"
29
+ msgstr ""
30
+
31
+ #: admin.php:143
32
+ msgid ""
33
+ "%s must be activated via the Network Admin interface when WordPress is in "
34
+ "multistie network mode."
35
+ msgstr ""
36
+
37
+ #: admin.php:249
38
+ msgid "Idle Timeout"
39
+ msgstr ""
40
+
41
+ #: admin.php:250
42
+ msgid ""
43
+ "Close inactive sessions after this many minutes. 0 disables this feature."
44
+ msgstr ""
45
+
46
+ #: admin.php:255
47
+ msgid "Maintenance Mode"
48
+ msgstr ""
49
+
50
+ #: admin.php:256
51
+ msgid ""
52
+ "Disable logins from users who are not administrators and disable posting of "
53
+ "comments?"
54
+ msgstr ""
55
+
56
+ #: admin.php:258
57
+ msgid "Off, let all users log in."
58
+ msgstr ""
59
+
60
+ #: admin.php:259
61
+ msgid "On, disable comments and only let administrators log in."
62
+ msgstr ""
63
+
64
+ #: admin.php:263
65
+ msgid "Deactivation"
66
+ msgstr ""
67
+
68
+ #: admin.php:264
69
+ msgid ""
70
+ "Should deactivating the plugin remove all of the plugin's data and settings?"
71
+ msgstr ""
72
+
73
+ #: admin.php:266
74
+ msgid "No, preserve the data for future use."
75
+ msgstr ""
76
+
77
+ #: admin.php:267
78
+ msgid "Yes, delete the damn data."
79
+ msgstr ""
80
+
81
+ #: admin.php:272
82
+ msgid "Match Time"
83
+ msgstr ""
84
+
85
+ #: admin.php:273
86
+ msgid "How far back, in minutes, should login failures look for matching data?"
87
+ msgstr ""
88
+
89
+ #: admin.php:278
90
+ msgid "Delay Tier 2"
91
+ msgstr ""
92
+
93
+ #: admin.php:279
94
+ msgid ""
95
+ "How many matching login failures should it take to get into this (%d - %d "
96
+ "second) Delay Tier? Must be >= %d."
97
+ msgstr ""
98
+
99
+ #: admin.php:285
100
+ msgid "Delay Tier 3"
101
+ msgstr ""
102
+
103
+ #: admin.php:286
104
+ msgid ""
105
+ "How many matching login failures should it take to get into this (%d - %d "
106
+ "second) Delay Tier? Must be > Delay Tier 2."
107
+ msgstr ""
108
+
109
+ #: admin.php:291
110
+ msgid "Notifications To"
111
+ msgstr ""
112
+
113
+ #: admin.php:292
114
+ msgid ""
115
+ "The email address(es) the failure and breach notifications should be sent "
116
+ "to. For multiple addresses, separate them with commas. WordPress' "
117
+ "'admin_email' setting is used if none is provided here."
118
+ msgstr ""
119
+
120
+ #: admin.php:297
121
+ msgid "Failure Notification"
122
+ msgstr ""
123
+
124
+ #: admin.php:298
125
+ msgid ""
126
+ "Notify the administrator upon every x matching login failures. 0 disables "
127
+ "this feature."
128
+ msgstr ""
129
+
130
+ #: admin.php:303
131
+ msgid "Breach Notification"
132
+ msgstr ""
133
+
134
+ #: admin.php:304
135
+ msgid ""
136
+ "Notify the administrator if a successful login uses data matching x login "
137
+ "failures. 0 disables this feature."
138
+ msgstr ""
139
+
140
+ #: admin.php:309
141
+ msgid "Breach Email Confirm"
142
+ msgstr ""
143
+
144
+ #: admin.php:310
145
+ msgid ""
146
+ "If a successful login uses data matching x login failures, immediately log "
147
+ "the user out and require them to use WordPress' lost password process. 0 "
148
+ "disables this feature."
149
+ msgstr ""
150
+
151
+ #: admin.php:316
152
+ msgid "Length"
153
+ msgstr ""
154
+
155
+ #: admin.php:317
156
+ msgid "How long must passwords be? Must be >= %d."
157
+ msgstr ""
158
+
159
+ #: admin.php:323
160
+ msgid "Complexity Exemption"
161
+ msgstr ""
162
+
163
+ #: admin.php:324
164
+ msgid ""
165
+ "How long must passwords be to be exempt from the complexity requirements? "
166
+ "Must be >= %d."
167
+ msgstr ""
168
+
169
+ #: admin.php:330
170
+ msgid "Aging"
171
+ msgstr ""
172
+
173
+ #: admin.php:331
174
+ msgid ""
175
+ "How many days old can a password be before requiring it be changed? Not "
176
+ "recommended. 0 disables this feature."
177
+ msgstr ""
178
+
179
+ #: admin.php:336
180
+ msgid "Grace Period"
181
+ msgstr ""
182
+
183
+ #: admin.php:337
184
+ msgid ""
185
+ "How many minutes should a user have to change their password once they know "
186
+ "it has expired? Must be >= %d."
187
+ msgstr ""
188
+
189
+ #: admin.php:343
190
+ msgid "History"
191
+ msgstr ""
192
+
193
+ #: admin.php:344
194
+ msgid ""
195
+ "How many passwords should be remembered? Prevents reuse of old passwords. 0 "
196
+ "disables this feature."
197
+ msgstr ""
198
+
199
+ #: admin.php:405
200
+ msgid "Login Failure Policies"
201
+ msgstr ""
202
+
203
+ #: admin.php:411
204
+ msgid "Password Policies"
205
+ msgstr ""
206
+
207
+ #: admin.php:417
208
+ msgid "Miscellaneous Policies"
209
+ msgstr ""
210
+
211
+ #: admin.php:467
212
+ msgid ""
213
+ "This plugin stores the IP address, username and password for each failed log "
214
+ "in attempt."
215
+ msgstr ""
216
+
217
+ #: admin.php:469
218
+ msgid ""
219
+ "The data from future login failures are compared against the historical data."
220
+ msgstr ""
221
+
222
+ #: admin.php:471
223
+ msgid ""
224
+ "If any of the data points match, the plugin delays printing out the failure "
225
+ "message."
226
+ msgstr ""
227
+
228
+ #: admin.php:473
229
+ msgid ""
230
+ "The goal is for the responses to take so long that the attackers give up and "
231
+ "go find an easier target."
232
+ msgstr ""
233
+
234
+ #: admin.php:475
235
+ msgid "The length of the delay is broken up into three tiers."
236
+ msgstr ""
237
+
238
+ #: admin.php:477
239
+ msgid "The amount of the delay increases in higher tiers."
240
+ msgstr ""
241
+
242
+ #: admin.php:479
243
+ msgid ""
244
+ "The delay time within each tier is randomized to complicate profiling by "
245
+ "attackers."
246
+ msgstr ""
247
+
248
+ #: admin.php:538 admin.php:553
249
+ msgid "Default:"
250
+ msgstr ""
251
+
252
+ #: admin.php:577
253
+ msgid "must be >= '%s',"
254
+ msgstr ""
255
+
256
+ #: admin.php:578
257
+ msgid "so we used the default value instead."
258
+ msgstr ""
259
+
260
+ #: admin.php:611
261
+ msgid "must be an integer,"
262
+ msgstr ""
263
+
264
+ #: admin.php:714
265
+ msgid "There may be cases where everyone's password should be reset."
266
+ msgstr ""
267
+
268
+ #: admin.php:716
269
+ msgid "This page, provided by the %s plugin, offers that functionality."
270
+ msgstr ""
271
+
272
+ #: admin.php:720
273
+ msgid ""
274
+ "Submitting this form sets a flag that forces all users to utilize WordPress' "
275
+ "built in password reset functionality."
276
+ msgstr ""
277
+
278
+ #: admin.php:722
279
+ msgid ""
280
+ "Users who are presently logged in will be logged out the next time they view "
281
+ "a page that requires authentication."
282
+ msgstr ""
283
+
284
+ #: admin.php:734
285
+ msgid ""
286
+ "Confirm that you want to force all users to change their passwords by "
287
+ "checking this box, then click the button, below."
288
+ msgstr ""
289
+
290
+ #: admin.php:753
291
+ msgid "No thanks. I know what I'm doing. Please don't remind me about this."
292
+ msgstr ""
293
+
294
+ #: admin.php:785
295
+ msgid ""
296
+ "You have checked a box that does not correspond with the button you pressed. "
297
+ "Please check and press buttons inside the same section."
298
+ msgstr ""
299
+
300
+ #: admin.php:787
301
+ msgid ""
302
+ "Please confirm that you really want to do this. Put a check in the '%s' box "
303
+ "before hitting the submit button."
304
+ msgstr ""
305
+
306
+ #: admin.php:803 admin.php:823
307
+ msgid "Success!"
308
+ msgstr ""
309
+
310
+ #: admin.php:855
311
+ msgid ""
312
+ "WARNING: The site is in maintenance mode. DO NOT TOUCH ANYTHING! Your "
313
+ "changes may get overwritten!"
314
+ msgstr ""
315
+
316
+ #: admin.php:879
317
+ msgid ""
318
+ "You have not asked your users to change their passwords since the plugin was "
319
+ "activated. Most users have weak passwords. This plugin's password policies "
320
+ "protect your site from brute force attacks. Please improve security for "
321
+ "everyone on the Internet by making all users pick new, strong, passwords."
322
+ msgstr ""
323
+
324
+ #: admin.php:883
325
+ msgid ""
326
+ "Speaking of which, do YOU have a strong password? Make sure by changing "
327
+ "yours too."
328
+ msgstr ""
329
+
330
+ #: admin.php:887
331
+ msgid ""
332
+ "The following link leads to a user interface where you can either require "
333
+ "all passwords to be reset or disable this notice."
334
+ msgstr ""
335
+
336
+ #: admin.php:917
337
+ msgid "You do not have sufficient permissions to access this page."
338
+ msgstr ""
339
+
340
+ #: admin.php:923
341
+ msgid "$user_ID variable not set. Another plugin is misbehaving."
342
+ msgstr ""
343
+
344
+ #: login-security-solution.php:500 tests/LoginErrorsTest.php:97
345
+ #: tests/LoginErrorsTest.php:111
346
  msgid "Invalid username or password."
347
  msgstr ""
348
 
349
+ #: login-security-solution.php:506 tests/LoginErrorsTest.php:125
350
+ #: tests/LoginErrorsTest.php:139
351
  msgid "Password reset is not allowed for this user"
352
  msgstr ""
353
 
354
+ #: login-security-solution.php:531 tests/LoginMessageTest.php:66
355
  msgid "It has been over %d minutes since your last action."
356
  msgstr ""
357
 
358
+ #: login-security-solution.php:532 tests/LoginMessageTest.php:67
359
  msgid "Please log back in."
360
  msgstr ""
361
 
362
+ #: login-security-solution.php:535 tests/LoginMessageTest.php:77
363
  msgid "The grace period for changing your password has expired."
364
  msgstr ""
365
 
366
+ #: login-security-solution.php:536 tests/LoginMessageTest.php:78
367
  msgid "Please submit this form to reset your password."
368
  msgstr ""
369
 
370
+ #: login-security-solution.php:539 tests/LoginMessageTest.php:88
371
  msgid "Your password must be reset."
372
  msgstr ""
373
 
374
+ #: login-security-solution.php:540 tests/LoginMessageTest.php:89
375
  msgid "Please submit this form to reset it."
376
  msgstr ""
377
 
378
+ #: login-security-solution.php:543 tests/LoginMessageTest.php:104
379
  msgid "Your password has expired. Please log and change it."
380
  msgstr ""
381
 
382
+ #: login-security-solution.php:544 tests/LoginMessageTest.php:105
383
  msgid "We provide a %d minute grace period to do so."
384
  msgstr ""
385
 
386
+ #: login-security-solution.php:547 tests/LoginMessageTest.php:115
387
  msgid "The password you tried to create is not secure. Please try again."
388
  msgstr ""
389
 
390
+ #: login-security-solution.php:553 tests/LoginMessageTest.php:129
391
  #: tests/LoginMessageTest.php:144
392
  msgid "The site is undergoing maintenance."
393
  msgstr ""
394
 
395
+ #: login-security-solution.php:554 tests/LoginMessageTest.php:130
396
  #: tests/LoginMessageTest.php:145
397
  msgid "Please try again later."
398
  msgstr ""
399
 
400
+ #: login-security-solution.php:625
401
  msgid ""
402
  "The password should either be: A) at least %d characters long and contain "
403
  "upper and lower case letters plus numbers and punctuation, or B) at least %d "
404
  "characters long."
405
  msgstr ""
406
 
407
+ #: login-security-solution.php:659 tests/PasswordChangeTest.php:277
408
  msgid "Passwords can not be reused."
409
  msgstr ""
410
 
411
+ #: login-security-solution.php:834
412
  msgid "ERROR"
413
  msgstr ""
414
 
415
+ #: login-security-solution.php:971
416
+ msgid ""
417
+ "\n"
418
+ "Component Count Value from Current Attempt\n"
419
+ "------------------------ ----- --------------------------------\n"
420
+ "Network IP %5d %s\n"
421
+ "Username %5d %s\n"
422
+ "Password MD5 %5d %s\n"
 
 
 
 
 
 
423
  msgstr ""
424
 
425
+ #: login-security-solution.php:1776 login-security-solution.php:1813
426
  msgid "POTENTIAL INTRUSION AT %s"
427
  msgstr ""
428
 
429
+ #: login-security-solution.php:1780
430
  msgid "Your website, %s, may have been broken in to."
431
  msgstr ""
432
 
433
+ #: login-security-solution.php:1783
434
  msgid ""
435
  "Someone just logged in using the following components. Prior to that, some "
436
  "combination of those components were a part of %d failed attempts to log in "
437
  "during the past %d minutes:"
438
  msgstr ""
439
 
440
+ #: login-security-solution.php:1789
441
  msgid ""
442
  "The user's current IP address is one they have verified with your site in "
443
  "the past. Therefore, the user will NOT be required to confirm their "
445
  "just in case this actually was a breach."
446
  msgstr ""
447
 
448
+ #: login-security-solution.php:1791
449
  msgid ""
450
  "The user has been logged out and will be required to confirm their identity "
451
  "via the password reset functionality."
452
  msgstr ""
453
 
454
+ #: login-security-solution.php:1817
455
  msgid ""
456
  "Someone just logged into your '%s' account at %s. Was it you that logged "
457
  "in? We are asking because the site is being attacked."
458
  msgstr ""
459
 
460
+ #: login-security-solution.php:1818
461
  msgid "IF IT WAS NOT YOU, please do the following right away:"
462
  msgstr ""
463
 
464
+ #: login-security-solution.php:1819
465
  msgid "1) Log into %s and change your password."
466
  msgstr ""
467
 
468
+ #: login-security-solution.php:1820
469
  msgid "2) Send an email to %s letting them know it was not you who logged in."
470
  msgstr ""
471
 
472
+ #: login-security-solution.php:1846
473
  msgid "ATTACK HAPPENING TO %s"
474
  msgstr ""
475
 
476
+ #: login-security-solution.php:1850
477
  msgid "Your website, %s, is undergoing a brute force attack."
478
  msgstr ""
479
 
480
+ #: login-security-solution.php:1853
481
  msgid ""
482
  "There have been at least %d failed attempts to log in during the past %d "
483
  "minutes that used one or more of the following components:"
484
  msgstr ""
485
 
486
+ #: login-security-solution.php:1858
487
  msgid ""
488
  "The %s plugin for WordPress is repelling the attack by making their login "
489
  "failures take a very long time."
490
  msgstr ""
491
 
492
+ #: login-security-solution.php:2209 tests/PasswordValidationTest.php:450
493
  msgid "Password not set."
494
  msgstr ""
495
 
496
+ #: login-security-solution.php:2224 tests/PasswordValidationTest.php:461
497
  msgid "Passwords must be strings."
498
  msgstr ""
499
 
500
+ #: login-security-solution.php:2242 tests/PasswordValidationTest.php:474
501
  msgid "Passwords must use ASCII characters."
502
  msgstr ""
503
 
504
+ #: login-security-solution.php:2261 tests/PasswordChangeTest.php:310
505
+ #: tests/PasswordValidationTest.php:491 tests/PasswordValidationTest.php:505
506
  msgid "Password is too short."
507
  msgstr ""
508
 
509
+ #: login-security-solution.php:2270 tests/PasswordValidationTest.php:531
510
  msgid "Passwords must either contain numbers or be %d characters long."
511
  msgstr ""
512
 
513
+ #: login-security-solution.php:2279 tests/PasswordValidationTest.php:518
514
  msgid ""
515
  "Passwords must either contain punctuation marks / symbols or be %d "
516
  "characters long."
517
  msgstr ""
518
 
519
+ #: login-security-solution.php:2288 tests/PasswordValidationTest.php:544
520
  msgid ""
521
  "Passwords must either contain upper-case and lower-case letters or be %d "
522
  "characters long."
523
  msgstr ""
524
 
525
+ #: login-security-solution.php:2298 tests/PasswordValidationTest.php:557
526
  msgid "Passwords can't be sequential keys."
527
  msgstr ""
528
 
529
+ #: login-security-solution.php:2307 tests/PasswordValidationTest.php:570
530
  msgid "Passwords can't have that many sequential characters."
531
  msgstr ""
532
 
533
+ #: login-security-solution.php:2323 tests/PasswordValidationTest.php:583
534
+ #: tests/PasswordValidationTest.php:596
535
  msgid "Passwords can't contain user data."
536
  msgstr ""
537
 
538
+ #: login-security-solution.php:2334 tests/PasswordValidationTest.php:609
539
  msgid "Passwords can't contain site info."
540
  msgstr ""
541
 
542
+ #: login-security-solution.php:2343 tests/PasswordValidationTest.php:622
543
  msgid "Password is too common."
544
  msgstr ""
545
 
546
+ #: login-security-solution.php:2352 tests/PasswordValidationTest.php:638
547
  msgid "Passwords can't be variations of dictionary words."
548
  msgstr ""
549
 
languages/makemos.sh ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ #! /bin/bash -e
2
+
3
+ cd "`dirname "$0"`"
4
+
5
+ while read file ; do
6
+ lang=${file%*.po}
7
+ echo "Building $lang..."
8
+ msgfmt -o $lang.mo $lang.po
9
+ done < <(ls *po)
languages/makepot.sh ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ #! /bin/bash -e
2
+
3
+ cd "`dirname "$0"`/../../makepot"
4
+
5
+ svn up
6
+
7
+ php -d 'error_reporting=E_ALL^E_STRICT' \
8
+ makepot.php wp-plugin \
9
+ ../login-security-solution \
10
+ ../login-security-solution/languages/login-security-solution.pot
login-security-solution.php CHANGED
@@ -6,7 +6,7 @@
6
  * Description: Requires very strong passwords, repels brute force login attacks, prevents login information disclosures, expires idle sessions, notifies admins of attacks and breaches, permits administrators to disable logins for maintenance or emergency reasons and reset all passwords.
7
  *
8
  * Plugin URI: http://wordpress.org/extend/plugins/login-security-solution/
9
- * Version: 0.20.2
10
  * Author: Daniel Convissor
11
  * Author URI: http://www.analysisandsolutions.com/
12
  * License: GPLv2
@@ -106,6 +106,7 @@ class login_security_solution {
106
  * @var array
107
  */
108
  protected $options_default = array(
 
109
  'deactivate_deletes_data' => 0,
110
  'disable_logins' => 0,
111
  'idle_timeout' => 15,
@@ -214,7 +215,7 @@ class login_security_solution {
214
  if (is_admin()) {
215
  $this->load_plugin_textdomain();
216
 
217
- require_once dirname(__FILE__) . '/admin.inc';
218
  $admin = new login_security_solution_admin;
219
 
220
  if (is_multisite()) {
@@ -835,6 +836,18 @@ class login_security_solution {
835
  return "<strong>$error</strong>: $message";
836
  }
837
 
 
 
 
 
 
 
 
 
 
 
 
 
838
  /**
839
  * Obtains the IP address from $_SERVER['REMOTE_ADDR']
840
  *
@@ -955,14 +968,16 @@ class login_security_solution {
955
  protected function get_notify_counts($network_ip, $user_name, $pass_md5,
956
  $fails)
957
  {
958
- return __("Component Count Value from Current Attempt", self::ID)
959
- . "\n------------ ----- --------------------------------\n"
960
- . sprintf(__("Network IP %5d %s", self::ID),
961
- $fails['network_ip'], $network_ip) . "\n"
962
- . sprintf(__("Username %5d %s", self::ID),
963
- $fails['user_name'], $user_name) . "\n"
964
- . sprintf(__("Password MD5 %5d %s", self::ID),
965
- $fails['pass_md5'], $pass_md5) . "\n\n";
 
 
966
  }
967
 
968
  /**
@@ -1444,7 +1459,7 @@ class login_security_solution {
1444
  * @return bool
1445
  */
1446
  protected function is_pw_outside_ascii($pw) {
1447
- return !preg_match('/^[!-~]+$/u', $pw);
1448
  }
1449
 
1450
  /**
@@ -1755,7 +1770,7 @@ class login_security_solution {
1755
  {
1756
  $this->load_plugin_textdomain();
1757
 
1758
- $to = $this->sanitize_whitespace(get_option('admin_email'));
1759
 
1760
  $blog = get_option('blogname');
1761
  $subject = sprintf(__("POTENTIAL INTRUSION AT %s", self::ID), $blog);
@@ -1802,7 +1817,7 @@ class login_security_solution {
1802
  sprintf(__("Someone just logged into your '%s' account at %s. Was it you that logged in? We are asking because the site is being attacked.", self::ID), $user->user_login, get_option('siteurl')) . "\n\n"
1803
  . __("IF IT WAS NOT YOU, please do the following right away:", self::ID) . "\n\n"
1804
  . sprintf(__("1) Log into %s and change your password.", self::ID), wp_login_url()) . "\n\n"
1805
- . sprintf(__("2) Send an email to %s letting them know it was not you who logged in.", self::ID), get_option('admin_email')) . "\n";
1806
 
1807
  return wp_mail($to, $subject, $message);
1808
  }
@@ -1825,7 +1840,7 @@ class login_security_solution {
1825
  {
1826
  $this->load_plugin_textdomain();
1827
 
1828
- $to = $this->sanitize_whitespace(get_option('admin_email'));
1829
 
1830
  $blog = get_option('blogname');
1831
  $subject = sprintf(__("ATTACK HAPPENING TO %s", self::ID), $blog);
6
  * Description: Requires very strong passwords, repels brute force login attacks, prevents login information disclosures, expires idle sessions, notifies admins of attacks and breaches, permits administrators to disable logins for maintenance or emergency reasons and reset all passwords.
7
  *
8
  * Plugin URI: http://wordpress.org/extend/plugins/login-security-solution/
9
+ * Version: 0.21.0
10
  * Author: Daniel Convissor
11
  * Author URI: http://www.analysisandsolutions.com/
12
  * License: GPLv2
106
  * @var array
107
  */
108
  protected $options_default = array(
109
+ 'admin_email' => '',
110
  'deactivate_deletes_data' => 0,
111
  'disable_logins' => 0,
112
  'idle_timeout' => 15,
215
  if (is_admin()) {
216
  $this->load_plugin_textdomain();
217
 
218
+ require_once dirname(__FILE__) . '/admin.php';
219
  $admin = new login_security_solution_admin;
220
 
221
  if (is_multisite()) {
836
  return "<strong>$error</strong>: $message";
837
  }
838
 
839
+ /**
840
+ * Obtains the email addresses the notifications should go to
841
+ * @return string
842
+ */
843
+ protected function get_admin_email() {
844
+ $email = $this->options['admin_email'];
845
+ if (!$email) {
846
+ $email = get_site_option('admin_email');
847
+ }
848
+ return $email;
849
+ }
850
+
851
  /**
852
  * Obtains the IP address from $_SERVER['REMOTE_ADDR']
853
  *
968
  protected function get_notify_counts($network_ip, $user_name, $pass_md5,
969
  $fails)
970
  {
971
+ return sprintf(__("
972
+ Component Count Value from Current Attempt
973
+ ------------------------ ----- --------------------------------
974
+ Network IP %5d %s
975
+ Username %5d %s
976
+ Password MD5 %5d %s
977
+ ", self::ID),
978
+ $fails['network_ip'], $network_ip,
979
+ $fails['user_name'], $user_name,
980
+ $fails['pass_md5'], $pass_md5) . "\n";
981
  }
982
 
983
  /**
1459
  * @return bool
1460
  */
1461
  protected function is_pw_outside_ascii($pw) {
1462
+ return !preg_match('/^[!-~ ]+$/u', $pw);
1463
  }
1464
 
1465
  /**
1770
  {
1771
  $this->load_plugin_textdomain();
1772
 
1773
+ $to = $this->sanitize_whitespace($this->get_admin_email());
1774
 
1775
  $blog = get_option('blogname');
1776
  $subject = sprintf(__("POTENTIAL INTRUSION AT %s", self::ID), $blog);
1817
  sprintf(__("Someone just logged into your '%s' account at %s. Was it you that logged in? We are asking because the site is being attacked.", self::ID), $user->user_login, get_option('siteurl')) . "\n\n"
1818
  . __("IF IT WAS NOT YOU, please do the following right away:", self::ID) . "\n\n"
1819
  . sprintf(__("1) Log into %s and change your password.", self::ID), wp_login_url()) . "\n\n"
1820
+ . sprintf(__("2) Send an email to %s letting them know it was not you who logged in.", self::ID), $this->get_admin_email()) . "\n";
1821
 
1822
  return wp_mail($to, $subject, $message);
1823
  }
1840
  {
1841
  $this->load_plugin_textdomain();
1842
 
1843
+ $to = $this->sanitize_whitespace($this->get_admin_email());
1844
 
1845
  $blog = get_option('blogname');
1846
  $subject = sprintf(__("ATTACK HAPPENING TO %s", self::ID), $blog);
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=danie
4
  Tags: login, password, passwords, strength, strong, strong passwords, password strength, idle, timeout, maintenance, security, attack, hack, lock, ban, brute force, brute, force, authentication, auth, cookie, users
5
  Requires at least: 3.3
6
  Tested up to: 3.4.1
7
- Stable tag: 0.20.2
8
 
9
  Security against brute force attacks by tracking IP, name, password; requiring very strong passwords. Idle timeout. Maintenance mode. Multisite ready!
10
 
@@ -86,6 +86,7 @@ The tests have caught every password dictionary entry I've tried.
86
  * Monitors auth cookie failures
87
  * Clean, documented code
88
  * Unit tests covering 100% of the main class
 
89
 
90
 
91
  = Securing Your WordPress Site is Important =
@@ -266,18 +267,38 @@ attacks are fairly easy to initiate these days. If someone really wants to
266
  shut down your site, they'll be able to do it without even touching this
267
  plugin's login failure process.
268
 
269
- = How do developers generate the POT translation file? =
270
 
271
- Get the translation tools from `http://i18n.svn.wordpress.org/tools/trunk/`
272
- then `cd` into that directory and run:
273
 
274
- php -d 'error_reporting=E_ALL^E_STRICT' makepot.php wp-plugin \
275
- ../login-security-solution \
276
- ../login-security-solution/languages/login-security-solution.pot
 
 
 
 
 
 
 
277
 
278
 
279
  == Changelog ==
280
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  = 0.20.2 =
282
  * Ugh, update the translation pot file.
283
 
4
  Tags: login, password, passwords, strength, strong, strong passwords, password strength, idle, timeout, maintenance, security, attack, hack, lock, ban, brute force, brute, force, authentication, auth, cookie, users
5
  Requires at least: 3.3
6
  Tested up to: 3.4.1
7
+ Stable tag: 0.21.0
8
 
9
  Security against brute force attacks by tracking IP, name, password; requiring very strong passwords. Idle timeout. Maintenance mode. Multisite ready!
10
 
86
  * Monitors auth cookie failures
87
  * Clean, documented code
88
  * Unit tests covering 100% of the main class
89
+ * Internationalized unit tests
90
 
91
 
92
  = Securing Your WordPress Site is Important =
267
  shut down your site, they'll be able to do it without even touching this
268
  plugin's login failure process.
269
 
270
+ = How do developers generate the translation files? =
271
 
272
+ To update the POT file, do this:
 
273
 
274
+ * cd into the directory above this one.
275
+ * `svn checkout http://i18n.svn.wordpress.org/tools/trunk/ makepot`
276
+ * `cd login-security-solution/languages`
277
+ * `./makepot.sh`
278
+
279
+ To produce the machine readable translations used by WordPress' gettext
280
+ implementation, use the script I made for generating all of the .mo files:
281
+
282
+ * `cd languages`
283
+ * `./makemos.sh`
284
 
285
 
286
  == Changelog ==
287
 
288
+ = 0.21.0 =
289
+ * Fix is_pw_outside_ascii() to permit spaces.
290
+ * In multisite mode, send notifications to network admin, not blog admin.
291
+ * Add "Notifiations To" setting for admins to specify the email addresses
292
+ the failure and breach notifications get sent to. (Request #1560)
293
+ * Clarify that the Change All Passwords link just goes to the UI.
294
+ * Get all unit tests to pass when mbstring isn't enabled.
295
+ * Internationalize the unit tests.
296
+ * Rename admin.inc to admin.php.
297
+ * Rename temporary files holding actual test results. (Bug #1552 redux)
298
+ * Unit tests pass using PHP 5.4.5-dev, 5.3.16-dev, and 5.2.18-dev.
299
+ * Tested under WordPress 3.4.1 using regular and multisite.
300
+ * Also tested on Windows 7 using PHP 5.4.5 and WordPress 3.4.1.
301
+
302
  = 0.20.2 =
303
  * Ugh, update the translation pot file.
304
 
tests/Accessor.php CHANGED
@@ -18,7 +18,7 @@ require_once dirname(dirname(__FILE__)) . '/login-security-solution.php';
18
  /**
19
  * Get the admin class
20
  */
21
- require_once dirname(dirname(__FILE__)) . '/admin.inc';
22
 
23
  // Remove automatically created object.
24
  unset($GLOBALS['login_security_solution']);
18
  /**
19
  * Get the admin class
20
  */
21
+ require_once dirname(dirname(__FILE__)) . '/admin.php';
22
 
23
  // Remove automatically created object.
24
  unset($GLOBALS['login_security_solution']);
tests/LoginErrorsTest.php CHANGED
@@ -60,6 +60,10 @@ class LoginErrorsTest extends TestCase {
60
  unset($_REQUEST['action']);
61
  }
62
 
 
 
 
 
63
 
64
  public function test_login_errors__nothing() {
65
  global $errors, $user_name;
@@ -89,7 +93,8 @@ class LoginErrorsTest extends TestCase {
89
 
90
  $actual = self::$lss->login_errors('input');
91
 
92
- $this->assertEquals('Invalid username or password.',
 
93
  $actual, 'Output should have been modified.');
94
  $this->assertArrayNotHasKey('log', $_POST, "POST log should be unset.");
95
  }
@@ -102,7 +107,8 @@ class LoginErrorsTest extends TestCase {
102
 
103
  $actual = self::$lss->login_errors('input');
104
 
105
- $this->assertEquals('Invalid username or password.',
 
106
  $actual, 'Output should have been modified.');
107
  $this->assertArrayNotHasKey('log', $_POST, "POST log should be unset.");
108
  }
@@ -114,7 +120,9 @@ class LoginErrorsTest extends TestCase {
114
 
115
  $actual = self::$lss->login_errors('input');
116
 
117
- $this->assertEquals(__('Password reset is not allowed for this user'),
 
 
118
  $actual, 'Output should have been modified.');
119
  $this->assertArrayHasKey('log', $_POST, "POST log shouldn't be touched.");
120
  }
@@ -126,7 +134,9 @@ class LoginErrorsTest extends TestCase {
126
 
127
  $actual = self::$lss->login_errors('input');
128
 
129
- $this->assertEquals(__('Password reset is not allowed for this user'),
 
 
130
  $actual, 'Output should have been modified.');
131
  $this->assertArrayHasKey('log', $_POST, "POST log shouldn't be touched.");
132
  }
60
  unset($_REQUEST['action']);
61
  }
62
 
63
+ protected function err($message) {
64
+ return self::$lss->hsc_utf8($message);
65
+ }
66
+
67
 
68
  public function test_login_errors__nothing() {
69
  global $errors, $user_name;
93
 
94
  $actual = self::$lss->login_errors('input');
95
 
96
+ $this->assertEquals(
97
+ $this->err(__("Invalid username or password.", self::ID)),
98
  $actual, 'Output should have been modified.');
99
  $this->assertArrayNotHasKey('log', $_POST, "POST log should be unset.");
100
  }
107
 
108
  $actual = self::$lss->login_errors('input');
109
 
110
+ $this->assertEquals(
111
+ $this->err(__("Invalid username or password.", self::ID)),
112
  $actual, 'Output should have been modified.');
113
  $this->assertArrayNotHasKey('log', $_POST, "POST log should be unset.");
114
  }
120
 
121
  $actual = self::$lss->login_errors('input');
122
 
123
+ // This text is lifted directly from WordPress.
124
+ $this->assertEquals(
125
+ $this->err(__('Password reset is not allowed for this user')),
126
  $actual, 'Output should have been modified.');
127
  $this->assertArrayHasKey('log', $_POST, "POST log shouldn't be touched.");
128
  }
134
 
135
  $actual = self::$lss->login_errors('input');
136
 
137
+ // This text is lifted directly from WordPress.
138
+ $this->assertEquals(
139
+ $this->err(__('Password reset is not allowed for this user')),
140
  $actual, 'Output should have been modified.');
141
  $this->assertArrayHasKey('log', $_POST, "POST log shouldn't be touched.");
142
  }
tests/LoginMessageTest.php CHANGED
@@ -31,7 +31,7 @@ class LoginMessageTest extends TestCase {
31
 
32
  public function ours($ours) {
33
  return '<p class="login message">'
34
- . htmlspecialchars($ours) . '</p>';
35
  }
36
 
37
  public function test_login_message__unset() {
31
 
32
  public function ours($ours) {
33
  return '<p class="login message">'
34
+ . self::$lss->hsc_utf8($ours) . '</p>';
35
  }
36
 
37
  public function test_login_message__unset() {
tests/PasswordChangeTest.php CHANGED
@@ -33,7 +33,11 @@ class PasswordChangeTest extends TestCase {
33
  parent::$db_needed = true;
34
  parent::set_up_before_class();
35
 
36
- self::$pass_1 = self::USER_PASS;
 
 
 
 
37
  self::$pass_2 = '!AJd81aasjk2@';
38
  self::$hash_1 = wp_hash_password(self::$pass_1);
39
  self::$hash_2 = wp_hash_password(self::$pass_2);
@@ -48,6 +52,10 @@ class PasswordChangeTest extends TestCase {
48
  $options['pw_reuse_count'] = 3;
49
  self::$lss->options = $options;
50
 
 
 
 
 
51
  self::$lss->set_pw_force_change($this->user->ID);
52
  $actual = self::$lss->get_pw_force_change($this->user->ID);
53
  $this->assertTrue($actual, 'Problem setting up force change.');
@@ -74,6 +82,10 @@ class PasswordChangeTest extends TestCase {
74
  $this->assertGreaterThan(0, $actual, 'Grace period should not be cleared.');
75
  }
76
 
 
 
 
 
77
 
78
  /*
79
  * HASHES / REUSED
@@ -262,7 +274,7 @@ class PasswordChangeTest extends TestCase {
262
  $actual = self::$lss->user_profile_update_errors($errors, 1, $this->user);
263
  $this->assertFalse($actual, 'Bad return value.');
264
  $this->assertEquals(
265
- "<strong>ERROR</strong>: Passwords can not be reused.",
266
  $errors->get_error_message()
267
  );
268
 
@@ -295,7 +307,7 @@ class PasswordChangeTest extends TestCase {
295
  $actual = self::$lss->user_profile_update_errors($errors, 0, $this->user);
296
  $this->assertFalse($actual, 'Bad return value.');
297
  $this->assertEquals(
298
- "<strong>ERROR</strong>: Password is too short.",
299
  $errors->get_error_message()
300
  );
301
 
33
  parent::$db_needed = true;
34
  parent::set_up_before_class();
35
 
36
+ if (extension_loaded('mbstring')) {
37
+ self::$pass_1 = self::USER_PASS;
38
+ } else {
39
+ self::$pass_1 = 'Some ASCII Only PW 4 You!';
40
+ }
41
  self::$pass_2 = '!AJd81aasjk2@';
42
  self::$hash_1 = wp_hash_password(self::$pass_1);
43
  self::$hash_2 = wp_hash_password(self::$pass_2);
52
  $options['pw_reuse_count'] = 3;
53
  self::$lss->options = $options;
54
 
55
+ if (!extension_loaded('mbstring')) {
56
+ $this->user->user_pass = self::$pass_1;
57
+ }
58
+
59
  self::$lss->set_pw_force_change($this->user->ID);
60
  $actual = self::$lss->get_pw_force_change($this->user->ID);
61
  $this->assertTrue($actual, 'Problem setting up force change.');
82
  $this->assertGreaterThan(0, $actual, 'Grace period should not be cleared.');
83
  }
84
 
85
+ protected function err($message) {
86
+ return self::$lss->err($message);
87
+ }
88
+
89
 
90
  /*
91
  * HASHES / REUSED
274
  $actual = self::$lss->user_profile_update_errors($errors, 1, $this->user);
275
  $this->assertFalse($actual, 'Bad return value.');
276
  $this->assertEquals(
277
+ $this->err(__("Passwords can not be reused.", self::ID)),
278
  $errors->get_error_message()
279
  );
280
 
307
  $actual = self::$lss->user_profile_update_errors($errors, 0, $this->user);
308
  $this->assertFalse($actual, 'Bad return value.');
309
  $this->assertEquals(
310
+ $this->err(__("Password is too short.", self::ID)),
311
  $errors->get_error_message()
312
  );
313
 
tests/PasswordValidationTest.php CHANGED
@@ -227,6 +227,7 @@ class PasswordValidationTest extends TestCase {
227
  $tests = array(
228
  "aba!123",
229
  "aba~123",
 
230
  );
231
  foreach ($tests as $pw) {
232
  $actual = self::$lss->is_pw_outside_ascii($pw);
@@ -310,9 +311,13 @@ class PasswordValidationTest extends TestCase {
310
  "aA1!",
311
  "aAb",
312
  "aA!",
313
- "БбƤƥ", // Bicameral UTF-8.
314
- "חح", // Unicameral UTF-8.
315
  );
 
 
 
 
 
 
316
  foreach ($tests as $pw) {
317
  $actual = self::$lss->is_pw_missing_upper_lower_chars($pw);
318
  $this->assertFalse($actual, "Should have passed: '$pw'");
@@ -442,7 +447,7 @@ class PasswordValidationTest extends TestCase {
442
  $this->assertFalse($actual,
443
  "password not being set should have failed.");
444
  $this->assertEquals(
445
- $this->err("Password not set."),
446
  $errors->get_error_message()
447
  );
448
  }
@@ -453,7 +458,7 @@ class PasswordValidationTest extends TestCase {
453
  $this->assertFalse($actual,
454
  "'array('abc')' should have failed.");
455
  $this->assertEquals(
456
- $this->err("Passwords must be strings."),
457
  $errors->get_error_message()
458
  );
459
  }
@@ -466,7 +471,7 @@ class PasswordValidationTest extends TestCase {
466
  $this->assertFalse($actual,
467
  "'" . $this->user->user_pass . "' should have failed.");
468
  $this->assertEquals(
469
- $this->err("Passwords must use ASCII characters."),
470
  $errors->get_error_message()
471
  );
472
  }
@@ -483,7 +488,7 @@ class PasswordValidationTest extends TestCase {
483
  $this->assertFalse($actual,
484
  "'" . $this->user->user_pass . "' should have failed.");
485
  $this->assertEquals(
486
- $this->err("Password is too short."),
487
  $errors->get_error_message()
488
  );
489
  }
@@ -497,7 +502,7 @@ class PasswordValidationTest extends TestCase {
497
  $this->assertFalse($actual,
498
  "'" . $this->user->user_pass . "' should have failed.");
499
  $this->assertEquals(
500
- $this->err("Password is too short."),
501
  $errors->get_error_message()
502
  );
503
  }
@@ -510,7 +515,7 @@ class PasswordValidationTest extends TestCase {
510
  $this->assertFalse($actual,
511
  "'" . $this->user->user_pass . "' should have failed.");
512
  $this->assertEquals(
513
- $this->err(sprintf("Passwords must either contain punctuation marks / symbols or be %d characters long.", self::$lss->options['pw_complexity_exemption_length'])),
514
  $errors->get_error_message()
515
  );
516
  }
@@ -523,7 +528,7 @@ class PasswordValidationTest extends TestCase {
523
  $this->assertFalse($actual,
524
  "'" . $this->user->user_pass . "' should have failed.");
525
  $this->assertEquals(
526
- $this->err(sprintf("Passwords must either contain numbers or be %d characters long.", self::$lss->options['pw_complexity_exemption_length'])),
527
  $errors->get_error_message()
528
  );
529
  }
@@ -536,7 +541,7 @@ class PasswordValidationTest extends TestCase {
536
  $this->assertFalse($actual,
537
  "'" . $this->user->user_pass . "' should have failed.");
538
  $this->assertEquals(
539
- $this->err(sprintf("Passwords must either contain upper-case and lower-case letters or be %d characters long.", self::$lss->options['pw_complexity_exemption_length'])),
540
  $errors->get_error_message()
541
  );
542
  }
@@ -549,7 +554,7 @@ class PasswordValidationTest extends TestCase {
549
  $this->assertFalse($actual,
550
  "'" . $this->user->user_pass . "' should have failed.");
551
  $this->assertEquals(
552
- $this->err("Passwords can't be sequential keys."),
553
  $errors->get_error_message()
554
  );
555
  }
@@ -562,7 +567,7 @@ class PasswordValidationTest extends TestCase {
562
  $this->assertFalse($actual,
563
  "'" . $this->user->user_pass . "' should have failed.");
564
  $this->assertEquals(
565
- $this->err("Passwords can't have that many sequential characters."),
566
  $errors->get_error_message()
567
  );
568
  }
@@ -575,7 +580,7 @@ class PasswordValidationTest extends TestCase {
575
  $this->assertFalse($actual,
576
  "'" . $this->user->user_pass . "' should have failed.");
577
  $this->assertEquals(
578
- $this->err("Passwords can't contain user data."),
579
  $errors->get_error_message()
580
  );
581
  }
@@ -588,7 +593,7 @@ class PasswordValidationTest extends TestCase {
588
  $this->assertFalse($actual,
589
  "'" . $this->user->user_pass . "' should have failed.");
590
  $this->assertEquals(
591
- $this->err("Passwords can't contain user data."),
592
  $errors->get_error_message()
593
  );
594
  }
@@ -601,7 +606,7 @@ class PasswordValidationTest extends TestCase {
601
  $this->assertFalse($actual,
602
  "'" . $this->user->user_pass . "' should have failed.");
603
  $this->assertEquals(
604
- $this->err("Passwords can't contain site info."),
605
  $errors->get_error_message()
606
  );
607
  }
@@ -614,7 +619,7 @@ class PasswordValidationTest extends TestCase {
614
  $this->assertFalse($actual,
615
  "'" . $this->user->user_pass . "' should have failed.");
616
  $this->assertEquals(
617
- $this->err("Password is too common."),
618
  $errors->get_error_message()
619
  );
620
  }
@@ -630,16 +635,21 @@ class PasswordValidationTest extends TestCase {
630
  $this->assertFalse($actual,
631
  "'" . $this->user->user_pass . "' should have failed.");
632
  $this->assertEquals(
633
- $this->err("Passwords can't be variations of dictionary words."),
634
  $errors->get_error_message()
635
  );
636
  }
637
 
638
  public function test_validate_pw__good() {
 
 
 
 
639
  $errors = new WP_Error;
640
  $actual = self::$lss->validate_pw($this->user, $errors);
641
  $this->assertTrue($actual,
642
- "'" . $this->user->user_pass . "' should have passed.");
 
643
  $this->assertEmpty($errors->get_error_message());
644
  }
645
 
@@ -649,7 +659,8 @@ class PasswordValidationTest extends TestCase {
649
  $errors = new WP_Error;
650
  $actual = self::$lss->validate_pw($this->user, $errors);
651
  $this->assertTrue($actual,
652
- "'" . $this->user->user_pass . "' should have passed.");
 
653
  $this->assertEmpty($errors->get_error_message());
654
  }
655
 
227
  $tests = array(
228
  "aba!123",
229
  "aba~123",
230
+ "aba 123",
231
  );
232
  foreach ($tests as $pw) {
233
  $actual = self::$lss->is_pw_outside_ascii($pw);
311
  "aA1!",
312
  "aAb",
313
  "aA!",
 
 
314
  );
315
+
316
+ if (self::$mbstring_available) {
317
+ $tests[] = "БбƤƥ"; // Bicameral UTF-8.
318
+ $tests[] = "חح"; // Unicameral UTF-8.
319
+ }
320
+
321
  foreach ($tests as $pw) {
322
  $actual = self::$lss->is_pw_missing_upper_lower_chars($pw);
323
  $this->assertFalse($actual, "Should have passed: '$pw'");
447
  $this->assertFalse($actual,
448
  "password not being set should have failed.");
449
  $this->assertEquals(
450
+ $this->err(__("Password not set.", self::ID)),
451
  $errors->get_error_message()
452
  );
453
  }
458
  $this->assertFalse($actual,
459
  "'array('abc')' should have failed.");
460
  $this->assertEquals(
461
+ $this->err(__("Passwords must be strings.", self::ID)),
462
  $errors->get_error_message()
463
  );
464
  }
471
  $this->assertFalse($actual,
472
  "'" . $this->user->user_pass . "' should have failed.");
473
  $this->assertEquals(
474
+ $this->err(__("Passwords must use ASCII characters.", self::ID)),
475
  $errors->get_error_message()
476
  );
477
  }
488
  $this->assertFalse($actual,
489
  "'" . $this->user->user_pass . "' should have failed.");
490
  $this->assertEquals(
491
+ $this->err(__("Password is too short.", self::ID)),
492
  $errors->get_error_message()
493
  );
494
  }
502
  $this->assertFalse($actual,
503
  "'" . $this->user->user_pass . "' should have failed.");
504
  $this->assertEquals(
505
+ $this->err(__("Password is too short.", self::ID)),
506
  $errors->get_error_message()
507
  );
508
  }
515
  $this->assertFalse($actual,
516
  "'" . $this->user->user_pass . "' should have failed.");
517
  $this->assertEquals(
518
+ $this->err(sprintf(__("Passwords must either contain punctuation marks / symbols or be %d characters long.", self::ID), self::$lss->options['pw_complexity_exemption_length'])),
519
  $errors->get_error_message()
520
  );
521
  }
528
  $this->assertFalse($actual,
529
  "'" . $this->user->user_pass . "' should have failed.");
530
  $this->assertEquals(
531
+ $this->err(sprintf(__("Passwords must either contain numbers or be %d characters long.", self::ID), self::$lss->options['pw_complexity_exemption_length'])),
532
  $errors->get_error_message()
533
  );
534
  }
541
  $this->assertFalse($actual,
542
  "'" . $this->user->user_pass . "' should have failed.");
543
  $this->assertEquals(
544
+ $this->err(sprintf(__("Passwords must either contain upper-case and lower-case letters or be %d characters long.", self::ID), self::$lss->options['pw_complexity_exemption_length'])),
545
  $errors->get_error_message()
546
  );
547
  }
554
  $this->assertFalse($actual,
555
  "'" . $this->user->user_pass . "' should have failed.");
556
  $this->assertEquals(
557
+ $this->err(__("Passwords can't be sequential keys.", self::ID)),
558
  $errors->get_error_message()
559
  );
560
  }
567
  $this->assertFalse($actual,
568
  "'" . $this->user->user_pass . "' should have failed.");
569
  $this->assertEquals(
570
+ $this->err(__("Passwords can't have that many sequential characters.", self::ID)),
571
  $errors->get_error_message()
572
  );
573
  }
580
  $this->assertFalse($actual,
581
  "'" . $this->user->user_pass . "' should have failed.");
582
  $this->assertEquals(
583
+ $this->err(__("Passwords can't contain user data.", self::ID)),
584
  $errors->get_error_message()
585
  );
586
  }
593
  $this->assertFalse($actual,
594
  "'" . $this->user->user_pass . "' should have failed.");
595
  $this->assertEquals(
596
+ $this->err(__("Passwords can't contain user data.", self::ID)),
597
  $errors->get_error_message()
598
  );
599
  }
606
  $this->assertFalse($actual,
607
  "'" . $this->user->user_pass . "' should have failed.");
608
  $this->assertEquals(
609
+ $this->err(__("Passwords can't contain site info.", self::ID)),
610
  $errors->get_error_message()
611
  );
612
  }
619
  $this->assertFalse($actual,
620
  "'" . $this->user->user_pass . "' should have failed.");
621
  $this->assertEquals(
622
+ $this->err(__("Password is too common.", self::ID)),
623
  $errors->get_error_message()
624
  );
625
  }
635
  $this->assertFalse($actual,
636
  "'" . $this->user->user_pass . "' should have failed.");
637
  $this->assertEquals(
638
+ $this->err(__("Passwords can't be variations of dictionary words.", self::ID)),
639
  $errors->get_error_message()
640
  );
641
  }
642
 
643
  public function test_validate_pw__good() {
644
+ if (!self::$mbstring_available) {
645
+ $this->user->user_pass = 'Some ASCII Only PW 4 You!';
646
+ }
647
+
648
  $errors = new WP_Error;
649
  $actual = self::$lss->validate_pw($this->user, $errors);
650
  $this->assertTrue($actual,
651
+ "'" . $this->user->user_pass . "' should have passed, but got: "
652
+ . $errors->get_error_message());
653
  $this->assertEmpty($errors->get_error_message());
654
  }
655
 
659
  $errors = new WP_Error;
660
  $actual = self::$lss->validate_pw($this->user, $errors);
661
  $this->assertTrue($actual,
662
+ "'" . $this->user->user_pass . "' should have passed, but got: "
663
+ . $errors->get_error_message());
664
  $this->assertEmpty($errors->get_error_message());
665
  }
666
 
tests/TestCase.php CHANGED
@@ -226,7 +226,7 @@ abstract class TestCase extends PHPUnit_Framework_TestCase {
226
 
227
  $this->user = new WP_User;
228
  $this->user->data = new StdClass;
229
- $this->user->ID = 9999999999;
230
  $this->user->user_login = 'aaaa';
231
  $this->user->user_email = 'bbbb';
232
  $this->user->user_url = 'cccc';
@@ -355,7 +355,8 @@ abstract class TestCase extends PHPUnit_Framework_TestCase {
355
  throw new Exception('wp_mail() called at unexpected time'
356
  . ' (mail_file_basename was not set).');
357
  }
358
- self::$mail_file = self::$temp_dir . '/' . self::$mail_file_basename;
 
359
 
360
  $contents = 'To: ' . implode(', ', (array) $to) . "\n"
361
  . "Subject: $subject\n\n$message";
@@ -371,9 +372,15 @@ abstract class TestCase extends PHPUnit_Framework_TestCase {
371
  $this->fail('wp_mail() has not been called.');
372
  }
373
 
 
 
 
 
 
 
374
  $basename = str_replace('::', '--', self::$mail_file_basename);
375
  $this->assertStringMatchesFormatFile(
376
- dirname(__FILE__) . '/expected/' . $basename,
377
  file_get_contents(self::$mail_file)
378
  );
379
  }
226
 
227
  $this->user = new WP_User;
228
  $this->user->data = new StdClass;
229
+ $this->user->ID = 9999999;
230
  $this->user->user_login = 'aaaa';
231
  $this->user->user_email = 'bbbb';
232
  $this->user->user_url = 'cccc';
355
  throw new Exception('wp_mail() called at unexpected time'
356
  . ' (mail_file_basename was not set).');
357
  }
358
+ $basename = str_replace('::', '--', self::$mail_file_basename);
359
+ self::$mail_file = self::$temp_dir . '/' . $basename;
360
 
361
  $contents = 'To: ' . implode(', ', (array) $to) . "\n"
362
  . "Subject: $subject\n\n$message";
372
  $this->fail('wp_mail() has not been called.');
373
  }
374
 
375
+ $basedir = dirname(__FILE__) . '/expected/';
376
+ $locale = get_locale();
377
+ if (!file_exists("$basedir/$locale")) {
378
+ $locale = 'en_US';
379
+ }
380
+
381
  $basename = str_replace('::', '--', self::$mail_file_basename);
382
  $this->assertStringMatchesFormatFile(
383
+ "$basedir/$locale/$basename",
384
  file_get_contents(self::$mail_file)
385
  );
386
  }
tests/VerifiedIpTest.php CHANGED
@@ -124,7 +124,7 @@ class VerifiedIpTest extends TestCase {
124
 
125
  // Check the outcome.
126
  $actual = self::$lss->get_verified_ips($this->user->ID);
127
- $this->assertSame(array($ip), $actual, 'Expected IP missing.');
128
 
129
  $wpdb->query('ROLLBACK TO empty');
130
  wp_cache_reset();
@@ -141,12 +141,16 @@ class VerifiedIpTest extends TestCase {
141
  // So user id = current user id in our profile update errors method.
142
  $current_user = $this->user;
143
 
 
 
 
 
144
  $errors = new WP_Error;
145
  $actual = self::$lss->user_profile_update_errors($errors, 1, $this->user);
146
  $this->assertTrue($actual, 'Bad return value.');
147
 
148
  // Check the outcome.
149
  $actual = self::$lss->get_verified_ips($this->user->ID);
150
- $this->assertSame(array($ip), $actual, 'Expected IP missing.');
151
  }
152
  }
124
 
125
  // Check the outcome.
126
  $actual = self::$lss->get_verified_ips($this->user->ID);
127
+ $this->assertSame(array($ip), $actual, 'Expected IP was not found.');
128
 
129
  $wpdb->query('ROLLBACK TO empty');
130
  wp_cache_reset();
141
  // So user id = current user id in our profile update errors method.
142
  $current_user = $this->user;
143
 
144
+ if (!extension_loaded('mbstring')) {
145
+ $this->user->user_pass = 'Some ASCII Only PW 4 You!';
146
+ }
147
+
148
  $errors = new WP_Error;
149
  $actual = self::$lss->user_profile_update_errors($errors, 1, $this->user);
150
  $this->assertTrue($actual, 'Bad return value.');
151
 
152
  // Check the outcome.
153
  $actual = self::$lss->get_verified_ips($this->user->ID);
154
+ $this->assertSame(array($ip), $actual, 'Expected IP was not found.');
155
  }
156
  }
tests/expected/{LoginFailTest--test_process_login_fail__post_threshold → en_US/LoginFailTest--test_process_login_fail__post_threshold} RENAMED
@@ -5,10 +5,11 @@ Your website, %s, is undergoing a brute force attack.
5
 
6
  There have been at least 4 failed attempts to log in during the past 60 minutes that used one or more of the following components:
7
 
8
- Component Count Value from Current Attempt
9
- ------------ ----- --------------------------------
10
- Network IP 4 1.2.38
11
- Username 4 test
12
- Password MD5 2 %s
 
13
 
14
  The Login Security Solution plugin for WordPress is repelling the attack by making their login failures take a very long time.
5
 
6
  There have been at least 4 failed attempts to log in during the past 60 minutes that used one or more of the following components:
7
 
8
+
9
+ Component Count Value from Current Attempt
10
+ ------------------------ ----- --------------------------------
11
+ Network IP 4 1.2.38
12
+ Username 4 test
13
+ Password MD5 %d %s
14
 
15
  The Login Security Solution plugin for WordPress is repelling the attack by making their login failures take a very long time.
tests/expected/{LoginFailTest--test_wp_login__post_breach_threshold → en_US/LoginFailTest--test_wp_login__post_breach_threshold} RENAMED
@@ -5,10 +5,11 @@ Your website, %s, may have been broken in to.
5
 
6
  Someone just logged in using the following components. Prior to that, some combination of those components were a part of 4 failed attempts to log in during the past 60 minutes:
7
 
8
- Component Count Value from Current Attempt
9
- ------------ ----- --------------------------------
10
- Network IP 4 1.2.38
11
- Username 4 test
12
- Password MD5 %d %s
 
13
 
14
  The user has been logged out and will be required to confirm their identity via the password reset functionality.
5
 
6
  Someone just logged in using the following components. Prior to that, some combination of those components were a part of 4 failed attempts to log in during the past 60 minutes:
7
 
8
+
9
+ Component Count Value from Current Attempt
10
+ ------------------------ ----- --------------------------------
11
+ Network IP 4 1.2.38
12
+ Username 4 test
13
+ Password MD5 %d %s
14
 
15
  The user has been logged out and will be required to confirm their identity via the password reset functionality.
tests/expected/{LoginFailTest--test_wp_login__post_breach_threshold_verified_ip → en_US/LoginFailTest--test_wp_login__post_breach_threshold_verified_ip} RENAMED
@@ -5,11 +5,12 @@ Your website, %s, may have been broken in to.
5
 
6
  Someone just logged in using the following components. Prior to that, some combination of those components were a part of 4 failed attempts to log in during the past 60 minutes:
7
 
8
- Component Count Value from Current Attempt
9
- ------------ ----- --------------------------------
10
- Network IP 0 1.2.33
11
- Username 4 test
12
- Password MD5 %d %s
 
13
 
14
  The user's current IP address is one they have verified with your site in the past. Therefore, the user will NOT be required to confirm their identity via the password reset process. An email will be sent to them, just in case this actually was a breach.
15
  To: %a
5
 
6
  Someone just logged in using the following components. Prior to that, some combination of those components were a part of 4 failed attempts to log in during the past 60 minutes:
7
 
8
+
9
+ Component Count Value from Current Attempt
10
+ ------------------------ ----- --------------------------------
11
+ Network IP 0 1.2.33
12
+ Username 4 test
13
+ Password MD5 %d %s
14
 
15
  The user's current IP address is one they have verified with your site in the past. Therefore, the user will NOT be required to confirm their identity via the password reset process. An email will be sent to them, just in case this actually was a breach.
16
  To: %a
tests/expected/fr_FR/LoginFailTest--test_process_login_fail__post_threshold ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ To: %a
2
+ Subject: ATTAQUE SUR %a
3
+
4
+ Votre site, %s, subi une attaque de type brute force.
5
+
6
+ Au moins %d tentatives infructueuses de connexion au cours des dernières %d minutes ont utilisées les données suivantes:
7
+
8
+
9
+ Composant Nombre Valeur de la tentative courante
10
+ ------------------------ ----- --------------------------------
11
+ Réseau IP 4 1.2.38
12
+ Nom d'utilisateur 4 test
13
+ MD5 du mot de passe %d %s
14
+
15
+ Le plugin %s pour WordPress pare l'attaque en ralentissant la réponse à chaque tentative échouée.
tests/expected/fr_FR/LoginFailTest--test_wp_login__post_breach_threshold ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ To: %a
2
+ Subject: INTRUSION POSSIBLE A %a
3
+
4
+ Votre site, %s, a peut-être été corrompu.
5
+
6
+ Quelqu'un vient de se connecter avec les données qui suivent. Avant cela, plusieurs de ces éléments ont été utilisés parmi les %d tentatives de connexion au cours des %d dernières minutes:
7
+
8
+
9
+ Composant Nombre Valeur de la tentative courante
10
+ ------------------------ ----- --------------------------------
11
+ Réseau IP 4 1.2.38
12
+ Nom d'utilisateur 4 test
13
+ MD5 du mot de passe %d %s
14
+
15
+ L'utilisateur à été déconnecté et il devra confirmer son identité via le processus de changement de mot de passe.
tests/expected/fr_FR/LoginFailTest--test_wp_login__post_breach_threshold_verified_ip ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ To: %a
2
+ Subject: INTRUSION POSSIBLE A %a
3
+
4
+ Votre site, %s, a peut-être été corrompu.
5
+
6
+ Quelqu'un vient de se connecter avec les données qui suivent. Avant cela, plusieurs de ces éléments ont été utilisés parmi les %d tentatives de connexion au cours des %d dernières minutes:
7
+
8
+
9
+ Composant Nombre Valeur de la tentative courante
10
+ ------------------------ ----- --------------------------------
11
+ Réseau IP 0 1.2.33
12
+ Nom d'utilisateur 4 test
13
+ MD5 du mot de passe %d %s
14
+
15
+ L'adresse IP utilisée à déjà été vérifiée auparavant. C'est pourquoi l'utilisateur ne devra PAS nécessairement confirmer son identité via le processus de changement de mot de passe. Un email lui sera envoyé, au cas où ce serait effectivement un intrusion.
16
+ To: %a
17
+ Subject: INTRUSION POSSIBLE A %a
18
+
19
+ Quelqu'un a %s vient de se connecter en tant que '%s'. Était-ce vous? Nous vous posons la question parce que le site semble subir une attaque.
20
+
21
+ SI CE N'ÉTAIT PAS VOUS, veuillez suivre ces consignes au plus vite:
22
+
23
+ 1) Connectez vous à %s et changez votre mot de passe.
24
+
25
+ 2) Envoyez un message à %s pour les prévenir que ce n'était pas vous qui vous êtes connecté récemment.