From 1ac09e7fe4a5408290d06116c6fb8152e018fe26 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 31 Dec 2013 02:59:07 +0100 Subject: Multi-utilisateur fonctionnel en HTTP Auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + Possibilité d'ajout / suppression d'utilisateur (seulement par l'administrateur) + Divers changements pour le mode multi-utilisateur https://github.com/marienfressinaud/FreshRSS/issues/126 + Minz : Renomme "sel_application" en "salt' --- app/Controllers/usersController.php | 132 ++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 app/Controllers/usersController.php (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php new file mode 100644 index 000000000..7d9568083 --- /dev/null +++ b/app/Controllers/usersController.php @@ -0,0 +1,132 @@ +view->loginOk) { + Minz_Error::error( + 403, + array('error' => array(Minz_Translate::t('access_denied'))) + ); + } + } + + public function idAction() { + if (Minz_Request::isPost()) { + $ok = true; + $mail = Minz_Request::param('mail_login', false); + $this->view->conf->_mail_login($mail); + $ok &= $this->view->conf->save(); + + Minz_Session::_param('mail', $this->view->conf->mail_login); + + //TODO: use $ok + $notif = array( + 'type' => 'good', + 'content' => Minz_Translate::t('configuration_updated') + ); + Minz_Session::_param('notification', $notif); + + Minz_Request::forward(array('c' => 'configure', 'a' => 'users'), true); + } + } + + public function authAction() { + if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + $ok = true; + $current_token = $this->view->conf->token; + $token = Minz_Request::param('token', $current_token); + $this->view->conf->_token($token); + $ok &= $this->view->conf->save(); + + Minz_Session::_param('mail', $this->view->conf->mail_login); + + $anon = Minz_Request::param('anon_access', false); + $anon = ((bool)$anon) && ($anon !== 'no'); + $auth_type = Minz_Request::param('auth_type', 'none'); + if ($anon != Minz_Configuration::allowAnonymous() || + $auth_type != Minz_Configuration::authType()) { + Minz_Configuration::_allowAnonymous($anon); + Minz_Configuration::_authType($auth_type); + $ok &= Minz_Configuration::writeFile(); + } + + $notif = array( + 'type' => $ok ? 'good' : 'bad', + 'content' => Minz_Translate::t($ok ? 'configuration_updated' : 'error_occurred') + ); + Minz_Session::_param('notification', $notif); + } + Minz_Request::forward(array('c' => 'configure', 'a' => 'users'), true); + } + + public function createAction() { + if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + require_once(APP_PATH . '/sql.php'); + + $new_user_language = Minz_Request::param('new_user_language', $this->view->conf->language); + if (!in_array($new_user_language, $this->view->conf->availableLanguages())) { + $new_user_language = $this->view->conf->language; + } + + $new_user_name = Minz_Request::param('new_user_name'); + $ok = ctype_alnum($new_user_name); + + $new_user_email = filter_var($_POST['new_user_email'], FILTER_VALIDATE_EMAIL); + if (empty($new_user_email)) { + $new_user_email = ''; + $ok &= Minz_Configuration::authType() !== 'persona'; + } + + if ($ok) { + $configPath = DATA_PATH . '/' . $new_user_name . '_user.php'; + $ok &= !file_exists($configPath); + } + if ($ok) { + $config_array = array( + 'language' => $new_user_language, + 'mail_login' => $new_user_email, + ); + $ok &= (file_put_contents($configPath, "createUser($new_user_name); + } + + $notif = array( + 'type' => $ok ? 'good' : 'bad', + 'content' => Minz_Translate::t($ok ? 'user_created' : 'error_occurred', $new_user_name) + ); + Minz_Session::_param('notification', $notif); + } + Minz_Request::forward(array('c' => 'configure', 'a' => 'users'), true); + } + + public function deleteAction() { + if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + require_once(APP_PATH . '/sql.php'); + + $username = Minz_Request::param('username'); + $ok = ctype_alnum($username); + + if ($ok) { + $ok &= ($username !== Minz_Configuration::defaultUser()); //It is forbidden to delete the default user + } + if ($ok) { + $configPath = DATA_PATH . '/' . $username . '_user.php'; + $ok &= file_exists($configPath); + } + if ($ok) { + $userDAO = new FreshRSS_UserDAO(); + $ok &= $userDAO->deleteUser($username); + $ok &= unlink($configPath); + } + $notif = array( + 'type' => $ok ? 'good' : 'bad', + 'content' => Minz_Translate::t($ok ? 'user_deleted' : 'error_occurred', $username) + ); + Minz_Session::_param('notification', $notif); + } + Minz_Request::forward(array('c' => 'configure', 'a' => 'users'), true); + } +} -- cgit v1.2.3 From 5c9a32329ad68dc5ae8bc8a3566a0d603b80a934 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 31 Dec 2013 14:52:01 +0100 Subject: Multi-utilisateur fonctionnel avec Mozilla Persona MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Il faut ré-enregistrer l'adresse courriel une fois dans l'interface de FreshRSS pour créer le fichier nécessaire. + Comparaison sans tenir compte de la casse pour les noms d'utilisateur. Contribue à https://github.com/marienfressinaud/FreshRSS/issues/126 ll faudra tester la sécurité --- app/Controllers/indexController.php | 32 +++++++++++++++++++++++++++++--- app/Controllers/usersController.php | 37 ++++++++++++++++++++++++++----------- app/FreshRSS.php | 18 ++++++++++++++---- data/cache/index.html | 13 +++++++++++++ data/favicons/index.html | 13 +++++++++++++ data/log/index.html | 13 +++++++++++++ data/persona/.gitignore | 1 + data/persona/index.html | 13 +++++++++++++ p/i/install.php | 6 ++++++ 9 files changed, 128 insertions(+), 18 deletions(-) create mode 100644 data/cache/index.html create mode 100644 data/favicons/index.html create mode 100644 data/log/index.html create mode 100644 data/persona/.gitignore create mode 100644 data/persona/index.html (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 7309169a6..5b51b3e28 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -249,14 +249,40 @@ class FreshRSS_index_Controller extends Minz_ActionController { curl_close ($ch); $res = json_decode ($result, true); - if ($res['status'] === 'okay' && $res['email'] === $this->view->conf->mail_login) { - Minz_Session::_param ('mail', $res['email']); + + $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'] = Minz_Translate::t ('invalid_login'); + $res['reason'] = $reason == '' ? Minz_Translate::t ('invalid_login') : $reason; + Minz_Log::record ('Persona: ' . $res['reason'], Minz_Log::WARNING); } header('Content-Type: application/json; charset=UTF-8'); diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 7d9568083..5b3ffe81a 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -17,7 +17,14 @@ class FreshRSS_users_Controller extends Minz_ActionController { $this->view->conf->_mail_login($mail); $ok &= $this->view->conf->save(); - Minz_Session::_param('mail', $this->view->conf->mail_login); + $email = $this->view->conf->mail_login; + Minz_Session::_param('mail', $email); + + if ($email != '') { + $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; + @unlink($personaFile); + $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); + } //TODO: use $ok $notif = array( @@ -38,8 +45,6 @@ class FreshRSS_users_Controller extends Minz_ActionController { $this->view->conf->_token($token); $ok &= $this->view->conf->save(); - Minz_Session::_param('mail', $this->view->conf->mail_login); - $anon = Minz_Request::param('anon_access', false); $anon = ((bool)$anon) && ($anon !== 'no'); $auth_type = Minz_Request::param('auth_type', 'none'); @@ -69,18 +74,27 @@ class FreshRSS_users_Controller extends Minz_ActionController { } $new_user_name = Minz_Request::param('new_user_name'); - $ok = ctype_alnum($new_user_name); - - $new_user_email = filter_var($_POST['new_user_email'], FILTER_VALIDATE_EMAIL); - if (empty($new_user_email)) { - $new_user_email = ''; - $ok &= Minz_Configuration::authType() !== 'persona'; - } + $ok = ($new_user_name != '') && ctype_alnum($new_user_name); if ($ok) { + $ok &= (strcasecmp($new_user_name, Minz_Configuration::defaultUser()) !== 0); //It is forbidden to alter the default user + + $ok &= !in_array(strtoupper($new_user_name), array_map('strtoupper', listUsers())); //Not an existing user, case-insensitive + $configPath = DATA_PATH . '/' . $new_user_name . '_user.php'; $ok &= !file_exists($configPath); } + if ($ok) { + $new_user_email = filter_var($_POST['new_user_email'], FILTER_VALIDATE_EMAIL); + if (empty($new_user_email)) { + $new_user_email = ''; + $ok &= Minz_Configuration::authType() !== 'persona'; + } else { + $personaFile = DATA_PATH . '/persona/' . $new_user_email . '.txt'; + @unlink($personaFile); + $ok &= (file_put_contents($personaFile, $new_user_name) !== false); + } + } if ($ok) { $config_array = array( 'language' => $new_user_language, @@ -110,7 +124,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $ok = ctype_alnum($username); if ($ok) { - $ok &= ($username !== Minz_Configuration::defaultUser()); //It is forbidden to delete the default user + $ok &= (strcasecmp($username, Minz_Configuration::defaultUser()) !== 0); //It is forbidden to delete the default user } if ($ok) { $configPath = DATA_PATH . '/' . $username . '_user.php'; @@ -120,6 +134,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $userDAO = new FreshRSS_UserDAO(); $ok &= $userDAO->deleteUser($username); $ok &= unlink($configPath); + //TODO: delete Persona file } $notif = array( 'type' => $ok ? 'good' : 'bad', diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 0e166cc3b..0af0c01da 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -18,8 +18,18 @@ class FreshRSS extends Minz_FrontController { $loginOk = $currentUser != ''; break; case 'persona': - $currentUser = Minz_Configuration::defaultUser(); //TODO: Make Persona compatible with multi-user - $loginOk = Minz_Session::param('mail') != ''; + $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(); @@ -51,10 +61,10 @@ class FreshRSS extends Minz_FrontController { if ($loginOk) { switch (Minz_Configuration::authType()) { case 'http_auth': - $loginOk = $currentUser === httpAuthUser(); + $loginOk = strcasecmp($currentUser, httpAuthUser()) === 0; break; case 'persona': - $loginOk = Minz_Session::param('mail') === $this->conf->mail_login; + $loginOk = strcasecmp(Minz_Session::param('mail'), $this->conf->mail_login) === 0; break; case 'none': $loginOk = true; diff --git a/data/cache/index.html b/data/cache/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/data/cache/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/data/favicons/index.html b/data/favicons/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/data/favicons/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/data/log/index.html b/data/log/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/data/log/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/data/persona/.gitignore b/data/persona/.gitignore new file mode 100644 index 000000000..314f02b1b --- /dev/null +++ b/data/persona/.gitignore @@ -0,0 +1 @@ +*.txt \ No newline at end of file diff --git a/data/persona/index.html b/data/persona/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/data/persona/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/p/i/install.php b/p/i/install.php index e953cf699..0cd952fef 100644 --- a/p/i/install.php +++ b/p/i/install.php @@ -178,6 +178,12 @@ function saveStep2 () { @unlink($configPath); //To avoid access-rights problems file_put_contents($configPath, " Date: Tue, 31 Dec 2013 15:21:39 +0100 Subject: Ajouts de quelques invalidateHttpCache --- app/Controllers/configureController.php | 7 +++++++ app/Controllers/usersController.php | 5 +++++ 2 files changed, 12 insertions(+) (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 17abf6b89..0e4801a2d 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -50,6 +50,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $catDAO->addCategory ($values); } } + invalidateHttpCache(); $notif = array ( 'type' => 'good', @@ -124,6 +125,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { 'content' => Minz_Translate::t ('error_occurred_update') ); } + invalidateHttpCache(); Minz_Session::_param ('notification', $notif); Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => array ('id' => $id)), true); @@ -168,6 +170,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_Session::_param ('language', $this->view->conf->language); Minz_Translate::reset (); + invalidateHttpCache(); $notif = array ( 'type' => 'good', @@ -196,6 +199,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { 'print' => Minz_Request::param ('print', false), )); $this->view->conf->save(); + invalidateHttpCache(); $notif = array ( 'type' => 'good', @@ -235,6 +239,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->categories = $list; } elseif ($this->view->req == 'import' && Minz_Request::isPost ()) { if ($_FILES['file']['error'] == 0) { + invalidateHttpCache(); // on parse le fichier OPML pour récupérer les catégories et les flux associés try { list ($categories, $feeds) = opml_import ( @@ -295,6 +300,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->conf->_shortcuts ($shortcuts_ok); $this->view->conf->save(); + invalidateHttpCache(); $notif = array ( 'type' => 'good', @@ -320,6 +326,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->conf->_old_entries($old); $this->view->conf->_keep_history_default($keepHistoryDefault); $this->view->conf->save(); + invalidateHttpCache(); $notif = array( 'type' => 'good', diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 5b3ffe81a..0ce3b3447 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -25,6 +25,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { @unlink($personaFile); $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); } + invalidateHttpCache(); //TODO: use $ok $notif = array( @@ -54,6 +55,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { Minz_Configuration::_authType($auth_type); $ok &= Minz_Configuration::writeFile(); } + invalidateHttpCache(); $notif = array( 'type' => $ok ? 'good' : 'bad', @@ -106,6 +108,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $userDAO = new FreshRSS_UserDAO(); $ok &= $userDAO->createUser($new_user_name); } + invalidateHttpCache(); $notif = array( 'type' => $ok ? 'good' : 'bad', @@ -136,6 +139,8 @@ class FreshRSS_users_Controller extends Minz_ActionController { $ok &= unlink($configPath); //TODO: delete Persona file } + invalidateHttpCache(); + $notif = array( 'type' => $ok ? 'good' : 'bad', 'content' => Minz_Translate::t($ok ? 'user_deleted' : 'error_occurred', $username) -- cgit v1.2.3 From 50c41d9bb2b1766feac984685bb2a954ab4799f3 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 1 Jan 2014 13:48:32 +0100 Subject: Détails multi-utilisateur MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/marienfressinaud/FreshRSS/issues/126 --- app/Controllers/usersController.php | 47 ++++++++++++++----------------------- app/views/configure/archiving.phtml | 4 ++-- app/views/configure/feed.phtml | 4 ++-- app/views/configure/users.phtml | 9 ++++--- p/themes/default/global.css | 2 +- p/themes/flat-design/global.css | 2 +- 6 files changed, 28 insertions(+), 40 deletions(-) (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 0ce3b3447..482e35c3e 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -10,9 +10,10 @@ class FreshRSS_users_Controller extends Minz_ActionController { } } - public function idAction() { + public function authAction() { if (Minz_Request::isPost()) { $ok = true; + $mail = Minz_Request::param('mail_login', false); $this->view->conf->_mail_login($mail); $ok &= $this->view->conf->save(); @@ -25,36 +26,24 @@ class FreshRSS_users_Controller extends Minz_ActionController { @unlink($personaFile); $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); } - invalidateHttpCache(); - //TODO: use $ok - $notif = array( - 'type' => 'good', - 'content' => Minz_Translate::t('configuration_updated') - ); - Minz_Session::_param('notification', $notif); - - Minz_Request::forward(array('c' => 'configure', 'a' => 'users'), true); - } - } - - public function authAction() { - if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { - $ok = true; - $current_token = $this->view->conf->token; - $token = Minz_Request::param('token', $current_token); - $this->view->conf->_token($token); - $ok &= $this->view->conf->save(); - - $anon = Minz_Request::param('anon_access', false); - $anon = ((bool)$anon) && ($anon !== 'no'); - $auth_type = Minz_Request::param('auth_type', 'none'); - if ($anon != Minz_Configuration::allowAnonymous() || - $auth_type != Minz_Configuration::authType()) { - Minz_Configuration::_allowAnonymous($anon); - Minz_Configuration::_authType($auth_type); - $ok &= Minz_Configuration::writeFile(); + if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + $current_token = $this->view->conf->token; + $token = Minz_Request::param('token', $current_token); + $this->view->conf->_token($token); + $ok &= $this->view->conf->save(); + + $anon = Minz_Request::param('anon_access', false); + $anon = ((bool)$anon) && ($anon !== 'no'); + $auth_type = Minz_Request::param('auth_type', 'none'); + if ($anon != Minz_Configuration::allowAnonymous() || + $auth_type != Minz_Configuration::authType()) { + Minz_Configuration::_allowAnonymous($anon); + Minz_Configuration::_authType($auth_type); + $ok &= Minz_Configuration::writeFile(); + } } + invalidateHttpCache(); $notif = array( diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index cbe3b086c..6e26ca81e 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -17,8 +17,8 @@
- '', 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', -1 => '∞') as $v => $t) { echo ''; } ?> () diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml index e738ab64f..a0fe39f8a 100644 --- a/app/views/configure/feed.phtml +++ b/app/views/configure/feed.phtml @@ -87,8 +87,8 @@
- '', -2 => Minz_Translate::t('by_default'), 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', -1 => '∞') as $v => $t) { echo ''; } ?> diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 223f81e8d..d40a3ad5b 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -3,7 +3,7 @@
-
+
@@ -34,20 +34,19 @@
- -
- + - + $_SERVER['REMOTE_USER'] = ``
diff --git a/p/themes/default/global.css b/p/themes/default/global.css index 913da4b27..2cc195f90 100644 --- a/p/themes/default/global.css +++ b/p/themes/default/global.css @@ -112,7 +112,7 @@ input, select, textarea { border-color: #33BBFF; box-shadow: 0 2px 2px #DDDDFF inset; } - input:invalid { + input:invalid, select:invalid { border-color: red; box-shadow: 0 0 2px 1px red; } diff --git a/p/themes/flat-design/global.css b/p/themes/flat-design/global.css index cb9495865..c24a9f481 100644 --- a/p/themes/flat-design/global.css +++ b/p/themes/flat-design/global.css @@ -113,7 +113,7 @@ input, select, textarea { color: #333; border-color: #2980b9; } - input:invalid { + input:invalid, select:invalid { border-color: red; box-shadow: 0 0 2px 1px red; } -- cgit v1.2.3 From 43f1b227b459f8edade9d551164c18f56cfa1925 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 11 Jan 2014 17:13:22 +0100 Subject: Configuration du mot de passe https://github.com/marienfressinaud/FreshRSS/issues/104 --- app/Controllers/usersController.php | 13 +++++++++++++ app/i18n/en.php | 3 ++- app/i18n/fr.php | 3 ++- app/views/configure/users.phtml | 8 ++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 482e35c3e..8954c845d 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -14,8 +14,21 @@ class FreshRSS_users_Controller extends Minz_ActionController { if (Minz_Request::isPost()) { $ok = true; + $passwordPlain = Minz_Request::param('passwordPlain', false); + if ($passwordPlain != '') { + Minz_Request::_param('passwordPlain'); //Discard plain-text password ASAP + $_POST['passwordPlain'] = ''; + if (!function_exists('password_hash')) { + include_once(LIB_PATH . '/password_compat.php'); + } + $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT); //A bit expensive, on purpose + $passwordPlain = ''; + $this->view->conf->_passwordHash($passwordHash); + } + $mail = Minz_Request::param('mail_login', false); $this->view->conf->_mail_login($mail); + $ok &= $this->view->conf->save(); $email = $this->view->conf->mail_login; diff --git a/app/i18n/en.php b/app/i18n/en.php index 89af15b17..3b9936e8e 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -161,7 +161,8 @@ return array ( 'current_user' => 'Current user', 'default_user' => 'Username of the default user (maximum 16 alphanumeric characters)', - 'persona_connection_email' => 'Login mail address (for Mozilla Persona)', + 'password' =>'Password
(for the Web-form login method)', + 'persona_connection_email' => 'Login mail address
(for Mozilla Persona)', 'allow_anonymous' => 'Allow anonymous reading for the default user (%s)', 'auth_token' => 'Authentication token', 'explain_token' => 'Allows to access RSS output of the default user without authentication.
%s?token=%s', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index d4c96c1db..7e71cbb6d 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -160,8 +160,9 @@ return array ( 'think_to_add' => 'Pensez à en ajouter !', 'current_user' => 'Utilisateur actuel', + 'password' =>'Mot de passe
(pour connexion par formulaire)', 'default_user' => 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)', - 'persona_connection_email' => 'Adresse courriel de connexion (pour Mozilla Persona)', + 'persona_connection_email' => 'Adresse courriel de connexion
(pour Mozilla Persona)', 'allow_anonymous' => 'Autoriser la lecture anonyme pour l’utilisateur par défaut (%s)', 'auth_token' => 'Jeton d’identification', 'explain_token' => 'Permet d’accéder à la sortie RSS de l’utilisateur par défaut sans besoin de s’authentifier.
%s?output=rss&token=%s', diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index d40a3ad5b..68111bdbe 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -17,6 +17,14 @@
+
+ +
+ + +
+
+
conf->mail_login; ?> -- cgit v1.2.3 From d58886a937cbe425163526fc2ba3d2a118602035 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 12 Jan 2014 03:10:31 +0100 Subject: Implémentation de l'indentification par mot de passe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implémentation de https://github.com/marienfressinaud/FreshRSS/issues/104 --- CHANGELOG | 3 ++ app/Controllers/indexController.php | 52 +++++++++++++++++++++++++++-- app/Controllers/javascriptController.php | 12 +++---- app/Controllers/usersController.php | 26 ++++++++++++--- app/FreshRSS.php | 27 ++++++++++++--- app/i18n/en.php | 7 ++-- app/i18n/fr.php | 7 ++-- app/layout/header.phtml | 51 +++++++++++++++++++--------- app/views/configure/users.phtml | 16 ++++++--- app/views/helpers/javascript_vars.phtml | 4 +-- app/views/helpers/view/login.phtml | 43 ++++++++++++++++++++++++ app/views/index/index.phtml | 14 ++------ lib/Minz/Configuration.php | 3 +- lib/Minz/FrontController.php | 2 +- p/scripts/main.js | 57 ++++++++++++++++++++++++++++++-- 15 files changed, 265 insertions(+), 59 deletions(-) create mode 100644 app/views/helpers/view/login.phtml (limited to 'app/Controllers/usersController.php') diff --git a/CHANGELOG b/CHANGELOG index fe856fe4a..5c9b56465 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,8 @@ * Nouveau mode multi-utilisateur * L’utilisateur par défaut (administrateur) peut créer et supprimer d’autres utilisateurs * Nécessite un contrôle d’accès, soit : + * par le nouveau mode de connexion par formulaire (nom d’utilisateur + mot de passe) + * relativement sûr même sans HTTPS (le mot de passe n’est pas transmis en clair) * par HTTP (par exemple sous Apache en créant un fichier ./p/i/.htaccess et .htpasswd) * le nom d’utilisateur HTTP doit correspondre au nom d’utilisateur FreshRSS * par Mozilla Persona, en renseignant l’adresse courriel des utilisateurs @@ -68,6 +70,7 @@ * Réorganisation des fichiers et répertoires, en particulier : * Tous les fichiers utilisateur sont dans “./data/” (y compris “cache”, “favicons”, et “log”) * Déplacement de “./app/configuration/application.ini” vers “./data/config.php” + * Meilleure sécurité et compatibilité * Déplacement de “./public/data/Configuration.array.php” vers “./data/*_user.php” * Déplacement de “./public/” vers “./p/” * Déplacement de “./public/index.php” vers “./p/i/index.php” (voir cookie ci-dessous) diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 81dfefabb..772a08f30 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -47,8 +47,6 @@ class FreshRSS_index_Controller extends Minz_ActionController { $this->view->_useLayout (false); header('Content-Type: application/rss+xml; charset=utf-8'); } else { - Minz_View::appendScript (Minz_Url::display ('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); - if ($output === 'global') { Minz_View::appendScript (Minz_Url::display ('/scripts/global_view.js?' . @filemtime(PUBLIC_PATH . '/scripts/global_view.js'))); } @@ -290,8 +288,56 @@ class FreshRSS_index_Controller extends Minz_ActionController { } public function logoutAction () { + $this->view->_useLayout(false); + invalidateHttpCache(); + Minz_Session::_param('currentUser'); + Minz_Session::_param('mail'); + Minz_Session::_param('passwordHash'); + } + + public function formLoginAction () { $this->view->_useLayout (false); - Minz_Session::_param ('mail'); + 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); + } else { + Minz_Log::record('Password mismatch for user ' . $username . ', nonce=' . $nonce . ', c=' . $c, Minz_Log::WARNING); + } + } catch (Minz_Exception $me) { + Minz_Log::record('Login failure: ' . $me->getMessage(), Minz_Log::WARNING); + } + } + if (!$ok) { + $notif = array( + 'type' => 'bad', + 'content' => Minz_Translate::t('invalid_login') + ); + Minz_Session::_param('notification', $notif); + } + } + invalidateHttpCache(); + Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); + } + + public function formLogoutAction () { + $this->view->_useLayout(false); invalidateHttpCache(); + Minz_Session::_param('currentUser'); + Minz_Session::_param('mail'); + Minz_Session::_param('passwordHash'); + Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); } } diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index e29f439d8..02e424437 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -17,7 +17,7 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { $this->view->categories = $catDAO->listCategories(true, false); } - // For Web-form login + //For Web-form login public function nonceAction() { header('Content-Type: application/json; charset=UTF-8'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s \G\M\T')); @@ -29,15 +29,15 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { if (ctype_alnum($user)) { try { $conf = new FreshRSS_Configuration($user); - $hash = $conf->passwordHash; //CRYPT_BLOWFISH - Blowfish hashing with a salt as follows: "$2a$", "$2x$" or "$2y$", a two digit cost parameter, "$", and 22 characters from the alphabet "./0-9A-Za-z". - if (strlen($hash) >= 60) { - $this->view->salt1 = substr($hash, 0, 29); + $s = $conf->passwordHash; + if (strlen($s) >= 60) { + $this->view->salt1 = substr($s, 0, 29); //CRYPT_BLOWFISH Salt: "$2a$", a two digit cost parameter, "$", and 22 characters from the alphabet "./0-9A-Za-z". $this->view->nonce = sha1(Minz_Configuration::salt() . uniqid(mt_rand(), true)); - Minz_Session::_param ('nonce', $this->view->nonce); + Minz_Session::_param('nonce', $this->view->nonce); return; //Success } } catch (Minz_Exception $me) { - Minz_Log::record ('Login failure: ' . $me->getMessage(), Minz_Log::WARNING); + Minz_Log::record('Login failure: ' . $me->getMessage(), Minz_Log::WARNING); } } $this->view->nonce = ''; //Failure diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 8954c845d..cb5ebd209 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -21,18 +21,20 @@ class FreshRSS_users_Controller extends Minz_ActionController { if (!function_exists('password_hash')) { include_once(LIB_PATH . '/password_compat.php'); } - $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT); //A bit expensive, on purpose + $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => 8)); //This will also have to be computed client side on mobile devices, so do not use a too high cost $passwordPlain = ''; + $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js $this->view->conf->_passwordHash($passwordHash); } - $mail = Minz_Request::param('mail_login', false); - $this->view->conf->_mail_login($mail); + $email = Minz_Request::param('mail_login', false); + $this->view->conf->_mail_login($email); $ok &= $this->view->conf->save(); $email = $this->view->conf->mail_login; Minz_Session::_param('mail', $email); + Minz_Session::_param('passwordHash', $this->view->conf->passwordHash); if ($email != '') { $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; @@ -89,10 +91,25 @@ class FreshRSS_users_Controller extends Minz_ActionController { $ok &= !file_exists($configPath); } if ($ok) { + + $passwordPlain = Minz_Request::param('new_user_passwordPlain', false); + $passwordHash = ''; + if ($passwordPlain != '') { + Minz_Request::_param('new_user_passwordPlain'); //Discard plain-text password ASAP + $_POST['new_user_passwordPlain'] = ''; + if (!function_exists('password_hash')) { + include_once(LIB_PATH . '/password_compat.php'); + } + $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => 8)); + $passwordPlain = ''; + } + if (empty($passwordHash)) { + $passwordHash = ''; + } + $new_user_email = filter_var($_POST['new_user_email'], FILTER_VALIDATE_EMAIL); if (empty($new_user_email)) { $new_user_email = ''; - $ok &= Minz_Configuration::authType() !== 'persona'; } else { $personaFile = DATA_PATH . '/persona/' . $new_user_email . '.txt'; @unlink($personaFile); @@ -102,6 +119,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { if ($ok) { $config_array = array( 'language' => $new_user_language, + 'passwordHash' => $passwordHash, 'mail_login' => $new_user_email, ); $ok &= (file_put_contents($configPath, "accessControl(Minz_Session::param('currentUser', '')); + $loginOk = $this->accessControl(Minz_Session::param('currentUser', '')); $this->loadParamsView(); - $this->loadStylesAndScripts(); //TODO: Do not load that when not needed, e.g. some Ajax requests + $this->loadStylesAndScripts($loginOk); //TODO: Do not load that when not needed, e.g. some Ajax requests $this->loadNotifications(); } private function accessControl($currentUser) { if ($currentUser == '') { switch (Minz_Configuration::authType()) { + case 'form': + $currentUser = Minz_Configuration::defaultUser(); + Minz_Session::_param('passwordHash'); + $loginOk = false; + break; case 'http_auth': $currentUser = httpAuthUser(); $loginOk = $currentUser != ''; @@ -73,6 +78,9 @@ class FreshRSS extends Minz_FrontController { 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; @@ -92,6 +100,7 @@ class FreshRSS extends Minz_FrontController { } } Minz_View::_param ('loginOk', $loginOk); + return $loginOk; } private function loadParamsView () { @@ -104,7 +113,7 @@ class FreshRSS extends Minz_FrontController { } } - private function loadStylesAndScripts () { + private function loadStylesAndScripts ($loginOk) { $theme = FreshRSS_Themes::get_infos($this->conf->theme); if ($theme) { foreach($theme['files'] as $file) { @@ -112,14 +121,22 @@ class FreshRSS extends Minz_FrontController { } } - if (Minz_Configuration::authType() === 'persona') { - Minz_View::appendScript ('https://login.persona.org/include.js'); + 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; } $includeLazyLoad = $this->conf->lazyload && ($this->conf->display_posts || Minz_Request::param ('output') === 'reader'); Minz_View::appendScript (Minz_Url::display ('/scripts/jquery.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.min.js')), false, !$includeLazyLoad, !$includeLazyLoad); if ($includeLazyLoad) { Minz_View::appendScript (Minz_Url::display ('/scripts/jquery.lazyload.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.lazyload.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'))); } diff --git a/app/i18n/en.php b/app/i18n/en.php index 3b9936e8e..71ca9538f 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -170,6 +170,9 @@ return array ( 'is_admin' => 'is administrator', 'auth_type' => 'Authentication method', 'auth_none' => 'None (dangerous)', + 'auth_form' => 'Web form (traditional, requires JavaScript)', + 'http_auth' => 'HTTP (for advanced users with HTTPS)', + 'auth_persona' => 'Mozilla Persona (modern, requires JavaScript)', 'users_list' => 'List of users', 'create_user' => 'Create new user', 'username' => 'Username', @@ -258,8 +261,8 @@ return array ( 'logs_empty' => 'Log file is empty', 'clear_logs' => 'Clear the logs', - 'forbidden_access' => 'Forbidden access', - 'forbidden_access_description' => 'Access is password protected, please to read your feeds.', + 'forbidden_access' => 'Access forbidden! (%s)', + 'login_required' => 'Login required:', 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 7e71cbb6d..8ffc5ec88 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -170,6 +170,9 @@ return array ( 'is_admin' => 'est administrateur', 'auth_type' => 'Méthode d’authentification', 'auth_none' => 'Aucune (dangereux)', + 'auth_form' => 'Formulaire (traditionnel, requiert JavaScript)', + 'http_auth' => 'HTTP (pour utilisateurs avancés avec HTTPS)', + 'auth_persona' => 'Mozilla Persona (moderne, requiert JavaScript)', 'users_list' => 'Liste des utilisateurs', 'create_user' => 'Créer un nouvel utilisateur', 'username' => 'Nom d’utilisateur', @@ -258,8 +261,8 @@ return array ( 'logs_empty' => 'Les logs sont vides', 'clear_logs' => 'Effacer les logs', - 'forbidden_access' => 'Accès interdit', - 'forbidden_access_description' => 'L’accès est protégé par un mot de passe, veuillez pour accéder aux flux.', + 'forbidden_access' => 'Accès interdit ! (%s)', + 'login_required' => 'Accès protégé par mot de passe :', 'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !', diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 0f2c524c4..e90da6196 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -1,12 +1,25 @@ - - - +
@@ -62,16 +75,24 @@
  • - -
  • -
  • - +
  • - +
    - +
    diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 68111bdbe..1597004e1 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -20,7 +20,7 @@
    - +
    @@ -52,11 +52,11 @@
    - $_SERVER['REMOTE_USER'] = ``
    @@ -141,6 +141,14 @@
    +
    + +
    + + +
    +
    +
    conf->mail_login; ?> diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 92c068f7e..935294e60 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -30,8 +30,8 @@ if ($mail != 'null') { $mail = '"' . $mail . '"'; } - echo 'use_persona=', Minz_Configuration::authType() === 'persona' ? 'true' : 'false', - ',url_freshrss="', _url ('index', 'index'), '",', + echo 'authType="', Minz_Configuration::authType(), '",', + 'url_freshrss="', _url ('index', 'index'), '",', 'url_login="', _url ('index', 'login'), '",', 'url_logout="', _url ('index', 'logout'), '",', 'current_user_mail=', $mail, ",\n"; diff --git a/app/views/helpers/view/login.phtml b/app/views/helpers/view/login.phtml new file mode 100644 index 000000000..e4a24f9ed --- /dev/null +++ b/app/views/helpers/view/login.phtml @@ -0,0 +1,43 @@ +
    + +

    +
    + +
    + +
    +
    +
    + +
    + + + +
    +
    +
    +
    + +
    +
    +

    FreshRSS

    +

    + +

    +
    diff --git a/app/views/index/index.phtml b/app/views/index/index.phtml index 549d0b61e..9b69233e9 100644 --- a/app/views/index/index.phtml +++ b/app/views/index/index.phtml @@ -1,15 +1,5 @@
    -

    -

    -

    -
    loginOk || Minz_Configuration::allowAnonymous()) { @@ -31,8 +21,8 @@ if ($this->loginOk || Minz_Configuration::allowAnonymous()) { if ($token_is_ok) { $this->renderHelper ('view/rss_view'); } else { - showForbidden(); + $this->renderHelper ('view/login'); } } else { - showForbidden(); + $this->renderHelper ('view/login'); } diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 2c30661ed..433992e0d 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -109,7 +109,7 @@ class Minz_Configuration { return self::$auth_type !== 'none'; } public static function canLogIn() { - return self::$auth_type === 'persona'; + return self::$auth_type === 'form' || self::$auth_type === 'persona'; } public static function _allowAnonymous($allow = false) { @@ -118,6 +118,7 @@ class Minz_Configuration { public static function _authType($value) { $value = strtolower($value); switch ($value) { + case 'form': case 'http_auth': case 'persona': case 'none': diff --git a/lib/Minz/FrontController.php b/lib/Minz/FrontController.php index 7b8526bc8..80eda8877 100644 --- a/lib/Minz/FrontController.php +++ b/lib/Minz/FrontController.php @@ -34,7 +34,7 @@ class Minz_FrontController { */ public function __construct () { if (LOG_PATH === false) { - $this->killApp ('Path doesn’t exist : LOG_PATH'); + $this->killApp ('Path not found: LOG_PATH'); } try { diff --git a/p/scripts/main.js b/p/scripts/main.js index 24af1b210..0c4c3f1b2 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -587,6 +587,54 @@ function init_load_more(box) { } // +// +function poormanSalt() { //If crypto.getRandomValues is not available + var text = '$2a$04$', + base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ.0123456789/abcdefghijklmnopqrstuvwxyz'; + for (var i = 22; i > 0; i--) { + text += base.charAt(Math.floor(Math.random() * 64)); + } + return text; +} + +function init_loginForm() { + var $loginForm = $('#loginForm'); + if ($loginForm.length === 0) { + return; + } + if (!(window.dcodeIO)) { + if (window.console) { + console.log('FreshRSS waiting for bcrypt.js…'); + } + window.setTimeout(init_loginForm, 100); + return; + } + $loginForm.on('submit', function() { + $('#loginButton').attr('disabled', ''); + var success = false; + $.ajax({ + url: './?c=javascript&a=nonce&user=' + $('#username').val(), + dataType: 'json', + async: false + }).done(function (data) { + if (data.salt1 == '' || data.nonce == '') { + alert('Invalid user!'); + } else { + var strong = window.Uint32Array && window.crypto && (typeof window.crypto.getRandomValues === 'function'), + s = dcodeIO.bcrypt.hashSync($('#passwordPlain').val(), data.salt1), + c = dcodeIO.bcrypt.hashSync(data.nonce + s, strong ? 4 : poormanSalt()); + $('#challenge').val(c); + success = true; + } + }).fail(function() { + alert('Communication error!'); + }); + $('#loginButton').removeAttr('disabled'); + return success; + }); +} +// + // function init_persona() { if (!(navigator.id)) { @@ -696,8 +744,13 @@ function init_all() { init_notifications(); init_actualize(); init_load_more($stream); - if (use_persona) { - init_persona(); + switch (authType) { + case 'form': + init_loginForm(); + break; + case 'persona': + init_persona(); + break; } init_confirm_action(); init_print_action(); -- cgit v1.2.3 From 0f481f7f24dfad3bf9775213f487dd6802b6cb6a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 12 Jan 2014 14:00:02 +0100 Subject: Permet aux utilisations non-administrateurs de changer leur mot de passe https://github.com/marienfressinaud/FreshRSS/issues/104 --- app/Controllers/usersController.php | 21 +++++++++++++-------- app/views/configure/users.phtml | 2 -- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index cb5ebd209..7e44b3d35 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -1,6 +1,9 @@ view->loginOk) { Minz_Error::error( @@ -21,20 +24,21 @@ class FreshRSS_users_Controller extends Minz_ActionController { if (!function_exists('password_hash')) { include_once(LIB_PATH . '/password_compat.php'); } - $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => 8)); //This will also have to be computed client side on mobile devices, so do not use a too high cost + $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); $passwordPlain = ''; $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js + $ok &= ($passwordHash != ''); $this->view->conf->_passwordHash($passwordHash); } + Minz_Session::_param('passwordHash', $this->view->conf->passwordHash); - $email = Minz_Request::param('mail_login', false); - $this->view->conf->_mail_login($email); - - $ok &= $this->view->conf->save(); - + if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + $this->view->conf->_mail_login(Minz_Request::param('mail_login', false)); + } $email = $this->view->conf->mail_login; Minz_Session::_param('mail', $email); - Minz_Session::_param('passwordHash', $this->view->conf->passwordHash); + + $ok &= $this->view->conf->save(); if ($email != '') { $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; @@ -100,8 +104,9 @@ class FreshRSS_users_Controller extends Minz_ActionController { if (!function_exists('password_hash')) { include_once(LIB_PATH . '/password_compat.php'); } - $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => 8)); + $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); $passwordPlain = ''; + $ok &= ($passwordHash != ''); } if (empty($passwordHash)) { $passwordHash = ''; diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 1597004e1..0419df747 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -34,14 +34,12 @@
    -
    - -- cgit v1.2.3 From 41033768c3eacbd564c3ec15455587e4f725a055 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 18 Jan 2014 01:00:17 +0100 Subject: Mode anonyme pour connexion avec formulaire MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contribue à https://github.com/marienfressinaud/FreshRSS/issues/361 --- app/Controllers/usersController.php | 2 +- app/views/configure/users.phtml | 18 ++++-------------- lib/Minz/Configuration.php | 9 +++++---- 3 files changed, 10 insertions(+), 19 deletions(-) (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 7e44b3d35..a044cd25b 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -57,8 +57,8 @@ class FreshRSS_users_Controller extends Minz_ActionController { $auth_type = Minz_Request::param('auth_type', 'none'); if ($anon != Minz_Configuration::allowAnonymous() || $auth_type != Minz_Configuration::authType()) { - Minz_Configuration::_allowAnonymous($anon); Minz_Configuration::_authType($auth_type); + Minz_Configuration::_allowAnonymous($anon); $ok &= Minz_Configuration::writeFile(); } } diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 602dfaf62..3f352f9bf 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -58,20 +58,11 @@ -
    -
    - - -
    -
    - - - - Mozilla Persona
    @@ -81,7 +72,8 @@ conf->token; ?>
    - + />
    @@ -92,8 +84,6 @@ - -
    diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 433992e0d..72e2cedc0 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -113,7 +113,7 @@ class Minz_Configuration { } public static function _allowAnonymous($allow = false) { - self::$allow_anonymous = (bool)$allow; + self::$allow_anonymous = ((bool)$allow) && self::canLogIn(); } public static function _authType($value) { $value = strtolower($value); @@ -125,6 +125,7 @@ class Minz_Configuration { self::$auth_type = $value; break; } + self::_allowAnonymous(self::$allow_anonymous); } /** @@ -252,12 +253,12 @@ class Minz_Configuration { if (isset ($general['default_user'])) { self::$default_user = $general['default_user']; } - if (isset ($general['allow_anonymous'])) { - self::$allow_anonymous = ((bool)($general['allow_anonymous'])) && ($general['allow_anonymous'] !== 'no'); - } if (isset ($general['auth_type'])) { self::_authType($general['auth_type']); } + if (isset ($general['allow_anonymous'])) { + self::$allow_anonymous = ((bool)($general['allow_anonymous'])) && ($general['allow_anonymous'] !== 'no'); + } // Base de données if (isset ($ini_array['db'])) { -- cgit v1.2.3 From 7a510af73a0ef04ce09fb7eedd98c844e7bff51c Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 26 Jan 2014 19:06:42 +0100 Subject: Compatibilité bcrypt.js oubliée MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Corrige https://github.com/marienfressinaud/FreshRSS/issues/396 + Ajoute de meilleurs messages d'erreur --- app/Controllers/indexController.php | 2 ++ app/Controllers/javascriptController.php | 2 +- app/Controllers/usersController.php | 1 + p/scripts/main.js | 20 ++++++++++++-------- 4 files changed, 16 insertions(+), 9 deletions(-) (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index cb6be6049..c49054a5c 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -320,6 +320,8 @@ class FreshRSS_index_Controller extends Minz_ActionController { } catch (Minz_Exception $me) { Minz_Log::record('Login failure: ' . $me->getMessage(), Minz_Log::WARNING); } + } else { + Minz_Log::record('Invalid credential parameters: user=' . $username . ' challenge=' . $c . ' nonce=' . $nonce, Minz_Log::DEBUG); } if (!$ok) { $notif = array( diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index 02e424437..b879dcd6d 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -37,7 +37,7 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { return; //Success } } catch (Minz_Exception $me) { - Minz_Log::record('Login failure: ' . $me->getMessage(), Minz_Log::WARNING); + Minz_Log::record('Nonce failure: ' . $me->getMessage(), Minz_Log::WARNING); } } $this->view->nonce = ''; //Failure diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index a044cd25b..8314b75fc 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -106,6 +106,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { } $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); $passwordPlain = ''; + $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js $ok &= ($passwordHash != ''); } if (empty($passwordHash)) { diff --git a/p/scripts/main.js b/p/scripts/main.js index d891299a8..d775b3a20 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -626,14 +626,18 @@ function init_loginForm() { if (data.salt1 == '' || data.nonce == '') { alert('Invalid user!'); } else { - var strong = window.Uint32Array && window.crypto && (typeof window.crypto.getRandomValues === 'function'), - s = dcodeIO.bcrypt.hashSync($('#passwordPlain').val(), data.salt1), - c = dcodeIO.bcrypt.hashSync(data.nonce + s, strong ? 4 : poormanSalt()); - $('#challenge').val(c); - if (s == '' || c == '') { - alert('Crypto error!'); - } else { - success = true; + try { + var strong = window.Uint32Array && window.crypto && (typeof window.crypto.getRandomValues === 'function'), + s = dcodeIO.bcrypt.hashSync($('#passwordPlain').val(), data.salt1), + c = dcodeIO.bcrypt.hashSync(data.nonce + s, strong ? 4 : poormanSalt()); + $('#challenge').val(c); + if (s == '' || c == '') { + alert('Crypto error!'); + } else { + success = true; + } + } catch (e) { + alert('Crypto exception! ' + e); } } }).fail(function() { -- cgit v1.2.3 From 4dd673157b05fea5fe3643f16e22d01bbf005fe9 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 13 Feb 2014 21:45:25 +0100 Subject: Add possibility to anonymous to refresh feeds Obviously, it's optional! (and deactivate by default) Need some more tests? See #351 --- app/Controllers/feedController.php | 4 +++- app/Controllers/usersController.php | 7 ++++++- app/i18n/en.php | 1 + app/i18n/fr.php | 1 + app/layout/nav_menu.phtml | 4 +++- app/views/configure/users.phtml | 10 ++++++++++ lib/Minz/Configuration.php | 19 ++++++++++++++++++- 7 files changed, 42 insertions(+), 4 deletions(-) (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 264607216..7114fc196 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -7,7 +7,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $token_param = Minz_Request::param ('token', ''); $token_is_ok = ($token != '' && $token == $token_param); $action = Minz_Request::actionName (); - if (!($token_is_ok && $action === 'actualize')) { + if (!(($token_is_ok || Minz_Configuration::allowAnonymousRefresh()) && + $action === 'actualize') + ) { Minz_Error::error ( 403, array ('error' => array (Minz_Translate::t ('access_denied'))) diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 8314b75fc..bb4f34c5e 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -54,11 +54,16 @@ class FreshRSS_users_Controller extends Minz_ActionController { $anon = Minz_Request::param('anon_access', false); $anon = ((bool)$anon) && ($anon !== 'no'); + $anon_refresh = Minz_Request::param('anon_refresh', false); + $anon_refresh = ((bool)$anon_refresh) && ($anon_refresh !== 'no'); $auth_type = Minz_Request::param('auth_type', 'none'); if ($anon != Minz_Configuration::allowAnonymous() || - $auth_type != Minz_Configuration::authType()) { + $auth_type != Minz_Configuration::authType() || + $anon_refresh != Minz_Configuration::allowAnonymousRefresh()) { + Minz_Configuration::_authType($auth_type); Minz_Configuration::_allowAnonymous($anon); + Minz_Configuration::_allowAnonymousRefresh($anon_refresh); $ok &= Minz_Configuration::writeFile(); } } diff --git a/app/i18n/en.php b/app/i18n/en.php index 369853610..fd51eb1ca 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -175,6 +175,7 @@ return array ( 'password_form' => 'Password
    (for the Web-form login method)', 'persona_connection_email' => 'Login mail address
    (for Mozilla Persona)', 'allow_anonymous' => 'Allow anonymous reading of the articles of the default user (%s)', + 'allow_anonymous_refresh' => 'Allow anonymous refresh of the articles', 'auth_token' => 'Authentication token', 'explain_token' => 'Allows to access RSS output of the default user without authentication.
    %s?output=rss&token=%s', 'login_configuration' => 'Login', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 275c3b1d8..17e26f493 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -175,6 +175,7 @@ return array ( 'default_user' => 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)', 'persona_connection_email' => 'Adresse courriel de connexion
    (pour Mozilla Persona)', 'allow_anonymous' => 'Autoriser la lecture anonyme des articles de l’utilisateur par défaut (%s)', + 'allow_anonymous_refresh' => 'Autoriser le rafraîchissement anonyme des flux', 'auth_token' => 'Jeton d’identification', 'explain_token' => 'Permet d’accéder à la sortie RSS de l’utilisateur par défaut sans besoin de s’authentifier.
    %s?output=rss&token=%s', 'login_configuration' => 'Identification', diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index c807e6dd5..98064a6f7 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -6,9 +6,11 @@ - loginOk) { ?> + loginOk || Minz_Configuration::allowAnonymousRefresh()) { ?> + + loginOk) { ?> +
    +
    + +
    +
    +
    diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 572b9984d..b3de9e39e 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -52,6 +52,7 @@ class Minz_Configuration { private static $delay_cache = 3600; private static $default_user = ''; private static $allow_anonymous = false; + private static $allow_anonymous_refresh = false; private static $auth_type = 'none'; private static $db = array ( @@ -118,6 +119,9 @@ class Minz_Configuration { public static function allowAnonymous() { return self::$allow_anonymous; } + public static function allowAnonymousRefresh() { + return self::$allow_anonymous_refresh; + } public static function authType() { return self::$auth_type; } @@ -131,6 +135,9 @@ class Minz_Configuration { public static function _allowAnonymous($allow = false) { self::$allow_anonymous = ((bool)$allow) && self::canLogIn(); } + public static function _allowAnonymousRefresh($allow = false) { + self::$allow_anonymous_refresh = ((bool)$allow) && self::allowAnonymous(); + } public static function _authType($value) { $value = strtolower($value); switch ($value) { @@ -170,6 +177,7 @@ class Minz_Configuration { 'title' => self::$title, 'default_user' => self::$default_user, 'allow_anonymous' => self::$allow_anonymous, + 'allow_anonymous_refresh' => self::$allow_anonymous_refresh, 'auth_type' => self::$auth_type, ), 'db' => self::$db, @@ -276,7 +284,16 @@ class Minz_Configuration { self::_authType($general['auth_type']); } if (isset ($general['allow_anonymous'])) { - self::$allow_anonymous = ((bool)($general['allow_anonymous'])) && ($general['allow_anonymous'] !== 'no'); + self::$allow_anonymous = ( + ((bool)($general['allow_anonymous'])) && + ($general['allow_anonymous'] !== 'no') + ); + } + if (isset ($general['allow_anonymous_refresh'])) { + self::$allow_anonymous_refresh = ( + ((bool)($general['allow_anonymous_refresh'])) && + ($general['allow_anonymous_refresh'] !== 'no') + ); } // Base de données -- cgit v1.2.3 From 29b3bbfe284a6e56413a2e89b740ffc4172c6847 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 1 Mar 2014 14:45:58 +0100 Subject: API: Real password system https://github.com/marienfressinaud/FreshRSS/issues/13 Expiring token not implemented yet --- app/Controllers/usersController.php | 12 +++++ app/Models/Configuration.php | 4 ++ app/i18n/en.php | 1 + app/i18n/fr.php | 1 + app/views/configure/users.phtml | 12 ++++- p/api/greader.php | 89 ++++++++++++++++++++++--------------- 6 files changed, 82 insertions(+), 37 deletions(-) (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index bb4f34c5e..b03989cd7 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -32,6 +32,18 @@ class FreshRSS_users_Controller extends Minz_ActionController { } Minz_Session::_param('passwordHash', $this->view->conf->passwordHash); + $passwordPlain = Minz_Request::param('apiPasswordPlain', false); + if ($passwordPlain != '') { + if (!function_exists('password_hash')) { + include_once(LIB_PATH . '/password_compat.php'); + } + $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); + $passwordPlain = ''; + $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js + $ok &= ($passwordHash != ''); + $this->view->conf->_apiPasswordHash($passwordHash); + } + if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { $this->view->conf->_mail_login(Minz_Request::param('mail_login', false)); } diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 48efe3bf6..827a1d166 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -10,6 +10,7 @@ class FreshRSS_Configuration { 'mail_login' => '', 'token' => '', 'passwordHash' => '', //CRYPT_BLOWFISH + 'apiPasswordHash' => '', //CRYPT_BLOWFISH 'posts_per_page' => 20, 'view_mode' => 'normal', 'default_view' => 'not_read', @@ -165,6 +166,9 @@ class FreshRSS_Configuration { public function _passwordHash ($value) { $this->data['passwordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : ''; } + public function _apiPasswordHash ($value) { + $this->data['apiPasswordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : ''; + } public function _mail_login ($value) { $value = filter_var($value, FILTER_VALIDATE_EMAIL); if ($value) { diff --git a/app/i18n/en.php b/app/i18n/en.php index e67447520..d504ffc11 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -176,6 +176,7 @@ return array ( 'current_user' => 'Current user', 'default_user' => 'Username of the default user (maximum 16 alphanumeric characters)', 'password_form' => 'Password
    (for the Web-form login method)', + 'password_api' => 'Password API
    (e.g., for mobile apps)', 'persona_connection_email' => 'Login mail address
    (for Mozilla Persona)', 'allow_anonymous' => 'Allow anonymous reading of the articles of the default user (%s)', 'allow_anonymous_refresh' => 'Allow anonymous refresh of the articles', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 2bd4fabab..c5581a78b 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -175,6 +175,7 @@ return array ( 'current_user' => 'Utilisateur actuel', 'password_form' => 'Mot de passe
    (pour connexion par formulaire)', + 'password_api' => 'Mot de passe API
    (ex. : pour applis mobiles)', 'default_user' => 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)', 'persona_connection_email' => 'Adresse courriel de connexion
    (pour Mozilla Persona)', 'allow_anonymous' => 'Autoriser la lecture anonyme des articles de l’utilisateur par défaut (%s)', diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 0677db881..f5c7dff17 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -20,7 +20,15 @@
    - + /> + +
    +
    + +
    + +
    + />
    @@ -85,7 +93,7 @@ conf->token; ?>
    - />
    diff --git a/p/api/greader.php b/p/api/greader.php index e99e1c0c8..035a031dd 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -20,9 +20,6 @@ Server-side API compatible with Google Reader API layer 2 * https://github.com/theoldreader/api */ -define('TEMP_PASSWORD', 'temp123'); //Change to another ASCII password -define('TEMP_AUTH', 'XtofqkkOkCULRLH8'); //Change to another random ASCII auth - require('../../constants.php'); require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader @@ -119,14 +116,28 @@ function checkCompatibility() { exit(); } -function authorizationToUser() { +function authorizationToUserConf() { $headerAuth = headerVariable('Authorization', 'GoogleLogin_auth'); //Input is 'GoogleLogin auth', but PHP replaces spaces by '_' http://php.net/language.variables.external if ($headerAuth != '') { $headerAuthX = explode('/', $headerAuth, 2); - if ((count($headerAuthX) === 2) && ($headerAuthX[1] === TEMP_AUTH)) { + if (count($headerAuthX) === 2) { $user = $headerAuthX[0]; if (ctype_alnum($user)) { - return $user; + try { + $conf = new FreshRSS_Configuration($user); + } catch (Exception $e) { + logMe($e->getMessage() . "\n"); + unauthorized(); + } + if ($headerAuthX[1] === sha1(Minz_Configuration::salt() . $conf->user . $conf->apiPasswordHash)) { + return $conf; + } else { + logMe('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1] . "\n"); + Minz_Log::record('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1], Minz_Log::WARNING); + unauthorized(); + } + } else { + badRequest(); } } } @@ -135,28 +146,45 @@ function authorizationToUser() { function clientLogin($email, $pass) { //http://web.archive.org/web/20130604091042/http://undoc.in/clientLogin.html logMe('clientLogin(' . $email . ")\n"); - if ($pass !== TEMP_PASSWORD) { - unauthorized(); + if (ctype_alnum($email)) { + if (!function_exists('password_verify')) { + include_once(LIB_PATH . '/password_compat.php'); + } + try { + $conf = new FreshRSS_Configuration($email); + } catch (Exception $e) { + logMe($e->getMessage() . "\n"); + Minz_Log::record('Invalid API user ' . $email, Minz_Log::WARNING); + unauthorized(); + } + if ($conf->apiPasswordHash != '' && password_verify($pass, $conf->apiPasswordHash)) { + header('Content-Type: text/plain; charset=UTF-8'); + $auth = $email . '/' . sha1(Minz_Configuration::salt() . $conf->user . $conf->apiPasswordHash); + echo 'SID=', $auth, "\n", + 'Auth=', $auth, "\n"; + exit(); + } else { + Minz_Log::record('Password API mismatch for user ' . $email, Minz_Log::WARNING); + unauthorized(); + } + } else { + badRequest(); } - header('Content-Type: text/plain; charset=UTF-8'); - $auth = $email . '/' . TEMP_AUTH; - echo 'SID=', $auth, "\n", - 'Auth=', $auth, "\n"; - exit(); + die(); } -function token($user) { +function token($conf) { //http://blog.martindoms.com/2009/08/15/using-the-google-reader-api-part-1/ https://github.com/ericmann/gReader-Library/blob/master/greader.class.php - logMe('token('. $user . ")\n"); - $token = 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ01234'; //Must have 57 characters... + logMe('token('. $conf->user . ")\n"); //TODO: Implement real token that expires + $token = str_pad(sha1(Minz_Configuration::salt() . $conf->user . $conf->apiPasswordHash), 57, 'Z'); //Must have 57 characters echo $token, "\n"; exit(); } -function checkToken($user, $token) { +function checkToken($conf, $token) { //http://code.google.com/p/google-reader-api/wiki/ActionToken logMe('checkToken(' . $token . ")\n"); - if ($token === 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ01234') { + if ($token === str_pad(sha1(Minz_Configuration::salt() . $conf->user . $conf->apiPasswordHash), 57, 'Z')) { return true; } unauthorized(); @@ -462,32 +490,23 @@ if (!Minz_Configuration::apiEnabled()) { Minz_Session::init('FreshRSS'); -$user = authorizationToUser(); -$conf = null; +$conf = authorizationToUserConf(); +$user = $conf == null ? '' : $conf->user; logMe('User => ' . $user . "\n"); -if ($user != null) { - try { - $conf = new FreshRSS_Configuration($user); - } catch (Exception $e) { - logMe($e->getMessage()); - $user = null; - badRequest(); - } -} - Minz_Session::_param('currentUser', $user); if (count($pathInfos) < 3) { badRequest(); } elseif ($pathInfos[1] === 'accounts') { - if (($pathInfos[2] === 'ClientLogin') && isset($_REQUEST['Email']) && isset($_REQUEST['Passwd'])) + if (($pathInfos[2] === 'ClientLogin') && isset($_REQUEST['Email']) && isset($_REQUEST['Passwd'])) { clientLogin($_REQUEST['Email'], $_REQUEST['Passwd']); + } } elseif ($pathInfos[1] === 'reader' && $pathInfos[2] === 'api' && isset($pathInfos[3]) && $pathInfos[3] === '0' && isset($pathInfos[4])) { - if ($user == null) { + if ($user == '') { unauthorized(); } $timestamp = isset($_GET['ck']) ? intval($_GET['ck']) : 0; //ck=[unix timestamp] : Use the current Unix time here, helps Google with caching. @@ -543,7 +562,7 @@ elseif ($pathInfos[1] === 'reader' && $pathInfos[2] === 'api' && isset($pathInfo break; case 'edit-tag': //http://blog.martindoms.com/2010/01/20/using-the-google-reader-api-part-3/ $token = isset($_POST['T']) ? trim($_POST['T']) : ''; - checkToken($user, $token); + checkToken($conf, $token); $a = isset($_POST['a']) ? $_POST['a'] : ''; //Add: user/-/state/com.google/read user/-/state/com.google/starred $r = isset($_POST['r']) ? $_POST['r'] : ''; //Remove: user/-/state/com.google/read user/-/state/com.google/starred $e_ids = multiplePosts('i'); //item IDs @@ -551,7 +570,7 @@ elseif ($pathInfos[1] === 'reader' && $pathInfos[2] === 'api' && isset($pathInfo break; case 'mark-all-as-read': $token = isset($_POST['T']) ? trim($_POST['T']) : ''; - checkToken($user, $token); + checkToken($conf, $token); $streamId = $_POST['s']; //StreamId $ts = isset($_POST['ts']) ? $_POST['ts'] : '0'; //Older than timestamp in nanoseconds if (!ctype_digit($ts)) { @@ -560,7 +579,7 @@ elseif ($pathInfos[1] === 'reader' && $pathInfos[2] === 'api' && isset($pathInfo markAllAsRead($streamId, $ts); break; case 'token': - Token($user); + Token($conf); break; } } elseif ($pathInfos[1] === 'check' && $pathInfos[2] === 'compatibility') { -- cgit v1.2.3 From 670ee57b6288549ac611d53d86d8f5ffee641b0e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 8 Mar 2014 20:16:10 +0100 Subject: Interface to enable/disable API and unsafe automatic login https://github.com/marienfressinaud/FreshRSS/issues/13 https://github.com/marienfressinaud/FreshRSS/issues/440 --- app/Controllers/usersController.php | 8 +++++++- app/Models/Feed.php | 11 ++++++----- app/i18n/en.php | 2 ++ app/i18n/fr.php | 2 ++ app/views/configure/users.phtml | 21 +++++++++++++++++++++ 5 files changed, 38 insertions(+), 6 deletions(-) (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index b03989cd7..fa967cedc 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -69,13 +69,19 @@ class FreshRSS_users_Controller extends Minz_ActionController { $anon_refresh = Minz_Request::param('anon_refresh', false); $anon_refresh = ((bool)$anon_refresh) && ($anon_refresh !== 'no'); $auth_type = Minz_Request::param('auth_type', 'none'); + $unsafe_autologin = Minz_Request::param('unsafe_autologin', false); + $api_enabled = Minz_Request::param('api_enabled', false); if ($anon != Minz_Configuration::allowAnonymous() || $auth_type != Minz_Configuration::authType() || - $anon_refresh != Minz_Configuration::allowAnonymousRefresh()) { + $anon_refresh != Minz_Configuration::allowAnonymousRefresh() || + $unsafe_autologin != Minz_Configuration::unsafeAutologinEnabled() || + $api_enabled != Minz_Configuration::apiEnabled()) { Minz_Configuration::_authType($auth_type); Minz_Configuration::_allowAnonymous($anon); Minz_Configuration::_allowAnonymousRefresh($anon_refresh); + Minz_Configuration::_enableAutologin($unsafe_autologin); + Minz_Configuration::_enableApi($api_enabled); $ok &= Minz_Configuration::writeFile(); } } diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 73f9c32fb..bce3bd24f 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -254,11 +254,12 @@ class FreshRSS_Feed extends Minz_Model { $elinks = array(); foreach ($item->get_enclosures() as $enclosure) { $elink = $enclosure->get_link(); - if (array_key_exists($elink, $elinks)) continue; - $elinks[$elink] = '1'; - $mime = strtolower($enclosure->get_type()); - if (strpos($mime, 'image/') === 0) { - $content .= '
    '; + if (empty($elinks[$elink])) { + $elinks[$elink] = '1'; + $mime = strtolower($enclosure->get_type()); + if (strpos($mime, 'image/') === 0) { + $content .= '
    '; + } } } diff --git a/app/i18n/en.php b/app/i18n/en.php index d504ffc11..69247165f 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -180,6 +180,8 @@ return array ( 'persona_connection_email' => 'Login mail address
    (for Mozilla Persona)', 'allow_anonymous' => 'Allow anonymous reading of the articles of the default user (%s)', 'allow_anonymous_refresh' => 'Allow anonymous refresh of the articles', + 'unsafe_autologin' => 'Allow unsafe automatic login using the format: ', + 'api_enabled' => 'Allow API access (required for mobile apps)', 'auth_token' => 'Authentication token', 'explain_token' => 'Allows to access RSS output of the default user without authentication.
    %s?output=rss&token=%s', 'login_configuration' => 'Login', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index c5581a78b..e364ed130 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -180,6 +180,8 @@ return array ( 'persona_connection_email' => 'Adresse courriel de connexion
    (pour Mozilla Persona)', 'allow_anonymous' => 'Autoriser la lecture anonyme des articles de l’utilisateur par défaut (%s)', 'allow_anonymous_refresh' => 'Autoriser le rafraîchissement anonyme des flux', + 'unsafe_autologin' => 'Autoriser les connexion automatiques non-sûres au format : ', + 'api_enabled' => 'Autoriser l’accès par API (nécessaire pour les applis mobiles)', 'auth_token' => 'Jeton d’identification', 'explain_token' => 'Permet d’accéder à la sortie RSS de l’utilisateur par défaut sans besoin de s’authentifier.
    %s?output=rss&token=%s', 'login_configuration' => 'Identification', diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 3f3f19418..1a02b0e90 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -90,6 +90,17 @@
    +
    +
    + +
    +
    +
    @@ -102,6 +113,16 @@
    +
    +
    + +
    +
    +
    -- cgit v1.2.3 From ab233dc2d29a36c58495a87b23a7a7883c7a7dbd Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 14 Jun 2014 14:19:44 +0200 Subject: Solve bug for passwords with special characters https://github.com/marienfressinaud/FreshRSS/issues/328#issuecomment-43250647 --- app/Controllers/usersController.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index fa967cedc..38b8f829b 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -17,7 +17,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { if (Minz_Request::isPost()) { $ok = true; - $passwordPlain = Minz_Request::param('passwordPlain', false); + $passwordPlain = Minz_Request::param('passwordPlain', '', true); if ($passwordPlain != '') { Minz_Request::_param('passwordPlain'); //Discard plain-text password ASAP $_POST['passwordPlain'] = ''; @@ -32,7 +32,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { } Minz_Session::_param('passwordHash', $this->view->conf->passwordHash); - $passwordPlain = Minz_Request::param('apiPasswordPlain', false); + $passwordPlain = Minz_Request::param('apiPasswordPlain', '', true); if ($passwordPlain != '') { if (!function_exists('password_hash')) { include_once(LIB_PATH . '/password_compat.php'); @@ -45,7 +45,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { } if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { - $this->view->conf->_mail_login(Minz_Request::param('mail_login', false)); + $this->view->conf->_mail_login(Minz_Request::param('mail_login', '', true)); } $email = $this->view->conf->mail_login; Minz_Session::_param('mail', $email); @@ -119,7 +119,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { } if ($ok) { - $passwordPlain = Minz_Request::param('new_user_passwordPlain', false); + $passwordPlain = Minz_Request::param('new_user_passwordPlain', '', true); $passwordHash = ''; if ($passwordPlain != '') { Minz_Request::_param('new_user_passwordPlain'); //Discard plain-text password ASAP -- cgit v1.2.3 From d6f414108667f32fe2b480adeb7ec9c218db2f4a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 3 Jul 2014 21:26:30 +0200 Subject: Preparation for SQLite https://github.com/marienfressinaud/FreshRSS/issues/100 --- app/Controllers/configureController.php | 2 +- app/Controllers/entryController.php | 6 +- app/Controllers/feedController.php | 4 +- app/Controllers/importExportController.php | 2 +- app/Controllers/indexController.php | 2 +- app/Controllers/usersController.php | 6 +- app/Models/CategoryDAO.php | 12 ++-- app/Models/Entry.php | 2 +- app/Models/EntryDAO.php | 101 +++++++++++++++++------------ app/Models/EntryDAO_SQLite.php | 42 ++++++++++++ app/Models/Factory.php | 13 ++++ app/Models/FeedDAO.php | 46 ++++++------- app/Models/UserDAO.php | 31 ++++++--- app/SQL/install.sql.mysql.php | 60 +++++++++++++++++ app/SQL/install.sql.sqlite.php | 57 ++++++++++++++++ app/sql.php | 58 ----------------- lib/Minz/Configuration.php | 80 ++++++++++++++--------- lib/Minz/ModelPdo.php | 52 +++++++++------ 18 files changed, 375 insertions(+), 201 deletions(-) create mode 100644 app/Models/EntryDAO_SQLite.php create mode 100644 app/Models/Factory.php create mode 100644 app/SQL/install.sql.mysql.php create mode 100644 app/SQL/install.sql.sqlite.php delete mode 100644 app/sql.php (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 89130cae4..cb8e6528f 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -291,7 +291,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_View::prependTitle(Minz_Translate::t('archiving_configuration') . ' · '); - $entryDAO = new FreshRSS_EntryDAO(); + $entryDAO = FreshRSS_Factory::createEntryDao(); $this->view->nb_total = $entryDAO->count(); $this->view->size_user = $entryDAO->size(); diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index bbcb990f5..c2d897cf3 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -43,7 +43,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $nextGet = Minz_Request::param ('nextGet', $get); $idMax = Minz_Request::param ('idMax', 0); - $entryDAO = new FreshRSS_EntryDAO (); + $entryDAO = FreshRSS_Factory::createEntryDao(); if ($id == false) { if (!$get) { $entryDAO->markReadEntries ($idMax); @@ -85,7 +85,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $id = Minz_Request::param ('id'); if ($id) { - $entryDAO = new FreshRSS_EntryDAO (); + $entryDAO = FreshRSS_Factory::createEntryDao(); $entryDAO->markFavorite ($id, (bool)(Minz_Request::param ('is_favorite', true))); } } @@ -97,7 +97,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { // La table des entrées a tendance à grossir énormément // Cette action permet d'optimiser cette table permettant de grapiller un peu de place // Cette fonctionnalité n'est à appeler qu'occasionnellement - $entryDAO = new FreshRSS_EntryDAO(); + $entryDAO = FreshRSS_Factory::createEntryDao(); $entryDAO->optimizeTable(); $feedDAO = new FreshRSS_FeedDAO(); diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 5f5a40bc7..149557a48 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -102,7 +102,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $is_read = $this->view->conf->mark_when['reception'] ? 1 : 0; - $entryDAO = new FreshRSS_EntryDAO (); + $entryDAO = FreshRSS_Factory::createEntryDao(); $entries = array_reverse($feed->entries()); //We want chronological order and SimplePie uses reverse order // on calcule la date des articles les plus anciens qu'on accepte @@ -217,7 +217,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { @set_time_limit(300); $feedDAO = new FreshRSS_FeedDAO (); - $entryDAO = new FreshRSS_EntryDAO (); + $entryDAO = FreshRSS_Factory::createEntryDao(); Minz_Session::_param('actualize_feeds', false); $id = Minz_Request::param ('id'); diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 3cd791781..12154d9b6 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -12,7 +12,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { require_once(LIB_PATH . '/lib_opml.php'); $this->catDAO = new FreshRSS_CategoryDAO(); - $this->entryDAO = new FreshRSS_EntryDAO(); + $this->entryDAO = FreshRSS_Factory::createEntryDao(); $this->feedDAO = new FreshRSS_FeedDAO(); } diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index c3f39fbe5..46c9518c9 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -45,7 +45,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } $catDAO = new FreshRSS_CategoryDAO(); - $entryDAO = new FreshRSS_EntryDAO(); + $entryDAO = FreshRSS_Factory::createEntryDao(); $this->view->cat_aside = $catDAO->listCategories (); $this->view->nb_favorites = $entryDAO->countUnreadReadFavorites (); diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 38b8f829b..35fa3675f 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -99,7 +99,8 @@ class FreshRSS_users_Controller extends Minz_ActionController { public function createAction() { if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { - require_once(APP_PATH . '/sql.php'); + $db = Minz_Configuration::dataBase(); + require_once(APP_PATH . '/SQL/sql.' . $db['type'] . '.php'); $new_user_language = Minz_Request::param('new_user_language', $this->view->conf->language); if (!in_array($new_user_language, $this->view->conf->availableLanguages())) { @@ -170,7 +171,8 @@ class FreshRSS_users_Controller extends Minz_ActionController { public function deleteAction() { if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { - require_once(APP_PATH . '/sql.php'); + $db = Minz_Configuration::dataBase(); + require_once(APP_PATH . '/SQL/sql.' . $db['type'] . '.php'); $username = Minz_Request::param('username'); $ok = ctype_alnum($username); diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index 6a9b839b9..3003dea0d 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -12,8 +12,8 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { if ($stm && $stm->execute ($values)) { return $this->bd->lastInsertId(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error addCategory: ' . $info[2], Minz_Log::ERROR); return false; } } @@ -43,8 +43,8 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error updateCategory: ' . $info[2], Minz_Log::ERROR); return false; } } @@ -58,8 +58,8 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error deleteCategory: ' . $info[2], Minz_Log::ERROR); return false; } } diff --git a/app/Models/Entry.php b/app/Models/Entry.php index fa9066d5b..a24a902d5 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -154,7 +154,7 @@ class FreshRSS_Entry extends Minz_Model { // Gestion du contenu // On cherche à récupérer les articles en entier... même si le flux ne le propose pas if ($pathEntries) { - $entryDAO = new FreshRSS_EntryDAO(); + $entryDAO = FreshRSS_Factory::createEntryDao(); $entry = $entryDAO->searchByGuid($this->feed, $this->guid); if($entry) { diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 4e24541dc..9ba0d2128 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -1,9 +1,18 @@ prefix . 'entry`(id, guid, title, author, content_bin, link, date, is_read, is_favorite, id_feed, tags) ' - . 'VALUES(?, ?, ?, ?, COMPRESS(?), ?, ?, ?, ?, ?, ?)'; + $sql = 'INSERT INTO `' . $this->prefix . 'entry`(id, guid, title, author, ' + . ($this->isCompressed() ? 'content_bin' : 'content') + . ', link, date, is_read, is_favorite, id_feed, tags) ' + . 'VALUES(?, ?, ?, ?, ' + . ($this->isCompressed() ? 'COMPRESS(?)' : '?') + . ', ?, ?, ?, ?, ?, ?)'; $stm = $this->bd->prepare ($sql); $values = array ( @@ -23,9 +32,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { if ($stm && $stm->execute ($values)) { return $this->bd->lastInsertId(); } else { - $info = $stm->errorInfo(); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); if ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries - Minz_Log::record ('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] + Minz_Log::record('SQL error addEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title'], Minz_Log::ERROR); } /*else { Minz_Log::record ('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] @@ -78,14 +87,14 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markFavorite: ' . $info[2], Minz_Log::ERROR); return false; } } public function markRead($ids, $is_read = true) { - if (is_array($ids)) { + if (is_array($ids)) { //Many IDs at once if (count($ids) < 6) { //Speed heuristics $affected = 0; foreach ($ids as $id) { @@ -102,8 +111,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $values = array_merge($values, $ids); $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { - $info = $stm->errorInfo(); - Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markRead: ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack(); return false; } @@ -121,8 +130,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { . 'SET f.cache_nbEntries=x.nbEntries, f.cache_nbUnreads=x.nbUnreads'; $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute())) { - $info = $stm->errorInfo(); - Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markRead: ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack(); return false; } @@ -134,14 +143,14 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' . 'SET e.is_read = ?,' . 'f.cache_nbUnreads=f.cache_nbUnreads' . ($is_read ? '-' : '+') . '1 ' - . 'WHERE e.id=?'; - $values = array($is_read ? 1 : 0, $ids); + . 'WHERE e.id=? AND e.is_read<>?'; + $values = array($is_read ? 1 : 0, $ids, $is_read ? 1 : 0); $stm = $this->bd->prepare($sql); if ($stm && $stm->execute($values)) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markRead: ' . $info[2], Minz_Log::ERROR); return false; } } @@ -161,8 +170,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { if ($stm && $stm->execute ()) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markReadEntries: ' . $info[2], Minz_Log::ERROR); return false; } } else { @@ -179,8 +188,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $values = array ($idMax); $stm = $this->bd->prepare ($sql); if (!($stm && $stm->execute ($values))) { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markReadEntries: ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack (); return false; } @@ -198,8 +207,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { . 'SET f.cache_nbUnreads=COALESCE(x.nbUnreads, 0)'; $stm = $this->bd->prepare ($sql); if (!($stm && $stm->execute ())) { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markReadEntries: ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack (); return false; } @@ -220,8 +229,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markReadCat: ' . $info[2], Minz_Log::ERROR); return false; } } else { @@ -233,8 +242,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $values = array ($id, $idMax); $stm = $this->bd->prepare ($sql); if (!($stm && $stm->execute ($values))) { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markReadCat: ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack (); return false; } @@ -254,8 +263,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $values = array ($id); $stm = $this->bd->prepare ($sql); if (!($stm && $stm->execute ($values))) { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markReadCat: ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack (); return false; } @@ -278,8 +287,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { if ($stm && $stm->execute($values)) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markReadCatName: ' . $info[2], Minz_Log::ERROR); return false; } } else { @@ -293,8 +302,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $values = array($name, $idMax); $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { - $info = $stm->errorInfo(); - Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markReadCatName: ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack(); return false; } @@ -315,8 +324,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $values = array($name); $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { - $info = $stm->errorInfo(); - Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markReadCatName: ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack(); return false; } @@ -337,8 +346,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markReadFeed: ' . $info[2], Minz_Log::ERROR); return false; } } else { @@ -350,8 +359,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $values = array ($id, $idMax); $stm = $this->bd->prepare ($sql); if (!($stm && $stm->execute ($values))) { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markReadFeed: ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack (); return false; } @@ -364,8 +373,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $values = array ($id); $stm = $this->bd->prepare ($sql); if (!($stm && $stm->execute ($values))) { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markReadFeed: ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack (); return false; } @@ -378,7 +387,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { public function searchByGuid ($feed_id, $id) { // un guid est unique pour un flux donné - $sql = 'SELECT id, guid, title, author, UNCOMPRESS(content_bin) AS content, link, date, is_read, is_favorite, id_feed, tags ' + $sql = 'SELECT id, guid, title, author, ' + . ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content') + . ', link, date, is_read, is_favorite, id_feed, tags ' . 'FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND guid=?'; $stm = $this->bd->prepare ($sql); @@ -394,7 +405,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { } public function searchById ($id) { - $sql = 'SELECT id, guid, title, author, UNCOMPRESS(content_bin) AS content, link, date, is_read, is_favorite, id_feed, tags ' + $sql = 'SELECT id, guid, title, author, ' + . ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content') + . ', link, date, is_read, is_favorite, id_feed, tags ' . 'FROM `' . $this->prefix . 'entry` WHERE id=?'; $stm = $this->bd->prepare ($sql); @@ -520,7 +533,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $search .= 'AND e1.tags LIKE ? '; $values[] = '%' . $word .'%'; } else { - $search .= 'AND CONCAT(e1.title, UNCOMPRESS(e1.content_bin)) LIKE ? '; + $search .= 'AND CONCAT(e1.title, ' . ($this->isCompressed() ? 'UNCOMPRESS(content_bin)' : 'content') . ') LIKE ? '; $values[] = '%' . $word .'%'; } } @@ -539,7 +552,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { public function listWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault); - $sql = 'SELECT e.id, e.guid, e.title, e.author, UNCOMPRESS(e.content_bin) AS content, e.link, e.date, e.is_read, e.is_favorite, e.id_feed, e.tags ' + $sql = 'SELECT e.id, e.guid, e.title, e.author, ' + . ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content') + . ', e.link, e.date, e.is_read, e.is_favorite, e.id_feed, e.tags ' . 'FROM `' . $this->prefix . 'entry` e ' . 'INNER JOIN (' . $sql diff --git a/app/Models/EntryDAO_SQLite.php b/app/Models/EntryDAO_SQLite.php new file mode 100644 index 000000000..f148f3c63 --- /dev/null +++ b/app/Models/EntryDAO_SQLite.php @@ -0,0 +1,42 @@ +markRead($id, $is_read); + } + return $affected; + } + } else { + $this->bd->beginTransaction(); + $sql = 'UPDATE `' . $this->prefix . 'entry` e SET e.is_read = ? WHERE e.id=? AND e.is_read<>?'; + $values = array($is_read ? 1 : 0, $ids, $is_read ? 1 : 0); + $stm = $this->bd->prepare($sql); + if (!($stm && $stm->execute ($values))) { + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markRead: ' . $info[2], Minz_Log::ERROR); + $this->bd->rollBack (); + return false; + } + $affected = $stm->rowCount(); + if ($affected > 0) { + $sql = 'UPDATE `' . $this->prefix . 'feed` f SET f.cache_nbUnreads=f.cache_nbUnreads' . ($is_read ? '-' : '+') . '1 ' + . 'WHERE f.id=(SELECT e.id_feed FROM `' . $this->prefix . 'entry` e WHERE e.id=?)'; + $values = array($ids); + $stm = $this->bd->prepare($sql); + if (!($stm && $stm->execute ($values))) { + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error markRead: ' . $info[2], Minz_Log::ERROR); + $this->bd->rollBack (); + return false; + } + } + $this->bd->commit(); + return $affected; + } + } +} diff --git a/app/Models/Factory.php b/app/Models/Factory.php new file mode 100644 index 000000000..bea89c114 --- /dev/null +++ b/app/Models/Factory.php @@ -0,0 +1,13 @@ +execute ($values)) { return $this->bd->lastInsertId(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error addFeed: ' . $info[2], Minz_Log::ERROR); return false; } } @@ -76,8 +76,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error updateFeed: ' . $info[2], Minz_Log::ERROR); return false; } } @@ -106,8 +106,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error updateLastUpdate: ' . $info[2], Minz_Log::ERROR); return false; } } @@ -130,8 +130,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error changeCategory: ' . $info[2], Minz_Log::ERROR); return false; } } @@ -155,8 +155,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error deleteFeed: ' . $info[2], Minz_Log::ERROR); return false; } } @@ -181,8 +181,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error deleteFeedByCategory: ' . $info[2], Minz_Log::ERROR); return false; } } @@ -301,8 +301,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { if ($stm && $stm->execute()) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error updateCachedValues: ' . $info[2], Minz_Log::ERROR); return false; } } @@ -313,11 +313,11 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $values = array($id); $this->bd->beginTransaction (); if (!($stm && $stm->execute ($values))) { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); - $this->bd->rollBack (); - return false; - } + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error truncate: ' . $info[2], Minz_Log::ERROR); + $this->bd->rollBack (); + return false; + } $affected = $stm->rowCount(); $sql = 'UPDATE `' . $this->prefix . 'feed` f ' @@ -325,8 +325,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $values = array ($id); $stm = $this->bd->prepare ($sql); if (!($stm && $stm->execute ($values))) { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error truncate: ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack (); return false; } @@ -350,8 +350,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { if ($stm && $stm->execute ()) { return $stm->rowCount(); } else { - $info = $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::record('SQL error cleanOldEntries: ' . $info[2], Minz_Log::ERROR); return false; } } diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index a25b57f89..dcf847a62 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -2,33 +2,44 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { public function createUser($username) { - require_once(APP_PATH . '/sql.php'); $db = Minz_Configuration::dataBase(); + require_once(APP_PATH . '/SQL/sql.' . $db['type'] . '.php'); + + if (defined('SQL_CREATE_TABLES')) { + $sql = sprintf(SQL_CREATE_TABLES, $db['prefix'] . $username . '_', Minz_Translate::t('default_category')); + $stm = $c->prepare($sql); + $ok = $stm && $stm->execute(); + } else { + global $SQL_CREATE_TABLES; + if (is_array($SQL_CREATE_TABLES)) { + $ok = true; + foreach ($SQL_CREATE_TABLES as $instruction) { + $sql = sprintf($instruction, '', Minz_Translate::t('default_category')); + $stm = $c->prepare($sql); + $ok &= ($stm && $stm->execute()); + } + } + } - $sql = sprintf(SQL_CREATE_TABLES, $db['prefix'] . $username . '_'); - $stm = $this->bd->prepare($sql, array(PDO::ATTR_EMULATE_PREPARES => true)); - $values = array( - 'catName' => Minz_Translate::t('default_category'), - ); - if ($stm && $stm->execute($values)) { + if ($ok) { return true; } else { - $info = $stm->errorInfo(); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); return false; } } public function deleteUser($username) { - require_once(APP_PATH . '/sql.php'); $db = Minz_Configuration::dataBase(); + require_once(APP_PATH . '/SQL/sql.' . $db['type'] . '.php'); $sql = sprintf(SQL_DROP_TABLES, $db['prefix'] . $username . '_'); $stm = $this->bd->prepare($sql); if ($stm && $stm->execute()) { return true; } else { - $info = $stm->errorInfo(); + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); return false; } diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php new file mode 100644 index 000000000..d509cb4a8 --- /dev/null +++ b/app/SQL/install.sql.mysql.php @@ -0,0 +1,60 @@ +bd = self::$sharedBd; $this->prefix = self::$sharedPrefix; return; } - $db = Minz_Configuration::dataBase (); - $driver_options = null; + $db = Minz_Configuration::dataBase(); try { $type = $db['type']; - if($type == 'mysql') { - $string = $type - . ':host=' . $db['host'] + if ($type === 'mysql') { + $string = 'mysql:host=' . $db['host'] . ';dbname=' . $db['base'] . ';charset=utf8'; $driver_options = array( - PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8' + PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', + ); + $this->prefix = $db['prefix'] . Minz_Session::param('currentUser', '_') . '_'; + } elseif ($type === 'sqlite') { + $string = 'sqlite:' . DATA_PATH . '/' . Minz_Session::param('currentUser', '_') . '.sqlite'; + $driver_options = array( + //PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + ); + $this->prefix = ''; + } else { + throw new Minz_PDOConnectionException( + 'Invalid database type!', + $db['user'], Minz_Exception::ERROR ); - } elseif($type == 'sqlite') { - $string = $type . ':/' . DATA_PATH . $db['base'] . '.sqlite'; //TODO: DEBUG UTF-8 http://www.siteduzero.com/forum/sujet/sqlite-connexion-utf-8-18797 } + self::$sharedDbType = $type; + self::$sharedPrefix = $this->prefix; - $this->bd = new FreshPDO ( + $this->bd = new FreshPDO( $string, $db['user'], $db['password'], $driver_options ); self::$sharedBd = $this->bd; - - $this->prefix = $db['prefix'] . Minz_Session::param('currentUser', '_') . '_'; - self::$sharedPrefix = $this->prefix; } catch (Exception $e) { - throw new Minz_PDOConnectionException ( + throw new Minz_PDOConnectionException( $string, $db['user'], Minz_Exception::ERROR ); @@ -81,15 +93,15 @@ class Minz_ModelPdo { } public function size($all = false) { - $db = Minz_Configuration::dataBase (); + $db = Minz_Configuration::dataBase(); $sql = 'SELECT SUM(data_length + index_length) FROM information_schema.TABLES WHERE table_schema = ?'; - $values = array ($db['base']); + $values = array($db['base']); if (!$all) { $sql .= ' AND table_name LIKE ?'; $values[] = $this->prefix . '%'; } - $stm = $this->bd->prepare ($sql); - $stm->execute ($values); + $stm = $this->bd->prepare($sql); + $stm->execute($values); $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); return $res[0]; } @@ -107,12 +119,12 @@ class FreshPDO extends PDO { } } - public function prepare ($statement, $driver_options = array()) { + public function prepare($statement, $driver_options = array()) { FreshPDO::check($statement); return parent::prepare($statement, $driver_options); } - public function exec ($statement) { + public function exec($statement) { FreshPDO::check($statement); return parent::exec($statement); } -- cgit v1.2.3 From ad9fbf3887b79d69dcb53080e3f7c367b5bc17e1 Mon Sep 17 00:00:00 2001 From: plopoyop Date: Sat, 26 Jul 2014 13:29:55 +0200 Subject: Correct bug in add/remove users --- app/Controllers/usersController.php | 4 ++-- app/Models/UserDAO.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 35fa3675f..a9e6c32bc 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -100,7 +100,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { public function createAction() { if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { $db = Minz_Configuration::dataBase(); - require_once(APP_PATH . '/SQL/sql.' . $db['type'] . '.php'); + require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); $new_user_language = Minz_Request::param('new_user_language', $this->view->conf->language); if (!in_array($new_user_language, $this->view->conf->availableLanguages())) { @@ -172,7 +172,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { public function deleteAction() { if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { $db = Minz_Configuration::dataBase(); - require_once(APP_PATH . '/SQL/sql.' . $db['type'] . '.php'); + require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); $username = Minz_Request::param('username'); $ok = ctype_alnum($username); diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index dcf847a62..1763fac67 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -3,11 +3,11 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { public function createUser($username) { $db = Minz_Configuration::dataBase(); - require_once(APP_PATH . '/SQL/sql.' . $db['type'] . '.php'); + require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); if (defined('SQL_CREATE_TABLES')) { $sql = sprintf(SQL_CREATE_TABLES, $db['prefix'] . $username . '_', Minz_Translate::t('default_category')); - $stm = $c->prepare($sql); + $stm = $this->bd->prepare($sql); $ok = $stm && $stm->execute(); } else { global $SQL_CREATE_TABLES; @@ -32,7 +32,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { public function deleteUser($username) { $db = Minz_Configuration::dataBase(); - require_once(APP_PATH . '/SQL/sql.' . $db['type'] . '.php'); + require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); $sql = sprintf(SQL_DROP_TABLES, $db['prefix'] . $username . '_'); $stm = $this->bd->prepare($sql); -- cgit v1.2.3