Version Description
- Ensure all files are in the state I intended. Needed because WordPress' plugin site automatically rolls releases.
Download this release
Release Info
Developer | convissor |
Plugin | Login Security Solution |
Version | 0.2.1 |
Comparing to | |
See all releases |
Code changes from version 0.1.0 to 0.2.1
- admin.inc +29 -29
- login-security-solution.php +60 -2
- readme.txt +15 -2
- tests/TestCase.php +13 -7
admin.inc
CHANGED
@@ -389,7 +389,7 @@ class login_security_solution_admin extends login_security_solution {
|
|
389 |
* @return void
|
390 |
*/
|
391 |
public function page_settings() {
|
392 |
-
echo '<h2>' .
|
393 |
echo '<form action="options.php" method="post">' . "\n";
|
394 |
settings_fields($this->option_name);
|
395 |
do_settings_sections(self::ID);
|
@@ -454,18 +454,18 @@ class login_security_solution_admin extends login_security_solution {
|
|
454 |
* @return void
|
455 |
*/
|
456 |
protected function input_radio($name) {
|
457 |
-
echo
|
458 |
echo '<input type="radio" value="0" name="'
|
459 |
-
.
|
460 |
-
. '[' .
|
461 |
. ($this->options[$name] ? '' : ' checked="checked"') . ' /> ';
|
462 |
-
echo
|
463 |
echo '<br/>';
|
464 |
echo '<input type="radio" value="1" name="'
|
465 |
-
.
|
466 |
-
. '[' .
|
467 |
. ($this->options[$name] ? ' checked="checked"' : '') . ' /> ';
|
468 |
-
echo
|
469 |
}
|
470 |
|
471 |
/**
|
@@ -474,12 +474,12 @@ class login_security_solution_admin extends login_security_solution {
|
|
474 |
*/
|
475 |
protected function input_text($name) {
|
476 |
echo '<input type="text" size="3" name="'
|
477 |
-
.
|
478 |
-
. '[' .
|
479 |
-
. ' value="' .
|
480 |
-
echo
|
481 |
echo ' ' . __('Default:', self::ID) . ' '
|
482 |
-
.
|
483 |
}
|
484 |
|
485 |
/**
|
@@ -513,7 +513,7 @@ class login_security_solution_admin extends login_security_solution {
|
|
513 |
if (!is_scalar($in[$name])) {
|
514 |
// Not translating this since only hackers will see it.
|
515 |
add_settings_error($this->option_name, $name, "'"
|
516 |
-
.
|
517 |
. "' was not a scalar, $default");
|
518 |
continue;
|
519 |
}
|
@@ -523,7 +523,7 @@ class login_security_solution_admin extends login_security_solution {
|
|
523 |
if ($in[$name] != 0 && $in[$name] != 1) {
|
524 |
// Not translating this since only hackers will see it.
|
525 |
add_settings_error($this->option_name, $name, "'"
|
526 |
-
.
|
527 |
. "' must be '0' or '1', $default");
|
528 |
continue 2;
|
529 |
}
|
@@ -531,7 +531,7 @@ class login_security_solution_admin extends login_security_solution {
|
|
531 |
case 'int':
|
532 |
if (!ctype_digit($in[$name])) {
|
533 |
add_settings_error($this->option_name, $name, "'"
|
534 |
-
.
|
535 |
. "' " . __("must be an integer,", self::ID)
|
536 |
. ' ' . $default);
|
537 |
continue 2;
|
@@ -540,7 +540,7 @@ class login_security_solution_admin extends login_security_solution {
|
|
540 |
&& $in[$name] < $field['greater_than'])
|
541 |
{
|
542 |
add_settings_error($this->option_name, $name, "'"
|
543 |
-
.
|
544 |
. "' " . sprintf($gt_format,
|
545 |
$field['greater_than'])
|
546 |
. ' ' . $default);
|
@@ -555,9 +555,9 @@ class login_security_solution_admin extends login_security_solution {
|
|
555 |
$name = 'login_fail_tier_3';
|
556 |
if ($out[$name] <= $out['login_fail_tier_2']) {
|
557 |
add_settings_error($this->option_name, $name, "'"
|
558 |
-
.
|
559 |
. "' " . sprintf($gt_format,
|
560 |
-
|
561 |
. ' ' . $default);
|
562 |
|
563 |
$out[$name] = $out['login_fail_tier_2'] + 5;
|
@@ -567,7 +567,7 @@ class login_security_solution_admin extends login_security_solution {
|
|
567 |
$name = 'pw_reuse_count';
|
568 |
if ($out['pw_change_days'] && !$out[$name]) {
|
569 |
add_settings_error($this->option_name, $name, "'"
|
570 |
-
.
|
571 |
. "' " . sprintf($gt_format, 1)
|
572 |
. ' ' . $default);
|
573 |
|
@@ -630,12 +630,12 @@ class login_security_solution_admin extends login_security_solution {
|
|
630 |
* @return void
|
631 |
*/
|
632 |
public function page_pw_force_change() {
|
633 |
-
echo '<h2>' .
|
634 |
|
635 |
echo '<p>';
|
636 |
_e("There may be cases where everyone's password should be reset.", self::ID);
|
637 |
echo ' ';
|
638 |
-
printf(__("This page, provided by the %s plugin, offers that functionality.", self::ID),
|
639 |
echo '</p>';
|
640 |
|
641 |
echo '<p>';
|
@@ -650,8 +650,8 @@ class login_security_solution_admin extends login_security_solution {
|
|
650 |
$this->echo_div();
|
651 |
|
652 |
echo '<p><strong><input type="checkbox" value="1" name="'
|
653 |
-
.
|
654 |
-
. '[' .
|
655 |
. ']" /> ';
|
656 |
_e("Confirm that you want to force all users to change their passwords by checking this box, then click the button, below.", self::ID);
|
657 |
echo '</strong></p>';
|
@@ -659,7 +659,7 @@ class login_security_solution_admin extends login_security_solution {
|
|
659 |
submit_button(
|
660 |
$this->text_button_require,
|
661 |
'primary',
|
662 |
-
|
663 |
);
|
664 |
|
665 |
echo "</div>\n";
|
@@ -668,8 +668,8 @@ class login_security_solution_admin extends login_security_solution {
|
|
668 |
$this->echo_div();
|
669 |
|
670 |
echo '<p><input type="checkbox" value="1" name="'
|
671 |
-
.
|
672 |
-
. '[' .
|
673 |
. ']" /> ';
|
674 |
_e("No thanks. I know what I'm doing. Please don't remind me about this.", self::ID);
|
675 |
echo '</p>';
|
@@ -677,7 +677,7 @@ class login_security_solution_admin extends login_security_solution {
|
|
677 |
submit_button(
|
678 |
$this->text_button_remind,
|
679 |
'secondary',
|
680 |
-
|
681 |
);
|
682 |
|
683 |
echo "</div>\n";
|
@@ -770,7 +770,7 @@ class login_security_solution_admin extends login_security_solution {
|
|
770 |
_e("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);
|
771 |
echo '</strong></p>';
|
772 |
|
773 |
-
echo '<p><strong><a href="options-general.php?page=' .
|
774 |
|
775 |
echo "</div>\n";
|
776 |
}
|
389 |
* @return void
|
390 |
*/
|
391 |
public function page_settings() {
|
392 |
+
echo '<h2>' . $this->hsc($this->text_settings) . '</h2>';
|
393 |
echo '<form action="options.php" method="post">' . "\n";
|
394 |
settings_fields($this->option_name);
|
395 |
do_settings_sections(self::ID);
|
454 |
* @return void
|
455 |
*/
|
456 |
protected function input_radio($name) {
|
457 |
+
echo $this->hsc($this->fields[$name]['text']) . '<br/>';
|
458 |
echo '<input type="radio" value="0" name="'
|
459 |
+
. $this->hsc($this->option_name)
|
460 |
+
. '[' . $this->hsc($name) . ']"'
|
461 |
. ($this->options[$name] ? '' : ' checked="checked"') . ' /> ';
|
462 |
+
echo $this->hsc($this->fields[$name]['bool0']);
|
463 |
echo '<br/>';
|
464 |
echo '<input type="radio" value="1" name="'
|
465 |
+
. $this->hsc($this->option_name)
|
466 |
+
. '[' . $this->hsc($name) . ']"'
|
467 |
. ($this->options[$name] ? ' checked="checked"' : '') . ' /> ';
|
468 |
+
echo $this->hsc($this->fields[$name]['bool1']);
|
469 |
}
|
470 |
|
471 |
/**
|
474 |
*/
|
475 |
protected function input_text($name) {
|
476 |
echo '<input type="text" size="3" name="'
|
477 |
+
. $this->hsc($this->option_name)
|
478 |
+
. '[' . $this->hsc($name) . ']"'
|
479 |
+
. ' value="' . $this->hsc($this->options[$name]) . '" /> ';
|
480 |
+
echo $this->hsc($this->fields[$name]['text']);
|
481 |
echo ' ' . __('Default:', self::ID) . ' '
|
482 |
+
. $this->hsc($this->options_default[$name]) . '.';
|
483 |
}
|
484 |
|
485 |
/**
|
513 |
if (!is_scalar($in[$name])) {
|
514 |
// Not translating this since only hackers will see it.
|
515 |
add_settings_error($this->option_name, $name, "'"
|
516 |
+
. $this->hsc($field['label'])
|
517 |
. "' was not a scalar, $default");
|
518 |
continue;
|
519 |
}
|
523 |
if ($in[$name] != 0 && $in[$name] != 1) {
|
524 |
// Not translating this since only hackers will see it.
|
525 |
add_settings_error($this->option_name, $name, "'"
|
526 |
+
. $this->hsc($field['label'])
|
527 |
. "' must be '0' or '1', $default");
|
528 |
continue 2;
|
529 |
}
|
531 |
case 'int':
|
532 |
if (!ctype_digit($in[$name])) {
|
533 |
add_settings_error($this->option_name, $name, "'"
|
534 |
+
. $this->hsc($field['label'])
|
535 |
. "' " . __("must be an integer,", self::ID)
|
536 |
. ' ' . $default);
|
537 |
continue 2;
|
540 |
&& $in[$name] < $field['greater_than'])
|
541 |
{
|
542 |
add_settings_error($this->option_name, $name, "'"
|
543 |
+
. $this->hsc($field['label'])
|
544 |
. "' " . sprintf($gt_format,
|
545 |
$field['greater_than'])
|
546 |
. ' ' . $default);
|
555 |
$name = 'login_fail_tier_3';
|
556 |
if ($out[$name] <= $out['login_fail_tier_2']) {
|
557 |
add_settings_error($this->option_name, $name, "'"
|
558 |
+
. $this->hsc($this->fields[$name]['label'])
|
559 |
. "' " . sprintf($gt_format,
|
560 |
+
$this->hsc($this->fields['login_fail_tier_2']['label']))
|
561 |
. ' ' . $default);
|
562 |
|
563 |
$out[$name] = $out['login_fail_tier_2'] + 5;
|
567 |
$name = 'pw_reuse_count';
|
568 |
if ($out['pw_change_days'] && !$out[$name]) {
|
569 |
add_settings_error($this->option_name, $name, "'"
|
570 |
+
. $this->hsc($this->fields[$name]['label'])
|
571 |
. "' " . sprintf($gt_format, 1)
|
572 |
. ' ' . $default);
|
573 |
|
630 |
* @return void
|
631 |
*/
|
632 |
public function page_pw_force_change() {
|
633 |
+
echo '<h2>' . $this->hsc($this->text_pw_force_change) . '</h2>';
|
634 |
|
635 |
echo '<p>';
|
636 |
_e("There may be cases where everyone's password should be reset.", self::ID);
|
637 |
echo ' ';
|
638 |
+
printf(__("This page, provided by the %s plugin, offers that functionality.", self::ID), $this->hsc(self::NAME));
|
639 |
echo '</p>';
|
640 |
|
641 |
echo '<p>';
|
650 |
$this->echo_div();
|
651 |
|
652 |
echo '<p><strong><input type="checkbox" value="1" name="'
|
653 |
+
. $this->hsc($this->option_pw_force_change_name)
|
654 |
+
. '[' . $this->hsc($this->key_checkbox_require)
|
655 |
. ']" /> ';
|
656 |
_e("Confirm that you want to force all users to change their passwords by checking this box, then click the button, below.", self::ID);
|
657 |
echo '</strong></p>';
|
659 |
submit_button(
|
660 |
$this->text_button_require,
|
661 |
'primary',
|
662 |
+
$this->hsc($this->option_pw_force_change_name) . '[submit]'
|
663 |
);
|
664 |
|
665 |
echo "</div>\n";
|
668 |
$this->echo_div();
|
669 |
|
670 |
echo '<p><input type="checkbox" value="1" name="'
|
671 |
+
. $this->hsc($this->option_pw_force_change_name)
|
672 |
+
. '[' . $this->hsc($this->key_checkbox_remind)
|
673 |
. ']" /> ';
|
674 |
_e("No thanks. I know what I'm doing. Please don't remind me about this.", self::ID);
|
675 |
echo '</p>';
|
677 |
submit_button(
|
678 |
$this->text_button_remind,
|
679 |
'secondary',
|
680 |
+
$this->hsc($this->option_pw_force_change_name) . '[submit]'
|
681 |
);
|
682 |
|
683 |
echo "</div>\n";
|
770 |
_e("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);
|
771 |
echo '</strong></p>';
|
772 |
|
773 |
+
echo '<p><strong><a href="options-general.php?page=' . $this->hsc($this->option_pw_force_change_name) . '">' . $this->text_pw_force_change . "</a></strong></p>\n";
|
774 |
|
775 |
echo "</div>\n";
|
776 |
}
|
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.1
|
10 |
* Author: Daniel Convissor
|
11 |
* Author URI: http://www.analysisandsolutions.com/
|
12 |
* License: GPLv2
|
@@ -475,7 +475,7 @@ class login_security_solution {
|
|
475 |
|
476 |
if ($ours) {
|
477 |
$out .= '<p class="login message">'
|
478 |
-
.
|
479 |
}
|
480 |
|
481 |
return $out;
|
@@ -863,6 +863,64 @@ class login_security_solution {
|
|
863 |
return false;
|
864 |
}
|
865 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
866 |
/**
|
867 |
* Saves the failed login's info in the database
|
868 |
*
|
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.2.1
|
10 |
* Author: Daniel Convissor
|
11 |
* Author URI: http://www.analysisandsolutions.com/
|
12 |
* License: GPLv2
|
475 |
|
476 |
if ($ours) {
|
477 |
$out .= '<p class="login message">'
|
478 |
+
. $this->hsc($ours) . '</p>';
|
479 |
}
|
480 |
|
481 |
return $out;
|
863 |
return false;
|
864 |
}
|
865 |
|
866 |
+
/**
|
867 |
+
* Sanitizes output via htmlspecialchars()
|
868 |
+
*
|
869 |
+
* Created this method to make using the $encoding parameter easier.
|
870 |
+
*
|
871 |
+
* @param string $in the string to sanitize
|
872 |
+
* @return string the sanitized string
|
873 |
+
*
|
874 |
+
* @uses DB_CHARSET set in wp-config.php to know which $encoding to use
|
875 |
+
*/
|
876 |
+
protected function hsc($in) {
|
877 |
+
static $encoding;
|
878 |
+
|
879 |
+
if (!isset($encoding)) {
|
880 |
+
// Translate MySQL encoding to PHP encoding.
|
881 |
+
switch (DB_CHARSET) {
|
882 |
+
case 'latin1':
|
883 |
+
$encoding = 'ISO-8859-1';
|
884 |
+
break;
|
885 |
+
case 'utf8':
|
886 |
+
case 'utf8mb4':
|
887 |
+
$encoding = 'UTF-8';
|
888 |
+
break;
|
889 |
+
case 'cp866':
|
890 |
+
$encoding = 'cp866';
|
891 |
+
break;
|
892 |
+
case 'cp1251':
|
893 |
+
$encoding = 'cp1251';
|
894 |
+
break;
|
895 |
+
case 'koi8r':
|
896 |
+
$encoding = 'KOI8-R';
|
897 |
+
break;
|
898 |
+
case 'big5':
|
899 |
+
$encoding = 'BIG5';
|
900 |
+
break;
|
901 |
+
case 'gb2312':
|
902 |
+
$encoding = 'GB2312';
|
903 |
+
break;
|
904 |
+
case 'sjis':
|
905 |
+
$encoding = 'Shift_JIS';
|
906 |
+
break;
|
907 |
+
case 'ujis':
|
908 |
+
$encoding = 'EUC-JP';
|
909 |
+
break;
|
910 |
+
case 'macroman':
|
911 |
+
$encoding = 'MacRoman';
|
912 |
+
break;
|
913 |
+
default:
|
914 |
+
$encoding = 'UTF-8';
|
915 |
+
if (WP_DEBUG) {
|
916 |
+
trigger_error("Your DB_CHARSET doesn't map to a PHP encoding.", E_USER_WARNING);
|
917 |
+
}
|
918 |
+
}
|
919 |
+
}
|
920 |
+
|
921 |
+
return htmlspecialchars($in, ENT_COMPAT, $encoding);
|
922 |
+
}
|
923 |
+
|
924 |
/**
|
925 |
* Saves the failed login's info in the database
|
926 |
*
|
readme.txt
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
=== Login Security Solution ===
|
2 |
Contributors: convissor
|
|
|
3 |
Tags: login, password, idle, timeout, maintenance, security, attack, hack, lock, ban
|
4 |
Requires at least: 3.0
|
5 |
Tested up to: 3.3.1
|
@@ -146,8 +147,10 @@ clients and friends.
|
|
146 |
* If a translation file for your language does not exist in this
|
147 |
plugin's `languages` directory, add one. Read
|
148 |
http://codex.wordpress.org/I18n_for_WordPress_Developers
|
149 |
-
for details.
|
150 |
-
|
|
|
|
|
151 |
|
152 |
1. The last step of the new password validation process is checking if
|
153 |
the password matches an entry in the `dict` program. See if `dict`
|
@@ -207,6 +210,16 @@ Ask and ye shall receive.
|
|
207 |
|
208 |
== Changelog ==
|
209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
210 |
= 0.1.0 =
|
211 |
* Beta release.
|
212 |
|
1 |
=== Login Security Solution ===
|
2 |
Contributors: convissor
|
3 |
+
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=danielc%40analysisandsolutions%2ecom&lc=US&item_name=Donate%3a%20Login%20Security%20Solution¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted
|
4 |
Tags: login, password, idle, timeout, maintenance, security, attack, hack, lock, ban
|
5 |
Requires at least: 3.0
|
6 |
Tested up to: 3.3.1
|
147 |
* If a translation file for your language does not exist in this
|
148 |
plugin's `languages` directory, add one. Read
|
149 |
http://codex.wordpress.org/I18n_for_WordPress_Developers
|
150 |
+
for details. The file should use the same character set encoding as
|
151 |
+
the `DB_CHARSET` setting in `wp-config.php`. Send me the file and
|
152 |
+
I'll include it in future releases. See the features request
|
153 |
+
section, below.
|
154 |
|
155 |
1. The last step of the new password validation process is checking if
|
156 |
the password matches an entry in the `dict` program. See if `dict`
|
210 |
|
211 |
== Changelog ==
|
212 |
|
213 |
+
= 0.2.1 =
|
214 |
+
* Ensure all files are in the state I intended. Needed because
|
215 |
+
WordPress' plugin site automatically rolls releases.
|
216 |
+
|
217 |
+
= 0.2.0 =
|
218 |
+
* Utilize the $encoding parameter of `htmlspecialchars()` to avoid
|
219 |
+
problems under PHP 5.4.
|
220 |
+
* Tested under WordPress 3.3.1.
|
221 |
+
* Unit tests pass using PHP 5.4.0RC8-dev, 5.3.11-dev, and 5.2.18-dev.
|
222 |
+
|
223 |
= 0.1.0 =
|
224 |
* Beta release.
|
225 |
|
tests/TestCase.php
CHANGED
@@ -14,8 +14,10 @@
|
|
14 |
* Keep PHPUnit from messing up WordPress' crazy use of globals.
|
15 |
*
|
16 |
* This prevents the following errors:
|
17 |
-
* Call to a member function add_rule() on a non-object in
|
18 |
-
*
|
|
|
|
|
19 |
*/
|
20 |
global $wp_rewrite;
|
21 |
|
@@ -202,6 +204,7 @@ abstract class TestCase extends PHPUnit_Framework_TestCase {
|
|
202 |
$_SERVER['SERVER_PROTOCOL'] = 'http';
|
203 |
|
204 |
$this->user = new WP_User;
|
|
|
205 |
$this->user->ID = 9999999999;
|
206 |
$this->user->user_login = 'aaaa';
|
207 |
$this->user->user_email = 'bbbb';
|
@@ -263,11 +266,14 @@ abstract class TestCase extends PHPUnit_Framework_TestCase {
|
|
263 |
"'pass_md5' field mismatch.");
|
264 |
|
265 |
$date_failed = new DateTime($actual->date_failed);
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
|
|
|
|
|
|
271 |
}
|
272 |
|
273 |
/**
|
14 |
* Keep PHPUnit from messing up WordPress' crazy use of globals.
|
15 |
*
|
16 |
* This prevents the following errors:
|
17 |
+
* + Call to a member function add_rule() on a non-object in
|
18 |
+
* wp-includes/rewrite.php
|
19 |
+
* + Call to a member function add_rewrite_tag() on a non-object in
|
20 |
+
* wp-includes/taxonomy.php
|
21 |
*/
|
22 |
global $wp_rewrite;
|
23 |
|
204 |
$_SERVER['SERVER_PROTOCOL'] = 'http';
|
205 |
|
206 |
$this->user = new WP_User;
|
207 |
+
$this->user->data = new StdClass;
|
208 |
$this->user->ID = 9999999999;
|
209 |
$this->user->user_login = 'aaaa';
|
210 |
$this->user->user_email = 'bbbb';
|
266 |
"'pass_md5' field mismatch.");
|
267 |
|
268 |
$date_failed = new DateTime($actual->date_failed);
|
269 |
+
// Keep tests from going fatal under PHP 5.2.
|
270 |
+
if (method_exists($date_failed, 'diff')) {
|
271 |
+
$sysdate = new DateTime($actual->sysdate);
|
272 |
+
$interval = $date_failed->diff($sysdate);
|
273 |
+
$this->assertLessThanOrEqual('00000000000001',
|
274 |
+
$interval->format('%Y%M%D%H%I%S'),
|
275 |
+
"'date_failed' field off by over 1 second: $actual->date_failed.");
|
276 |
+
}
|
277 |
}
|
278 |
|
279 |
/**
|