Example #1
0
 /**
  * Enregistre un message dans un fichier de log spécifique
  * Message non loggué si
  * 	- environment = SILENT
  * 	- level = WARNING et environment = PRODUCTION
  * 	- level = NOTICE et environment = PRODUCTION
  * @param $information message d'erreur / information à enregistrer
  * @param $level niveau d'erreur
  * @param $file_name fichier de log
  */
 public static function record($information, $level, $file_name = null)
 {
     try {
         $conf = Minz_Configuration::get('system');
         $env = $conf->environment;
     } catch (Minz_ConfigurationException $e) {
         $env = 'production';
     }
     if (!($env === 'silent' || $env === 'production' && $level >= Minz_Log::NOTICE)) {
         if ($file_name === null) {
             $file_name = join_path(USERS_PATH, Minz_Session::param('currentUser', '_'), 'log.txt');
         }
         switch ($level) {
             case Minz_Log::ERROR:
                 $level_label = 'error';
                 break;
             case Minz_Log::WARNING:
                 $level_label = 'warning';
                 break;
             case Minz_Log::NOTICE:
                 $level_label = 'notice';
                 break;
             case Minz_Log::DEBUG:
                 $level_label = 'debug';
                 break;
             default:
                 $level_label = 'unknown';
         }
         $log = '[' . date('r') . ']' . ' [' . $level_label . ']' . ' --- ' . $information . "\n";
         if (file_put_contents($file_name, $log, FILE_APPEND | LOCK_EX) === false) {
             throw new Minz_PermissionDeniedException($file_name, Minz_Exception::ERROR);
         }
     }
 }
 /**
  * This action handles the display configuration page.
  *
  * It displays the display configuration page.
  * If this action is reached through a POST request, it stores all new
  * configuration values then sends a notification to the user.
  *
  * The options available on the page are:
  *   - language (default: en)
  *   - theme (default: Origin)
  *   - content width (default: thin)
  *   - display of read action in header
  *   - display of favorite action in header
  *   - display of date in header
  *   - display of open action in header
  *   - display of read action in footer
  *   - display of favorite action in footer
  *   - display of sharing action in footer
  *   - display of tags in footer
  *   - display of date in footer
  *   - display of open action in footer
  *   - html5 notification timeout (default: 0)
  * Default values are false unless specified.
  */
 public function displayAction()
 {
     if (Minz_Request::isPost()) {
         FreshRSS_Context::$user_conf->language = Minz_Request::param('language', 'en');
         FreshRSS_Context::$user_conf->theme = Minz_Request::param('theme', FreshRSS_Themes::$defaultTheme);
         FreshRSS_Context::$user_conf->content_width = Minz_Request::param('content_width', 'thin');
         FreshRSS_Context::$user_conf->topline_read = Minz_Request::param('topline_read', false);
         FreshRSS_Context::$user_conf->topline_favorite = Minz_Request::param('topline_favorite', false);
         FreshRSS_Context::$user_conf->topline_date = Minz_Request::param('topline_date', false);
         FreshRSS_Context::$user_conf->topline_link = Minz_Request::param('topline_link', false);
         FreshRSS_Context::$user_conf->bottomline_read = Minz_Request::param('bottomline_read', false);
         FreshRSS_Context::$user_conf->bottomline_favorite = Minz_Request::param('bottomline_favorite', false);
         FreshRSS_Context::$user_conf->bottomline_sharing = Minz_Request::param('bottomline_sharing', false);
         FreshRSS_Context::$user_conf->bottomline_tags = Minz_Request::param('bottomline_tags', false);
         FreshRSS_Context::$user_conf->bottomline_date = Minz_Request::param('bottomline_date', false);
         FreshRSS_Context::$user_conf->bottomline_link = Minz_Request::param('bottomline_link', false);
         FreshRSS_Context::$user_conf->html5_notif_timeout = Minz_Request::param('html5_notif_timeout', 0);
         FreshRSS_Context::$user_conf->save();
         Minz_Session::_param('language', FreshRSS_Context::$user_conf->language);
         Minz_Translate::reset(FreshRSS_Context::$user_conf->language);
         invalidateHttpCache();
         Minz_Request::good(_t('feedback.conf.updated'), array('c' => 'configure', 'a' => 'display'));
     }
     $this->view->themes = FreshRSS_Themes::get();
     Minz_View::prependTitle(_t('conf.display.title') . ' · ');
 }
Example #3
0
 /**
  * Créé la connexion à la base de données à l'aide des variables
  * HOST, BASE, USER et PASS définies dans le fichier de configuration
  */
 public function __construct()
 {
     if (self::$useSharedBd && self::$sharedBd != null) {
         $this->bd = self::$sharedBd;
         $this->prefix = self::$sharedPrefix;
         return;
     }
     $db = Minz_Configuration::dataBase();
     $driver_options = null;
     try {
         $type = $db['type'];
         if ($type == 'mysql') {
             $string = $type . ':host=' . $db['host'] . ';dbname=' . $db['base'] . ';charset=utf8';
             $driver_options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8');
         } 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
         }
         $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($string, $db['user'], Minz_Exception::ERROR);
     }
 }
Example #4
0
 /**
  * Enregistre un message dans un fichier de log spécifique
  * Message non loggué si
  * 	- environment = SILENT
  * 	- level = WARNING et environment = PRODUCTION
  * 	- level = NOTICE et environment = PRODUCTION
  * @param $information message d'erreur / information à enregistrer
  * @param $level niveau d'erreur
  * @param $file_name fichier de log, par défaut LOG_PATH/application.log
  */
 public static function record($information, $level, $file_name = null)
 {
     $env = Minz_Configuration::environment();
     if (!($env === Minz_Configuration::SILENT || $env === Minz_Configuration::PRODUCTION && $level >= Minz_Log::NOTICE)) {
         if ($file_name === null) {
             $file_name = LOG_PATH . '/' . Minz_Session::param('currentUser', '_') . '.log';
         }
         switch ($level) {
             case Minz_Log::ERROR:
                 $level_label = 'error';
                 break;
             case Minz_Log::WARNING:
                 $level_label = 'warning';
                 break;
             case Minz_Log::NOTICE:
                 $level_label = 'notice';
                 break;
             case Minz_Log::DEBUG:
                 $level_label = 'debug';
                 break;
             default:
                 $level_label = 'unknown';
         }
         $log = '[' . date('r') . ']' . ' [' . $level_label . ']' . ' --- ' . $information . "\n";
         if (file_put_contents($file_name, $log, FILE_APPEND | LOCK_EX) === false) {
             throw new Minz_PermissionDeniedException($file_name, Minz_Exception::ERROR);
         }
     }
 }
Example #5
0
 /**
  * This action is the default one for the controller.
  *
  * It is called by Minz_Error::error() method.
  *
  * Parameters are passed by Minz_Session to have a proper url:
  *   - error_code (default: 404)
  *   - error_logs (default: array())
  */
 public function indexAction()
 {
     $code_int = Minz_Session::param('error_code', 404);
     $error_logs = Minz_Session::param('error_logs', array());
     Minz_Session::_param('error_code');
     Minz_Session::_param('error_logs');
     switch ($code_int) {
         case 200:
             header('HTTP/1.1 200 OK');
             break;
         case 403:
             header('HTTP/1.1 403 Forbidden');
             $this->view->code = 'Error 403 - Forbidden';
             $this->view->errorMessage = _t('feedback.access.denied');
             break;
         case 500:
             header('HTTP/1.1 500 Internal Server Error');
             $this->view->code = 'Error 500 - Internal Server Error';
             break;
         case 503:
             header('HTTP/1.1 503 Service Unavailable');
             $this->view->code = 'Error 503 - Service Unavailable';
             break;
         case 404:
         default:
             header('HTTP/1.1 404 Not Found');
             $this->view->code = 'Error 404 - Not found';
             $this->view->errorMessage = _t('feedback.access.not_found');
     }
     $error_message = trim(implode($error_logs));
     if ($error_message !== '') {
         $this->view->errorMessage = $error_message;
     }
     Minz_View::prependTitle($this->view->code . ' · ');
 }
 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'));
     header('Expires: 0');
     header('Cache-Control: private, no-cache, no-store, must-revalidate');
     header('Pragma: no-cache');
     $user = isset($_GET['user']) ? $_GET['user'] : '';
     if (ctype_alnum($user)) {
         try {
             $salt = FreshRSS_Context::$system_conf->salt;
             $conf = get_user_configuration($user);
             $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($salt . uniqid(mt_rand(), true));
                 Minz_Session::_param('nonce', $this->view->nonce);
                 return;
                 //Success
             }
         } catch (Minz_Exception $me) {
             Minz_Log::warning('Nonce failure: ' . $me->getMessage());
         }
     } else {
         Minz_Log::notice('Nonce failure due to invalid username!');
     }
     //Failure: Return random data.
     $this->view->salt1 = sprintf('$2a$%02d$', FreshRSS_user_Controller::BCRYPT_COST);
     $alphabet = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
     for ($i = 22; $i > 0; $i--) {
         $this->view->salt1 .= $alphabet[rand(0, 63)];
     }
     $this->view->nonce = sha1(rand());
 }
 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'));
     header('Expires: 0');
     header('Cache-Control: private, no-cache, no-store, must-revalidate');
     header('Pragma: no-cache');
     $user = isset($_GET['user']) ? $_GET['user'] : '';
     if (ctype_alnum($user)) {
         try {
             $conf = new FreshRSS_Configuration($user);
             $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);
                 return;
                 //Success
             }
         } catch (Minz_Exception $me) {
             Minz_Log::record('Nonce failure: ' . $me->getMessage(), Minz_Log::WARNING);
         }
     }
     $this->view->nonce = '';
     //Failure
     $this->view->salt1 = '';
 }
Example #8
0
 public static function truncate()
 {
     file_put_contents(join_path(DATA_PATH, 'users', Minz_Session::param('currentUser', '_'), 'log.txt'), '');
     if (FreshRSS_Auth::hasAccess('admin')) {
         file_put_contents(join_path(DATA_PATH, 'users', '_', 'log.txt'), '');
         file_put_contents(join_path(DATA_PATH, 'users', '_', 'log_api.txt'), '');
         file_put_contents(join_path(DATA_PATH, 'users', '_', 'log_pshb.txt'), '');
     }
 }
Example #9
0
 /**
  * Inclus le fichier de langue qui va bien
  * l'enregistre dans $translates
  */
 public static function init()
 {
     $l = Minz_Configuration::language();
     self::$language = Minz_Session::param('language', $l);
     $l_path = APP_PATH . '/i18n/' . self::$language . '.php';
     if (file_exists($l_path)) {
         self::$translates = (include $l_path);
     }
 }
Example #10
0
 /**
  * Permet d'effacer une session
  * @param $force si à false, n'efface pas le paramètre de langue
  */
 public static function unset_session($force = false)
 {
     $language = self::param('language');
     session_destroy();
     self::$session = array();
     if (!$force) {
         self::_param('language', $language);
         Minz_Translate::reset();
     }
 }
Example #11
0
 public function handleConfigureAction()
 {
     $this->registerTranslates();
     $current_user = Minz_Session::param('currentUser');
     $filename = 'style.' . $current_user . '.css';
     $filepath = join_path($this->getPath(), 'static', $filename);
     if (Minz_Request::isPost()) {
         $css_rules = Minz_Request::param('css-rules', '');
         file_put_contents($filepath, $css_rules);
     }
     $this->css_rules = '';
     if (file_exists($filepath)) {
         $this->css_rules = file_get_contents($filepath);
     }
 }
Example #12
0
 /**
  * Créé la connexion à la base de données à l'aide des variables
  * HOST, BASE, USER et PASS définies dans le fichier de configuration
  */
 public function __construct($currentUser = null)
 {
     if (self::$useSharedBd && self::$sharedBd != null && $currentUser === null) {
         $this->bd = self::$sharedBd;
         $this->prefix = self::$sharedPrefix;
         $this->current_user = self::$sharedCurrentUser;
         return;
     }
     $conf = Minz_Configuration::get('system');
     $db = $conf->db;
     if ($currentUser === null) {
         $currentUser = Minz_Session::param('currentUser', '_');
     }
     $this->current_user = $currentUser;
     self::$sharedCurrentUser = $currentUser;
     $driver_options = isset($conf->db['pdo_options']) && is_array($conf->db['pdo_options']) ? $conf->db['pdo_options'] : array();
     try {
         $type = $db['type'];
         if ($type === 'mysql') {
             $string = 'mysql:host=' . $db['host'] . ';dbname=' . $db['base'] . ';charset=utf8';
             $driver_options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES utf8';
             $this->prefix = $db['prefix'] . $currentUser . '_';
         } elseif ($type === 'pgsql') {
             $string = 'pgsql:host=' . $db['host'] . ';dbname=' . $db['base'];
             $this->prefix = $db['prefix'] . $currentUser . '_';
         } elseif ($type === 'sqlite') {
             $string = 'sqlite:' . join_path(DATA_PATH, 'users', $currentUser, 'db.sqlite');
             //$driver_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
             $this->prefix = '';
         } else {
             throw new Minz_PDOConnectionException('Invalid database type!', $db['user'], Minz_Exception::ERROR);
         }
         self::$sharedDbType = $type;
         self::$sharedPrefix = $this->prefix;
         $this->bd = new MinzPDO($string, $db['user'], $db['password'], $driver_options);
         if ($type === 'sqlite') {
             $this->bd->exec('PRAGMA foreign_keys = ON;');
         }
         self::$sharedBd = $this->bd;
     } catch (Exception $e) {
         throw new Minz_PDOConnectionException($string, $db['user'], Minz_Exception::ERROR);
     }
 }
Example #13
0
 /**
  * Permet de lancer une erreur
  * @param $code le type de l'erreur, par défaut 404 (page not found)
  * @param $logs logs d'erreurs découpés de la forme
  *      > $logs['error']
  *      > $logs['warning']
  *      > $logs['notice']
  * @param $redirect indique s'il faut forcer la redirection (les logs ne seront pas transmis)
  */
 public static function error($code = 404, $logs = array(), $redirect = true)
 {
     $logs = self::processLogs($logs);
     $error_filename = APP_PATH . '/Controllers/errorController.php';
     if (file_exists($error_filename)) {
         Minz_Session::_param('error_code', $code);
         Minz_Session::_param('error_logs', $logs);
         Minz_Request::forward(array('c' => 'error'), $redirect);
     } else {
         echo '<h1>An error occured</h1>' . "\n";
         if (!empty($logs)) {
             echo '<ul>' . "\n";
             foreach ($logs as $log) {
                 echo '<li>' . $log . '</li>' . "\n";
             }
             echo '</ul>' . "\n";
         }
         exit;
     }
 }
Example #14
0
function checkToken($conf, $token)
{
    //http://code.google.com/p/google-reader-api/wiki/ActionToken
    $user = Minz_Session::param('currentUser', '_');
    logMe('checkToken(' . $token . ")\n");
    $system_conf = Minz_Configuration::get('system');
    if ($token === str_pad(sha1($system_conf->salt . $user . $conf->apiPasswordHash), 57, 'Z')) {
        return true;
    }
    unauthorized();
}
Example #15
0
 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);
 }
Example #16
0
 /**
  * This action actualizes entries from one or several feeds.
  *
  * Parameters are:
  *   - id (default: false): Feed ID
  *   - url (default: false): Feed URL
  *   - force (default: false)
  * If id and url are not specified, all the feeds are actualized. But if force is
  * false, process stops at 10 feeds to avoid time execution problem.
  */
 public function actualizeAction($simplePiePush = null)
 {
     @set_time_limit(300);
     $feedDAO = FreshRSS_Factory::createFeedDao();
     $entryDAO = FreshRSS_Factory::createEntryDao();
     Minz_Session::_param('actualize_feeds', false);
     $id = Minz_Request::param('id');
     $url = Minz_Request::param('url');
     $force = Minz_Request::param('force');
     // Create a list of feeds to actualize.
     // If id is set and valid, corresponding feed is added to the list but
     // alone in order to automatize further process.
     $feeds = array();
     if ($id || $url) {
         $feed = $id ? $feedDAO->searchById($id) : $feedDAO->searchByUrl($url);
         if ($feed) {
             $feeds[] = $feed;
         }
     } else {
         $feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$user_conf->ttl_default);
     }
     // Calculate date of oldest entries we accept in DB.
     $nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1);
     $date_min = time() - 3600 * 24 * 30 * $nb_month_old;
     // PubSubHubbub support
     $pubsubhubbubEnabledGeneral = FreshRSS_Context::$system_conf->pubsubhubbub_enabled;
     $pshbMinAge = time() - 3600 * 24;
     //TODO: Make a configuration.
     $updated_feeds = 0;
     $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0;
     foreach ($feeds as $feed) {
         $url = $feed->url();
         //For detection of HTTP 301
         $pubSubHubbubEnabled = $pubsubhubbubEnabledGeneral && $feed->pubSubHubbubEnabled();
         if (!$simplePiePush && !$id && $pubSubHubbubEnabled && $feed->lastUpdate() > $pshbMinAge) {
             //$text = 'Skip pull of feed using PubSubHubbub: ' . $url;
             //Minz_Log::debug($text);
             //file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
             continue;
             //When PubSubHubbub is used, do not pull refresh so often
         }
         if (!$feed->lock()) {
             Minz_Log::notice('Feed already being actualized: ' . $feed->url());
             continue;
         }
         try {
             if ($simplePiePush) {
                 $feed->loadEntries($simplePiePush);
                 //Used by PubSubHubbub
             } else {
                 $feed->load(false);
             }
         } catch (FreshRSS_Feed_Exception $e) {
             Minz_Log::warning($e->getMessage());
             $feedDAO->updateLastUpdate($feed->id(), true);
             $feed->unlock();
             continue;
         }
         $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;
         }
         // We want chronological order and SimplePie uses reverse order.
         $entries = array_reverse($feed->entries());
         if (count($entries) > 0) {
             $newGuids = array();
             foreach ($entries as $entry) {
                 $newGuids[] = $entry->guid();
             }
             // For this feed, check existing GUIDs already in database.
             $existingHashForGuids = $entryDAO->listHashForFeedGuids($feed->id(), $newGuids);
             unset($newGuids);
             $oldGuids = array();
             // Add entries in database if possible.
             foreach ($entries as $entry) {
                 $entry_date = $entry->date(true);
                 if (isset($existingHashForGuids[$entry->guid()])) {
                     $existingHash = $existingHashForGuids[$entry->guid()];
                     if (strcasecmp($existingHash, $entry->hash()) === 0 || $existingHash === '00000000000000000000000000000000') {
                         //This entry already exists and is unchanged. TODO: Remove the test with the zero'ed hash in FreshRSS v1.3
                         $oldGuids[] = $entry->guid();
                     } else {
                         //This entry already exists but has been updated
                         Minz_Log::debug('Entry with GUID `' . $entry->guid() . '` updated in feed ' . $feed->id() . ', old hash ' . $existingHash . ', new hash ' . $entry->hash());
                         //TODO: Make an updated/is_read policy by feed, in addition to the global one.
                         $entry->_isRead(FreshRSS_Context::$user_conf->mark_updated_article_unread ? false : null);
                         //Change is_read according to policy.
                         if (!$entryDAO->hasTransaction()) {
                             $entryDAO->beginTransaction();
                         }
                         $entryDAO->updateEntry($entry->toArray());
                     }
                 } elseif ($feed_history == 0 && $entry_date < $date_min) {
                     // This entry should not be added considering configuration and date.
                     $oldGuids[] = $entry->guid();
                 } else {
                     if ($entry_date < $date_min) {
                         $id = min(time(), $entry_date) . uSecString();
                         $entry->_isRead(true);
                         //Old article that was not in database. Probably an error, so mark as read
                     } else {
                         $id = uTimeString();
                         $entry->_isRead($is_read);
                     }
                     $entry->_id($id);
                     $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry);
                     if ($entry === null) {
                         // An extension has returned a null value, there is nothing to insert.
                         continue;
                     }
                     if ($pubSubHubbubEnabled && !$simplePiePush) {
                         //We use push, but have discovered an article by pull!
                         $text = 'An article was discovered by pull although we use PubSubHubbub!: Feed ' . $url . ' GUID ' . $entry->guid();
                         file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
                         Minz_Log::warning($text);
                         $pubSubHubbubEnabled = false;
                         $feed->pubSubHubbubError(true);
                     }
                     if (!$entryDAO->hasTransaction()) {
                         $entryDAO->beginTransaction();
                     }
                     $entryDAO->addEntry($entry->toArray());
                 }
             }
             $entryDAO->updateLastSeen($feed->id(), $oldGuids);
         }
         if ($feed_history >= 0 && rand(0, 30) === 1) {
             // TODO: move this function in web cron when available (see entry::purge)
             // Remove old entries once in 30.
             if (!$entryDAO->hasTransaction()) {
                 $entryDAO->beginTransaction();
             }
             $nb = $feedDAO->cleanOldEntries($feed->id(), $date_min, max($feed_history, count($entries) + 10));
             if ($nb > 0) {
                 Minz_Log::debug($nb . ' old entries cleaned in feed [' . $feed->url() . ']');
             }
         }
         $feedDAO->updateLastUpdate($feed->id(), 0, $entryDAO->hasTransaction());
         if ($entryDAO->hasTransaction()) {
             $entryDAO->commit();
         }
         if ($feed->hubUrl() && $feed->selfUrl()) {
             //selfUrl has priority for PubSubHubbub
             if ($feed->selfUrl() !== $url) {
                 //https://code.google.com/p/pubsubhubbub/wiki/MovingFeedsOrChangingHubs
                 $selfUrl = checkUrl($feed->selfUrl());
                 if ($selfUrl) {
                     Minz_Log::debug('PubSubHubbub unsubscribe ' . $feed->url());
                     if (!$feed->pubSubHubbubSubscribe(false)) {
                         //Unsubscribe
                         Minz_Log::warning('Error while PubSubHubbub unsubscribing from ' . $feed->url());
                     }
                     $feed->_url($selfUrl, false);
                     Minz_Log::notice('Feed ' . $url . ' canonical address moved to ' . $feed->url());
                     $feedDAO->updateFeed($feed->id(), array('url' => $feed->url()));
                 }
             }
         } elseif ($feed->url() !== $url) {
             // HTTP 301 Moved Permanently
             Minz_Log::notice('Feed ' . $url . ' moved permanently to ' . $feed->url());
             $feedDAO->updateFeed($feed->id(), array('url' => $feed->url()));
         }
         $feed->faviconPrepare();
         if ($pubsubhubbubEnabledGeneral && $feed->pubSubHubbubPrepare()) {
             Minz_Log::notice('PubSubHubbub subscribe ' . $feed->url());
             if (!$feed->pubSubHubbubSubscribe(true)) {
                 //Subscribe
                 Minz_Log::warning('Error while PubSubHubbub subscribing to ' . $feed->url());
             }
         }
         $feed->unlock();
         $updated_feeds++;
         unset($feed);
         // No more than 10 feeds unless $force is true to avoid overloading
         // the server.
         if ($updated_feeds >= 10 && !$force) {
             break;
         }
     }
     if (Minz_Request::param('ajax')) {
         // Most of the time, ajax request is for only one feed. But since
         // there are several parallel requests, we should return that there
         // are several updated feeds.
         $notif = array('type' => 'good', 'content' => _t('feedback.sub.feed.actualizeds'));
         Minz_Session::_param('notification', $notif);
         // No layout in ajax request.
         $this->view->_useLayout(false);
     } else {
         // Redirect to the main page with correct notification.
         if ($updated_feeds === 1) {
             $feed = reset($feeds);
             Minz_Request::good(_t('feedback.sub.feed.actualized', $feed->name()), array('params' => array('get' => 'f_' . $feed->id())));
         } elseif ($updated_feeds > 1) {
             Minz_Request::good(_t('feedback.sub.feed.n_actualized', $updated_feeds), array());
         } else {
             Minz_Request::good(_t('feedback.sub.feed.no_refresh'), array());
         }
     }
     return $updated_feeds;
 }
Example #17
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'));
         }
     }
 }
Example #18
0
 public function purgeAction()
 {
     @set_time_limit(300);
     $nb_month_old = max($this->view->conf->old_entries, 1);
     $date_min = time() - 3600 * 24 * 30 * $nb_month_old;
     $feedDAO = new FreshRSS_FeedDAO();
     $feeds = $feedDAO->listFeedsOrderUpdate();
     $nbTotal = 0;
     invalidateHttpCache();
     foreach ($feeds as $feed) {
         $feedHistory = $feed->keepHistory();
         if ($feedHistory == -2) {
             //default
             $feedHistory = $this->view->conf->keep_history_default;
         }
         if ($feedHistory >= 0) {
             $nb = $feedDAO->cleanOldEntries($feed->id(), $date_min, $feedHistory);
             if ($nb > 0) {
                 $nbTotal += $nb;
                 Minz_Log::record($nb . ' old entries cleaned in feed [' . $feed->url() . ']', Minz_Log::DEBUG);
                 $feedDAO->updateLastUpdate($feed->id());
             }
         }
     }
     invalidateHttpCache();
     $notif = array('type' => 'good', 'content' => Minz_Translate::t('purge_completed', $nbTotal));
     Minz_Session::_param('notification', $notif);
     Minz_Request::forward(array('c' => 'configure', 'a' => 'archiving'), true);
 }
Example #19
0
 function pubSubHubbubPrepare()
 {
     $key = '';
     if (FreshRSS_Context::$system_conf->base_url && $this->hubUrl && $this->selfUrl && @is_dir(PSHB_PATH)) {
         $path = PSHB_PATH . '/feeds/' . base64url_encode($this->selfUrl);
         $hubFilename = $path . '/!hub.json';
         if ($hubFile = @file_get_contents($hubFilename)) {
             $hubJson = json_decode($hubFile, true);
             if (!$hubJson || empty($hubJson['key']) || !ctype_xdigit($hubJson['key'])) {
                 $text = 'Invalid JSON for PubSubHubbub: ' . $this->url;
                 Minz_Log::warning($text);
                 file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
                 return false;
             }
             if (!empty($hubJson['lease_end']) && $hubJson['lease_end'] < time() + 3600 * 23) {
                 //TODO: Make a better policy
                 $text = 'PubSubHubbub lease ends at ' . date('c', empty($hubJson['lease_end']) ? time() : $hubJson['lease_end']) . ' and needs renewal: ' . $this->url;
                 Minz_Log::warning($text);
                 file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
                 $key = $hubJson['key'];
                 //To renew our lease
             } elseif ((!empty($hubJson['error']) || empty($hubJson['lease_end'])) && (empty($hubJson['lease_start']) || $hubJson['lease_start'] < time() - 3600 * 23)) {
                 //Do not renew too often
                 $key = $hubJson['key'];
                 //To renew our lease
             }
         } else {
             @mkdir($path, 0777, true);
             $key = sha1($path . FreshRSS_Context::$system_conf->salt . uniqid(mt_rand(), true));
             $hubJson = array('hub' => $this->hubUrl, 'key' => $key);
             file_put_contents($hubFilename, json_encode($hubJson));
             @mkdir(PSHB_PATH . '/keys/');
             file_put_contents(PSHB_PATH . '/keys/' . $key . '.txt', base64url_encode($this->selfUrl));
             $text = 'PubSubHubbub prepared for ' . $this->url;
             Minz_Log::debug($text);
             file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND);
         }
         $currentUser = Minz_Session::param('currentUser');
         if (ctype_alnum($currentUser) && !file_exists($path . '/' . $currentUser . '.txt')) {
             touch($path . '/' . $currentUser . '.txt');
         }
     }
     return $key;
 }
 /**
  * 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 #21
0
function invalidateHttpCache()
{
    Minz_Session::_param('touch', uTimeString());
    return touch(LOG_PATH . '/' . Minz_Session::param('currentUser', '_') . '.log');
}
Example #22
0
function invalidateHttpCache()
{
    Minz_Session::_param('touch', uTimeString());
    return touch(join_path(DATA_PATH, 'users', Minz_Session::param('currentUser', '_'), 'log.txt'));
}
Example #23
0
 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 &= strcasecmp($username, Minz_Configuration::defaultUser()) !== 0;
             //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);
             //TODO: delete Persona file
         }
         invalidateHttpCache();
         $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);
 }
Example #24
0
 private function loadNotifications()
 {
     $notif = Minz_Session::param('notification');
     if ($notif) {
         Minz_View::_param('notification', $notif);
         Minz_Session::_param('notification');
     }
 }
Example #25
0
$self = isset($links[0]) ? $links[0] : null;
if ($self !== base64url_decode($canonical64)) {
    //header('HTTP/1.1 422 Unprocessable Entity');
    logMe('Warning: Self URL [' . $self . '] does not match registered canonical URL!: ' . base64url_decode($canonical64));
    //die('Self URL does not match registered canonical URL!');
    $self = base64url_decode($canonical64);
}
Minz_Request::_param('url', $self);
$nb = 0;
foreach ($users as $userFilename) {
    $username = basename($userFilename, '.txt');
    if (!file_exists(USERS_PATH . '/' . $username . '/config.php')) {
        break;
    }
    try {
        Minz_Session::_param('currentUser', $username);
        Minz_Configuration::register('user', join_path(USERS_PATH, $username, 'config.php'), join_path(USERS_PATH, '_', 'config.default.php'));
        FreshRSS_Context::init();
        if ($feedController->actualizeAction($simplePie) > 0) {
            $nb++;
        }
    } catch (Exception $e) {
        logMe('Error: ' . $e->getMessage());
    }
}
$simplePie->__destruct();
unset($simplePie);
if ($nb === 0) {
    header('HTTP/1.1 410 Gone');
    logMe('Error: Nobody is subscribed to this feed anymore after all!: ' . $self);
    die('Nobody is subscribed to this feed anymore after all!');
 public function archivingAction()
 {
     if (Minz_Request::isPost()) {
         $old = Minz_Request::param('old_entries', 3);
         $keepHistoryDefault = Minz_Request::param('keep_history_default', 0);
         $this->view->conf->_old_entries($old);
         $this->view->conf->_keep_history_default($keepHistoryDefault);
         $this->view->conf->save();
         invalidateHttpCache();
         $notif = array('type' => 'good', 'content' => Minz_Translate::t('configuration_updated'));
         Minz_Session::_param('notification', $notif);
         Minz_Request::forward(array('c' => 'configure', 'a' => 'archiving'), true);
     }
     Minz_View::prependTitle(Minz_Translate::t('archiving_configuration') . ' · ');
     $entryDAO = new FreshRSS_EntryDAO();
     $this->view->nb_total = $entryDAO->count();
     $this->view->size_user = $entryDAO->size();
     if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) {
         $this->view->size_total = $entryDAO->size(true);
     }
 }
Example #27
0
 public static function bad($msg, $url = array())
 {
     Minz_Session::_param('notification', array('type' => 'bad', 'content' => $msg));
     Minz_Request::forward($url, true);
 }
Example #28
0
 /**
  * This action delete an existing user.
  *
  * Request parameter is:
  *   - username
  *
  * @todo clean up this method. Idea: create a User->clean() method.
  */
 public function deleteAction()
 {
     $username = Minz_Request::param('username');
     $redirect_url = urldecode(Minz_Request::param('r', false, true));
     if (!$redirect_url) {
         $redirect_url = array('c' => 'user', 'a' => 'manage');
     }
     $self_deletion = Minz_Session::param('currentUser', '_') === $username;
     if (Minz_Request::isPost() && (FreshRSS_Auth::hasAccess('admin') || $self_deletion)) {
         $db = FreshRSS_Context::$system_conf->db;
         require_once APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php';
         $ok = ctype_alnum($username);
         $user_data = join_path(DATA_PATH, 'users', $username);
         if ($ok) {
             $default_user = FreshRSS_Context::$system_conf->default_user;
             $ok &= strcasecmp($username, $default_user) !== 0;
             //It is forbidden to delete the default user
         }
         if ($ok && $self_deletion) {
             // We check the password if it's a self-destruction
             $nonce = Minz_Session::param('nonce');
             $challenge = Minz_Request::param('challenge', '');
             $ok &= FreshRSS_FormAuth::checkCredentials($username, FreshRSS_Context::$user_conf->passwordHash, $nonce, $challenge);
         }
         if ($ok) {
             $ok &= is_dir($user_data);
         }
         if ($ok) {
             $userDAO = new FreshRSS_UserDAO();
             $ok &= $userDAO->deleteUser($username);
             $ok &= recursive_unlink($user_data);
             //TODO: delete Persona file
         }
         if ($ok && $self_deletion) {
             FreshRSS_Auth::removeAccess();
             $redirect_url = array('c' => 'index', 'a' => 'index');
         }
         invalidateHttpCache();
         $notif = array('type' => $ok ? 'good' : 'bad', 'content' => _t('feedback.user.deleted' . (!$ok ? '.error' : ''), $username));
         Minz_Session::_param('notification', $notif);
     }
     Minz_Request::forward($redirect_url, true);
 }
Example #29
0
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# ***** END LICENSE BLOCK *****
require '../../constants.php';
require LIB_PATH . '/lib_rss.php';
//Includes class autoloader
if (file_exists(DATA_PATH . '/do-install.txt')) {
    require APP_PATH . '/install.php';
} else {
    session_cache_limiter('');
    Minz_Session::init('FreshRSS');
    Minz_Session::_param('keepAlive', 1);
    //For Persona
    if (!file_exists(DATA_PATH . '/no-cache.txt')) {
        require LIB_PATH . '/http-conditional.php';
        $currentUser = Minz_Session::param('currentUser', '');
        $dateLastModification = $currentUser === '' ? time() : max(@filemtime(join_path(USERS_PATH, $currentUser, 'log.txt')), @filemtime(join_path(DATA_PATH, 'config.php')));
        if (httpConditional($dateLastModification, 0, 0, false, PHP_COMPRESSION, true)) {
            exit;
            //No need to send anything
        }
    }
    try {
        $front_controller = new FreshRSS();
        $front_controller->init();
        $front_controller->run();
    } catch (Exception $e) {
        echo '### Fatal error! ###<br />', "\n";
        Minz_Log::error($e->getMessage());
        echo 'See logs files.';
    }
Example #30
0
 public static function truncate()
 {
     file_put_contents(LOG_PATH . '/' . Minz_Session::param('currentUser', '_') . '.log', '');
 }