From eceb7756cfcf117c2a18984291181a84697ed3cd Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 10 Aug 2014 20:29:43 +0200 Subject: Add possibility to keep logged in with form Add an option to keep logged in. Change lifetime of session cookie to 1 year. See https://github.com/marienfressinaud/FreshRSS/issues/465 --- app/Controllers/indexController.php | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 3119073b8..18b99d0df 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -298,6 +298,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { public function formLoginAction () { if (Minz_Request::isPost()) { $ok = false; + $keep_logged_in = Minz_Request::param('keep_logged_in', false); $nonce = Minz_Session::param('nonce'); $username = Minz_Request::param('username', ''); $c = Minz_Request::param('challenge', ''); @@ -312,6 +313,11 @@ class FreshRSS_index_Controller extends Minz_ActionController { if ($ok) { Minz_Session::_param('currentUser', $username); Minz_Session::_param('passwordHash', $s); + if ($keep_logged_in) { + // New cookie with a lifetime of 1 year! + Minz_Session::keepCookie(31536000); + Minz_Session::regenerateID(); + } } else { Minz_Log::record('Password mismatch for user ' . $username . ', nonce=' . $nonce . ', c=' . $c, Minz_Log::WARNING); } @@ -371,6 +377,9 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Session::_param('currentUser'); Minz_Session::_param('mail'); Minz_Session::_param('passwordHash'); + Minz_Session::keepCookie(0); + Minz_Session::regenerateID(); + Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); } } -- cgit v1.2.3 From 93a77f84d45ee4eccda7c837dc08f17360f3de0f Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 10 Aug 2014 21:08:10 +0200 Subject: Change cookie lifetime to 1 month. See https://github.com/marienfressinaud/FreshRSS/issues/465 --- app/Controllers/indexController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 18b99d0df..b907c8eed 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -314,8 +314,8 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Session::_param('currentUser', $username); Minz_Session::_param('passwordHash', $s); if ($keep_logged_in) { - // New cookie with a lifetime of 1 year! - Minz_Session::keepCookie(31536000); + // New cookie with a lifetime of 1 month. + Minz_Session::keepCookie(2592000); Minz_Session::regenerateID(); } } else { -- cgit v1.2.3 From ee1b8f6f72e8c2cbd3e0ad7b4322a4bb6863c028 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 13 Aug 2014 00:09:48 +0200 Subject: Long term cookie to keep session open Token system https://github.com/marienfressinaud/FreshRSS/issues/465 --- app/Controllers/indexController.php | 41 +++++++++++++++++++++++++++++-------- app/FreshRSS.php | 28 ++++++++++++++++++++++--- data/tokens/.gitignore | 1 + data/tokens/index.html | 13 ++++++++++++ lib/Minz/Session.php | 19 ++++++++++++----- 5 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 data/tokens/.gitignore create mode 100644 data/tokens/index.html (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index b907c8eed..dd5b91e47 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -295,10 +295,39 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Session::_param('passwordHash'); } + private static function makeLongTermCookie($username, $passwordHash) { + do { + $token = sha1(Minz_Configuration::salt() . $username . uniqid(mt_rand(), true)); + $tokenFile = DATA_PATH . '/tokens/' . $token . '.txt'; + } while (file_exists($tokenFile)); + if (@file_put_contents($tokenFile, $username . "\t" . $passwordHash) === false) { + return false; + } + $expire = time() + 2629744; //1 month //TODO: Use a configuration instead + Minz_Session::setLongTermCookie('FreshRSS_login', $token, $expire); + Minz_Session::_param('token', $token); + return $token; + } + + private static function deleteLongTermCookie() { + Minz_Session::deleteLongTermCookie('FreshRSS_login'); + $token = Minz_Session::param('token', null); + if (ctype_alnum($token)) { + @unlink(DATA_PATH . '/tokens/' . $token . '.txt'); + } + Minz_Session::_param('token'); + if (rand(0, 10) === 1) { + self::purgeTokens(); + } + } + + private static function purgeTokens() { + //TODO: Delete old token files + } + public function formLoginAction () { if (Minz_Request::isPost()) { $ok = false; - $keep_logged_in = Minz_Request::param('keep_logged_in', false); $nonce = Minz_Session::param('nonce'); $username = Minz_Request::param('username', ''); $c = Minz_Request::param('challenge', ''); @@ -313,10 +342,8 @@ class FreshRSS_index_Controller extends Minz_ActionController { if ($ok) { Minz_Session::_param('currentUser', $username); Minz_Session::_param('passwordHash', $s); - if ($keep_logged_in) { - // New cookie with a lifetime of 1 month. - Minz_Session::keepCookie(2592000); - Minz_Session::regenerateID(); + if (Minz_Request::param('keep_logged_in', false)) { + self::makeLongTermCookie($username, $s); } } else { Minz_Log::record('Password mismatch for user ' . $username . ', nonce=' . $nonce . ', c=' . $c, Minz_Log::WARNING); @@ -377,9 +404,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Session::_param('currentUser'); Minz_Session::_param('mail'); Minz_Session::_param('passwordHash'); - Minz_Session::keepCookie(0); - Minz_Session::regenerateID(); - + self::deleteLongTermCookie(); Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); } } diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 7c333b090..30f711e20 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -20,13 +20,35 @@ class FreshRSS extends Minz_FrontController { $this->loadNotifications(); } + private static function getCredentialsFromLongTermCookie() { + $token = Minz_Session::getLongTermCookie('FreshRSS_login'); + if (!ctype_alnum($token)) { + return array(); + } + $tokenFile = DATA_PATH . '/tokens/' . $token . '.txt'; + $mtime = @filemtime($tokenFile); + if ($mtime + 2629744 < time()) { //1 month //TODO: Use a configuration instead + @unlink($tokenFile); + return array(); //Expired or token does not exist + } + $credentials = @file_get_contents($tokenFile); + return $credentials === false ? array() : explode("\t", $credentials, 2); + } + private function accessControl($currentUser) { if ($currentUser == '') { switch (Minz_Configuration::authType()) { case 'form': - $currentUser = Minz_Configuration::defaultUser(); - Minz_Session::_param('passwordHash'); - $loginOk = false; + $credentials = self::getCredentialsFromLongTermCookie(); + if (isset($credentials[1])) { + $currentUser = trim($credentials[0]); + Minz_Session::_param('passwordHash', trim($credentials[1])); + } + $loginOk = $currentUser != ''; + if (!$loginOk) { + $currentUser = Minz_Configuration::defaultUser(); + Minz_Session::_param('passwordHash'); + } break; case 'http_auth': $currentUser = httpAuthUser(); diff --git a/data/tokens/.gitignore b/data/tokens/.gitignore new file mode 100644 index 000000000..2211df63d --- /dev/null +++ b/data/tokens/.gitignore @@ -0,0 +1 @@ +*.txt diff --git a/data/tokens/index.html b/data/tokens/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/data/tokens/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/lib/Minz/Session.php b/lib/Minz/Session.php index 906acc03c..af4de75bb 100644 --- a/lib/Minz/Session.php +++ b/lib/Minz/Session.php @@ -65,11 +65,8 @@ class Minz_Session { * @param $l la durée de vie */ public static function keepCookie($l) { - $cookie_dir = dirname( - empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI'] - ) . '/'; - session_set_cookie_params($l, $cookie_dir, $_SERVER['HTTP_HOST'], - false, true); + $cookie_dir = empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI']; + session_set_cookie_params($l, $cookie_dir, '', false, true); } @@ -81,4 +78,16 @@ class Minz_Session { session_regenerate_id(true); } + public static function deleteLongTermCookie($name) { + setcookie($name, '', 1, '', '', false, true); + } + + public static function setLongTermCookie($name, $value, $expire) { + setcookie($name, $value, $expire, '', '', false, true); + } + + public static function getLongTermCookie($name) { + return isset($_COOKIE[$name]) ? $_COOKIE[$name] : null; + } + } -- cgit v1.2.3 From 359ccc8e4c20a60506c680e5054dbe8416fef4a9 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 13 Aug 2014 00:25:52 +0200 Subject: Long term cookie minor change https://github.com/marienfressinaud/FreshRSS/issues/465 --- app/Controllers/indexController.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index dd5b91e47..834db496c 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -344,6 +344,8 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Session::_param('passwordHash', $s); if (Minz_Request::param('keep_logged_in', false)) { self::makeLongTermCookie($username, $s); + } else { + self::deleteLongTermCookie(); } } else { Minz_Log::record('Password mismatch for user ' . $username . ', nonce=' . $nonce . ', c=' . $c, Minz_Log::WARNING); -- cgit v1.2.3 From 5c2f3349fa4341533aad6294c896b32c4befd58f Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 13 Aug 2014 20:09:23 +0200 Subject: Long term cookie: purge old tokens https://github.com/marienfressinaud/FreshRSS/issues/465 --- app/Controllers/indexController.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 834db496c..9202f2b85 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -322,7 +322,12 @@ class FreshRSS_index_Controller extends Minz_ActionController { } private static function purgeTokens() { - //TODO: Delete old token files + $oldest = time() - 2629744; //1 month //TODO: Use a configuration instead + foreach (new DirectoryIterator(DATA_PATH . '/tokens/') as $fileInfo) { + if ($fileInfo->getExtension() === 'txt' && $fileInfo->getMTime() < $oldest) { + @unlink($fileInfo->getPathname()); + } + } } public function formLoginAction () { -- cgit v1.2.3 From fb664c2405d6efd3d2581c9613fef0e7063ef21b Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 23 Aug 2014 11:04:17 +0200 Subject: Correction pagination bug for read articles https://github.com/marienfressinaud/FreshRSS/issues/587 --- app/Controllers/indexController.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 9202f2b85..b0b051119 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -76,14 +76,14 @@ class FreshRSS_index_Controller extends Minz_ActionController { ); // On récupère les différents éléments de filtrage - $this->view->state = $state = Minz_Request::param ('state', $this->view->conf->default_view); + $this->view->state = Minz_Request::param('state', $this->view->conf->default_view); $state_param = Minz_Request::param ('state', null); $filter = Minz_Request::param ('search', ''); $this->view->order = $order = Minz_Request::param ('order', $this->view->conf->sort_order); $nb = Minz_Request::param ('nb', $this->view->conf->posts_per_page); $first = Minz_Request::param ('next', ''); - if ($state === FreshRSS_Entry::STATE_NOT_READ) { //Any unread article in this category at all? + if ($this->view->state === FreshRSS_Entry::STATE_NOT_READ) { //Any unread article in this category at all? switch ($getType) { case 'a': $hasUnread = $this->view->nb_not_read > 0; @@ -104,7 +104,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { break; } if (!$hasUnread && ($state_param === null)) { - $this->view->state = $state = FreshRSS_Entry::STATE_ALL; + $this->view->state = FreshRSS_Entry::STATE_ALL; } } @@ -117,11 +117,11 @@ class FreshRSS_index_Controller extends Minz_ActionController { $keepHistoryDefault = $this->view->conf->keep_history_default; try { - $entries = $entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter, $date_min, true, $keepHistoryDefault); + $entries = $entryDAO->listWhere($getType, $getId, $this->view->state, $order, $nb + 1, $first, $filter, $date_min, true, $keepHistoryDefault); // Si on a récupéré aucun article "non lus" // on essaye de récupérer tous les articles - if ($state === FreshRSS_Entry::STATE_NOT_READ && empty($entries) && ($state_param === null) && ($filter == '')) { + if ($this->view->state === FreshRSS_Entry::STATE_NOT_READ && empty($entries) && ($state_param === null) && ($filter == '')) { Minz_Log::record('Conflicting information about nbNotRead!', Minz_Log::DEBUG); $feedDAO = FreshRSS_Factory::createFeedDao(); try { @@ -132,6 +132,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $this->view->state = FreshRSS_Entry::STATE_ALL; $entries = $entryDAO->listWhere($getType, $getId, $this->view->state, $order, $nb, $first, $filter, $date_min, true, $keepHistoryDefault); } + Minz_Request::_param('state', $this->view->state); if (count($entries) <= $nb) { $this->view->nextId = ''; -- cgit v1.2.3