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!'); } $this->view->nonce = ''; //Failure $this->view->salt1 = ''; }
public function postUpdateHook() { $res = $this->install(); if ($res !== true) { Minz_Log::warning('Problem during TTRSS API extension post update: ' . $res); } }
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 checkAction() { $this->view->change_view('update', 'index'); if (file_exists(UPDATE_FILENAME)) { // There is already an update file to apply: we don't need to check // the webserver! // Or if already check during the last hour, do nothing. Minz_Request::forward(array('c' => 'update'), true); return; } $auto_update_url = FreshRSS_Context::$system_conf->auto_update_url . '?v=' . FRESHRSS_VERSION; $c = curl_init($auto_update_url); curl_setopt($c, CURLOPT_RETURNTRANSFER, true); curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); $result = curl_exec($c); $c_status = curl_getinfo($c, CURLINFO_HTTP_CODE); $c_error = curl_error($c); curl_close($c); if ($c_status !== 200) { Minz_Log::warning('Error during update (HTTP code ' . $c_status . '): ' . $c_error); $this->view->message = array('status' => 'bad', 'title' => _t('gen.short.damn'), 'body' => _t('feedback.update.server_not_found', $auto_update_url)); return; } $res_array = explode("\n", $result, 2); $status = $res_array[0]; if (strpos($status, 'UPDATE') !== 0) { $this->view->message = array('status' => 'bad', 'title' => _t('gen.short.damn'), 'body' => _t('feedback.update.none')); @touch(join_path(DATA_PATH, 'last_update.txt')); return; } $script = $res_array[1]; if (file_put_contents(UPDATE_FILENAME, $script) !== false) { $version = explode(' ', $status, 2); $version = $version[1]; @file_put_contents(join_path(DATA_PATH, 'last_update.txt'), $version); Minz_Request::forward(array('c' => 'update'), true); } else { $this->view->message = array('status' => 'bad', 'title' => _t('gen.short.damn'), 'body' => _t('feedback.update.error', 'Cannot save the update script')); } }
/** * Load the extension source code based on info metadata. * * @param $info an array containing information about extension. * @return an extension inheriting from Minz_Extension. */ public static function load($info) { $entry_point_filename = $info['path'] . '/' . self::$ext_entry_point; $ext_class_name = $info['entrypoint'] . 'Extension'; include_once $entry_point_filename; // Test if the given extension class exists. if (!class_exists($ext_class_name)) { Minz_Log::warning('`' . $ext_class_name . '` cannot be found in `' . $entry_point_filename . '`'); return null; } // Try to load the class. $extension = null; try { $extension = new $ext_class_name($info); } catch (Minz_ExtensionException $e) { // We cannot load the extension? Invalid! Minz_Log::warning('In `' . $metadata_filename . '`: ' . $e->getMessage()); return null; } // Test if class is correct. if (!$extension instanceof Minz_Extension) { Minz_Log::warning('`' . $ext_class_name . '` is not an instance of `Minz_Extension`'); return null; } return $extension; }
function clientLogin($email, $pass) { //http://web.archive.org/web/20130604091042/http://undoc.in/clientLogin.html logMe('clientLogin(' . $email . ")\n"); if (ctype_alnum($email)) { if (!function_exists('password_verify')) { include_once LIB_PATH . '/password_compat.php'; } $conf = get_user_configuration($email); if (is_null($conf)) { Minz_Log::warning('Invalid API user ' . $email . ': configuration cannot be found.'); unauthorized(); } if ($conf->apiPasswordHash != '' && password_verify($pass, $conf->apiPasswordHash)) { header('Content-Type: text/plain; charset=UTF-8'); $system_conf = Minz_Configuration::get('system'); $auth = $email . '/' . sha1($system_conf->salt . $email . $conf->apiPasswordHash); echo 'SID=', $auth, "\n", 'Auth=', $auth, "\n"; exit; } else { Minz_Log::warning('Password API mismatch for user ' . $email); unauthorized(); } } else { badRequest(); } die; }
/** * This action changes the category of a feed. * * This page must be reached by a POST request. * * Parameters are: * - f_id (default: false) * - c_id (default: false) * If c_id is false, default category is used. * * @todo should handle order of the feed inside the category. */ public function moveAction() { if (!Minz_Request::isPost()) { Minz_Request::forward(array('c' => 'subscription'), true); } $feed_id = Minz_Request::param('f_id'); $cat_id = Minz_Request::param('c_id'); if ($cat_id === false) { // If category was not given get the default one. $catDAO = new FreshRSS_CategoryDAO(); $catDAO->checkDefault(); $def_cat = $catDAO->getDefault(); $cat_id = $def_cat->id(); } $feedDAO = FreshRSS_Factory::createFeedDao(); $values = array('category' => $cat_id); $feed = $feedDAO->searchById($feed_id); if ($feed && ($feed->category() == $cat_id || $feedDAO->updateFeed($feed_id, $values))) { // TODO: return something useful } else { Minz_Log::warning('Cannot move feed `' . $feed_id . '` ' . 'in the category `' . $cat_id . '`'); Minz_Error::error(404); } }
/** * 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')); } } }
/** * Load the files associated to $key into $translates. * @param $key the top level i18n key we want to load. */ private static function loadKey($key) { // The top level key is not in $lang_files, it means it does not exist! if (!isset(self::$lang_files[$key])) { Minz_Log::debug($key . ' is not a valid top level key'); return false; } self::$translates[$key] = array(); foreach (self::$lang_files[$key] as $lang_pathname) { $i18n_array = (include $lang_pathname); if (!is_array($i18n_array)) { Minz_Log::warning('`' . $lang_pathname . '` does not contain a PHP array'); continue; } // We must avoid to erase previous data so we just override them if // needed. self::$translates[$key] = array_replace_recursive(self::$translates[$key], $i18n_array); } return true; }
/** * Register and return the configuration for a given user. * * Note this function has been created to generate temporary configuration * objects. If you need a long-time configuration, please don't use this function. * * @param $username the name of the user of which we want the configuration. * @return a Minz_Configuration object, null if the configuration cannot be loaded. */ function get_user_configuration($username) { $namespace = 'user_' . $username; try { Minz_Configuration::register($namespace, join_path(USERS_PATH, $username, 'config.php'), join_path(USERS_PATH, '_', 'config.default.php')); } catch (Minz_ConfigurationNamespaceException $e) { // namespace already exists, do nothing. } catch (Minz_FileNotExistException $e) { Minz_Log::warning($e->getMessage()); return null; } return Minz_Configuration::get($namespace); }
function pubSubHubbubSubscribe($state) { if (FreshRSS_Context::$system_conf->base_url && $this->hubUrl && $this->selfUrl) { $hubFilename = PSHB_PATH . '/feeds/' . base64url_encode($this->selfUrl) . '/!hub.json'; $hubFile = @file_get_contents($hubFilename); if ($hubFile === false) { Minz_Log::warning('JSON not found for PubSubHubbub: ' . $this->url); return false; } $hubJson = json_decode($hubFile, true); if (!$hubJson || empty($hubJson['key']) || !ctype_xdigit($hubJson['key'])) { Minz_Log::warning('Invalid JSON for PubSubHubbub: ' . $this->url); return false; } $callbackUrl = checkUrl(FreshRSS_Context::$system_conf->base_url . 'api/pshb.php?k=' . $hubJson['key']); if ($callbackUrl == '') { Minz_Log::warning('Invalid callback for PubSubHubbub: ' . $this->url); return false; } $ch = curl_init(); curl_setopt_array($ch, array(CURLOPT_URL => $this->hubUrl, CURLOPT_FOLLOWLOCATION => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_USERAGENT => _t('gen.freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ')', CURLOPT_POSTFIELDS => 'hub.verify=sync' . '&hub.mode=' . ($state ? 'subscribe' : 'unsubscribe') . '&hub.topic=' . urlencode($this->selfUrl) . '&hub.callback=' . urlencode($callbackUrl))); $response = curl_exec($ch); $info = curl_getinfo($ch); file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . 'PubSubHubbub ' . ($state ? 'subscribe' : 'unsubscribe') . ' to ' . $this->selfUrl . ' with callback ' . $callbackUrl . ': ' . $info['http_code'] . ' ' . $response . "\n", FILE_APPEND); if (!$state) { //unsubscribe $hubJson['lease_end'] = time() - 60; file_put_contents($hubFilename, json_encode($hubJson)); } if (substr($info['http_code'], 0, 1) == '2') { return true; } else { $hubJson['lease_start'] = time(); //Prevent trying again too soon $hubJson['error'] = true; file_put_contents($hubFilename, json_encode($hubJson)); return false; } } return false; }
/** * This method import a JSON-based feed (Google Reader format). * * @param array $origin represents a feed. * @param boolean $google_compliant takes care of some specific values if true. * @return FreshRSS_Feed if feed is in database at the end of the process, * else null. */ private function addFeedJson($origin, $google_compliant) { $default_cat = $this->catDAO->getDefault(); $return = null; $key = $google_compliant ? 'htmlUrl' : 'feedUrl'; $url = $origin[$key]; $name = $origin['title']; $website = $origin['htmlUrl']; try { // Create a Feed object and add it in database. $feed = new FreshRSS_Feed($url); $feed->_category($default_cat->id()); $feed->_name($name); $feed->_website($website); // Call the extension hook $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); if (!is_null($feed)) { // addFeedObject checks if feed is already in DB so nothing else to // check here. $id = $this->feedDAO->addFeedObject($feed); if ($id !== false) { $feed->_id($id); $return = $feed; } } } catch (FreshRSS_Feed_Exception $e) { Minz_Log::warning($e->getMessage()); } return $return; }
/** * Return the value of the given param. * * @param $key the name of the param. * @param $default default value to return if key does not exist. * @return the value corresponding to the key. * @throws Minz_ConfigurationParamException if the param does not exist */ public function param($key, $default = null) { if (isset($this->data[$key])) { return $this->data[$key]; } elseif (!is_null($default)) { return $default; } else { Minz_Log::warning($key . ' does not exist in configuration'); return null; } }
public function unsubscribeFeed() { Minz_Log::warning('TTRSS API: unsubscribeFeed() not implemented'); }
/** * Affiche un élément graphique situé dans APP./views/helpers/ * @param $helper l'élément à afficher */ public function renderHelper($helper) { $fic_helper = '/views/helpers/' . $helper . '.phtml'; if (!$this->includeFile($fic_helper)) { Minz_Log::warning('File not found: `' . $fic_helper . '`'); } }
/** * This action disables an enabled extension for the current user. * * System extensions can only be disabled by an administrator. * This action must be reached by a POST request. * * Parameter is: * - e: the extension name (urlencoded). */ public function disableAction() { $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); } if (!$ext->isEnabled()) { Minz_Request::bad(_t('feedback.extensions.not_enabled', $ext_name), $url_redirect); } $conf = null; if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { $conf = FreshRSS_Context::$system_conf; } elseif ($ext->getType() === 'user') { $conf = FreshRSS_Context::$user_conf; } else { Minz_Request::bad(_t('feedback.extensions.no_access', $ext_name), $url_redirect); } $res = $ext->uninstall(); if ($res === true) { $ext_list = $conf->extensions_enabled; array_remove($ext_list, $ext_name); $conf->extensions_enabled = $ext_list; $conf->save(); Minz_Request::good(_t('feedback.extensions.disable.ok', $ext_name), $url_redirect); } else { Minz_Log::warning('Can not unable extension ' . $ext_name . ': ' . $res); Minz_Request::bad(_t('feedback.extensions.disable.ko', $ext_name, _url('index', 'logs')), $url_redirect); } } Minz_Request::forward($url_redirect, true); }