Login Security Solution - Version 0.2.1

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 Icon wp plugin Login Security Solution
Version 0.2.1
Comparing to
See all releases

Code changes from version 0.1.0 to 0.2.1

Files changed (4) hide show
  1. admin.inc +29 -29
  2. login-security-solution.php +60 -2
  3. readme.txt +15 -2
  4. 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>' . htmlspecialchars($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,18 +454,18 @@ class login_security_solution_admin extends login_security_solution {
454
  * @return void
455
  */
456
  protected function input_radio($name) {
457
- echo htmlspecialchars($this->fields[$name]['text']) . '<br/>';
458
  echo '<input type="radio" value="0" name="'
459
- . htmlspecialchars($this->option_name)
460
- . '[' . htmlspecialchars($name) . ']"'
461
  . ($this->options[$name] ? '' : ' checked="checked"') . ' /> ';
462
- echo htmlspecialchars($this->fields[$name]['bool0']);
463
  echo '<br/>';
464
  echo '<input type="radio" value="1" name="'
465
- . htmlspecialchars($this->option_name)
466
- . '[' . htmlspecialchars($name) . ']"'
467
  . ($this->options[$name] ? ' checked="checked"' : '') . ' /> ';
468
- echo htmlspecialchars($this->fields[$name]['bool1']);
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
- . htmlspecialchars($this->option_name)
478
- . '[' . htmlspecialchars($name) . ']"'
479
- . ' value="' . htmlspecialchars($this->options[$name]) . '" /> ';
480
- echo htmlspecialchars($this->fields[$name]['text']);
481
  echo ' ' . __('Default:', self::ID) . ' '
482
- . htmlspecialchars($this->options_default[$name]) . '.';
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
- . htmlspecialchars($field['label'])
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
- . htmlspecialchars($field['label'])
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
- . htmlspecialchars($field['label'])
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
- . htmlspecialchars($field['label'])
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
- . htmlspecialchars($this->fields[$name]['label'])
559
  . "' " . sprintf($gt_format,
560
- htmlspecialchars($this->fields['login_fail_tier_2']['label']))
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
- . htmlspecialchars($this->fields[$name]['label'])
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>' . htmlspecialchars($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), htmlspecialchars(self::NAME));
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
- . htmlspecialchars($this->option_pw_force_change_name)
654
- . '[' . htmlspecialchars($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,7 +659,7 @@ class login_security_solution_admin extends login_security_solution {
659
  submit_button(
660
  $this->text_button_require,
661
  'primary',
662
- htmlspecialchars($this->option_pw_force_change_name) . '[submit]'
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
- . htmlspecialchars($this->option_pw_force_change_name)
672
- . '[' . htmlspecialchars($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,7 +677,7 @@ class login_security_solution_admin extends login_security_solution {
677
  submit_button(
678
  $this->text_button_remind,
679
  'secondary',
680
- htmlspecialchars($this->option_pw_force_change_name) . '[submit]'
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=' . htmlspecialchars($this->option_pw_force_change_name) . '">' . $this->text_pw_force_change . "</a></strong></p>\n";
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.0
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
- . htmlspecialchars($ours) . '</p>';
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. Send me the file and I'll include it in future
150
- releases. See the features request section, below.
 
 
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&currency_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 wp-includes/rewrite.php
18
- * Call to a member function add_rewrite_tag() on a non-object in wp-includes/taxonomy.php
 
 
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
- $sysdate = new DateTime($actual->sysdate);
267
- $interval = $date_failed->diff($sysdate);
268
- $this->assertLessThanOrEqual('00000000000001',
269
- $interval->format('%Y%M%D%H%I%S'),
270
- "'date_failed' field off by over 1 second: $actual->date_failed.");
 
 
 
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
  /**