diff --git a/config.default.php b/config.default.php
index 3232cdf..262fcb9 100755
--- a/config.default.php
+++ b/config.default.php
@@ -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;
diff --git a/helpers/config.php b/helpers/config.php
index f47ed84..8f2e4bd 100644
--- a/helpers/config.php
+++ b/helpers/config.php
@@ -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;
+ }
}
?>
\ No newline at end of file
diff --git a/helpers/user.php b/helpers/user.php
index d03a0c9..41ddf54 100644
--- a/helpers/user.php
+++ b/helpers/user.php
@@ -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,16 +123,18 @@
* @return bool True on success, false otherwise
*/
public function setPass($pass) {
- $hash = password_hash($pass, PASSWORD_DEFAULT);
$ret = false;
- $sql = "UPDATE users SET password = ? WHERE login = ?";
- $stmt = self::$db->prepare($sql);
- $stmt->bind_param('ss', $hash, $this->login);
- $stmt->execute();
- if (!self::$db->error && !$stmt->errno) {
- $ret = true;
+ 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);
+ $stmt->execute();
+ if (!self::$db->error && !$stmt->errno) {
+ $ret = true;
+ }
+ $stmt->close();
}
- $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;
}
/**
diff --git a/index.php b/index.php
index 6cfc78c..9855869 100755
--- a/index.php
+++ b/index.php
@@ -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() ?>;
diff --git a/js/admin.js b/js/admin.js
index 0153ec0..8fcca1a 100644
--- a/js/admin.js
+++ b/js/admin.js
@@ -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;
diff --git a/js/pass.js b/js/pass.js
index 7e59688..9c7b284 100644
--- a/js/pass.js
+++ b/js/pass.js
@@ -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) {
diff --git a/lang.php b/lang.php
index 1a16ca3..b3dff4b 100755
--- a/lang.php
+++ b/lang.php
@@ -17,7 +17,6 @@
* along with this program; if not, see .
*/
-
// 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);
+
?>
diff --git a/lang/en.php b/lang/en.php
index 1f9e855..4291885 100644
--- a/lang/en.php
+++ b/lang/en.php
@@ -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";
?>