Optionally enforce password strength (adds config options)

This commit is contained in:
Bartek Fabiszewski 2017-04-14 15:55:00 +02:00
parent 04b2b77139
commit e89d30bb98
8 changed files with 97 additions and 19 deletions

View File

@ -62,6 +62,16 @@ $public_tracks = 0;
// none if empty
$admin_user = "admin";
// miniumum required length of user password
$pass_lenmin = 12;
// required strength of user password
// 0 = no requirements,
// 1 = require mixed case letters (lower and upper),
// 2 = require mixed case and numbers
// 3 = require mixed case, numbers and non-alphanumeric characters
$pass_strength = 2;
// Default interval in seconds for live auto reload
$interval = 10;

View File

@ -25,7 +25,6 @@
static $version = "0.2-beta";
// default map drawing framework
// (gmaps = google maps, openlayers = openlayers/osm)
static $mapapi = "openlayers";
// gmaps key
@ -45,17 +44,12 @@
static $init_latitude = 52.23;
static $init_longitude = 21.01;
// you may set your google maps api key
// this is not obligatory by now
//$gkey = "";
// MySQL config
static $dbhost = ""; // mysql host, eg. localhost
static $dbuser = ""; // database user
static $dbpass = ""; // database pass
static $dbname = ""; // database name
// other
// require login/password authentication
static $require_authentication = true;
@ -66,15 +60,23 @@
// none if empty
static $admin_user = "";
// miniumum required length of user password
static $pass_lenmin = 12;
// required strength of user password
// 0 = no requirements,
// 1 = require mixed case letters (lower and upper),
// 2 = require mixed case and numbers
// 3 = require mixed case, numbers and non-alphanumeric characters
static $pass_strength = 2;
// Default interval in seconds for live auto reload
static $interval = 10;
// Default language
// (en, pl, de, hu, fr, it)
static $lang = "en";
// units
// (metric, imperial)
static $units = "metric";
private static $fileLoaded = false;
@ -113,7 +115,9 @@
if (isset($require_authentication)) { self::$require_authentication = (bool) $require_authentication; }
if (isset($public_tracks)) { self::$public_tracks = (bool) $public_tracks; }
if (isset($admin_user)) { self::$admin_user = $admin_user; }
if (isset($interval)) { self::$interval = $interval; }
if (isset($pass_lenmin)) { self::$pass_lenmin = (int) $pass_lenmin; }
if (isset($pass_strength)) { self::$pass_strength = (int) $pass_strength; }
if (isset($interval)) { self::$interval = (int) $interval; }
if (isset($lang)) { self::$lang = $lang; }
if (isset($units)) { self::$units = $units; }
@ -132,6 +136,33 @@
if (isset($_COOKIE["ulogger_units"])) { self::$units = $_COOKIE["ulogger_units"]; }
if (isset($_COOKIE["ulogger_interval"])) { self::$interval = $_COOKIE["ulogger_interval"]; }
}
/**
* Regex to test if password matches strength and length requirements.
* Valid for both php and javascript
*/
public function passRegex() {
static $regex = "";
if (self::$pass_strength > 0) {
// lower and upper case
$regex .= "(?=.*[a-z])(?=.*[A-Z])";
}
if (self::$pass_strength > 1) {
// digits
$regex .= "(?=.*[0-9])";
}
if (self::$pass_strength > 2) {
// not latin, not digits
$regex .= "(?=.*[^a-zA-Z0-9])";
}
if (self::$pass_lenmin > 0) {
$regex .= "(?=.{" . self::$pass_lenmin . ",})";
}
if (!empty($regex)) {
$regex = "/" . $regex . "/";
}
return $regex;
}
}
?>

View File

@ -65,7 +65,7 @@
*/
public function add($login, $pass) {
$userid = false;
if (!empty($login) && !empty($pass)) {
if (!empty($login) && !empty($pass) && $this->validPassStrength($pass)) {
$hash = password_hash($pass, PASSWORD_DEFAULT);
$sql = "INSERT INTO users (login, password) VALUES (?, ?)";
$stmt = self::$db->prepare($sql);
@ -105,6 +105,11 @@
$stmt->execute();
if (!self::$db->error && !$stmt->errno) {
$ret = true;
$this->id = NULL;
$this->login = NULL;
$this->hash = NULL;
$this->isValid = false;
$this->isAdmin = false;
}
$stmt->close();
}
@ -118,8 +123,9 @@
* @return bool True on success, false otherwise
*/
public function setPass($pass) {
$hash = password_hash($pass, PASSWORD_DEFAULT);
$ret = false;
if ($this->validPassStrength($pass)) {
$hash = password_hash($pass, PASSWORD_DEFAULT);
$sql = "UPDATE users SET password = ? WHERE login = ?";
$stmt = self::$db->prepare($sql);
$stmt->bind_param('ss', $hash, $this->login);
@ -128,6 +134,7 @@
$ret = true;
}
$stmt->close();
}
return $ret;
}
@ -141,6 +148,17 @@
return password_verify($password, $this->hash);
}
/**
* Check if given password matches user's one
*
* @param String $password Password
* @return bool True if matches, false otherwise
*/
private function validPassStrength($password) {
$config = new uConfig();
return preg_match($config->passRegex(), $password);
}
/**
* Store uUser object in session
*/
@ -150,6 +168,7 @@
/**
* Fill uUser object properties from session data
* @return uPosition Self
*/
public function getFromSession() {
if (isset($_SESSION['user'])) {
@ -160,6 +179,7 @@
$this->isAdmin = $sessionUser->isAdmin;
$this->isValid = $sessionUser->isValid;
}
return $this;
}
/**

View File

@ -81,6 +81,7 @@
var init_longitude = '<?= $config::$init_longitude ?>';
var lang = <?= json_encode($lang) ?>;
var auth = '<?= ($user->isValid) ? $user->login : "null" ?>';
var pass_regex = <?= $config->passRegex() ?>;
</script>
<script type="text/javascript" src="js/main.js"></script>

View File

@ -70,6 +70,10 @@ function submitUser(action) {
alert(lang['passnotmatch']);
return;
}
if (!pass_regex.test(pass)) {
alert(lang['passlenmin'] + '\n' + lang['passrules']);
return;
}
} else {
if (!confirmedDelete(login)) {
return;

View File

@ -39,6 +39,11 @@ function submitPass() {
alert(lang['passnotmatch']);
return;
}
if (!pass_regex.test(pass)) {
alert(lang['passlenmin'] + '\n' + lang['passrules']);
return;
}
var xhr = getXHR();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {

View File

@ -17,7 +17,6 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
// available languages
$langsArr = [
"en" => "English",
@ -38,4 +37,8 @@
require_once(ROOT_DIR . "/lang/{$config::$lang}.php");
}
// choose password messages based on config
$lang['passrules'] = $lang["passrules"][$config::$pass_strength];
$lang['passlenmin'] = sprintf($lang["passlenmin"], $config::$pass_lenmin);
?>

View File

@ -76,5 +76,9 @@ $lang["deletewarn"] = "Warning!\n\nYou are going to permanently delete user %s,
$lang["editinguser"] = "You are editing user %s"; // substitutes user login
$lang["selfeditwarn"] = "Your can't edit your own user with this tool";
$lang["apifailure"] = "Sorry, can't load %s API"; // substitures api name (gmaps or openlayers)
$lang["passlenmin"] = "Password must be at least %d characters"; // substitutes password minimum length
$lang["passrules"][1] = "It should contain at least one upper case letter, one lower case letter";
$lang["passrules"][2] = "It should contain at least one upper case letter, one lower case letter and one digit";
$lang["passrules"][3] = "It should contain at least one upper case letter, one lower case letter, one digit and one non-alphanumeric character";
?>