Merge branch 'refactor-authentication' into dev

pull/664/head
Marien Fressinaud 10 years ago
commit 99cdd2a0ad
  1. 250
      app/Controllers/authController.php
  2. 2
      app/Controllers/categoryController.php
  3. 4
      app/Controllers/configureController.php
  4. 2
      app/Controllers/entryController.php
  5. 2
      app/Controllers/feedController.php
  6. 2
      app/Controllers/importExportController.php
  7. 268
      app/Controllers/indexController.php
  8. 2
      app/Controllers/statsController.php
  9. 2
      app/Controllers/subscriptionController.php
  10. 2
      app/Controllers/updateController.php
  11. 10
      app/Controllers/usersController.php
  12. 143
      app/FreshRSS.php
  13. 235
      app/Models/Auth.php
  14. 5
      app/layout/aside_configure.phtml
  15. 6
      app/layout/aside_flux.phtml
  16. 54
      app/layout/header.phtml
  17. 4
      app/layout/nav_menu.phtml
  18. 24
      app/views/auth/formLogin.phtml
  19. 0
      app/views/auth/logout.phtml
  20. 24
      app/views/auth/personaLogin.phtml
  21. 2
      app/views/auth/reset.phtml
  22. 2
      app/views/configure/archiving.phtml
  23. 13
      app/views/helpers/javascript_vars.phtml
  24. 6
      app/views/helpers/view/normal_view.phtml
  25. 2
      app/views/index/index.phtml
  26. 1
      app/views/index/login.phtml
  27. 1
      app/views/index/logout.phtml
  28. 6
      app/views/users/index.phtml
  29. 3
      lib/Minz/Configuration.php
  30. 65
      p/scripts/main.js
  31. 76
      p/scripts/persona.js

@ -0,0 +1,250 @@
<?php
/**
* This controller handles action about authentication.
*/
class FreshRSS_auth_Controller extends Minz_ActionController {
/**
* This action handles the login page.
*
* It forwards to the correct login page (form or Persona) or main page if
* the user is already connected.
*/
public function loginAction() {
if (FreshRSS_Auth::hasAccess()) {
Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true);
}
$auth_type = Minz_Configuration::authType();
switch ($auth_type) {
case 'form':
Minz_Request::forward(array('c' => 'auth', 'a' => 'formLogin'));
break;
case 'persona':
Minz_Request::forward(array('c' => 'auth', 'a' => 'personaLogin'));
break;
case 'http_auth':
case 'none':
// It should not happened!
Minz_Error::error(404);
default:
// TODO load plugin instead
Minz_Error::error(404);
}
}
/**
* This action handles form login page.
*
* If this action is reached through a POST request, username and password
* are compared to login the current user.
*
* Parameters are:
* - nonce (default: false)
* - username (default: '')
* - challenge (default: '')
* - keep_logged_in (default: false)
*/
public function formLoginAction() {
invalidateHttpCache();
$file_mtime = @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js');
Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . $file_mtime));
if (Minz_Request::isPost()) {
$nonce = Minz_Session::param('nonce');
$username = Minz_Request::param('username', '');
$challenge = Minz_Request::param('challenge', '');
try {
$conf = new FreshRSS_Configuration($username);
} catch(Minz_Exception $e) {
// $username is not a valid user, nor the configuration file!
Minz_Log::warning('Login failure: ' . $e->getMessage());
Minz_Request::bad(_t('invalid_login'),
array('c' => 'auth', 'a' => 'login'));
}
$ok = FreshRSS_FormAuth::checkCredentials(
$username, $conf->passwordHash, $nonce, $challenge
);
if ($ok) {
// Set session parameter to give access to the user.
Minz_Session::_param('currentUser', $username);
Minz_Session::_param('passwordHash', $conf->passwordHash);
FreshRSS_Auth::giveAccess();
// Set cookie parameter if nedded.
if (Minz_Request::param('keep_logged_in')) {
FreshRSS_FormAuth::makeCookie($username, $conf->passwordHash);
} else {
FreshRSS_FormAuth::deleteCookie();
}
// All is good, go back to the index.
Minz_Request::good(_t('login'),
array('c' => 'index', 'a' => 'index'));
} else {
Minz_Log::warning('Password mismatch for' .
' user=' . $username .
', nonce=' . $nonce .
', c=' . $challenge);
Minz_Request::bad(_t('invalid_login'),
array('c' => 'auth', 'a' => 'login'));
}
}
}
/**
* This action handles Persona login page.
*
* If this action is reached through a POST request, assertion from Persona
* is verificated and user connected if all is ok.
*
* Parameter is:
* - assertion (default: false)
*
* @todo: Persona system should be moved to a plugin
*/
public function personaLoginAction() {
$this->view->res = false;
if (Minz_Request::isPost()) {
$this->view->_useLayout(false);
$assert = Minz_Request::param('assertion');
$url = 'https://verifier.login.persona.org/verify';
$params = 'assertion=' . $assert . '&audience=' .
urlencode(Minz_Url::display(null, 'php', true));
$ch = curl_init();
$options = array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_POST => 2,
CURLOPT_POSTFIELDS => $params
);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
curl_close($ch);
$res = json_decode($result, true);
$login_ok = false;
$reason = '';
if ($res['status'] === 'okay') {
$email = filter_var($res['email'], FILTER_VALIDATE_EMAIL);
if ($email != '') {
$persona_file = DATA_PATH . '/persona/' . $email . '.txt';
if (($current_user = @file_get_contents($persona_file)) !== false) {
$current_user = trim($current_user);
try {
$conf = new FreshRSS_Configuration($current_user);
$login_ok = strcasecmp($email, $conf->mail_login) === 0;
} catch (Minz_Exception $e) {
//Permission denied or conf file does not exist
$reason = 'Invalid configuration for user ' .
'[' . $current_user . '] ' . $e->getMessage();
}
}
} else {
$reason = 'Invalid email format [' . $res['email'] . ']';
}
} else {
$reason = $res['reason'];
}
if ($login_ok) {
Minz_Session::_param('currentUser', $current_user);
Minz_Session::_param('mail', $email);
FreshRSS_Auth::giveAccess();
invalidateHttpCache();
} else {
Minz_Log::error($reason);
$res = array();
$res['status'] = 'failure';
$res['reason'] = _t('invalid_login');
}
header('Content-Type: application/json; charset=UTF-8');
$this->view->res = $res;
}
}
/**
* This action removes all accesses of the current user.
*/
public function logoutAction() {
invalidateHttpCache();
FreshRSS_Auth::removeAccess();
Minz_Request::good(_t('disconnected'),
array('c' => 'index', 'a' => 'index'));
}
/**
* This action resets the authentication system.
*
* After reseting, form auth is set by default.
*/
public function resetAction() {
Minz_View::prependTitle(_t('auth_reset') . ' · ');
Minz_View::appendScript(Minz_Url::display(
'/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js')
));
$this->view->no_form = false;
// Enable changement of auth only if Persona!
if (Minz_Configuration::authType() != 'persona') {
$this->view->message = array(
'status' => 'bad',
'title' => _t('damn'),
'body' => _t('auth_not_persona')
);
$this->view->no_form = true;
return;
}
$conf = new FreshRSS_Configuration(Minz_Configuration::defaultUser());
// Admin user must have set its master password.
if (!$conf->passwordHash) {
$this->view->message = array(
'status' => 'bad',
'title' => _t('damn'),
'body' => _t('auth_no_password_set')
);
$this->view->no_form = true;
return;
}
invalidateHttpCache();
if (Minz_Request::isPost()) {
$nonce = Minz_Session::param('nonce');
$username = Minz_Request::param('username', '');
$challenge = Minz_Request::param('challenge', '');
$ok = FreshRSS_FormAuth::checkCredentials(
$username, $conf->passwordHash, $nonce, $challenge
);
if ($ok) {
Minz_Configuration::_authType('form');
$ok = Minz_Configuration::writeFile();
if ($ok) {
Minz_Request::good(_t('auth_form_set'));
} else {
Minz_Request::bad(_t('auth_form_not_set'),
array('c' => 'auth', 'a' => 'reset'));
}
} else {
Minz_Log::warning('Password mismatch for' .
' user=' . $username .
', nonce=' . $nonce .
', c=' . $challenge);
Minz_Request::bad(_t('invalid_login'),
array('c' => 'auth', 'a' => 'reset'));
}
}
}
}

@ -12,7 +12,7 @@ class FreshRSS_category_Controller extends Minz_ActionController {
*
*/
public function firstAction() {
if (!$this->view->loginOk) {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(
403,
array('error' => array(_t('access_denied')))

@ -10,7 +10,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
* underlying framework.
*/
public function firstAction() {
if (!$this->view->loginOk) {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(
403,
array('error' => array(_t('access_denied')))
@ -229,7 +229,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
$this->view->nb_total = $entryDAO->count();
$this->view->size_user = $entryDAO->size();
if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) {
if (FreshRSS_Auth::hasAccess('admin')) {
$this->view->size_total = $entryDAO->size(true);
}
}

@ -10,7 +10,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController {
* underlying framework.
*/
public function firstAction() {
if (!$this->view->loginOk) {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(
403,
array('error' => array(_t('access_denied')))

@ -10,7 +10,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
* underlying framework.
*/
public function firstAction() {
if (!$this->view->loginOk) {
if (!FreshRSS_Auth::hasAccess()) {
// Token is useful in the case that anonymous refresh is forbidden
// and CRON task cannot be used with php command so the user can
// set a CRON task to refresh his feeds by using token inside url

@ -10,7 +10,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
* underlying framework.
*/
public function firstAction() {
if (!$this->view->loginOk) {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(
403,
array('error' => array(_t('access_denied')))

@ -8,7 +8,7 @@ class FreshRSS_index_Controller extends Minz_ActionController {
$token = $this->view->conf->token;
// check if user is logged in
if (!$this->view->loginOk && !Minz_Configuration::allowAnonymous()) {
if (!FreshRSS_Auth::hasAccess() && !Minz_Configuration::allowAnonymous()) {
$token_param = Minz_Request::param('token', '');
$token_is_ok = ($token != '' && $token === $token_param);
if ($output === 'rss' && !$token_is_ok) {
@ -20,7 +20,7 @@ class FreshRSS_index_Controller extends Minz_ActionController {
} elseif ($output !== 'rss') {
// "hard" redirection is not required, just ask dispatcher to
// forward to the login form without 302 redirection
Minz_Request::forward(array('c' => 'index', 'a' => 'formLogin'));
Minz_Request::forward(array('c' => 'auth', 'a' => 'login'));
return;
}
}
@ -207,7 +207,7 @@ class FreshRSS_index_Controller extends Minz_ActionController {
}
public function logsAction() {
if (!$this->view->loginOk) {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(
403,
array('error' => array(_t('access_denied')))
@ -228,266 +228,4 @@ class FreshRSS_index_Controller extends Minz_ActionController {
$this->view->logsPaginator->_nbItemsPerPage(50);
$this->view->logsPaginator->_currentPage($page);
}
public function loginAction() {
$this->view->_useLayout(false);
$url = 'https://verifier.login.persona.org/verify';
$assert = Minz_Request::param('assertion');
$params = 'assertion=' . $assert . '&audience=' .
urlencode(Minz_Url::display(null, 'php', true));
$ch = curl_init();
$options = array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_POST => 2,
CURLOPT_POSTFIELDS => $params
);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
curl_close($ch);
$res = json_decode($result, true);
$loginOk = false;
$reason = '';
if ($res['status'] === 'okay') {
$email = filter_var($res['email'], FILTER_VALIDATE_EMAIL);
if ($email != '') {
$personaFile = DATA_PATH . '/persona/' . $email . '.txt';
if (($currentUser = @file_get_contents($personaFile)) !== false) {
$currentUser = trim($currentUser);
if (ctype_alnum($currentUser)) {
try {
$this->conf = new FreshRSS_Configuration($currentUser);
$loginOk = strcasecmp($email, $this->conf->mail_login) === 0;
} catch (Minz_Exception $e) {
$reason = 'Invalid configuration for user [' . $currentUser . ']! ' . $e->getMessage(); //Permission denied or conf file does not exist
}
} else {
$reason = 'Invalid username format [' . $currentUser . ']!';
}
}
} else {
$reason = 'Invalid email format [' . $res['email'] . ']!';
}
}
if ($loginOk) {
Minz_Session::_param('currentUser', $currentUser);
Minz_Session::_param('mail', $email);
$this->view->loginOk = true;
invalidateHttpCache();
} else {
$res = array();
$res['status'] = 'failure';
$res['reason'] = $reason == '' ? _t('invalid_login') : $reason;
Minz_Log::warning('Persona: ' . $res['reason']);
}
header('Content-Type: application/json; charset=UTF-8');
$this->view->res = json_encode($res);
}
public function logoutAction() {
$this->view->_useLayout(false);
invalidateHttpCache();
Minz_Session::_param('currentUser');
Minz_Session::_param('mail');
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() {
$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() {
if ($this->view->loginOk) {
Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true);
}
if (Minz_Request::isPost()) {
$ok = false;
$nonce = Minz_Session::param('nonce');
$username = Minz_Request::param('username', '');
$c = Minz_Request::param('challenge', '');
if (ctype_alnum($username) && ctype_graph($c) && ctype_alnum($nonce)) {
if (!function_exists('password_verify')) {
include_once(LIB_PATH . '/password_compat.php');
}
try {
$conf = new FreshRSS_Configuration($username);
$s = $conf->passwordHash;
$ok = password_verify($nonce . $s, $c);
if ($ok) {
Minz_Session::_param('currentUser', $username);
Minz_Session::_param('passwordHash', $s);
if (Minz_Request::param('keep_logged_in', false)) {
self::makeLongTermCookie($username, $s);
} else {
self::deleteLongTermCookie();
}
} else {
Minz_Log::warning('Password mismatch for user ' . $username . ', nonce=' . $nonce . ', c=' . $c);
}
} catch (Minz_Exception $me) {
Minz_Log::warning('Login failure: ' . $me->getMessage());
}
} else {
Minz_Log::debug('Invalid credential parameters: user=' . $username . ' challenge=' . $c . ' nonce=' . $nonce);
}
if (!$ok) {
$notif = array(
'type' => 'bad',
'content' => _t('invalid_login')
);
Minz_Session::_param('notification', $notif);
}
$this->view->_useLayout(false);
Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true);
} elseif (Minz_Configuration::unsafeAutologinEnabled() && isset($_GET['u']) && isset($_GET['p'])) {
Minz_Session::_param('currentUser');
Minz_Session::_param('mail');
Minz_Session::_param('passwordHash');
$username = ctype_alnum($_GET['u']) ? $_GET['u'] : '';
$passwordPlain = $_GET['p'];
Minz_Request::_param('p'); //Discard plain-text password ASAP
$_GET['p'] = '';
if (!function_exists('password_verify')) {
include_once(LIB_PATH . '/password_compat.php');
}
try {
$conf = new FreshRSS_Configuration($username);
$s = $conf->passwordHash;
$ok = password_verify($passwordPlain, $s);
unset($passwordPlain);
if ($ok) {
Minz_Session::_param('currentUser', $username);
Minz_Session::_param('passwordHash', $s);
} else {
Minz_Log::warning('Unsafe password mismatch for user ' . $username);
}
} catch (Minz_Exception $me) {
Minz_Log::warning('Unsafe login failure: ' . $me->getMessage());
}
Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true);
} elseif (!Minz_Configuration::canLogIn()) {
Minz_Error::error(
403,
array('error' => array(_t('access_denied')))
);
}
invalidateHttpCache();
}
public function formLogoutAction() {
$this->view->_useLayout(false);
invalidateHttpCache();
Minz_Session::_param('currentUser');
Minz_Session::_param('mail');
Minz_Session::_param('passwordHash');
self::deleteLongTermCookie();
Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true);
}
public function resetAuthAction() {
Minz_View::prependTitle(_t('auth_reset') . ' · ');
Minz_View::appendScript(Minz_Url::display(
'/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js')
));
$this->view->no_form = false;
// Enable changement of auth only if Persona!
if (Minz_Configuration::authType() != 'persona') {
$this->view->message = array(
'status' => 'bad',
'title' => _t('damn'),
'body' => _t('auth_not_persona')
);
$this->view->no_form = true;
return;
}
$conf = new FreshRSS_Configuration(Minz_Configuration::defaultUser());
// Admin user must have set its master password.
if (!$conf->passwordHash) {
$this->view->message = array(
'status' => 'bad',
'title' => _t('damn'),
'body' => _t('auth_no_password_set')
);
$this->view->no_form = true;
return;
}
invalidateHttpCache();
if (Minz_Request::isPost()) {
$nonce = Minz_Session::param('nonce');
$username = Minz_Request::param('username', '');
$c = Minz_Request::param('challenge', '');
if (!(ctype_alnum($username) && ctype_graph($c) && ctype_alnum($nonce))) {
Minz_Log::debug('Invalid credential parameters:' .
' user=' . $username .
' challenge=' . $c .
' nonce=' . $nonce);
Minz_Request::bad(_t('invalid_login'),
array('c' => 'index', 'a' => 'resetAuth'));
}
if (!function_exists('password_verify')) {
include_once(LIB_PATH . '/password_compat.php');
}
$s = $conf->passwordHash;
$ok = password_verify($nonce . $s, $c);
if ($ok) {
Minz_Configuration::_authType('form');
$ok = Minz_Configuration::writeFile();
if ($ok) {
Minz_Request::good(_t('auth_form_set'));
} else {
Minz_Request::bad(_t('auth_form_not_set'),
array('c' => 'index', 'a' => 'resetAuth'));
}
} else {
Minz_Log::debug('Password mismatch for user ' . $username .
', nonce=' . $nonce . ', c=' . $c);
Minz_Request::bad(_t('invalid_login'),
array('c' => 'index', 'a' => 'resetAuth'));
}
}
}
}

@ -118,7 +118,7 @@ class FreshRSS_stats_Controller extends Minz_ActionController {
* underlying framework.
*/
public function firstAction() {
if (!$this->view->loginOk) {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(
403, array('error' => array(_t('access_denied')))
);

@ -10,7 +10,7 @@ class FreshRSS_subscription_Controller extends Minz_ActionController {
* underlying framework.
*/
public function firstAction() {
if (!$this->view->loginOk) {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(
403,
array('error' => array(_t('access_denied')))

@ -3,7 +3,7 @@
class FreshRSS_update_Controller extends Minz_ActionController {
public function firstAction() {
$current_user = Minz_Session::param('currentUser', '');
if (!$this->view->loginOk && Minz_Configuration::isAdmin($current_user)) {
if (!FreshRSS_Auth::hasAccess('admin')) {
Minz_Error::error(
403,
array('error' => array(_t('access_denied')))

@ -5,7 +5,7 @@ class FreshRSS_users_Controller extends Minz_ActionController {
const BCRYPT_COST = 9; //Will also have to be computed client side on mobile devices, so do not use a too high cost
public function firstAction() {
if (!$this->view->loginOk) {
if (!FreshRSS_Auth::hasAccess()) {
Minz_Error::error(
403,
array('error' => array(_t('access_denied')))
@ -51,7 +51,7 @@ class FreshRSS_users_Controller extends Minz_ActionController {
$this->view->conf->_apiPasswordHash($passwordHash);
}
if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) {
if (FreshRSS_Auth::hasAccess('admin')) {
$this->view->conf->_mail_login(Minz_Request::param('mail_login', '', true));
}
$email = $this->view->conf->mail_login;
@ -65,7 +65,7 @@ class FreshRSS_users_Controller extends Minz_ActionController {
$ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false);
}
if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) {
if (FreshRSS_Auth::hasAccess('admin')) {
$current_token = $this->view->conf->token;
$token = Minz_Request::param('token', $current_token);
$this->view->conf->_token($token);
@ -105,7 +105,7 @@ class FreshRSS_users_Controller extends Minz_ActionController {
}
public function createAction() {
if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) {
if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) {
$db = Minz_Configuration::dataBase();
require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');
@ -177,7 +177,7 @@ class FreshRSS_users_Controller extends Minz_ActionController {
}
public function deleteAction() {
if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) {
if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) {
$db = Minz_Configuration::dataBase();
require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');

@ -4,130 +4,33 @@ class FreshRSS extends Minz_FrontController {
if (!isset($_SESSION)) {
Minz_Session::init('FreshRSS');
}
$loginOk = $this->accessControl(Minz_Session::param('currentUser', ''));
FreshRSS_Auth::init();
$this->loadConfiguration();
$this->loadParamsView();
if (Minz_Request::isPost() && !is_referer_from_same_domain()) {
$loginOk = false; //Basic protection against XSRF attacks
//Basic protection against XSRF attacks
FreshRSS_Auth::removeAccess();
Minz_Error::error(
403,
array('error' => array(_t('access_denied') . ' [HTTP_REFERER=' .
htmlspecialchars(empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']) . ']'))
htmlspecialchars(empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']) . ']'))
);
}
Minz_View::_param('loginOk', $loginOk);
$this->loadStylesAndScripts($loginOk); //TODO: Do not load that when not needed, e.g. some Ajax requests
$this->loadStylesAndScripts();
$this->loadNotifications();
$this->loadExtensions();
}
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':
$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();
$loginOk = $currentUser != '';
break;
case 'persona':
$loginOk = false;
$email = filter_var(Minz_Session::param('mail'), FILTER_VALIDATE_EMAIL);
if ($email != '') { //TODO: Remove redundancy with indexController
$personaFile = DATA_PATH . '/persona/' . $email . '.txt';
if (($currentUser = @file_get_contents($personaFile)) !== false) {
$currentUser = trim($currentUser);
$loginOk = true;
}
}
if (!$loginOk) {
$currentUser = Minz_Configuration::defaultUser();
}
break;
case 'none':
$currentUser = Minz_Configuration::defaultUser();
$loginOk = true;
break;
default:
$currentUser = Minz_Configuration::defaultUser();
$loginOk = false;
break;
}
} else {
$loginOk = true;
}
if (!ctype_alnum($currentUser)) {
Minz_Session::_param('currentUser', '');
die('Invalid username [' . $currentUser . ']!');
}
private function loadConfiguration() {
$current_user = Minz_Session::param('currentUser');
try {
$this->conf = new FreshRSS_Configuration($currentUser);
$this->conf = new FreshRSS_Configuration($current_user);
Minz_View::_param('conf', $this->conf);
Minz_Session::_param('currentUser', $currentUser);
} catch (Minz_Exception $me) {
$loginOk = false;
try {
$this->conf = new FreshRSS_Configuration(Minz_Configuration::defaultUser());
Minz_Session::_param('currentUser', Minz_Configuration::defaultUser());
Minz_View::_param('conf', $this->conf);
$notif = array(
'type' => 'bad',
'content' => 'Invalid configuration for user [' . $currentUser . ']!',
);
Minz_Session::_param('notification', $notif);
Minz_Log::warning($notif['content'] . ' ' . $me->getMessage());
Minz_Session::_param('currentUser', '');
} catch (Exception $e) {
die($e->getMessage());
}
}
if ($loginOk) {
switch (Minz_Configuration::authType()) {
case 'form':
$loginOk = Minz_Session::param('passwordHash') === $this->conf->passwordHash;
break;
case 'http_auth':
$loginOk = strcasecmp($currentUser, httpAuthUser()) === 0;
break;
case 'persona':
$loginOk = strcasecmp(Minz_Session::param('mail'), $this->conf->mail_login) === 0;
break;
case 'none':
$loginOk = true;
break;
default:
$loginOk = false;
break;
}
} catch(Minz_Exception $e) {
Minz_Log::error('Cannot load configuration file of user `' . $current_user . '`');
die($e->getMessage());
}
return $loginOk;
}
private function loadParamsView() {
@ -140,7 +43,7 @@ class FreshRSS extends Minz_FrontController {
}
}
private function loadStylesAndScripts($loginOk) {
private function loadStylesAndScripts() {
$theme = FreshRSS_Themes::load($this->conf->theme);
if ($theme) {
foreach($theme['files'] as $file) {
@ -158,19 +61,17 @@ class FreshRSS extends Minz_FrontController {
}
}
switch (Minz_Configuration::authType()) {
case 'form':
if (!$loginOk) {
Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js')));
}
break;
case 'persona':
Minz_View::appendScript('https://login.persona.org/include.js');
break;
}
Minz_View::appendScript(Minz_Url::display('/scripts/jquery.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.min.js')));
Minz_View::appendScript(Minz_Url::display('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js')));
Minz_View::appendScript(Minz_Url::display('/scripts/main.js?' . @filemtime(PUBLIC_PATH . '/scripts/main.js')));
if (Minz_Configuration::authType() === 'persona') {
// TODO move it in a plugin
// Needed for login AND logout with Persona.
Minz_View::appendScript('https://login.persona.org/include.js');
$file_mtime = @filemtime(PUBLIC_PATH . '/scripts/persona.js');
Minz_View::appendScript(Minz_Url::display('/scripts/persona.js?' . $file_mtime));
}
}
private function loadNotifications() {

@ -0,0 +1,235 @@
<?php
/**
* This class handles all authentication process.
*/
class FreshRSS_Auth {
/**
* Determines if user is connected.
*/
private static $login_ok = false;
/**
* This method initializes authentication system.
*/
public static function init() {
self::$login_ok = Minz_Session::param('loginOk', false);
$current_user = Minz_Session::param('currentUser', '');
if ($current_user === '') {
$current_user = Minz_Configuration::defaultUser();
Minz_Session::_param('currentUser', $current_user);
}
$access_ok = self::accessControl();
if ($access_ok) {
self::giveAccess();
} else {
// Be sure all accesses are removed!
self::removeAccess();
}
}
/**
* This method checks if user is allowed to connect.
*
* Required session parameters are also set in this method (such as
* currentUser).
*
* @return boolean true if user can be connected, false else.
*/
public static function accessControl() {
if (self::$login_ok) {
return true;
}
switch (Minz_Configuration::authType()) {
case 'form':
$credentials = FreshRSS_FormAuth::getCredentialsFromCookie();
$current_user = '';
if (isset($credentials[1])) {
$current_user = trim($credentials[0]);
Minz_Session::_param('currentUser', $current_user);
Minz_Session::_param('passwordHash', trim($credentials[1]));
}
return $current_user != '';
case 'http_auth':
$current_user = httpAuthUser();
$login_ok = $current_user != '';
if ($login_ok) {
Minz_Session::_param('currentUser', $current_user);
}
return $login_ok;
case 'persona':
$email = filter_var(Minz_Session::param('mail'), FILTER_VALIDATE_EMAIL);
$persona_file = DATA_PATH . '/persona/' . $email . '.txt';
if (($current_user = @file_get_contents($persona_file)) !== false) {
$current_user = trim($current_user);
Minz_Session::_param('currentUser', $current_user);
Minz_Session::_param('mail', $email);
return true;
}
return false;
case 'none':
return true;
default:
// TODO load extension
return false;
}
}
/**
* Gives access to the current user.
*/
public static function giveAccess() {
$current_user = Minz_Session::param('currentUser');
try {
$conf = new FreshRSS_Configuration($current_user);
} catch(Minz_Exception $e) {
die($e->getMessage());
}
switch (Minz_Configuration::authType()) {
case 'form':
self::$login_ok = Minz_Session::param('passwordHash') === $conf->passwordHash;
break;
case 'http_auth':
self::$login_ok = strcasecmp($current_user, httpAuthUser()) === 0;
break;
case 'persona':
self::$login_ok = strcasecmp(Minz_Session::param('mail'), $conf->mail_login) === 0;
break;
case 'none':
self::$login_ok = true;
break;
default:
// TODO: extensions
self::$login_ok = false;
}
Minz_Session::_param('loginOk', self::$login_ok);
}
/**
* Returns if current user has access to the given scope.
*
* @param string $scope general (default) or admin
* @return boolean true if user has corresponding access, false else.
*/
public static function hasAccess($scope = 'general') {
$ok = self::$login_ok;
switch ($scope) {
case 'general':
break;
case 'admin':
$ok &= Minz_Session::param('currentUser') === Minz_Configuration::defaultUser();
break;
default:
$ok = false;
}
return $ok;
}
/**
* Removes all accesses for the current user.
*/
public static function removeAccess() {
Minz_Session::_param('loginOk');
self::$login_ok = false;
Minz_Session::_param('currentUser', Minz_Configuration::defaultUser());
switch (Minz_Configuration::authType()) {
case 'form':
Minz_Session::_param('passwordHash');
FreshRSS_FormAuth::deleteCookie();
break;
case 'persona':
Minz_Session::_param('mail');
break;
case 'http_auth':
case 'none':
// Nothing to do...
break;
default:
// TODO: extensions
}
}
}
class FreshRSS_FormAuth {
public static function checkCredentials($username, $hash, $nonce, $challenge) {
if (!ctype_alnum($username) ||
!ctype_graph($challenge) ||
!ctype_alnum($nonce)) {
Minz_Log::debug('Invalid credential parameters:' .
' user=' . $username .
' challenge=' . $challenge .
' nonce=' . $nonce);
return false;
}
if (!function_exists('password_verify')) {
include_once(LIB_PATH . '/password_compat.php');
}
return password_verify($nonce . $hash, $challenge);
}
public static function getCredentialsFromCookie() {
$token = Minz_Session::getLongTermCookie('FreshRSS_login');
if (!ctype_alnum($token)) {
return array();
}
$token_file = DATA_PATH . '/tokens/' . $token . '.txt';
$mtime = @filemtime($token_file);
if ($mtime + 2629744 < time()) {
// Token has expired (> 1 month) or does not exist.
// TODO: 1 month -> use a configuration instead
@unlink($token_file);
return array();
}
$credentials = @file_get_contents($token_file);
return $credentials === false ? array() : explode("\t", $credentials, 2);
}
public static function makeCookie($username, $password_hash) {
do {
$token = sha1(Minz_Configuration::salt() . $username . uniqid(mt_rand(), true));
$token_file = DATA_PATH . '/tokens/' . $token . '.txt';
} while (file_exists($token_file));
if (@file_put_contents($token_file, $username . "\t" . $password_hash) === false) {
return false;
}
$expire = time() + 2629744; //1 month //TODO: Use a configuration instead
Minz_Session::setLongTermCookie('FreshRSS_login', $token, $expire);
return $token;
}
public static function deleteCookie() {
$token = Minz_Session::getLongTermCookie('FreshRSS_login');
Minz_Session::deleteLongTermCookie('FreshRSS_login');
if (ctype_alnum($token)) {
@unlink(DATA_PATH . '/tokens/' . $token . '.txt');
}
if (rand(0, 10) === 1) {
self::purgeTokens();
}
}
public static function purgeTokens() {
$oldest = time() - 2629744; // 1 month // TODO: Use a configuration instead
foreach (new DirectoryIterator(DATA_PATH . '/tokens/') as $file_info) {
// $extension = $file_info->getExtension(); doesn't work in PHP < 5.3.7
$extension = pathinfo($file_info->getFilename(), PATHINFO_EXTENSION);
if ($extension === 'txt' && $file_info->getMTime() < $oldest) {
@unlink($file_info->getPathname());
}
}
}
}

@ -22,10 +22,7 @@
<li class="item<?php echo Minz_Request::controllerName() === 'users' ? ' active' : ''; ?>">
<a href="<?php echo _url('users', 'index'); ?>"><?php echo _t('users'); ?></a>
</li>
<?php
$current_user = Minz_Session::param('currentUser', '');
if (Minz_Configuration::isAdmin($current_user)) {
?>
<?php if (FreshRSS_Auth::hasAccess('admin')) { ?>
<li class="item<?php echo Minz_Request::controllerName() === 'update' ? ' active' : ''; ?>">
<a href="<?php echo _url('update', 'index'); ?>"><?php echo _t('update'); ?></a>
</li>

@ -2,7 +2,7 @@
<a class="toggle_aside" href="#close"><?php echo _i('close'); ?></a>
<ul class="categories">
<?php if ($this->loginOk) { ?>
<?php if (FreshRSS_Auth::hasAccess()) { ?>
<form id="mark-read-aside" method="post" style="display: none"></form>
<li>
@ -83,11 +83,11 @@
<ul class="dropdown-menu">
<li class="dropdown-close"><a href="#close"></a></li>
<li class="item"><a href="<?php echo _url('index', 'index', 'get', 'f_!!!!!!'); ?>"><?php echo _t('filter'); ?></a></li>
<?php if ($this->loginOk) { ?>
<?php if (FreshRSS_Auth::hasAccess()) { ?>
<li class="item"><a href="<?php echo _url('stats', 'repartition', 'id', '!!!!!!'); ?>"><?php echo _t('stats'); ?></a></li>
<?php } ?>
<li class="item"><a target="_blank" href="http://example.net/"><?php echo _t('see_website'); ?></a></li>
<?php if ($this->loginOk) { ?>
<?php if (FreshRSS_Auth::hasAccess()) { ?>
<li class="separator"></li>
<li class="item"><a href="<?php echo _url('subscription', 'index', 'id', '!!!!!!'); ?>"><?php echo _t('administration'); ?></a></li>
<li class="item"><a href="<?php echo _url('feed', 'actualize', 'id', '!!!!!!'); ?>"><?php echo _t('actualize'); ?></a></li>

@ -1,22 +1,11 @@
<?php
if (Minz_Configuration::canLogIn()) {
?><ul class="nav nav-head nav-login"><?php
switch (Minz_Configuration::authType()) {
case 'form':
if ($this->loginOk) {
?><li class="item"><?php echo _i('logout'); ?> <a class="signout" href="<?php echo _url('index', 'formLogout'); ?>"><?php echo _t('logout'); ?></a></li><?php
if (FreshRSS_Auth::hasAccess()) {
?><li class="item"><?php echo _i('logout'); ?> <a class="signout" href="<?php echo _url('auth', 'logout'); ?>"><?php echo _t('logout'); ?></a></li><?php
} else {
?><li class="item"><?php echo _i('login'); ?> <a class="signin" href="<?php echo _url('index', 'formLogin'); ?>"><?php echo _t('login'); ?></a></li><?php
?><li class="item"><?php echo _i('login'); ?> <a class="signin" href="<?php echo _url('auth', 'login'); ?>"><?php echo _t('login'); ?></a></li><?php
}
break;
case 'persona':
if ($this->loginOk) {
?><li class="item"><?php echo _i('logout'); ?> <a class="signout" href="#"><?php echo _t('logout'); ?></a></li><?php
} else {
?><li class="item"><?php echo _i('login'); ?> <a class="signin" href="#"><?php echo _t('login'); ?></a></li><?php
}
break;
}
?></ul><?php
}
?>
@ -32,7 +21,7 @@ if (Minz_Configuration::canLogIn()) {
</div>
<div class="item search">
<?php if ($this->loginOk || Minz_Configuration::allowAnonymous()) { ?>
<?php if (FreshRSS_Auth::hasAccess() || Minz_Configuration::allowAnonymous()) { ?>
<form action="<?php echo _url('index', 'index'); ?>" method="get">
<div class="stick">
<?php $search = Minz_Request::param('search', ''); ?>
@ -59,7 +48,7 @@ if (Minz_Configuration::canLogIn()) {
<?php } ?>
</div>
<?php if ($this->loginOk) { ?>
<?php if (FreshRSS_Auth::hasAccess()) { ?>
<div class="item configure">
<div class="dropdown">
<div id="dropdown-configure" class="dropdown-target"></div>
@ -75,10 +64,7 @@ if (Minz_Configuration::canLogIn()) {
<li class="item"><a href="<?php echo _url('configure', 'queries'); ?>"><?php echo _t('queries'); ?></a></li>
<li class="separator"></li>
<li class="item"><a href="<?php echo _url('users', 'index'); ?>"><?php echo _t('users'); ?></a></li>
<?php
$current_user = Minz_Session::param('currentUser', '');
if (Minz_Configuration::isAdmin($current_user)) {
?>
<?php if (FreshRSS_Auth::hasAccess('admin')) { ?>
<li class="item"><a href="<?php echo _url('update', 'index'); ?>"><?php echo _t('update'); ?></a></li>
<?php } ?>
<li class="separator"></li>
@ -87,29 +73,15 @@ if (Minz_Configuration::canLogIn()) {
<li class="item"><a href="<?php echo _url('index', 'about'); ?>"><?php echo _t('about'); ?></a></li>
<?php
if (Minz_Configuration::canLogIn()) {
?><li class="separator"></li><?php
switch (Minz_Configuration::authType()) {
case 'form':
?><li class="item"><a class="signout" href="<?php echo _url('index', 'formLogout'); ?>"><?php echo _i('logout'), ' ', _t('logout'); ?></a></li><?php
break;
case 'persona':
?><li class="item"><a class="signout" href="#"><?php echo _i('logout'), ' ', _t('logout'); ?></a></li><?php
break;
}
?><li class="separator"></li>
<li class="item"><a class="signout" href="<?php echo _url('auth', 'logout'); ?>"><?php echo _i('logout'), ' ', _t('logout'); ?></a></li><?php
} ?>
</ul>
</div>
</div>
<?php } elseif (Minz_Configuration::canLogIn()) {
?><div class="item configure"><?php
switch (Minz_Configuration::authType()) {
case 'form':
echo _i('login'); ?><a class="signin" href="<?php echo _url('index', 'formLogin'); ?>"><?php echo _t('login'); ?></a></li><?php
break;
case 'persona':
echo _i('login'); ?><a class="signin" href="#"><?php echo _t('login'); ?></a></li><?php
break;
}
?></div><?php
} ?>
<?php } elseif (Minz_Configuration::canLogIn()) { ?>
<div class="item configure">
<?php echo _i('login'); ?><a class="signin" href="<?php echo _url('auth', 'login'); ?>"><?php echo _t('login'); ?></a>
</div>
<?php } ?>
</div>

@ -6,7 +6,7 @@
<a class="btn toggle_aside" href="#aside_flux"><?php echo _i('category'); ?></a>
<?php } ?>
<?php if ($this->loginOk) { ?>
<?php if (FreshRSS_Auth::hasAccess()) { ?>
<div id="nav_menu_actions" class="stick">
<?php
$url_state = $this->url;
@ -300,7 +300,7 @@
<?php echo _i($icon); ?>
</a>
<?php if ($this->loginOk || Minz_Configuration::allowAnonymousRefresh()) { ?>
<?php if (FreshRSS_Auth::hasAccess() || Minz_Configuration::allowAnonymousRefresh()) { ?>
<a id="actualize" class="btn" href="<?php echo _url('feed', 'actualize'); ?>"><?php echo _i('refresh'); ?></a>
<?php } ?>
</div>

@ -1,9 +1,7 @@
<div class="prompt">
<h1><?php echo _t('login'); ?></h1><?php
<h1><?php echo _t('login'); ?></h1>
switch (Minz_Configuration::authType()) {
case 'form':
?><form id="crypto-form" method="post" action="<?php echo _url('index', 'formLogin'); ?>">
<form id="crypto-form" method="post" action="<?php echo _url('auth', 'login'); ?>">
<div>
<label for="username"><?php echo _t('username'); ?></label>
<input type="text" id="username" name="username" size="16" required="required" maxlength="16" pattern="[0-9a-zA-Z]{1,16}" autofocus="autofocus" />
@ -24,23 +22,7 @@
<div>
<button id="loginButton" type="submit" class="btn btn-important"><?php echo _t('login'); ?></button>
</div>
</form><?php
break;
case 'persona':
?><p>
<a class="signin btn btn-important" href="#">
<?php echo _i('login'); ?>
<?php echo _t('login_with_persona'); ?>
</a><br /><br />
<?php echo _i('help'); ?>
<small>
<a href="<?php echo _url('index', 'resetAuth'); ?>"><?php echo _t('login_persona_problem'); ?></a>
</small>
</p><?php
break;
} ?>
</form>
<p><a href="<?php echo _url('index', 'about'); ?>"><?php echo _t('about_freshrss'); ?></a></p>
</div>

@ -0,0 +1,24 @@
<?php if ($this->res === false) { ?>
<div class="prompt">
<h1><?php echo _t('login'); ?></h1>
<p>
<a class="signin btn btn-important" href="<?php echo _url('auth', 'login'); ?>">
<?php echo _i('login'); ?> <?php echo _t('login_with_persona'); ?>
</a>
<br /><br />
<?php echo _i('help'); ?>
<small>
<a href="<?php echo _url('auth', 'reset'); ?>"><?php echo _t('login_persona_problem'); ?></a>
</small>
</p>
<p><a href="<?php echo _url('index', 'about'); ?>"><?php echo _t('about_freshrss'); ?></a></p>
</div>
<?php
} else {
echo json_encode($this->res);
}
?>

@ -9,7 +9,7 @@
<?php } ?>
<?php if (!$this->no_form) { ?>
<form id="crypto-form" method="post" action="<?php echo _url('index', 'resetAuth'); ?>">
<form id="crypto-form" method="post" action="<?php echo _url('auth', 'reset'); ?>">
<p class="alert alert-warn">
<span class="alert-head"><?php echo _t('attention'); ?></span><br />
<?php echo _t('auth_will_reset'); ?>

@ -67,7 +67,7 @@
</div>
</div>
<?php if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { ?>
<?php if (FreshRSS_Auth::hasAccess('admin')) { ?>
<div class="form-group">
<p class="group-name"><?php echo _t('users'); ?></p>
<div class="group-controls">

@ -8,6 +8,15 @@ $hide_posts = ($this->conf->display_posts ||
Minz_Request::param('output') === 'reader');
$s = $this->conf->shortcuts;
$url_login = Minz_Url::display(array(
'c' => 'auth',
'a' => 'login'
), 'php');
$url_logout = Minz_Url::display(array(
'c' => 'auth',
'a' => 'logout'
), 'php');
echo 'var context={',
'hide_posts:', $hide_posts ? 'false' : 'true', ',',
'display_order:"', Minz_Request::param('order', $this->conf->sort_order), '",',
@ -43,8 +52,8 @@ echo 'shortcuts={',
echo 'url={',
'index:"', _url('index', 'index'), '",',
'login:"', _url('index', 'login'), '",',
'logout:"', _url('index', 'logout'), '",',
'login:"', $url_login, '",',
'logout:"', $url_logout, '",',
'help:"', FRESHRSS_WIKI, '"',
"},\n";

@ -7,7 +7,7 @@ if (!empty($this->entries)) {
$display_today = true;
$display_yesterday = true;
$display_others = true;
if ($this->loginOk) {
if (FreshRSS_Auth::hasAccess()) {
$sharing = $this->conf->sharing;
} else {
$sharing = array();
@ -58,7 +58,7 @@ if (!empty($this->entries)) {
}
?><div class="flux<?php echo !$item->isRead() ? ' not_read' : ''; ?><?php echo $item->isFavorite() ? ' favorite' : ''; ?>" id="flux_<?php echo $item->id(); ?>">
<ul class="horizontal-list flux_header"><?php
if ($this->loginOk) {
if (FreshRSS_Auth::hasAccess()) {
if ($topline_read) {
?><li class="item manage"><?php
$arUrl = array('c' => 'entry', 'a' => 'read', 'params' => array('id' => $item->id()));
@ -103,7 +103,7 @@ if (!empty($this->entries)) {
?>
</div>
<ul class="horizontal-list bottom"><?php
if ($this->loginOk) {
if (FreshRSS_Auth::hasAccess()) {
if ($bottomline_read) {
?><li class="item manage"><?php
$arUrl = array('c' => 'entry', 'a' => 'read', 'params' => array('id' => $item->id()));

@ -2,7 +2,7 @@
$output = Minz_Request::param('output', 'normal');
if ($this->loginOk || Minz_Configuration::allowAnonymous()) {
if (FreshRSS_Auth::hasAccess() || Minz_Configuration::allowAnonymous()) {
if ($output === 'normal') {
$this->renderHelper('view/normal_view');
} elseif ($output === 'reader') {

@ -1 +0,0 @@
<?php print_r($this->res); ?>

@ -11,7 +11,7 @@
<div class="group-controls">
<input id="current_user" type="text" disabled="disabled" value="<?php echo Minz_Session::param('currentUser', '_'); ?>" />
<label class="checkbox" for="is_admin">
<input type="checkbox" id="is_admin" disabled="disabled" <?php echo Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_')) ? 'checked="checked" ' : ''; ?>/>
<input type="checkbox" id="is_admin" disabled="disabled" <?php echo FreshRSS_Auth::hasAccess('admin') ? 'checked="checked" ' : ''; ?>/>
<?php echo _t('is_admin'); ?>
</label>
</div>
@ -44,7 +44,7 @@
<label class="group-name" for="mail_login"><?php echo _t('persona_connection_email'); ?></label>
<?php $mail = $this->conf->mail_login; ?>
<div class="group-controls">
<input type="email" id="mail_login" name="mail_login" class="extend" autocomplete="off" value="<?php echo $mail; ?>" <?php echo Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_')) ? '' : 'disabled="disabled"'; ?> placeholder="alice@example.net" />
<input type="email" id="mail_login" name="mail_login" class="extend" autocomplete="off" value="<?php echo $mail; ?>" <?php echo FreshRSS_Auth::hasAccess('admin') ? '' : 'disabled="disabled"'; ?> placeholder="alice@example.net" />
<noscript><b><?php echo _t('javascript_should_be_activated'); ?></b></noscript>
</div>
</div>
@ -56,7 +56,7 @@
</div>
</div>
<?php if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { ?>
<?php if (FreshRSS_Auth::hasAccess('admin')) { ?>
<legend><?php echo _t('auth_type'); ?></legend>

@ -100,9 +100,6 @@ class Minz_Configuration {
public static function defaultUser () {
return self::$default_user;
}
public static function isAdmin($currentUser) {
return $currentUser === self::$default_user;
}
public static function allowAnonymous() {
return self::$allow_anonymous;
}

@ -1034,67 +1034,7 @@ function init_crypto_form() {
}
//</crypto form (Web login)>
//<persona>
function init_persona() {
if (!(navigator.id)) {
if (window.console) {
console.log('FreshRSS waiting for Persona…');
}
window.setTimeout(init_persona, 100);
return;
}
$('a.signin').click(function() {
navigator.id.request();
return false;
});
$('a.signout').click(function() {
navigator.id.logout();
return false;
});
navigator.id.watch({
loggedInUser: context['current_user_mail'],
onlogin: function(assertion) {
// A user has logged in! Here you need to:
// 1. Send the assertion to your backend for verification and to create a session.
// 2. Update your UI.
$.ajax ({
type: 'POST',
url: url['login'],
data: {assertion: assertion},
success: function(res, status, xhr) {
/*if (res.status === 'failure') {
alert (res_obj.reason);
} else*/ if (res.status === 'okay') {
location.href = url['index'];
}
},
error: function(res, status, xhr) {
alert("Login failure: " + res);
}
});
},
onlogout: function() {
// A user has logged out! Here you need to:
// Tear down the user's session by redirecting the user or making a call to your backend.
// Also, make sure loggedInUser will get set to null on the next page load.
// (That's a literal JavaScript null. Not false, 0, or undefined. null.)
$.ajax ({
type: 'POST',
url: url['logout'],
success: function(res, status, xhr) {
location.href = url['index'];
},
error: function(res, status, xhr) {
//alert("logout failure" + res);
}
});
}
});
}
//</persona>
function init_confirm_action() {
$('body').on('click', '.confirm', function () {
@ -1274,11 +1214,6 @@ function init_all() {
return;
}
init_notifications();
switch (context['auth_type']) {
case 'persona':
init_persona();
break;
}
init_confirm_action();
$stream = $('#stream');
if ($stream.length > 0) {

@ -0,0 +1,76 @@
"use strict";
function init_persona() {
if (!(navigator.id && window.$)) {
if (window.console) {
console.log('FreshRSS (Persona) waiting for JS…');
}
window.setTimeout(init_persona, 100);
return;
}
$('a.signin').click(function() {
navigator.id.request();
return false;
});
$('a.signout').click(function() {
navigator.id.logout();
return false;
});
navigator.id.watch({
loggedInUser: context['current_user_mail'],
onlogin: function(assertion) {
// A user has logged in! Here you need to:
// 1. Send the assertion to your backend for verification and to create a session.
// 2. Update your UI.
$.ajax ({
type: 'POST',
url: url['login'],
data: {assertion: assertion},
success: function(res, status, xhr) {
if (res.status === 'failure') {
openNotification(res.reason, 'bad');
} else if (res.status === 'okay') {
location.href = url['index'];
}
},
error: function(res, status, xhr) {
// alert(res);
}
});
},
onlogout: function() {
// A user has logged out! Here you need to:
// Tear down the user's session by redirecting the user or making a call to your backend.
// Also, make sure loggedInUser will get set to null on the next page load.
// (That's a literal JavaScript null. Not false, 0, or undefined. null.)
$.ajax ({
type: 'POST',
url: url['logout'],
success: function(res, status, xhr) {
location.href = url['index'];
},
error: function(res, status, xhr) {
// alert(res);
}
});
}
});
}
if (document.readyState && document.readyState !== 'loading') {
if (window.console) {
console.log('FreshRSS (Persona) immediate init…');
}
init_persona();
} else if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', function () {
if (window.console) {
console.log('FreshRSS (Persona) waiting for DOMContentLoaded…');
}
init_persona();
}, false);
}
Loading…
Cancel
Save