summaryrefslogtreecommitdiff
path: root/classes
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2021-02-26 19:16:17 +0300
committerAndrew Dolgov <[email protected]>2021-02-26 19:16:17 +0300
commit3fd785654372d493c031d9b541ab33a881023a32 (patch)
tree0a76cb410217074378de3d7012b95754cd3c7e6f /classes
parentbc4475b6698f5a74e475674aa7af43253c459892 (diff)
* switch to composer for qrcode and otp dependencies
* move most OTP-related stuff into userhelper * remove old phpqrcode and otphp libraries
Diffstat (limited to 'classes')
-rw-r--r--classes/pref/prefs.php103
-rwxr-xr-xclasses/rpc.php2
-rw-r--r--classes/userhelper.php79
3 files changed, 96 insertions, 88 deletions
diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php
index ba63d76b3..9eb27eb85 100644
--- a/classes/pref/prefs.php
+++ b/classes/pref/prefs.php
@@ -1,4 +1,5 @@
<?php
+use chillerlan\QRCode;
class Pref_Prefs extends Handler_Protected {
@@ -313,7 +314,7 @@ class Pref_Prefs extends Handler_Protected {
$authenticator = false;
}
- $otp_enabled = $this->is_otp_enabled();
+ $otp_enabled = UserHelper::is_otp_enabled($_SESSION["uid"]);
if ($authenticator && method_exists($authenticator, "change_password")) {
?>
@@ -406,20 +407,8 @@ class Pref_Prefs extends Handler_Protected {
<?php
}
- private function is_otp_enabled() {
- $sth = $this->pdo->prepare("SELECT otp_enabled FROM ttrss_users
- WHERE id = ?");
- $sth->execute([$_SESSION["uid"]]);
-
- if ($row = $sth->fetch()) {
- return sql_bool_to_bool($row["otp_enabled"]);
- }
-
- return false;
- }
-
private function index_auth_2fa() {
- $otp_enabled = $this->is_otp_enabled();
+ $otp_enabled = UserHelper::is_otp_enabled($_SESSION["uid"]);
if ($_SESSION["auth_module"] == "auth_internal") {
if ($otp_enabled) {
@@ -469,14 +458,13 @@ class Pref_Prefs extends Handler_Protected {
if (function_exists("imagecreatefromstring")) {
print "<h3>" . __("Scan the following code by the Authenticator application or copy the key manually") . "</h3>";
- $csrf_token_hash = sha1($_SESSION["csrf_token"]);
- print "<img alt='otp qr-code' src='backend.php?op=pref-prefs&method=otpqrcode&csrf_token_hash=$csrf_token_hash'>";
+ print "<img src=".($this->_get_otp_qrcode_img()).">";
} else {
print_error("PHP GD functions are required to generate QR codes.");
print "<h3>" . __("Use the following OTP key with a compatible Authenticator application") . "</h3>";
}
- $otp_secret = $this->otpsecret();
+ $otp_secret = UserHelper::get_otp_secret($_SESSION["uid"]);
?>
<form dojoType='dijit.form.Form'>
@@ -990,90 +978,39 @@ class Pref_Prefs extends Handler_Protected {
$_SESSION["prefs_show_advanced"] = !$_SESSION["prefs_show_advanced"];
}
- function otpsecret() {
- $sth = $this->pdo->prepare("SELECT salt, otp_enabled
- FROM ttrss_users
- WHERE id = ?");
- $sth->execute([$_SESSION['uid']]);
+ function _get_otp_qrcode_img() {
+ $secret = UserHelper::get_otp_secret($_SESSION["uid"]);
+ $login = UserHelper::get_login_by_id($_SESSION["uid"]);
- if ($row = $sth->fetch()) {
- $otp_enabled = sql_bool_to_bool($row["otp_enabled"]);
+ if ($secret && $login) {
+ $qrcode = new \chillerlan\QRCode\QRCode();
- if (!$otp_enabled) {
- $base32 = new \OTPHP\Base32();
- $secret = $base32->encode(mb_substr(sha1($row["salt"]), 0, 12), false);
+ $otpurl = "otpauth://totp/".urlencode($login)."?secret=$secret&issuer=".urlencode("Tiny Tiny RSS");
- return $secret;
- }
+ return $qrcode->render($otpurl);
}
return false;
}
- function otpqrcode() {
- $csrf_token_hash = clean($_REQUEST["csrf_token_hash"]);
-
- if (sha1($_SESSION["csrf_token"]) === $csrf_token_hash) {
- require_once "lib/phpqrcode/phpqrcode.php";
-
- $sth = $this->pdo->prepare("SELECT login
- FROM ttrss_users
- WHERE id = ?");
- $sth->execute([$_SESSION['uid']]);
-
- if ($row = $sth->fetch()) {
- $secret = $this->otpsecret();
- $login = $row['login'];
-
- if ($secret) {
- QRcode::png("otpauth://totp/".urlencode($login).
- "?secret=$secret&issuer=".urlencode("Tiny Tiny RSS"));
- }
- }
- } else {
- header("Content-Type: text/json");
- print Errors::to_json(Errors::E_UNAUTHORIZED);
- }
- }
-
function otpenable() {
-
$password = clean($_REQUEST["password"]);
- $otp = clean($_REQUEST["otp"]);
+ $otp_check = clean($_REQUEST["otp"]);
$authenticator = PluginHost::getInstance()->get_plugin($_SESSION["auth_module"]);
if ($authenticator->check_password($_SESSION["uid"], $password)) {
-
- $secret = $this->otpsecret();
-
- if ($secret) {
-
- $base32 = new \OTPHP\Base32();
-
- $topt = new \OTPHP\TOTP($secret);
-
- $otp_check = $topt->now();
-
- if ($otp == $otp_check) {
- $sth = $this->pdo->prepare("UPDATE ttrss_users
- SET otp_enabled = true WHERE id = ?");
-
- $sth->execute([$_SESSION['uid']]);
-
- print "OK";
- } else {
- print "ERROR:".__("Incorrect one time password");
- }
+ if (UserHelper::enable_otp($_SESSION["uid"], $otp_check)) {
+ print "OK";
+ } else {
+ print "ERROR:".__("Incorrect one time password");
}
-
} else {
print "ERROR:".__("Incorrect password");
}
-
}
- static function isdefaultpassword() {
+ static function _is_default_password() {
$authenticator = PluginHost::getInstance()->get_plugin($_SESSION["auth_module"]);
if ($authenticator &&
@@ -1116,9 +1053,7 @@ class Pref_Prefs extends Handler_Protected {
"message" => $message]);
}
- $sth = $this->pdo->prepare("UPDATE ttrss_users SET otp_enabled = false WHERE
- id = ?");
- $sth->execute([$_SESSION['uid']]);
+ UserHelper::disable_otp($_SESSION["uid"]);
print "OK";
} else {
diff --git a/classes/rpc.php b/classes/rpc.php
index 630ea50cb..016a3bd03 100755
--- a/classes/rpc.php
+++ b/classes/rpc.php
@@ -439,7 +439,7 @@ class RPC extends Handler_Protected {
$params["default_view_limit"] = (int) get_pref(Prefs::_DEFAULT_VIEW_LIMIT);
$params["default_view_order_by"] = get_pref(Prefs::_DEFAULT_VIEW_ORDER_BY);
$params["bw_limit"] = (int) $_SESSION["bw_limit"];
- $params["is_default_pw"] = Pref_Prefs::isdefaultpassword();
+ $params["is_default_pw"] = Pref_Prefs::_is_default_password();
$params["label_base_index"] = LABEL_BASE_INDEX;
$theme = get_pref(Prefs::USER_CSS_THEME);
diff --git a/classes/userhelper.php b/classes/userhelper.php
index ca673cf58..f366682ef 100644
--- a/classes/userhelper.php
+++ b/classes/userhelper.php
@@ -1,4 +1,6 @@
<?php
+use OTPHP\TOTP;
+
class UserHelper {
static function authenticate(string $login = null, string $password = null, bool $check_only = false, string $service = null) {
@@ -141,14 +143,29 @@ class UserHelper {
}
- static function get_user_ip() {
+ static function get_user_ip() : string {
foreach (["HTTP_X_REAL_IP", "REMOTE_ADDR"] as $hdr) {
if (isset($_SERVER[$hdr]))
return $_SERVER[$hdr];
}
+
+ return null;
+ }
+
+ static function get_login_by_id(int $id) : string {
+ $pdo = Db::pdo();
+
+ $sth = $pdo->prepare("SELECT login FROM ttrss_users WHERE id = ?");
+ $sth->execute([$id]);
+
+ if ($row = $sth->fetch()) {
+ return $row["login"];
+ }
+
+ return null;
}
- static function find_user_by_login(string $login) {
+ static function find_user_by_login(string $login) : int {
$pdo = Db::pdo();
$sth = $pdo->prepare("SELECT id FROM ttrss_users WHERE
@@ -159,7 +176,7 @@ class UserHelper {
return $row["id"];
}
- return false;
+ return null;
}
static function logout() {
@@ -203,4 +220,60 @@ class UserHelper {
}
}
+
+ 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 {
+ $sth = Db::pdo()->prepare("UPDATE ttrss_users SET otp_enabled = false WHERE id = ?");
+ $sth->execute([$owner_uid]);
+
+ return true;
+ }
+
+ static function enable_otp(int $owner_uid, int $otp_check) : bool {
+ $secret = self::get_otp_secret($owner_uid);
+
+ if ($secret) {
+ $otp = TOTP::create($secret);
+
+ if ($otp->now() == $otp_check) {
+ $sth = Db::pdo()->prepare("UPDATE ttrss_users
+ SET otp_enabled = true WHERE id = ?");
+
+ $sth->execute([$owner_uid]);
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ static function is_otp_enabled(int $owner_uid) : bool {
+ $sth = Db::pdo()->prepare("SELECT otp_enabled FROM ttrss_users WHERE id = ?");
+ $sth->execute([$owner_uid]);
+
+ if ($row = $sth->fetch()) {
+ return sql_bool_to_bool($row["otp_enabled"]);
+ }
+
+ return false;
+ }
+
+ static function get_otp_secret(int $owner_uid, bool $show_if_enabled = false) : string {
+ $sth = Db::pdo()->prepare("SELECT salt, otp_enabled FROM ttrss_users WHERE id = ?");
+ $sth->execute([$owner_uid]);
+
+ if ($row = $sth->fetch()) {
+ if (!sql_bool_to_bool($row["otp_enabled"]) || $show_if_enabled) {
+ return \ParagonIE\ConstantTime\Base32::encodeUpperUnpadded(mb_substr(sha1($row["salt"]), 0, 12));
+ }
+ }
+
+ return null;
+ }
}