1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/ttrss_ynh.git synced 2024-10-01 13:34:46 +02:00

update ttrss 1.15.3

This commit is contained in:
Adrien Beudin 2015-01-22 17:56:46 +01:00
parent f6f84fd2b0
commit a335861ed5
36 changed files with 2260 additions and 1676 deletions

View file

@ -1,4 +1,4 @@
ttrss for YunoHost
Tiny-Tiny RSS paquage for YunoHost
======================
http://tt-rss.org/redmine/projects/tt-rss/wiki

View file

@ -10,8 +10,9 @@ location PATHTOCHANGE {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
# Include SSOWAT user panel.

33
conf/ttrss.diff Normal file
View file

@ -0,0 +1,33 @@
--- update.php.ynh 2015-01-22 16:45:52.105737698 +0100
+++ update.php 2015-01-22 16:43:09.977745715 +0100
@@ -311,8 +311,8 @@
_debug("WARNING: please backup your database before continuing.");
_debug("Type 'yes' to continue.");
- //if (read_stdin() != 'yes')
- // exit;
+ if (read_stdin() != 'yes')
+ exit;
for ($i = $updater->getSchemaVersion() + 1; $i <= SCHEMA_VERSION; $i++) {
_debug("performing update up to version $i...");
--- plugins/auth_remote/init.php.ynh 2015-01-22 16:50:51.653723599 +0100
+++ plugins/auth_remote/init.php 2015-01-22 16:43:09.957745715 +0100
@@ -69,16 +69,6 @@
db_query("UPDATE ttrss_users SET email = '$email' WHERE id = " .
$user_id);
}
- // update user password to allow api access
- if (isset($_SERVER['PHP_AUTH_PW'])){
- $currentpassword = $_SERVER['PHP_AUTH_PW'];
- $new_salt = substr(bin2hex(get_random_bytes(125)), 0, 250);
- $new_password_hash = encrypt_password($currentpassword, $new_salt, true);
-
- db_query("UPDATE ttrss_users SET
- pwd_hash = '$new_password_hash', salt = '$new_salt', otp_enabled = false
- WHERE login = '$try_login'");
- }
}
return $user_id;

View file

@ -5,16 +5,17 @@
"en": "A PHP and Ajax feed reader",
"fr": "Un lecteur de flux en PHP et Ajax"
},
"developer": {
"url": "http://tt-rss.org",
"maintainer": {
"name": "titoko",
"email": "titoko@titoko.fr",
"url": "http://dev.yunohost.org"
"email": "titoko@titoko.fr"
},
"multi_instance": "true",
"arguments": {
"install" : [
{
"name": "domain",
"type": "domain",
"ask": {
"en": "Choose a domain for Tiny-Tiny-RSS",
"fr": "Choisissez un domaine pour Tiny-Tiny-RSS"
@ -23,6 +24,7 @@
},
{
"name": "path",
"type": "path",
"ask": {
"en": "Choose a path for Tiny-Tiny-RSS",
"fr": "Choisissez un chemin pour Tiny-Tiny-RSS"

View file

@ -22,10 +22,13 @@ sudo yunohost app initdb $db_user -p $db_pwd -s $(readlink -e ../source/schema/T
sudo yunohost app setting ttrss mysqlpwd -v $db_pwd
# Copy files to the right place
final_path=/var/www/ttrss
sudo mkdir -p $final_path
sudo cp -r ../source/* $final_path
sudo cp ../conf/config.php $final_path/
final_path=/var/www/ttrss
sudo mkdir -p $final_path
sudo cp -r ../source/* $final_path
sudo cp ../conf/config.php $final_path/
sudo cp ../conf/ttrss.diff $final_path/
sudo patch -p0 $final_path/ttrss.diff
# Change variables in ttrss configuration
sudo sed -i "s/yunouser/$db_user/g" $final_path/config.php

View file

@ -5,15 +5,21 @@ path=$(sudo yunohost app setting ttrss path)
db_user=ttrss
db_pwd=$(sudo yunohost app setting ttrss mysqlpwd)
<<<<<<< HEAD
=======
#db_file=../source/schema/versions/mysql/$(ls -vr ../source/schema/versions/mysql | head -1)
#mysql -u $db_user -p$db_pwd $db_user < $db_file
>>>>>>> f6f84fd2b073b67a92eaed31b51016470a2e0d4e
final_path=/var/www/ttrss
sudo mkdir -p $final_path
sudo cp -a ../source/* $final_path
sudo cp ../conf/config.php $final_path/
sudo cp ../conf/ttrss.diff $final_path/
sudo patch -p0 $final_path/ttrss.diff
# Change variables in ttrss configuration
sudo sed -i "s/yunouser/$db_user/g" $final_path/config.php

View file

@ -2,7 +2,7 @@
class API extends Handler {
const API_LEVEL = 9;
const API_LEVEL = 11;
const STATUS_OK = 0;
const STATUS_ERR = 1;
@ -201,6 +201,10 @@ class API extends Handler {
$sanitize_content = !isset($_REQUEST["sanitize"]) ||
sql_bool_to_bool($_REQUEST["sanitize"]);
$force_update = sql_bool_to_bool($_REQUEST["force_update"]);
$has_sandbox = sql_bool_to_bool($_REQUEST["has_sandbox"]);
$excerpt_length = (int)$this->dbh->escape_string($_REQUEST["excerpt_length"]);
$_SESSION['hasSandbox'] = $has_sandbox;
$override_order = false;
switch ($_REQUEST["order_by"]) {
@ -223,7 +227,7 @@ class API extends Handler {
$headlines = $this->api_get_headlines($feed_id, $limit, $offset,
$filter, $is_cat, $show_excerpt, $show_content, $view_mode, $override_order,
$include_attachments, $since_id, $search, $search_mode,
$include_nested, $sanitize_content, $force_update);
$include_nested, $sanitize_content, $force_update, $excerpt_length);
$this->wrap(self::STATUS_OK, $headlines);
} else {
@ -633,7 +637,7 @@ class API extends Handler {
$filter, $is_cat, $show_excerpt, $show_content, $view_mode, $order,
$include_attachments, $since_id,
$search = "", $search_mode = "",
$include_nested = false, $sanitize_content = true, $force_update = false) {
$include_nested = false, $sanitize_content = true, $force_update = false, $excerpt_length = 100) {
if ($force_update && $feed_id > 0 && is_numeric($feed_id)) {
// Update the feed if required with some basic flood control
@ -666,16 +670,31 @@ class API extends Handler {
$headlines = array();
while ($line = db_fetch_assoc($result)) {
$line["content_preview"] = truncate_string(strip_tags($line["content"]), 100);
$line["content_preview"] = truncate_string(strip_tags($line["content"]), $excerpt_length);
foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) {
$line = $p->hook_query_headlines($line, 100, true);
$line = $p->hook_query_headlines($line, $excerpt_length, true);
}
$is_updated = ($line["last_read"] == "" &&
($line["unread"] != "t" && $line["unread"] != "1"));
$tags = explode(",", $line["tag_cache"]);
$labels = json_decode($line["label_cache"], true);
$label_cache = $line["label_cache"];
$labels = false;
if ($label_cache) {
$label_cache = json_decode($label_cache, true);
if ($label_cache) {
if ($label_cache["no-labels"] == 1)
$labels = array();
else
$labels = $label_cache;
}
}
if (!is_array($labels)) $labels = get_article_labels($line["id"]);
//if (!$tags) $tags = get_article_tags($line["id"]);
//if (!$labels) $labels = get_article_labels($line["id"]);

View file

@ -491,7 +491,9 @@ class Opml extends Handler_Protected {
if (is_file($tmp_file)) {
$doc = new DOMDocument();
libxml_disable_entity_loader(false);
$doc->load($tmp_file);
libxml_disable_entity_loader(true);
unlink($tmp_file);
} else if (!$doc) {
print_error(__('Error: unable to find moved OPML file.'));

View file

@ -571,7 +571,8 @@ class Pref_Prefs extends Handler_Protected {
} else if ($pref_name == "USER_CSS_THEME") {
$themes = array_map("basename", glob("themes/*.css"));
$themes = array_filter(array_map("basename", glob("themes/*.css")),
"theme_valid");
print_select($pref_name, $value, $themes,
'dojoType="dijit.form.Select"');

View file

@ -93,6 +93,10 @@
background : white;
}
.claro #feedTree.dijitTree .dijitTreeRowSelected {
box-shadow : -1px 0px 2px -1px rgba(0,0,0,0.1);
}
.claro .dijitTree .dijitTreeRowHover {
background : #f0f0f0;
border-color : #ddd;

View file

@ -7,6 +7,11 @@ body#ttrssMain, body#ttrssPrefs, body#ttrssLogin, body {
font-size: 14px;
}
body#ttrssMain {
overflow : hidden;
max-height : 100%;
}
div.postReply {
padding : 0px;
}
@ -138,18 +143,30 @@ a:hover {
position : absolute;
}
#notify.visible {
transform: translate(0, -35px);
-webkit-transform: translate(0, -35px);
-o-transform: translate(0, -35px);
-moz-transform: translate(0, -35px);
}
#notify {
bottom : 10px;
right : 20px;
border-width : 1px;
bottom : -35px;
right : 0px;
height : 20px;
left : 0px;
border-width : 1px 0px 0px 0px;
border-style : solid;
position : absolute;
position : fixed;
font-size : 12px;
z-index : 99;
max-width : 200px;
min-width : 100px;
padding : 5px;
-width : 200px;
box-shadow : 0px -2px 2px rgba(0,0,0,0.1);
transition: all 0.5s ease-in-out;
-webkit-transition: all 0.5s ease-in-out;
-moz-transition: all 0.5s ease-in-out;
-o-transition: all 0.5s ease-in-out;
}
#notify img {
@ -176,17 +193,17 @@ a:hover {
background-color : #fff7d5;
}
.notify.progress {
.notify.notify_progress {
border-color : #d7c47a;
background-color : #fff7d5;
}
.notify.info {
.notify.notify_info {
border-color : #88b0f0;
background-color : #ecf4ff;
}
.notify.error {
.notify.notify_error {
background-color : #ffcccc;
border-color : #ff0000;
}
@ -796,7 +813,7 @@ div.fatalError textarea {
#feeds-holder {
padding : 0px;
border-width : 0px 1px 0px 0px;
border-width : 0px 0px 0px 0px;
border-style : solid;
border-color : #ddd;
overflow : hidden;

View file

@ -14,6 +14,8 @@
$fetch_curl_used = false;
$suppress_debugging = false;
libxml_disable_entity_loader(true);
mb_internal_encoding("UTF-8");
date_default_timezone_set('UTC');
if (defined('E_DEPRECATED')) {
@ -357,6 +359,9 @@
$url = ltrim($url, ' ');
$url = str_replace(' ', '%20', $url);
if (strpos($url, "//") === 0)
$url = 'http:' . $url;
if (!defined('NO_CURL') && function_exists('curl_init')) {
$fetch_curl_used = true;

View file

@ -17,7 +17,10 @@
$params["default_view_order_by"] = get_pref("_DEFAULT_VIEW_ORDER_BY");
$params["bw_limit"] = (int) $_SESSION["bw_limit"];
$params["label_base_index"] = (int) LABEL_BASE_INDEX;
$params["theme"] = get_pref("USER_CSS_THEME", false, false);
$theme = get_pref( "USER_CSS_THEME", false, false);
$params["theme"] = theme_valid("$theme") ? $theme : "";
$params["plugins"] = implode(", ", PluginHost::getInstance()->get_plugin_names());
$params["php_platform"] = PHP_OS;
@ -826,6 +829,21 @@
}
function iframe_whitelisted($entry) {
$whitelist = array("youtube.com", "youtu.be", "vimeo.com");
@$src = parse_url($entry->getAttribute("src"), PHP_URL_HOST);
if ($src) {
foreach ($whitelist as $w) {
if ($src == $w || $src == "www.$w")
return true;
}
}
return false;
}
function sanitize($str, $force_remove_images = false, $owner = false, $site_url = false, $highlight_words = false, $article_id = false) {
if (!$owner) $owner = $_SESSION["uid"];
@ -894,8 +912,15 @@
$entries = $xpath->query('//iframe');
foreach ($entries as $entry) {
$entry->setAttribute('sandbox', 'allow-scripts');
if (!iframe_whitelisted($entry)) {
$entry->setAttribute('sandbox', 'allow-scripts');
} else {
if ($_SERVER['HTTPS'] == "on") {
$entry->setAttribute("src",
str_replace("http://", "https://",
$entry->getAttribute("src")));
}
}
}
$allowed_elements = array('a', 'address', 'audio', 'article', 'aside',
@ -1958,8 +1983,8 @@
}
function getLastArticleId() {
$result = db_query("SELECT MAX(ref_id) AS id FROM ttrss_user_entries
WHERE owner_uid = " . $_SESSION["uid"]);
$result = db_query("SELECT ref_id AS id FROM ttrss_user_entries
WHERE owner_uid = " . $_SESSION["uid"] . " ORDER BY ref_id DESC LIMIT 1");
if (db_num_rows($result) == 1) {
return db_fetch_result($result, 0, "id");
@ -2400,4 +2425,21 @@
return LABEL_BASE_INDEX - 1 + abs($feed);
}
function theme_valid($file) {
if ($file == "default.css" || $file == "night.css") return true; // needed for array_filter
$file = "themes/" . basename($file);
if (file_exists($file) && is_readable($file)) {
$fh = fopen($file, "r");
if ($fh) {
$header = fgets($fh);
fclose($fh);
return strpos($header, "supports-version:" . VERSION_STATIC) !== FALSE;
}
}
return false;
}
?>

View file

@ -481,7 +481,7 @@
if (!$registered_title || $registered_title == "[Unknown]") {
$feed_title = db_escape_string($rss->get_title());
$feed_title = db_escape_string(mb_substr($rss->get_title(), 0, 199));
if ($feed_title) {
_debug("registering title: $feed_title", $debug_enabled);
@ -707,7 +707,11 @@
db_query("UPDATE ttrss_entries SET date_updated = NOW()
WHERE id = '$base_entry_id'");
continue;
// if we allow duplicate posts, we have to continue to
// create the user entries for this feed
if (!get_pref("ALLOW_DUPLICATE_POSTS", $owner_uid, false)) {
continue;
}
}
_debug("hash differs, applying plugin filters:", $debug_enabled);

View file

@ -1,5 +1,5 @@
<?php
define('VERSION_STATIC', '1.14');
define('VERSION_STATIC', '1.15.3');
function get_version() {
date_default_timezone_set('UTC');

View file

@ -65,7 +65,7 @@
<?php if ($_SESSION["uid"]) {
$theme = get_pref( "USER_CSS_THEME", $_SESSION["uid"], false);
if ($theme && file_exists("themes/$theme")) {
if ($theme && theme_valid("$theme")) {
echo stylesheet_tag("themes/$theme");
} else {
echo stylesheet_tag("themes/default.css");
@ -138,7 +138,7 @@
</div>
</div>
<div id="notify" class="notify" style="display : none"></div>
<div id="notify" class="notify"></div>
<div id="cmdline" style="display : none"></div>
<div id="headlines-tmp" style="display : none"></div>

View file

@ -182,11 +182,6 @@ function param_unescape(arg) {
return unescape(arg);
}
function hide_notify() {
Element.hide('notify');
}
function notify_real(msg, no_hide, n_type) {
var n = $("notify");
@ -198,13 +193,11 @@ function notify_real(msg, no_hide, n_type) {
}
if (msg == "") {
if (Element.visible(n)) {
notify_hide_timerid = window.setTimeout("hide_notify()", 0);
if (n.hasClassName("visible")) {
notify_hide_timerid = window.setTimeout(function() {
n.removeClassName("visible") }, 0);
}
return;
} else {
Element.show(n);
new Effect.Highlight(n);
}
/* types:
@ -218,30 +211,40 @@ function notify_real(msg, no_hide, n_type) {
msg = "<span class=\"msg\"> " + __(msg) + "</span>";
if (n_type == 1) {
n.className = "notify";
} else if (n_type == 2) {
n.className = "notify progress";
if (n_type == 2) {
msg = "<span><img src='images/indicator_white.gif'></span>" + msg;
no_hide = true;
} else if (n_type == 3) {
n.className = "notify error";
msg = "<span><img src='images/alert.png'></span>" + msg;
} else if (n_type == 4) {
n.className = "notify info";
msg = "<span><img src='images/information.png'></span>" + msg;
}
msg += " <span><img src=\"images/cross.png\" class=\"close\" title=\"" +
__("Click to close") + "\" onclick=\"notify('')\"></span>";
// msg = "<img src='images/live_com_loading.gif'> " + msg;
n.innerHTML = msg;
if (!no_hide) {
notify_hide_timerid = window.setTimeout("hide_notify()", 5*1000);
}
window.setTimeout(function() {
// goddamnit firefox
if (n_type == 2) {
n.className = "notify notify_progress visible";
} else if (n_type == 3) {
n.className = "notify notify_error visible";
msg = "<span><img src='images/alert.png'></span>" + msg;
} else if (n_type == 4) {
n.className = "notify notify_info visible";
} else {
n.className = "notify visible";
}
if (!no_hide) {
notify_hide_timerid = window.setTimeout(function() {
n.removeClassName("visible") }, 5*1000);
}
}, 10);
}
function notify(msg, no_hide) {

View file

@ -302,21 +302,27 @@ function init() {
hotkey_actions["collapse_article"] = function() {
var id = getActiveArticleId();
var elem = $("CICD-"+id);
if(elem.visible()) {
cdmCollapseArticle(null, id);
}
else {
cdmExpandArticle(id);
if (elem) {
if (elem.visible()) {
cdmCollapseArticle(null, id);
}
else {
cdmExpandArticle(id);
}
}
};
hotkey_actions["toggle_expand"] = function() {
var id = getActiveArticleId();
var elem = $("CICD-"+id);
if(elem.visible()) {
cdmCollapseArticle(null, id, false);
}
else {
cdmExpandArticle(id);
if (elem) {
if (elem.visible()) {
cdmCollapseArticle(null, id, false);
}
else {
cdmExpandArticle(id);
}
}
};
hotkey_actions["search_dialog"] = function() {

View file

@ -12,8 +12,8 @@ msgstr ""
"Project-Id-Version: Tiny Tiny RSS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-09-06 15:10+0400\n"
"PO-Revision-Date: 2014-09-06 20:33+0100\n"
"Last-Translator: Heiko Adams <heiko.adams@gmai.com>\n"
"PO-Revision-Date: 2014-11-19 18:13+0100\n"
"Last-Translator: Robert Wetzlmayr <r.wetzlmayr@gmail.com>\n"
"Language-Team: \n"
"Language: de\n"
"MIME-Version: 1.0\n"
@ -21,7 +21,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-Bookmarks: -1,557,558,-1,-1,-1,-1,-1,-1,-1\n"
"X-Generator: Poedit 1.5.4\n"
"X-Generator: Poedit 1.5.5\n"
#: backend.php:73
msgid "Use default"
@ -1771,7 +1771,7 @@ msgstr "Maximales Alter neuer Artikel (in Stunden)"
#: classes/pref/prefs.php:41
msgid "Hide feeds with no unread articles"
msgstr "Feeds ohne unglesene Nachrichten verbergen"
msgstr "Feeds ohne ungelesene Nachrichten verbergen"
#: classes/pref/prefs.php:42
msgid "Show special feeds when hiding read feeds"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -6,23 +6,33 @@ class Af_Comics_Dilbert extends Af_ComicFilter {
}
function process(&$article) {
$owner_uid = $article["owner_uid"];
if (strpos($article["guid"], "dilbert.com") !== FALSE) {
$res = fetch_file_contents($article["link"], false, false, false,
false, false, 0,
"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)");
global $fetch_last_error_content;
if (!$res && $fetch_last_error_content)
$res = $fetch_last_error_content;
$doc = new DOMDocument();
@$doc->loadHTML(fetch_file_contents($article["link"]));
@$doc->loadHTML($res);
$basenode = false;
if ($doc) {
$xpath = new DOMXPath($doc);
$entries = $xpath->query('(//img[@src])'); // we might also check for img[@class='strip'] I guess...
$basenode = $xpath->query('//div[@class="STR_Image"]')->item(0);
/* $entries = $xpath->query('(//img[@src])'); // we might also check for img[@class='strip'] I guess...
$matches = array();
foreach ($entries as $entry) {
if (preg_match("/dyn\/str_strip\/.*zoom\.gif$/", $entry->getAttribute("src"), $matches)) {
if (preg_match("/dyn\/str_strip\/.*strip\.gif$/", $entry->getAttribute("src"), $matches)) {
$entry->setAttribute("src",
rewrite_relative_url("http://dilbert.com/",
@ -31,7 +41,7 @@ class Af_Comics_Dilbert extends Af_ComicFilter {
$basenode = $entry;
break;
}
}
} */
if ($basenode) {
$article["content"] = $doc->saveXML($basenode);

View file

@ -56,7 +56,9 @@ class Af_Comics_Pa extends Af_ComicFilter {
if ($header->parentNode) { $header->parentNode->removeChild($header); }
$avatar = $xpath->query('(//div[@class="avatar"]//img)')->item(0);
$basenode->insertBefore($avatar, $basenode->firstChild);
if ($basenode)
$basenode->insertBefore($avatar, $basenode->firstChild);
$uninteresting = $xpath->query('(//div[@class="avatar"])');
foreach ($uninteresting as $i) {

View file

@ -0,0 +1,32 @@
<?php
class Af_Comics_Tfd extends Af_ComicFilter {
function supported() {
return array("Toothpaste For Dinner");
}
function process(&$article) {
$owner_uid = $article["owner_uid"];
if (strpos($article["link"], "toothpastefordinner.com") !== FALSE) {
$doc = new DOMDocument();
@$doc->loadHTML(fetch_file_contents($article["link"]));
$basenode = false;
if ($doc) {
$xpath = new DOMXPath($doc);
$basenode = $xpath->query('//img[@class="comic"]')->item(0);
if ($basenode) {
$article["content"] = $doc->saveXML($basenode);
return true;
}
}
}
return false;
}
}
?>

View file

@ -0,0 +1,79 @@
<?php
class Af_Tumblr_1280 extends Plugin {
private $host;
function about() {
return array(1.0,
"Replace Tumblr pictures with largest size if available",
"fox");
}
function init($host) {
$this->host = $host;
if (function_exists("curl_init")) {
$host->add_hook($host::HOOK_ARTICLE_FILTER, $this);
}
}
function hook_article_filter($article) {
$owner_uid = $article["owner_uid"];
$charset_hack = '<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>';
$doc = new DOMDocument();
$doc->loadHTML($charset_hack . $article["content"]);
$found = false;
if ($doc) {
$xpath = new DOMXpath($doc);
$images = $xpath->query('(//img[contains(@src, \'media.tumblr.com\')])');
foreach ($images as $img) {
$src = $img->getAttribute("src");
$test_src = preg_replace("/_\d{3}.(jpg|gif|png)/", "_1280.$1", $src);
if ($src != $test_src) {
$ch = curl_init($test_src);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,
!ini_get("safe_mode") && !ini_get("open_basedir"));
curl_setopt($ch, CURLOPT_USERAGENT, SELF_USER_AGENT);
@$result = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($result && $http_code == 200) {
$img->setAttribute("src", $test_src);
$found = true;
}
}
}
if ($found) {
$doc->removeChild($doc->firstChild); //remove doctype
$article["content"] = $doc->saveHTML();
}
}
return $article;
}
function api_version() {
return 2;
}
}
?>

View file

@ -0,0 +1,88 @@
<?php
class Af_Zz_ImgSetSizes extends Plugin {
private $host;
function about() {
return array(1.0,
"Set width/height attributes for images in articles (requires CURL and GD)",
"fox");
}
function init($host) {
$this->host = $host;
if (function_exists("curl_init") && function_exists("getimagesize")) {
$host->add_hook($host::HOOK_ARTICLE_FILTER, $this);
}
}
function hook_article_filter($article) {
$owner_uid = $article["owner_uid"];
$charset_hack = '<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>';
$doc = new DOMDocument();
$doc->loadHTML($charset_hack . $article["content"]);
$found = false;
if ($doc) {
$xpath = new DOMXpath($doc);
$images = $xpath->query('(//img[@src])');
foreach ($images as $img) {
$src = $img->getAttribute("src");
$ch = curl_init($src);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
curl_setopt($ch, CURLOPT_RANGE, "0-32768");
@$result = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($result && ($http_code == 200 || $http_code == 206)) {
$filename = tempnam(sys_get_temp_dir(), "ttsizecheck");
if ($filename) {
$fh = fopen($filename, "w");
if ($fh) {
fwrite($fh, $result);
fclose($fh);
@$info = getimagesize($filename);
if ($info && $info[0] > 0 && $info[1] > 0) {
$img->setAttribute("width", $info[0]);
$img->setAttribute("height", $info[1]);
$found = true;
}
unlink($filename);
}
}
}
}
if ($found) {
$doc->removeChild($doc->firstChild); //remove doctype
$article["content"] = $doc->saveHTML();
}
}
return $article;
}
function api_version() {
return 2;
}
}
?>

View file

@ -69,16 +69,6 @@ class Auth_Remote extends Plugin implements IAuthModule {
db_query("UPDATE ttrss_users SET email = '$email' WHERE id = " .
$user_id);
}
// update user password to allow api access
if (isset($_SERVER['PHP_AUTH_PW'])){
$currentpassword = $_SERVER['PHP_AUTH_PW'];
$new_salt = substr(bin2hex(get_random_bytes(125)), 0, 250);
$new_password_hash = encrypt_password($currentpassword, $new_salt, true);
db_query("UPDATE ttrss_users SET
pwd_hash = '$new_password_hash', salt = '$new_salt', otp_enabled = false
WHERE login = '$try_login'");
}
}
return $user_id;

View file

@ -0,0 +1,97 @@
<?php
class Auth_Remote extends Plugin implements IAuthModule {
private $host;
private $base;
function about() {
return array(1.0,
"Authenticates against remote password (e.g. supplied by Apache)",
"fox",
true);
}
function init($host) {
$this->host = $host;
$this->base = new Auth_Base();
$host->add_hook($host::HOOK_AUTH_USER, $this);
}
function get_login_by_ssl_certificate() {
$cert_serial = db_escape_string(get_ssl_certificate_id());
if ($cert_serial) {
$result = db_query("SELECT login FROM ttrss_user_prefs, ttrss_users
WHERE pref_name = 'SSL_CERT_SERIAL' AND value = '$cert_serial' AND
owner_uid = ttrss_users.id");
if (db_num_rows($result) != 0) {
return db_escape_string(db_fetch_result($result, 0, "login"));
}
}
return "";
}
function authenticate($login, $password) {
$try_login = db_escape_string($_SERVER["REMOTE_USER"]);
// php-cgi
if (!$try_login) $try_login = db_escape_string($_SERVER["REDIRECT_REMOTE_USER"]);
if (!$try_login) $try_login = $this->get_login_by_ssl_certificate();
# if (!$try_login) $try_login = "test_qqq";
if ($try_login) {
$user_id = $this->base->auto_create_user($try_login, $password);
if ($user_id) {
$_SESSION["fake_login"] = $try_login;
$_SESSION["fake_password"] = "******";
$_SESSION["hide_hello"] = true;
$_SESSION["hide_logout"] = true;
// LemonLDAP can send user informations via HTTP HEADER
if (defined('AUTH_AUTO_CREATE') && AUTH_AUTO_CREATE){
// update user name
$fullname = $_SERVER['HTTP_USER_NAME'] ? $_SERVER['HTTP_USER_NAME'] : $_SERVER['AUTHENTICATE_CN'];
if ($fullname){
$fullname = db_escape_string($fullname);
db_query("UPDATE ttrss_users SET full_name = '$fullname' WHERE id = " .
$user_id);
}
// update user mail
$email = $_SERVER['HTTP_USER_MAIL'] ? $_SERVER['HTTP_USER_MAIL'] : $_SERVER['AUTHENTICATE_MAIL'];
if ($email){
$email = db_escape_string($email);
db_query("UPDATE ttrss_users SET email = '$email' WHERE id = " .
$user_id);
}
// update user password to allow api access
if (isset($_SERVER['PHP_AUTH_PW'])){
$currentpassword = $_SERVER['PHP_AUTH_PW'];
$new_salt = substr(bin2hex(get_random_bytes(125)), 0, 250);
$new_password_hash = encrypt_password($currentpassword, $new_salt, true);
db_query("UPDATE ttrss_users SET
pwd_hash = '$new_password_hash', salt = '$new_salt', otp_enabled = false
WHERE login = '$try_login'");
}
}
return $user_id;
}
}
return false;
}
function api_version() {
return 2;
}
}
?>

View file

@ -4,7 +4,7 @@ class No_Iframes extends Plugin {
function about() {
return array(1.0,
"Remove embedded iframes",
"Remove embedded iframes (unless whitelisted)",
"fox");
}
@ -16,7 +16,13 @@ class No_Iframes extends Plugin {
function hook_sanitize($doc, $site_url, $allowed_elements, $disallowed_attributes) {
$allowed_elements = array_diff($allowed_elements, array("iframe"));
$xpath = new DOMXpath($doc);
$entries = $xpath->query('//iframe');
foreach ($entries as $entry) {
if (!iframe_whitelisted($entry))
$entry->parentNode->removeChild($entry);
}
return array($doc, $allowed_elements, $disallowed_attributes);
}

View file

@ -41,7 +41,7 @@
<?php if ($_SESSION["uid"]) {
$theme = get_pref( "USER_CSS_THEME", $_SESSION["uid"], false);
if ($theme && file_exists("themes/$theme")) {
if ($theme && theme_valid("$theme")) {
echo stylesheet_tag("themes/$theme");
} else {
echo stylesheet_tag("themes/default.css");
@ -94,7 +94,7 @@
<body id="ttrssPrefs" class="claro">
<div id="notify" class="notify" style="display : none"></div>
<div id="notify" class="notify"></div>
<div id="cmdline" style="display : none"></div>
<div id="overlay">

View file

@ -44,7 +44,6 @@ create table ttrss_users (id integer primary key not null auto_increment,
pwd_hash varchar(250) not null,
last_login datetime default null,
access_level integer not null default 0,
theme_id integer default null,
email varchar(250) not null default '',
full_name varchar(250) not null default '',
email_digest bool not null default false,
@ -53,7 +52,7 @@ create table ttrss_users (id integer primary key not null auto_increment,
created datetime default null,
twitter_oauth longtext default null,
otp_enabled boolean not null default false,
index (theme_id)) ENGINE=InnoDB DEFAULT CHARSET=UTF8;
resetpass_token varchar(250) default null) ENGINE=InnoDB DEFAULT CHARSET=UTF8;
insert into ttrss_users (login,pwd_hash,access_level) values ('admin',
'SHA1:5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8', 10);
@ -302,7 +301,7 @@ create table ttrss_tags (id integer primary key auto_increment,
create table ttrss_version (schema_version int not null) ENGINE=InnoDB DEFAULT CHARSET=UTF8;
insert into ttrss_version values (123);
insert into ttrss_version values (126);
create table ttrss_enclosures (id integer primary key auto_increment,
content_url text not null,
@ -310,6 +309,8 @@ create table ttrss_enclosures (id integer primary key auto_increment,
post_id integer not null,
title text not null,
duration text not null,
width integer not null default 0,
height integer not null default 0,
index (post_id),
foreign key (post_id) references ttrss_entries(id) ON DELETE cascade) ENGINE=InnoDB DEFAULT CHARSET=UTF8;

View file

@ -3,12 +3,17 @@
body#ttrssMain #feeds-holder {
background : #222;
border-color : #666;
border-left-width : 1px;
}
body#ttrssMain #headlines-frame {
border-color : #ddd;
}
body#ttrssMain div.whiteBox {
border-color : #666;
}
body#ttrssMain #content-insert {
background : #333;
}
@ -132,6 +137,7 @@ body#ttrssMain #feedTree img,
body#ttrssMain .postContent img {
filter: grayscale(1);
-webkit-filter: grayscale(1);
filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale"); // firefox lol
}
body#ttrssMain .hl img.hlScorePic {

359
source/update.php.ynh Executable file
View file

@ -0,0 +1,359 @@
#!/usr/bin/env php
<?php
set_include_path(dirname(__FILE__) ."/include" . PATH_SEPARATOR .
get_include_path());
define('DISABLE_SESSIONS', true);
chdir(dirname(__FILE__));
require_once "autoload.php";
require_once "functions.php";
require_once "rssfuncs.php";
require_once "config.php";
require_once "sanity_check.php";
require_once "db.php";
require_once "db-prefs.php";
if (!defined('PHP_EXECUTABLE'))
define('PHP_EXECUTABLE', '/usr/bin/php');
init_plugins();
$longopts = array("feeds",
"feedbrowser",
"daemon",
"daemon-loop",
"task:",
"cleanup-tags",
"quiet",
"log:",
"indexes",
"pidlock:",
"update-schema",
"convert-filters",
"force-update",
"list-plugins",
"help");
foreach (PluginHost::getInstance()->get_commands() as $command => $data) {
array_push($longopts, $command . $data["suffix"]);
}
$options = getopt("", $longopts);
if (!is_array($options)) {
die("error: getopt() failed. ".
"Most probably you are using PHP CGI to run this script ".
"instead of required PHP CLI. Check tt-rss wiki page on updating feeds for ".
"additional information.\n");
}
if (count($options) == 0 && !defined('STDIN')) {
?> <html>
<head>
<title>Tiny Tiny RSS data update script.</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="css/utility.css">
</head>
<body>
<div class="floatingLogo"><img src="images/logo_small.png"></div>
<h1><?php echo __("Tiny Tiny RSS data update script.") ?></h1>
<?php print_error("Please run this script from the command line. Use option \"-help\" to display command help if this error is displayed erroneously."); ?>
</body></html>
<?php
exit;
}
if (count($options) == 0 || isset($options["help"]) ) {
print "Tiny Tiny RSS data update script.\n\n";
print "Options:\n";
print " --feeds - update feeds\n";
print " --feedbrowser - update feedbrowser\n";
print " --daemon - start single-process update daemon\n";
print " --task N - create lockfile using this task id\n";
print " --cleanup-tags - perform tags table maintenance\n";
print " --quiet - don't output messages to stdout\n";
print " --log FILE - log messages to FILE\n";
print " --indexes - recreate missing schema indexes\n";
print " --update-schema - update database schema\n";
print " --convert-filters - convert type1 filters to type2\n";
print " --force-update - force update of all feeds\n";
print " --list-plugins - list all available plugins\n";
print " --help - show this help\n";
print "Plugin options:\n";
foreach (PluginHost::getInstance()->get_commands() as $command => $data) {
$args = $data['arghelp'];
printf(" --%-19s - %s\n", "$command $args", $data["description"]);
}
return;
}
if (!isset($options['daemon'])) {
require_once "errorhandler.php";
}
if (!isset($options['update-schema'])) {
$schema_version = get_schema_version();
if ($schema_version != SCHEMA_VERSION) {
die("Schema version is wrong, please upgrade the database.\n");
}
}
define('QUIET', isset($options['quiet']));
if (isset($options["log"])) {
_debug("Logging to " . $options["log"]);
define('LOGFILE', $options["log"]);
}
if (!isset($options["daemon"])) {
$lock_filename = "update.lock";
} else {
$lock_filename = "update_daemon.lock";
}
if (isset($options["task"])) {
_debug("Using task id " . $options["task"]);
$lock_filename = $lock_filename . "-task_" . $options["task"];
}
if (isset($options["pidlock"])) {
$my_pid = $options["pidlock"];
$lock_filename = "update_daemon-$my_pid.lock";
}
_debug("Lock: $lock_filename");
$lock_handle = make_lockfile($lock_filename);
$must_exit = false;
if (isset($options["task"]) && isset($options["pidlock"])) {
$waits = $options["task"] * 5;
_debug("Waiting before update ($waits)");
sleep($waits);
}
// Try to lock a file in order to avoid concurrent update.
if (!$lock_handle) {
die("error: Can't create lockfile ($lock_filename). ".
"Maybe another update process is already running.\n");
}
if (isset($options["force-update"])) {
_debug("marking all feeds as needing update...");
db_query( "UPDATE ttrss_feeds SET last_update_started = '1970-01-01',
last_updated = '1970-01-01'");
}
if (isset($options["feeds"])) {
update_daemon_common();
housekeeping_common(true);
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", $op);
}
if (isset($options["feedbrowser"])) {
$count = update_feedbrowser_cache();
print "Finished, $count feeds processed.\n";
}
if (isset($options["daemon"])) {
while (true) {
$quiet = (isset($options["quiet"])) ? "--quiet" : "";
$log = isset($options['log']) ? '--log '.$options['log'] : '';
passthru(PHP_EXECUTABLE . " " . $argv[0] ." --daemon-loop $quiet $log");
_debug("Sleeping for " . DAEMON_SLEEP_INTERVAL . " seconds...");
sleep(DAEMON_SLEEP_INTERVAL);
}
}
if (isset($options["daemon-loop"])) {
if (!make_stampfile('update_daemon.stamp')) {
_debug("warning: unable to create stampfile\n");
}
update_daemon_common(isset($options["pidlock"]) ? 50 : DAEMON_FEED_LIMIT);
if (!isset($options["pidlock"]) || $options["task"] == 0)
housekeeping_common(true);
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", $op);
}
if (isset($options["cleanup-tags"])) {
$rc = cleanup_tags( 14, 50000);
_debug("$rc tags deleted.\n");
}
if (isset($options["indexes"])) {
_debug("PLEASE BACKUP YOUR DATABASE BEFORE PROCEEDING!");
_debug("Type 'yes' to continue.");
if (read_stdin() != 'yes')
exit;
_debug("clearing existing indexes...");
if (DB_TYPE == "pgsql") {
$result = db_query( "SELECT relname FROM
pg_catalog.pg_class WHERE relname LIKE 'ttrss_%'
AND relname NOT LIKE '%_pkey'
AND relkind = 'i'");
} else {
$result = db_query( "SELECT index_name,table_name FROM
information_schema.statistics WHERE index_name LIKE 'ttrss_%'");
}
while ($line = db_fetch_assoc($result)) {
if (DB_TYPE == "pgsql") {
$statement = "DROP INDEX " . $line["relname"];
_debug($statement);
} else {
$statement = "ALTER TABLE ".
$line['table_name']." DROP INDEX ".$line['index_name'];
_debug($statement);
}
db_query( $statement, false);
}
_debug("reading indexes from schema for: " . DB_TYPE);
$fp = fopen("schema/ttrss_schema_" . DB_TYPE . ".sql", "r");
if ($fp) {
while ($line = fgets($fp)) {
$matches = array();
if (preg_match("/^create index ([^ ]+) on ([^ ]+)$/i", $line, $matches)) {
$index = $matches[1];
$table = $matches[2];
$statement = "CREATE INDEX $index ON $table";
_debug($statement);
db_query( $statement);
}
}
fclose($fp);
} else {
_debug("unable to open schema file.");
}
_debug("all done.");
}
if (isset($options["convert-filters"])) {
_debug("WARNING: this will remove all existing type2 filters.");
_debug("Type 'yes' to continue.");
if (read_stdin() != 'yes')
exit;
_debug("converting filters...");
db_query( "DELETE FROM ttrss_filters2");
$result = db_query( "SELECT * FROM ttrss_filters ORDER BY id");
while ($line = db_fetch_assoc($result)) {
$owner_uid = $line["owner_uid"];
// date filters are removed
if ($line["filter_type"] != 5) {
$filter = array();
if (sql_bool_to_bool($line["cat_filter"])) {
$feed_id = "CAT:" . (int)$line["cat_id"];
} else {
$feed_id = (int)$line["feed_id"];
}
$filter["enabled"] = $line["enabled"] ? "on" : "off";
$filter["rule"] = array(
json_encode(array(
"reg_exp" => $line["reg_exp"],
"feed_id" => $feed_id,
"filter_type" => $line["filter_type"])));
$filter["action"] = array(
json_encode(array(
"action_id" => $line["action_id"],
"action_param_label" => $line["action_param"],
"action_param" => $line["action_param"])));
// Oh god it's full of hacks
$_REQUEST = $filter;
$_SESSION["uid"] = $owner_uid;
$filters = new Pref_Filters($_REQUEST);
$filters->add();
}
}
}
if (isset($options["update-schema"])) {
_debug("checking for updates (" . DB_TYPE . ")...");
$updater = new DbUpdater(Db::get(), DB_TYPE, SCHEMA_VERSION);
if ($updater->isUpdateRequired()) {
_debug("schema update required, version " . $updater->getSchemaVersion() . " to " . SCHEMA_VERSION);
_debug("WARNING: please backup your database before continuing.");
_debug("Type 'yes' to continue.");
//if (read_stdin() != 'yes')
// exit;
for ($i = $updater->getSchemaVersion() + 1; $i <= SCHEMA_VERSION; $i++) {
_debug("performing update up to version $i...");
$result = $updater->performUpdateTo($i);
_debug($result ? "OK!" : "FAILED!");
if (!$result) return;
}
} else {
_debug("update not required.");
}
}
if (isset($options["list-plugins"])) {
$tmppluginhost = new PluginHost();
$tmppluginhost->load_all($tmppluginhost::KIND_ALL);
$enabled = array_map("trim", explode(",", PLUGINS));
echo "List of all available plugins:\n";
foreach ($tmppluginhost->get_plugins() as $name => $plugin) {
$about = $plugin->about();
$status = $about[3] ? "system" : "user";
if (in_array($name, $enabled)) $name .= "*";
printf("%-50s %-10s v%.2f (by %s)\n%s\n\n",
$name, $status, $about[0], $about[2], $about[1]);
}
echo "Plugins marked by * are currently enabled for all users.\n";
}
PluginHost::getInstance()->run_commands($options);
if (file_exists(LOCK_DIRECTORY . "/$lock_filename"))
unlink(LOCK_DIRECTORY . "/$lock_filename");
?>