summaryrefslogtreecommitdiff
path: root/classes/userhelper.php
diff options
context:
space:
mode:
Diffstat (limited to 'classes/userhelper.php')
-rw-r--r--classes/userhelper.php250
1 files changed, 203 insertions, 47 deletions
diff --git a/classes/userhelper.php b/classes/userhelper.php
index ca673cf58..ce26e6c71 100644
--- a/classes/userhelper.php
+++ b/classes/userhelper.php
@@ -1,6 +1,22 @@
<?php
+use OTPHP\TOTP;
+
class UserHelper {
+ const HASH_ALGO_SSHA512 = 'SSHA-512';
+ const HASH_ALGO_SSHA256 = 'SSHA-256';
+ const HASH_ALGO_MODE2 = 'MODE2';
+ const HASH_ALGO_SHA1X = 'SHA1X';
+ const HASH_ALGO_SHA1 = 'SHA1';
+
+ const HASH_ALGOS = [
+ self::HASH_ALGO_SSHA512,
+ self::HASH_ALGO_SSHA256,
+ self::HASH_ALGO_MODE2,
+ self::HASH_ALGO_SHA1X,
+ self::HASH_ALGO_SHA1
+ ];
+
static function authenticate(string $login = null, string $password = null, bool $check_only = false, string $service = null) {
if (!Config::get(Config::SINGLE_USER_MODE)) {
$user_id = false;
@@ -23,27 +39,24 @@ class UserHelper {
session_regenerate_id(true);
- $_SESSION["uid"] = $user_id;
- $_SESSION["auth_module"] = $auth_module;
+ $user = ORM::for_table('ttrss_users')->find_one($user_id);
- $pdo = Db::pdo();
- $sth = $pdo->prepare("SELECT login,access_level,pwd_hash FROM ttrss_users
- WHERE id = ?");
- $sth->execute([$user_id]);
- $row = $sth->fetch();
-
- $_SESSION["name"] = $row["login"];
- $_SESSION["access_level"] = $row["access_level"];
- $_SESSION["csrf_token"] = bin2hex(get_random_bytes(16));
+ if ($user) {
+ $_SESSION["uid"] = $user_id;
+ $_SESSION["auth_module"] = $auth_module;
+ $_SESSION["name"] = $user->login;
+ $_SESSION["access_level"] = $user->access_level;
+ $_SESSION["csrf_token"] = bin2hex(get_random_bytes(16));
+ $_SESSION["ip_address"] = UserHelper::get_user_ip();
+ $_SESSION["pwd_hash"] = $user->pwd_hash;
- $usth = $pdo->prepare("UPDATE ttrss_users SET last_login = NOW() WHERE id = ?");
- $usth->execute([$user_id]);
+ $user->last_login = Db::NOW();
+ $user->save();
- $_SESSION["ip_address"] = UserHelper::get_user_ip();
- $_SESSION["user_agent"] = sha1($_SERVER['HTTP_USER_AGENT']);
- $_SESSION["pwd_hash"] = $row["pwd_hash"];
+ return true;
+ }
- return true;
+ return false;
}
if ($login && $password && !$user_id && !$check_only)
@@ -75,7 +88,7 @@ class UserHelper {
if (!$pluginhost) $pluginhost = PluginHost::getInstance();
- if ($owner_uid && SCHEMA_VERSION >= 100 && empty($_SESSION["safe_mode"])) {
+ if ($owner_uid && Config::get_schema_version() >= 100 && empty($_SESSION["safe_mode"])) {
$plugins = get_pref(Prefs::_ENABLED_PLUGINS, $owner_uid);
$pluginhost->load((string)$plugins, PluginHost::KIND_USER, $owner_uid);
@@ -117,8 +130,9 @@ class UserHelper {
} else {
/* bump login timestamp */
- $sth = $pdo->prepare("UPDATE ttrss_users SET last_login = NOW() WHERE id = ?");
- $sth->execute([$_SESSION['uid']]);
+ $user = ORM::for_table('ttrss_users')->find_one($_SESSION["uid"]);
+ $user->last_login = Db::NOW();
+ $user->save();
$_SESSION["last_login_update"] = time();
}
@@ -146,20 +160,29 @@ class UserHelper {
if (isset($_SERVER[$hdr]))
return $_SERVER[$hdr];
}
- }
- static function find_user_by_login(string $login) {
- $pdo = Db::pdo();
+ return null;
+ }
- $sth = $pdo->prepare("SELECT id FROM ttrss_users WHERE
- LOWER(login) = LOWER(?)");
- $sth->execute([$login]);
+ static function get_login_by_id(int $id) {
+ $user = ORM::for_table('ttrss_users')
+ ->find_one($id);
- if ($row = $sth->fetch()) {
- return $row["id"];
- }
+ if ($user)
+ return $user->login;
+ else
+ return null;
+ }
- return false;
+ static function find_user_by_login(string $login) {
+ $user = ORM::for_table('ttrss_users')
+ ->where('login', $login)
+ ->find_one();
+
+ if ($user)
+ return $user->id;
+ else
+ return null;
}
static function logout() {
@@ -173,34 +196,167 @@ class UserHelper {
session_commit();
}
- static function reset_password($uid, $format_output = false) {
+ static function get_salt() {
+ return substr(bin2hex(get_random_bytes(125)), 0, 250);
+ }
- $pdo = Db::pdo();
+ static function reset_password($uid, $format_output = false, $new_password = "") {
- $sth = $pdo->prepare("SELECT login FROM ttrss_users WHERE id = ?");
- $sth->execute([$uid]);
+ $user = ORM::for_table('ttrss_users')->find_one($uid);
+ $message = "";
- if ($row = $sth->fetch()) {
+ if ($user) {
- $login = $row["login"];
+ $login = $user->login;
- $new_salt = substr(bin2hex(get_random_bytes(125)), 0, 250);
- $tmp_user_pwd = make_password();
+ $new_salt = self::get_salt();
+ $tmp_user_pwd = $new_password ? $new_password : make_password();
- $pwd_hash = encrypt_password($tmp_user_pwd, $new_salt, true);
+ $pwd_hash = self::hash_password($tmp_user_pwd, $new_salt, self::HASH_ALGOS[0]);
- $sth = $pdo->prepare("UPDATE ttrss_users
- SET pwd_hash = ?, salt = ?, otp_enabled = false
- WHERE id = ?");
- $sth->execute([$pwd_hash, $new_salt, $uid]);
+ $user->pwd_hash = $pwd_hash;
+ $user->salt = $new_salt;
+ $user->save();
$message = T_sprintf("Changed password of user %s to %s", "<strong>$login</strong>", "<strong>$tmp_user_pwd</strong>");
+ } else {
+ $message = __("User not found");
+ }
- if ($format_output)
- print_notice($message);
- else
- print $message;
+ if ($format_output)
+ print_notice($message);
+ else
+ print $message;
+ }
+ static function check_otp(int $owner_uid, int $otp_check) : bool {
+ $otp = TOTP::create(self::get_otp_secret($owner_uid, true));
+
+ return $otp->now() == $otp_check;
+ }
+
+ static function disable_otp(int $owner_uid) : bool {
+ $user = ORM::for_table('ttrss_users')->find_one($owner_uid);
+
+ if ($user) {
+ $user->otp_enabled = false;
+
+ // force new OTP secret when next enabled
+ if (Config::get_schema_version() >= 143) {
+ $user->otp_secret = null;
+ }
+
+ $user->save();
+
+ return true;
+ } else {
+ return false;
}
}
+
+ static function enable_otp(int $owner_uid, int $otp_check) : bool {
+ $secret = self::get_otp_secret($owner_uid);
+
+ if ($secret) {
+ $otp = TOTP::create($secret);
+ $user = ORM::for_table('ttrss_users')->find_one($owner_uid);
+
+ if ($otp->now() == $otp_check && $user) {
+
+ $user->otp_enabled = true;
+ $user->save();
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ static function is_otp_enabled(int $owner_uid) : bool {
+ $user = ORM::for_table('ttrss_users')->find_one($owner_uid);
+
+ if ($user) {
+ return $user->otp_enabled;
+ } else {
+ return false;
+ }
+ }
+
+ static function get_otp_secret(int $owner_uid, bool $show_if_enabled = false) {
+ $user = ORM::for_table('ttrss_users')->find_one($owner_uid);
+
+ if ($user) {
+
+ $salt_based_secret = mb_substr(sha1($user->salt), 0, 12);
+
+ if (Config::get_schema_version() >= 143) {
+ $secret = $user->otp_secret;
+
+ if (empty($secret)) {
+
+ /* migrate secret if OTP is already enabled, otherwise make a new one */
+ if ($user->otp_enabled) {
+ $user->otp_secret = $salt_based_secret;
+ } else {
+ $user->otp_secret = bin2hex(get_random_bytes(6));
+ }
+
+ $user->save();
+
+ $secret = $user->otp_secret;
+ }
+ } else {
+ $secret = $salt_based_secret;
+ }
+
+ if (!$user->otp_enabled || $show_if_enabled) {
+ return \ParagonIE\ConstantTime\Base32::encodeUpperUnpadded($secret);
+ }
+ }
+
+ return null;
+ }
+
+ static function is_default_password() {
+ $authenticator = PluginHost::getInstance()->get_plugin($_SESSION["auth_module"]);
+
+ if ($authenticator &&
+ method_exists($authenticator, "check_password") &&
+ $authenticator->check_password($_SESSION["uid"], "password")) {
+
+ return true;
+ }
+ return false;
+ }
+
+ static function hash_password(string $pass, string $salt, string $algo = "") {
+
+ if (!$algo) $algo = self::HASH_ALGOS[0];
+
+ $pass_hash = "";
+
+ switch ($algo) {
+ case self::HASH_ALGO_SHA1:
+ $pass_hash = sha1($pass);
+ break;
+ case self::HASH_ALGO_SHA1X:
+ $pass_hash = sha1("$salt:$pass");
+ break;
+ case self::HASH_ALGO_MODE2:
+ case self::HASH_ALGO_SSHA256:
+ $pass_hash = hash('sha256', $salt . $pass);
+ break;
+ case self::HASH_ALGO_SSHA512:
+ $pass_hash = hash('sha512', $salt . $pass);
+ break;
+ default:
+ user_error("hash_password: unknown hash algo: $algo", E_USER_ERROR);
+ }
+
+ if ($pass_hash)
+ return "$algo:$pass_hash";
+ else
+ return false;
+ }
}