Example #1
0
 public function applyAction()
 {
     if (!file_exists(UPDATE_FILENAME) || !is_writable(FRESHRSS_PATH)) {
         Minz_Request::forward(array('c' => 'update'), true);
     }
     require UPDATE_FILENAME;
     if (Minz_Request::param('post_conf', false)) {
         $res = do_post_update();
         Minz_ExtensionManager::callHook('post_update');
         if ($res === true) {
             @unlink(UPDATE_FILENAME);
             @file_put_contents(join_path(DATA_PATH, 'last_update.txt'), '');
             Minz_Request::good(_t('feedback.update.finished'));
         } else {
             Minz_Request::bad(_t('feedback.update.error', $res), array('c' => 'update', 'a' => 'index'));
         }
     }
     if (Minz_Request::isPost()) {
         save_info_update();
     }
     if (!need_info_update()) {
         $res = apply_update();
         if ($res === true) {
             Minz_Request::forward(array('c' => 'update', 'a' => 'apply', 'params' => array('post_conf' => true)), true);
         } else {
             Minz_Request::bad(_t('feedback.update.error', $res), array('c' => 'update', 'a' => 'index'));
         }
     }
 }
 /**
  * This action handles the feed configuration page.
  *
  * It displays the feed configuration page.
  * If this action is reached through a POST request, it stores all new
  * configuraiton values then sends a notification to the user.
  *
  * The options available on the page are:
  *   - name
  *   - description
  *   - website URL
  *   - feed URL
  *   - category id (default: default category id)
  *   - CSS path to article on website
  *   - display in main stream (default: 0)
  *   - HTTP authentication
  *   - number of article to retain (default: -2)
  *   - refresh frequency (default: -2)
  * Default values are empty strings unless specified.
  */
 public function feedAction()
 {
     if (Minz_Request::param('ajax')) {
         $this->view->_useLayout(false);
     }
     $feedDAO = FreshRSS_Factory::createFeedDao();
     $this->view->feeds = $feedDAO->listFeeds();
     $id = Minz_Request::param('id');
     if ($id === false || !isset($this->view->feeds[$id])) {
         Minz_Error::error(404);
         return;
     }
     $this->view->feed = $this->view->feeds[$id];
     Minz_View::prependTitle(_t('sub.title.feed_management') . ' · ' . $this->view->feed->name() . ' · ');
     if (Minz_Request::isPost()) {
         $user = Minz_Request::param('http_user', '');
         $pass = Minz_Request::param('http_pass', '');
         $httpAuth = '';
         if ($user != '' || $pass != '') {
             $httpAuth = $user . ':' . $pass;
         }
         $cat = intval(Minz_Request::param('category', 0));
         $values = array('name' => Minz_Request::param('name', ''), 'description' => sanitizeHTML(Minz_Request::param('description', '', true)), 'website' => Minz_Request::param('website', ''), 'url' => Minz_Request::param('url', ''), 'category' => $cat, 'pathEntries' => Minz_Request::param('path_entries', ''), 'priority' => intval(Minz_Request::param('priority', 0)), 'httpAuth' => $httpAuth, 'keep_history' => intval(Minz_Request::param('keep_history', -2)), 'ttl' => intval(Minz_Request::param('ttl', -2)));
         invalidateHttpCache();
         $url_redirect = array('c' => 'subscription', 'params' => array('id' => $id));
         if ($feedDAO->updateFeed($id, $values) !== false) {
             $this->view->feed->_category($cat);
             $this->view->feed->faviconPrepare();
             Minz_Request::good(_t('feedback.sub.feed.updated'), $url_redirect);
         } else {
             Minz_Request::bad(_t('feedback.sub.feed.error'), $url_redirect);
         }
     }
 }
Example #3
0
 /**
  * This action displays the user profile page.
  */
 public function profileAction()
 {
     Minz_View::prependTitle(_t('conf.profile.title') . ' · ');
     Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js')));
     if (Minz_Request::isPost()) {
         $ok = true;
         $passwordPlain = Minz_Request::param('newPasswordPlain', '', true);
         if ($passwordPlain != '') {
             Minz_Request::_param('newPasswordPlain');
             //Discard plain-text password ASAP
             $_POST['newPasswordPlain'] = '';
             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 != '';
             FreshRSS_Context::$user_conf->passwordHash = $passwordHash;
         }
         Minz_Session::_param('passwordHash', FreshRSS_Context::$user_conf->passwordHash);
         $passwordPlain = Minz_Request::param('apiPasswordPlain', '', true);
         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 != '';
             FreshRSS_Context::$user_conf->apiPasswordHash = $passwordHash;
         }
         // TODO: why do we need of hasAccess here?
         if (FreshRSS_Auth::hasAccess('admin')) {
             FreshRSS_Context::$user_conf->mail_login = Minz_Request::param('mail_login', '', true);
         }
         $email = FreshRSS_Context::$user_conf->mail_login;
         Minz_Session::_param('mail', $email);
         $ok &= FreshRSS_Context::$user_conf->save();
         if ($email != '') {
             $personaFile = DATA_PATH . '/persona/' . $email . '.txt';
             @unlink($personaFile);
             $ok &= file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false;
         }
         if ($ok) {
             Minz_Request::good(_t('feedback.profile.updated'), array('c' => 'user', 'a' => 'profile'));
         } else {
             Minz_Request::bad(_t('feedback.profile.error'), array('c' => 'user', 'a' => 'profile'));
         }
     }
 }
 /**
  * This action deletes all the feeds relative to a given category.
  * Feed-related queries are deleted.
  *
  * Request parameter is:
  *   - id (of a category)
  */
 public function emptyAction()
 {
     $feedDAO = FreshRSS_Factory::createFeedDao();
     $url_redirect = array('c' => 'subscription', 'a' => 'index');
     if (Minz_Request::isPost()) {
         invalidateHttpCache();
         $id = Minz_Request::param('id');
         if (!$id) {
             Minz_Request::bad(_t('feedback.sub.category.no_id'), $url_redirect);
         }
         // List feeds to remove then related user queries.
         $feeds = $feedDAO->listByCategory($id);
         if ($feedDAO->deleteFeedByCategory($id)) {
             // TODO: Delete old favicons
             // Remove related queries
             foreach ($feeds as $feed) {
                 FreshRSS_Context::$user_conf->queries = remove_query_by_get('f_' . $feed->id(), FreshRSS_Context::$user_conf->queries);
             }
             FreshRSS_Context::$user_conf->save();
             Minz_Request::good(_t('feedback.sub.category.emptied'), $url_redirect);
         } else {
             Minz_Request::bad(_t('feedback.sub.category.error'), $url_redirect);
         }
     }
     Minz_Request::forward($url_redirect, true);
 }
 /**
  * This action handles the creation of a user query.
  *
  * It gets the GET parameters and stores them in the configuration query
  * storage. Before it is saved, the unwanted parameters are unset to keep
  * lean data.
  */
 public function addQueryAction()
 {
     $whitelist = array('get', 'order', 'name', 'search', 'state');
     $queries = FreshRSS_Context::$user_conf->queries;
     $query = Minz_Request::params();
     $query['name'] = _t('conf.query.number', count($queries) + 1);
     foreach ($query as $key => $value) {
         if (!in_array($key, $whitelist)) {
             unset($query[$key]);
         }
     }
     $queries[] = $query;
     FreshRSS_Context::$user_conf->queries = $queries;
     FreshRSS_Context::$user_conf->save();
     Minz_Request::good(_t('feedback.conf.query_created', $query['name']), array('c' => 'configure', 'a' => 'queries'));
 }
Example #6
0
 /**
  * This action deletes a feed.
  *
  * This page must be reached by a POST request.
  * If there are related queries, they are deleted too.
  *
  * Parameters are:
  *   - id (default: false)
  *   - r (default: false)
  * r permits to redirect to a given page at the end of this action.
  *
  * @todo handle "r" redirection in Minz_Request::forward()?
  */
 public function deleteAction()
 {
     $redirect_url = Minz_Request::param('r', false, true);
     if (!$redirect_url) {
         $redirect_url = array('c' => 'subscription', 'a' => 'index');
     }
     if (!Minz_Request::isPost()) {
         Minz_Request::forward($redirect_url, true);
     }
     $id = Minz_Request::param('id');
     $feedDAO = FreshRSS_Factory::createFeedDao();
     if ($feedDAO->deleteFeed($id)) {
         // TODO: Delete old favicon
         // Remove related queries
         FreshRSS_Context::$user_conf->queries = remove_query_by_get('f_' . $id, FreshRSS_Context::$user_conf->queries);
         FreshRSS_Context::$user_conf->save();
         Minz_Request::good(_t('feedback.sub.feed.deleted'), $redirect_url);
     } else {
         Minz_Request::bad(_t('feedback.sub.feed.error'), $redirect_url);
     }
 }
Example #7
0
 /**
  * This action resets the authentication system.
  *
  * After reseting, form auth is set by default.
  */
 public function resetAction()
 {
     Minz_View::prependTitle(_t('admin.auth.title_reset') . ' · ');
     Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js')));
     $this->view->no_form = false;
     // Enable changement of auth only if Persona!
     if (FreshRSS_Context::$system_conf->auth_type != 'persona') {
         $this->view->message = array('status' => 'bad', 'title' => _t('gen.short.damn'), 'body' => _t('feedback.auth.not_persona'));
         $this->view->no_form = true;
         return;
     }
     $conf = get_user_configuration(FreshRSS_Context::$system_conf->default_user);
     if (is_null($conf)) {
         return;
     }
     // Admin user must have set its master password.
     if (!$conf->passwordHash) {
         $this->view->message = array('status' => 'bad', 'title' => _t('gen.short.damn'), 'body' => _t('feedback.auth.no_password_set'));
         $this->view->no_form = true;
         return;
     }
     invalidateHttpCache();
     if (Minz_Request::isPost()) {
         $nonce = Minz_Session::param('nonce');
         $username = Minz_Request::param('username', '');
         $challenge = Minz_Request::param('challenge', '');
         $ok = FreshRSS_FormAuth::checkCredentials($username, $conf->passwordHash, $nonce, $challenge);
         if ($ok) {
             FreshRSS_Context::$system_conf->auth_type = 'form';
             $ok = FreshRSS_Context::$system_conf->save();
             if ($ok) {
                 Minz_Request::good(_t('feedback.auth.form.set'));
             } else {
                 Minz_Request::bad(_t('feedback.auth.form.not_set'), array('c' => 'auth', 'a' => 'reset'));
             }
         } else {
             Minz_Log::warning('Password mismatch for' . ' user='******', nonce=' . $nonce . ', c=' . $challenge);
             Minz_Request::bad(_t('feedback.auth.login.invalid'), array('c' => 'auth', 'a' => 'reset'));
         }
     }
 }
 /**
  * This action handles import action.
  *
  * It must be reached by a POST request.
  *
  * Parameter is:
  *   - file (default: nothing!)
  * Available file types are: zip, json or xml.
  */
 public function importAction()
 {
     if (!Minz_Request::isPost()) {
         Minz_Request::forward(array('c' => 'importExport', 'a' => 'index'), true);
     }
     $file = $_FILES['file'];
     $status_file = $file['error'];
     if ($status_file !== 0) {
         Minz_Log::error('File cannot be uploaded. Error code: ' . $status_file);
         Minz_Request::bad(_t('feedback.import_export.file_cannot_be_uploaded'), array('c' => 'importExport', 'a' => 'index'));
     }
     @set_time_limit(300);
     $type_file = $this->guessFileType($file['name']);
     $list_files = array('opml' => array(), 'json_starred' => array(), 'json_feed' => array());
     // We try to list all files according to their type
     $list = array();
     if ($type_file === 'zip' && extension_loaded('zip')) {
         $zip = zip_open($file['tmp_name']);
         if (!is_resource($zip)) {
             // zip_open cannot open file: something is wrong
             Minz_Log::error('Zip archive cannot be imported. Error code: ' . $zip);
             Minz_Request::bad(_t('feedback.import_export.zip_error'), array('c' => 'importExport', 'a' => 'index'));
         }
         while (($zipfile = zip_read($zip)) !== false) {
             if (!is_resource($zipfile)) {
                 // zip_entry() can also return an error code!
                 Minz_Log::error('Zip file cannot be imported. Error code: ' . $zipfile);
             } else {
                 $type_zipfile = $this->guessFileType(zip_entry_name($zipfile));
                 if ($type_file !== 'unknown') {
                     $list_files[$type_zipfile][] = zip_entry_read($zipfile, zip_entry_filesize($zipfile));
                 }
             }
         }
         zip_close($zip);
     } elseif ($type_file === 'zip') {
         // Zip extension is not loaded
         Minz_Request::bad(_t('feedback.import_export.no_zip_extension'), array('c' => 'importExport', 'a' => 'index'));
     } elseif ($type_file !== 'unknown') {
         $list_files[$type_file][] = file_get_contents($file['tmp_name']);
     }
     // Import file contents.
     // OPML first(so categories and feeds are imported)
     // Starred articles then so the "favourite" status is already set
     // And finally all other files.
     $error = false;
     foreach ($list_files['opml'] as $opml_file) {
         $error = $this->importOpml($opml_file);
     }
     foreach ($list_files['json_starred'] as $article_file) {
         $error = $this->importJson($article_file, true);
     }
     foreach ($list_files['json_feed'] as $article_file) {
         $error = $this->importJson($article_file);
     }
     // And finally, we get import status and redirect to the home page
     Minz_Session::_param('actualize_feeds', true);
     $content_notif = $error === true ? _t('feedback.import_export.feeds_imported_with_errors') : _t('feedback.import_export.feeds_imported');
     Minz_Request::good($content_notif);
 }
Example #9
0
 /**
  * This action purges old entries from feeds.
  *
  * @todo should be a POST request
  * @todo should be in feedController
  */
 public function purgeAction()
 {
     @set_time_limit(300);
     $nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1);
     $date_min = time() - 3600 * 24 * 30 * $nb_month_old;
     $feedDAO = FreshRSS_Factory::createFeedDao();
     $feeds = $feedDAO->listFeeds();
     $nb_total = 0;
     invalidateHttpCache();
     foreach ($feeds as $feed) {
         $feed_history = $feed->keepHistory();
         if ($feed_history == -2) {
             // TODO: -2 must be a constant!
             // -2 means we take the default value from configuration
             $feed_history = FreshRSS_Context::$user_conf->keep_history_default;
         }
         if ($feed_history >= 0) {
             $nb = $feedDAO->cleanOldEntries($feed->id(), $date_min, $feed_history);
             if ($nb > 0) {
                 $nb_total += $nb;
                 Minz_Log::debug($nb . ' old entries cleaned in feed [' . $feed->url() . ']');
             }
         }
     }
     $feedDAO->updateCachedValues();
     invalidateHttpCache();
     Minz_Request::good(_t('feedback.sub.purge_completed', $nb_total), array('c' => 'configure', 'a' => 'archiving'));
 }
Example #10
0
 /**
  * This action handles the creation of a user query.
  *
  * It gets the GET parameters and stores them in the configuration query
  * storage. Before it is saved, the unwanted parameters are unset to keep
  * lean data.
  */
 public function addQueryAction()
 {
     $category_dao = FreshRSS_Factory::createCategoryDAO();
     $feed_dao = FreshRSS_Factory::createFeedDao();
     $queries = array();
     foreach (FreshRSS_Context::$user_conf->queries as $key => $query) {
         $queries[$key] = new FreshRSS_UserQuery($query, $feed_dao, $category_dao);
     }
     $params = Minz_Request::params();
     $params['url'] = Minz_Url::display(array('params' => $params));
     $params['name'] = _t('conf.query.number', count($queries) + 1);
     $queries[] = new FreshRSS_UserQuery($params, $feed_dao, $category_dao);
     FreshRSS_Context::$user_conf->queries = $queries;
     FreshRSS_Context::$user_conf->save();
     Minz_Request::good(_t('feedback.conf.query_created', $query['name']), array('c' => 'configure', 'a' => 'queries'));
 }
 /**
  * This action handles deletion of an extension.
  *
  * Only administrator can remove an extension.
  * This action must be reached by a POST request.
  *
  * Parameter is:
  * -e: extension name (urlencoded)
  */
 public function removeAction()
 {
     if (!FreshRSS_Auth::hasAccess('admin')) {
         Minz_Error::error(403);
     }
     $url_redirect = array('c' => 'extension', 'a' => 'index');
     if (Minz_Request::isPost()) {
         $ext_name = urldecode(Minz_Request::param('e'));
         $ext = Minz_ExtensionManager::findExtension($ext_name);
         if (is_null($ext)) {
             Minz_Request::bad(_t('feedback.extensions.not_found', $ext_name), $url_redirect);
         }
         $res = recursive_unlink($ext->getPath());
         if ($res) {
             Minz_Request::good(_t('feedback.extensions.removed', $ext_name), $url_redirect);
         } else {
             Minz_Request::bad(_t('feedback.extensions.cannot_delete', $ext_name), $url_redirect);
         }
     }
     Minz_Request::forward($url_redirect, true);
 }