diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/af_comics/filter_base.php | 18 | ||||
-rwxr-xr-x | plugins/af_comics/filters/af_comics_comicpress.php | 2 | ||||
-rw-r--r-- | plugins/af_comics/filters/af_comics_dilbert.php | 2 | ||||
-rw-r--r-- | plugins/af_comics/filters/af_comics_gocomics.php | 1 | ||||
-rw-r--r-- | plugins/af_comics/filters/af_comics_gocomics_farside.php | 16 | ||||
-rw-r--r-- | plugins/af_comics/filters/af_comics_tfd.php | 2 | ||||
-rwxr-xr-x | plugins/af_comics/init.php | 1 | ||||
-rw-r--r-- | plugins/af_psql_trgm/init.php | 41 | ||||
-rwxr-xr-x | plugins/af_readability/init.php | 45 | ||||
-rwxr-xr-x | plugins/af_redditimgur/init.php | 80 | ||||
-rw-r--r-- | plugins/af_youtube_embed/init.php | 4 | ||||
-rw-r--r-- | plugins/auth_internal/init.php | 98 | ||||
-rw-r--r-- | plugins/auth_remote/init.php | 4 | ||||
-rwxr-xr-x | plugins/auto_assign_labels/init.php | 7 | ||||
-rw-r--r-- | plugins/bookmarklets/init.php | 7 | ||||
-rwxr-xr-x | plugins/cache_starred_images/init.php | 33 | ||||
-rw-r--r-- | plugins/no_iframes/init.php | 2 | ||||
-rw-r--r-- | plugins/note/init.php | 4 | ||||
-rw-r--r-- | plugins/nsfw/init.php | 11 | ||||
-rw-r--r-- | plugins/share/init.php | 24 |
20 files changed, 263 insertions, 139 deletions
diff --git a/plugins/af_comics/filter_base.php b/plugins/af_comics/filter_base.php index 5c82bc870..83bc48184 100644 --- a/plugins/af_comics/filter_base.php +++ b/plugins/af_comics/filter_base.php @@ -1,20 +1,38 @@ <?php abstract class Af_ComicFilter { + /** @return array<string> */ public abstract function supported(); + + /** + * @param array<string,mixed> $article + * @return bool + */ public abstract function process(&$article); public function __construct(/*PluginHost $host*/) { } + /** + * @param string $url + * @return string|false + */ public function on_subscribe($url) { return false; } + /** + * @param string $url + * @return array{"title": string, "site_url": string}|false + */ public function on_basic_info($url) { return false; } + /** + * @param string $url + * @return string|false + */ public function on_fetch($url) { return false; } diff --git a/plugins/af_comics/filters/af_comics_comicpress.php b/plugins/af_comics/filters/af_comics_comicpress.php index 741d59672..89837d074 100755 --- a/plugins/af_comics/filters/af_comics_comicpress.php +++ b/plugins/af_comics/filters/af_comics_comicpress.php @@ -32,7 +32,7 @@ class Af_Comics_ComicPress extends Af_ComicFilter { return true; } - // buni-specific + /** @var DOMElement|null $webtoon_link (buni specific) */ $webtoon_link = $xpath->query("//a[contains(@href,'www.webtoons.com')]")->item(0); if ($webtoon_link) { diff --git a/plugins/af_comics/filters/af_comics_dilbert.php b/plugins/af_comics/filters/af_comics_dilbert.php index 49fa54cfa..a1c59b94c 100644 --- a/plugins/af_comics/filters/af_comics_dilbert.php +++ b/plugins/af_comics/filters/af_comics_dilbert.php @@ -22,7 +22,7 @@ class Af_Comics_Dilbert extends Af_ComicFilter { if ($res && $doc->loadHTML($res)) { $xpath = new DOMXPath($doc); - // Get the image container + /** @var DOMElement|null $basenode (image container) */ $basenode = $xpath->query('(//div[@class="img-comic-container"]/a[@class="img-comic-link"])')->item(0); // Get the comic title diff --git a/plugins/af_comics/filters/af_comics_gocomics.php b/plugins/af_comics/filters/af_comics_gocomics.php index 71d387918..732f7d0b8 100644 --- a/plugins/af_comics/filters/af_comics_gocomics.php +++ b/plugins/af_comics/filters/af_comics_gocomics.php @@ -50,6 +50,7 @@ class Af_Comics_Gocomics extends Af_ComicFilter { if (@$doc->loadHTML($body)) { $xpath = new DOMXPath($doc); + /** @var DOMElement|null $node */ $node = $xpath->query('//picture[contains(@class, "item-comic-image")]/img')->item(0); if ($node) { diff --git a/plugins/af_comics/filters/af_comics_gocomics_farside.php b/plugins/af_comics/filters/af_comics_gocomics_farside.php index 0399015ab..e4e230516 100644 --- a/plugins/af_comics/filters/af_comics_gocomics_farside.php +++ b/plugins/af_comics/filters/af_comics_gocomics_farside.php @@ -50,8 +50,22 @@ class Af_Comics_Gocomics_FarSide extends Af_ComicFilter { if ($content_node) { $imgs = $xpath->query('//img[@data-src]', $content_node); + $cache = new DiskCache("images"); + foreach ($imgs as $img) { - $img->setAttribute('src', $img->getAttribute('data-src')); + $image_url = $img->getAttribute('data-src'); + $local_filename = sha1($image_url); + + if ($image_url) { + $img->setAttribute('src', $image_url); + + // try to cache image locally because they just 401 us otherwise + if (!$cache->exists($local_filename)) { + Debug::log("[Af_Comics_Gocomics_FarSide] caching: $image_url", Debug::LOG_VERBOSE); + $res = $cache->download($image_url, sha1($image_url), ["http_referrer" => $image_url]); + Debug::log("[Af_Comics_Gocomics_FarSide] cache result: $res", Debug::LOG_VERBOSE); + } + } } $junk_elems = $xpath->query("//*[@data-shareable-popover]"); diff --git a/plugins/af_comics/filters/af_comics_tfd.php b/plugins/af_comics/filters/af_comics_tfd.php index 19ca43a24..2010da37e 100644 --- a/plugins/af_comics/filters/af_comics_tfd.php +++ b/plugins/af_comics/filters/af_comics_tfd.php @@ -12,7 +12,7 @@ class Af_Comics_Tfd extends Af_ComicFilter { false, false, 0, "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"); - if (!$res) return $article; + if (!$res) return false; $doc = new DOMDocument(); diff --git a/plugins/af_comics/init.php b/plugins/af_comics/init.php index 84d95a2ba..a9a8f3faa 100755 --- a/plugins/af_comics/init.php +++ b/plugins/af_comics/init.php @@ -1,6 +1,7 @@ <?php class Af_Comics extends Plugin { + /** @var array<object> $filters */ private $filters = array(); function about() { diff --git a/plugins/af_psql_trgm/init.php b/plugins/af_psql_trgm/init.php index 87415450b..89b66e20b 100644 --- a/plugins/af_psql_trgm/init.php +++ b/plugins/af_psql_trgm/init.php @@ -1,9 +1,13 @@ <?php class Af_Psql_Trgm extends Plugin { - /* @var PluginHost $host */ + /** @var PluginHost $host */ private $host; + + /** @var float */ private $default_similarity = 0.75; + + /** @var int */ private $default_min_length = 32; function about() { @@ -12,6 +16,7 @@ class Af_Psql_Trgm extends Plugin { "fox"); } + /** @return void */ function save() { $similarity = (float) $_POST["similarity"]; $min_title_length = (int) $_POST["min_title_length"]; @@ -45,6 +50,7 @@ class Af_Psql_Trgm extends Plugin { return file_get_contents(__DIR__ . "/init.js"); } + /** @return void */ function showrelated() { $id = (int) $_REQUEST['id']; $owner_uid = $_SESSION["uid"]; @@ -196,7 +202,7 @@ class Af_Psql_Trgm extends Plugin { <?php /* cleanup */ $enabled_feeds = $this->filter_unknown_feeds( - $this->get_stored_array("enabled_feeds")); + $this->host->get_array($this, "enabled_feeds")); $this->host->set($this, "enabled_feeds", $enabled_feeds); ?> @@ -221,7 +227,7 @@ class Af_Psql_Trgm extends Plugin { } function hook_prefs_edit_feed($feed_id) { - $enabled_feeds = $this->get_stored_array("enabled_feeds"); + $enabled_feeds = $this->host->get_array($this, "enabled_feeds"); ?> <header><?= __("Similarity (af_psql_trgm)") ?></header> @@ -238,7 +244,7 @@ class Af_Psql_Trgm extends Plugin { } function hook_prefs_save_feed($feed_id) { - $enabled_feeds = $this->get_stored_array("enabled_feeds"); + $enabled_feeds = $this->host->get_array($this, "enabled_feeds"); $enable = checkbox_to_sql_bool($_POST["trgm_similarity_enabled"] ?? ""); $key = array_search($feed_id, $enabled_feeds); @@ -267,7 +273,7 @@ class Af_Psql_Trgm extends Plugin { if (!$enable_globally && !in_array($article["feed"]["id"], - $this->get_stored_array("enabled_feeds"))) { + $this->host->get_array($this,"enabled_feeds"))) { return $article; } @@ -275,14 +281,14 @@ class Af_Psql_Trgm extends Plugin { $similarity = (float) $this->host->get($this, "similarity", $this->default_similarity); if ($similarity < 0.01) { - Debug::log("af_psql_trgm: similarity is set too low ($similarity)", Debug::$LOG_EXTENDED); + Debug::log("af_psql_trgm: similarity is set too low ($similarity)", Debug::LOG_EXTENDED); return $article; } $min_title_length = (int) $this->host->get($this, "min_title_length", $this->default_min_length); if (mb_strlen($article["title"]) < $min_title_length) { - Debug::log("af_psql_trgm: article title is too short (min: $min_title_length)", Debug::$LOG_EXTENDED); + Debug::log("af_psql_trgm: article title is too short (min: $min_title_length)", Debug::LOG_EXTENDED); return $article; } @@ -321,10 +327,10 @@ class Af_Psql_Trgm extends Plugin { $row = $sth->fetch(); $similarity_result = $row['ms']; - Debug::log("af_psql_trgm: similarity result for $title_escaped: $similarity_result", Debug::$LOG_EXTENDED); + Debug::log("af_psql_trgm: similarity result for $title_escaped: $similarity_result", Debug::LOG_EXTENDED); if ($similarity_result >= $similarity) { - Debug::log("af_psql_trgm: marking article as read ($similarity_result >= $similarity)", Debug::$LOG_EXTENDED); + Debug::log("af_psql_trgm: marking article as read ($similarity_result >= $similarity)", Debug::LOG_EXTENDED); $article["force_catchup"] = true; } @@ -336,7 +342,12 @@ class Af_Psql_Trgm extends Plugin { return 2; } - private function filter_unknown_feeds($enabled_feeds) { + /** + * @param array<int> $enabled_feeds + * @return array<int> + * @throws PDOException + */ + private function filter_unknown_feeds($enabled_feeds) : array { $tmp = array(); foreach ($enabled_feeds as $feed) { @@ -351,14 +362,4 @@ class Af_Psql_Trgm extends Plugin { return $tmp; } - - private function get_stored_array($name) { - $tmp = $this->host->get($this, $name); - - if (!is_array($tmp)) $tmp = []; - - return $tmp; - } - - } diff --git a/plugins/af_readability/init.php b/plugins/af_readability/init.php index a39cc278e..a13f2a5b2 100755 --- a/plugins/af_readability/init.php +++ b/plugins/af_readability/init.php @@ -6,7 +6,7 @@ use \andreskrey\Readability\Configuration; class Af_Readability extends Plugin { - /* @var PluginHost $host */ + /** @var PluginHost $host */ private $host; function about() { @@ -19,6 +19,7 @@ class Af_Readability extends Plugin { return array("needs_curl" => true); } + /** @return void */ function save() { $enable_share_anything = checkbox_to_sql_bool($_POST["enable_share_anything"] ?? ""); @@ -186,9 +187,14 @@ class Af_Readability extends Plugin { case "action_append": return $this->process_article($article, true); } + return $article; } - public function extract_content($url) { + /** + * @param string $url + * @return string|false + */ + public function extract_content(string $url) { $tmp = UrlHelper::fetch([ "url" => $url, @@ -222,13 +228,13 @@ class Af_Readability extends Plugin { foreach ($entries as $entry) { if ($entry->hasAttribute("href")) { $entry->setAttribute("href", - rewrite_relative_url(UrlHelper::$fetch_effective_url, $entry->getAttribute("href"))); + UrlHelper::rewrite_relative(UrlHelper::$fetch_effective_url, $entry->getAttribute("href"))); } if ($entry->hasAttribute("src")) { $entry->setAttribute("src", - rewrite_relative_url(UrlHelper::$fetch_effective_url, $entry->getAttribute("src"))); + UrlHelper::rewrite_relative(UrlHelper::$fetch_effective_url, $entry->getAttribute("src"))); } } @@ -244,7 +250,13 @@ class Af_Readability extends Plugin { return false; } - function process_article($article, $append_mode) { + /** + * @param array<string, mixed> $article + * @param bool $append_mode + * @return array<string,mixed> + * @throws PDOException + */ + function process_article(array $article, bool $append_mode) : array { $extracted_content = $this->extract_content($article["link"]); @@ -261,12 +273,14 @@ class Af_Readability extends Plugin { return $article; } - private function get_stored_array($name) { - $tmp = $this->host->get($this, $name); - - if (!is_array($tmp)) $tmp = []; - - return $tmp; + /** + * @param string $name + * @return array<int|string, mixed> + * @throws PDOException + * @deprecated + */ + private function get_stored_array(string $name) : array { + return $this->host->get_array($this, $name); } function hook_article_filter($article) { @@ -304,7 +318,12 @@ class Af_Readability extends Plugin { return 2; } - private function filter_unknown_feeds($enabled_feeds) { + /** + * @param array<int> $enabled_feeds + * @return array<int> + * @throws PDOException + */ + private function filter_unknown_feeds(array $enabled_feeds) : array { $tmp = array(); foreach ($enabled_feeds as $feed) { @@ -320,7 +339,7 @@ class Af_Readability extends Plugin { return $tmp; } - function embed() { + function embed() : void { $article_id = (int) $_REQUEST["id"]; $sth = $this->pdo->prepare("SELECT link FROM ttrss_entries WHERE id = ?"); diff --git a/plugins/af_redditimgur/init.php b/plugins/af_redditimgur/init.php index bd4032050..f40d21d35 100755 --- a/plugins/af_redditimgur/init.php +++ b/plugins/af_redditimgur/init.php @@ -3,10 +3,20 @@ class Af_RedditImgur extends Plugin { /** @var PluginHost $host */ private $host; + + /** @var array<string> */ private $domain_blacklist = [ "github.com" ]; + + /** @var bool */ private $dump_json_data = false; + + /** @var array<string> */ private $fallback_preview_urls = []; + + /** @var int */ private $default_max_score = 100; + + /** @var array<int, array<int, string|null>> */ private $generated_enclosures = []; function about() { @@ -118,7 +128,7 @@ class Af_RedditImgur extends Plugin { <?php } - function save() { + function save() : void { $enable_readability = checkbox_to_sql_bool($_POST["enable_readability"] ?? ""); $enable_content_dupcheck = checkbox_to_sql_bool($_POST["enable_content_dupcheck"] ?? ""); $reddit_to_teddit = checkbox_to_sql_bool($_POST["reddit_to_teddit"] ?? ""); @@ -138,7 +148,14 @@ class Af_RedditImgur extends Plugin { echo __("Configuration saved"); } - private function process_post_media($data, $doc, $xpath, $anchor) { + /** + * @param array<string,mixed> $data (this is a huge blob of random crap returned by reddit API) + * @param DOMDocument $doc + * @param DOMXPath $xpath + * @param DOMElement $anchor + * @return bool + */ + private function process_post_media(array $data, DOMDocument $doc, DOMXPath $xpath, DOMElement $anchor) : bool { $found = 0; if (isset($data["media_metadata"])) { @@ -242,14 +259,21 @@ class Af_RedditImgur extends Plugin { } } - return $found; + return $found > 0; } /* function score_convert(int $value, int $from1, int $from2, int $to1, int $to2) { return ($value - $from1) / ($from2 - $from1) * ($to2 - $to1) + $to1; } */ - private function inline_stuff(&$article, &$doc, $xpath) { + /** + * @param array<string, mixed> $article + * @param DOMDocument $doc + * @param DOMXPath $xpath + * @return bool + * @throws PDOException + */ + private function inline_stuff(array &$article, DOMDocument &$doc, DOMXpath $xpath) : bool { $max_score = (int) $this->host->get($this, "max_score", $this->default_max_score); $import_score = (bool) $this->host->get($this, "import_score", $this->default_max_score); @@ -263,7 +287,7 @@ class Af_RedditImgur extends Plugin { $this->generated_enclosures = []; - // embed anchor element, before reddit <table> post layout + /** @var DOMElement|null $anchor -- embed anchor element, before reddit <table> post layout */ $anchor = $xpath->query('//body/*')->item(0); // deal with json-provided media content first @@ -583,7 +607,7 @@ class Af_RedditImgur extends Plugin { if ($found) $this->remove_post_thumbnail($doc, $xpath); - return $found; + return $found > 0; } function hook_article_filter($article) { @@ -651,14 +675,14 @@ class Af_RedditImgur extends Plugin { return 2; } - private function remove_post_thumbnail($doc, $xpath) { + private function remove_post_thumbnail(DOMDocument $doc, DOMXpath $xpath) : void { $thumb = $xpath->query("//td/a/img[@src]")->item(0); if ($thumb) $thumb->parentNode->parentNode->removeChild($thumb->parentNode); } - private function handle_as_image($doc, $entry, $image_url, $link_url = false) { + private function handle_as_image(DOMDocument $doc, DOMElement $entry, string $image_url, string $link_url = "") : void { $img = $doc->createElement("img"); $img->setAttribute("src", $image_url); @@ -677,7 +701,7 @@ class Af_RedditImgur extends Plugin { $entry->parentNode->insertBefore($p, $entry); } - private function handle_as_video($doc, $entry, $source_stream, $poster_url = false) { + private function handle_as_video(DOMDocument $doc, DOMElement $entry, string $source_stream, string $poster_url = "") : void { Debug::log("handle_as_video: $source_stream", Debug::LOG_VERBOSE); @@ -709,7 +733,7 @@ class Af_RedditImgur extends Plugin { return $method === "testurl"; } - function testurl() { + function testurl() : void { $url = clean($_POST["url"] ?? ""); $article_url = clean($_POST["article_url"] ?? ""); @@ -804,8 +828,8 @@ class Af_RedditImgur extends Plugin { } /** $useragent defaults to Config::get_user_agent() */ - private function get_header($url, $header, $useragent = false) { - $ret = false; + private function get_header(string $url, int $header, string $useragent = "") : string { + $ret = ""; if (function_exists("curl_init")) { $ch = curl_init($url); @@ -823,16 +847,24 @@ class Af_RedditImgur extends Plugin { return $ret; } - private function get_content_type($url, $useragent = false) { + private function get_content_type(string $url, string $useragent = "") : string { return $this->get_header($url, CURLINFO_CONTENT_TYPE, $useragent); } - // @phpstan-ignore-next-line - private function get_location($url, $useragent = false) { + /*private function get_location(string $url, string $useragent = "") : string { return $this->get_header($url, CURLINFO_EFFECTIVE_URL, $useragent); - } - - private function readability($article, $url, $doc, $xpath, $debug = false) { + }*/ + + /** + * @param array<string,mixed> $article + * @param string $url + * @param DOMDocument $doc + * @param DOMXPath $xpath + * @param bool $debug + * @return array<string,mixed> + * @throws PDOException + */ + private function readability(array $article, string $url, DOMDocument $doc, DOMXpath $xpath, bool $debug = false) : array { if (function_exists("curl_init") && $this->host->get($this, "enable_readability") && mb_strlen(strip_tags($article["content"])) <= 150) { @@ -864,7 +896,12 @@ class Af_RedditImgur extends Plugin { return $article; } - private function is_blacklisted($src, $also_blacklist = []) { + /** + * @param string $src + * @param array<string> $also_blacklist + * @return bool + */ + private function is_blacklisted(string $src, array $also_blacklist = []) : bool { $src_domain = parse_url($src, PHP_URL_HOST); foreach (array_merge($this->domain_blacklist, $also_blacklist) as $domain) { @@ -880,7 +917,7 @@ class Af_RedditImgur extends Plugin { return $this->hook_render_article_cdm($article); } - private function rewrite_to_teddit($str) { + private function rewrite_to_teddit(string $str) : string { if (strpos($str, "reddit.com") !== false) { return preg_replace("/https?:\/\/([a-z]+\.)?reddit\.com/", "https://teddit.net", $str); } @@ -888,7 +925,7 @@ class Af_RedditImgur extends Plugin { return $str; } - private function rewrite_to_reddit($str) { + private function rewrite_to_reddit(string $str) : string { if (strpos($str, "teddit.net") !== false) { $str = preg_replace("/https?:\/\/teddit.net/", "https://reddit.com", $str); @@ -899,7 +936,6 @@ class Af_RedditImgur extends Plugin { return $str; } - function hook_render_article_cdm($article) { if ($this->host->get($this, "reddit_to_teddit")) { $need_saving = false; diff --git a/plugins/af_youtube_embed/init.php b/plugins/af_youtube_embed/init.php index 771ee8c46..ff44bb291 100644 --- a/plugins/af_youtube_embed/init.php +++ b/plugins/af_youtube_embed/init.php @@ -18,7 +18,7 @@ class Af_Youtube_Embed extends Plugin { "youtu.be"]); } - function hook_render_enclosure($entry, $hide_images) { + function hook_render_enclosure($entry, $id, $rv) { $url = $entry["content_url"]; @@ -32,6 +32,8 @@ class Af_Youtube_Embed extends Plugin { </div>"; } + + return ""; } function api_version() { diff --git a/plugins/auth_internal/init.php b/plugins/auth_internal/init.php index 77f7596f0..688a0f5d8 100644 --- a/plugins/auth_internal/init.php +++ b/plugins/auth_internal/init.php @@ -12,6 +12,7 @@ class Auth_Internal extends Auth_Base { $host->add_hook($host::HOOK_AUTH_USER, $this); } + /** @param string $service */ function authenticate($login, $password, $service = '') { $otp = (int) ($_REQUEST["otp"] ?? 0); @@ -29,22 +30,6 @@ class Auth_Internal extends Auth_Base { } if ($otp) { - - /*$base32 = new \OTPHP\Base32(); - - $secret = $base32->encode(mb_substr(sha1($row["salt"]), 0, 12), false); - $secret_legacy = $base32->encode(sha1($row["salt"])); - - $totp = new \OTPHP\TOTP($secret); - $otp_check = $totp->now(); - - $totp_legacy = new \OTPHP\TOTP($secret_legacy); - $otp_check_legacy = $totp_legacy->now(); - - if ($otp !== $otp_check && $otp !== $otp_check_legacy) { - return false; - } */ - if ($this->check_password($user_id, $password) && UserHelper::check_otp($user_id, $otp)) return $user_id; else @@ -129,48 +114,61 @@ class Auth_Internal extends Auth_Base { } if ($login) { - $try_user_id = $this->find_user_by_login($login); - - if ($try_user_id) { - return $this->check_password($try_user_id, $password); - } - } - - return false; - } - - function check_password(int $owner_uid, string $password, string $service = '') { + $user = ORM::for_table('ttrss_users') + ->where('login', $login) + ->find_one(); - $user = ORM::for_table('ttrss_users')->find_one($owner_uid); + if ($user) { + if (get_schema_version() >= 145) { + if ($user->last_auth_attempt) { + $last_auth_attempt = strtotime($user->last_auth_attempt); - if ($user) { + if ($last_auth_attempt && time() - $last_auth_attempt < Config::get(Config::AUTH_MIN_INTERVAL)) { + Logger::log(E_USER_NOTICE, "Too many authentication attempts for {$user->login}, throttled."); - // don't throttle app passwords - if (!$service && get_schema_version() >= 145) { + // start an empty session to deliver login error message + if (session_status() != PHP_SESSION_ACTIVE) + session_start(); - if ($user->last_auth_attempt) { - $last_auth_attempt = strtotime($user->last_auth_attempt); + $_SESSION["login_error_msg"] = __("Too many authentication attempts, throttled."); - if ($last_auth_attempt && time() - $last_auth_attempt < Config::get(Config::AUTH_MIN_INTERVAL)) { - Logger::log(E_USER_NOTICE, "Too many authentication attempts for {$user->login}, throttled."); + $user->last_auth_attempt = Db::NOW(); + $user->save(); - // start an empty session to deliver login error message - if (session_status() != PHP_SESSION_ACTIVE) - session_start(); + return false; + } + } + } - $_SESSION["login_error_msg"] = __("Too many authentication attempts, throttled."); + $auth_result = $this->check_password($user->id, $password); + if ($auth_result) { + return $auth_result; + } else { + if (get_schema_version() >= 145) { $user->last_auth_attempt = Db::NOW(); $user->save(); - - return false; } } - - $user->last_auth_attempt = Db::NOW(); - $user->save(); } + } + return false; + } + + /** + * @param int $owner_uid + * @param string $password + * @param string $service + * @return int|false (false if failed, user id otherwise) + * @throws PDOException + * @throws Exception + */ + function check_password(int $owner_uid, string $password, string $service = '') { + + $user = ORM::for_table('ttrss_users')->find_one($owner_uid); + + if ($user) { $salt = $user['salt'] ?? ""; $login = $user['login']; $pwd_hash = $user['pwd_hash']; @@ -202,7 +200,7 @@ class Auth_Internal extends Auth_Base { return false; } - function change_password($owner_uid, $old_password, $new_password) { + function change_password(int $owner_uid, string $old_password, string $new_password) : string { if ($this->check_password($owner_uid, $old_password)) { @@ -245,7 +243,15 @@ class Auth_Internal extends Auth_Base { } } - private function check_app_password($login, $password, $service) { + /** + * @param string $login + * @param string $password + * @param string $service + * @return false|int (false if failed, user id otherwise) + * @throws PDOException + * @throws Exception + */ + private function check_app_password(string $login, string $password, string $service) { $sth = $this->pdo->prepare("SELECT p.id, p.pwd_hash, u.id AS uid FROM ttrss_app_passwords p, ttrss_users u WHERE p.owner_uid = u.id AND LOWER(u.login) = LOWER(?) AND service = ?"); diff --git a/plugins/auth_remote/init.php b/plugins/auth_remote/init.php index b240a9402..9c15d3368 100644 --- a/plugins/auth_remote/init.php +++ b/plugins/auth_remote/init.php @@ -12,7 +12,7 @@ class Auth_Remote extends Auth_Base { $host->add_hook($host::HOOK_AUTH_USER, $this); } - function get_login_by_ssl_certificate() { + function get_login_by_ssl_certificate() : string { $cert_serial = Pref_Prefs::_get_ssl_certificate_id(); if ($cert_serial) { @@ -29,7 +29,7 @@ class Auth_Remote extends Auth_Base { return ""; } - function authenticate($login, $password) { + function authenticate($login, $password, $service = '') { $try_login = ""; foreach (["REMOTE_USER", "HTTP_REMOTE_USER", "REDIRECT_REMOTE_USER", "PHP_AUTH_USER"] as $hdr) { diff --git a/plugins/auto_assign_labels/init.php b/plugins/auto_assign_labels/init.php index 84fce8d64..b2e5718ea 100755 --- a/plugins/auto_assign_labels/init.php +++ b/plugins/auto_assign_labels/init.php @@ -11,7 +11,12 @@ class Auto_Assign_Labels extends Plugin { $host->add_hook($host::HOOK_ARTICLE_FILTER, $this); } - function get_all_labels_filter_format($owner_uid) { + /** + * @param int $owner_uid + * @return array<int, array<int, int|string>> + * @throws PDOException + */ + private function get_all_labels_filter_format(int $owner_uid) : array { $rv = array(); // TODO: use Labels::get_all() diff --git a/plugins/bookmarklets/init.php b/plugins/bookmarklets/init.php index 4bd527623..72aeb2c38 100644 --- a/plugins/bookmarklets/init.php +++ b/plugins/bookmarklets/init.php @@ -1,5 +1,7 @@ <?php class Bookmarklets extends Plugin { + + /** @var PluginHost $host */ private $host; function about() { @@ -20,7 +22,7 @@ class Bookmarklets extends Plugin { return in_array($method, ["subscribe", "sharepopup"]); } - function subscribe() { + function subscribe() : void { if (Config::get(Config::SINGLE_USER_MODE)) { UserHelper::login_sequence(); } @@ -171,7 +173,7 @@ class Bookmarklets extends Plugin { } } - function sharepopup() { + function sharepopup() : void { if (Config::get(Config::SINGLE_USER_MODE)) { UserHelper::login_sequence(); } @@ -332,7 +334,6 @@ class Bookmarklets extends Plugin { <?php } - function hook_prefs_tab($args) { if ($args != "prefFeeds") return; diff --git a/plugins/cache_starred_images/init.php b/plugins/cache_starred_images/init.php index d94e60504..731007b5b 100755 --- a/plugins/cache_starred_images/init.php +++ b/plugins/cache_starred_images/init.php @@ -1,11 +1,14 @@ <?php class Cache_Starred_Images extends Plugin { - /* @var PluginHost $host */ + /** @var PluginHost $host */ private $host; - /* @var DiskCache $cache */ + + /** @var DiskCache $cache */ private $cache; - private $max_cache_attempts = 5; // per-article + + /** @var int $max_cache_attempts (per article) */ + private $max_cache_attempts = 5; function about() { return array(null, @@ -32,8 +35,8 @@ class Cache_Starred_Images extends Plugin { } } + /** since HOOK_UPDATE_TASK is not available to user plugins, this hook is a next best thing */ function hook_house_keeping() { - /* since HOOK_UPDATE_TASK is not available to user plugins, this hook is a next best thing */ Debug::log("caching media of starred articles for user " . $this->host->get_owner_uid() . "..."); @@ -53,7 +56,7 @@ class Cache_Starred_Images extends Plugin { $usth = $this->pdo->prepare("UPDATE ttrss_entries SET plugin_data = ? WHERE id = ?"); while ($line = $sth->fetch()) { - Debug::log("processing article " . $line["title"], Debug::$LOG_VERBOSE); + Debug::log("processing article " . $line["title"], Debug::LOG_VERBOSE); if ($line["site_url"]) { $success = $this->cache_article_images($line["content"], $line["site_url"], $line["owner_uid"], $line["id"]); @@ -97,7 +100,7 @@ class Cache_Starred_Images extends Plugin { } } - function hook_enclosure_entry($enc, $article_id) { + function hook_enclosure_entry($enc, $article_id, $rv) { $local_filename = $article_id . "-" . sha1($enc["content_url"]); if ($this->cache->exists($local_filename)) { @@ -115,7 +118,7 @@ class Cache_Starred_Images extends Plugin { foreach ($entries as $entry) { if ($entry->hasAttribute('src')) { - $src = rewrite_relative_url($site_url, $entry->getAttribute('src')); + $src = UrlHelper::rewrite_relative($site_url, $entry->getAttribute('src')); $local_filename = $article_id . "-" . sha1($src); @@ -130,11 +133,11 @@ class Cache_Starred_Images extends Plugin { return $doc; } - private function cache_url($article_id, $url) { + private function cache_url(int $article_id, string $url) : bool { $local_filename = $article_id . "-" . sha1($url); if (!$this->cache->exists($local_filename)) { - Debug::log("cache_images: downloading: $url to $local_filename", Debug::$LOG_VERBOSE); + Debug::log("cache_images: downloading: $url to $local_filename", Debug::LOG_VERBOSE); $data = UrlHelper::fetch(["url" => $url, "max_size" => Config::get(Config::MAX_CACHE_FILE_SIZE)]); @@ -150,16 +153,16 @@ class Cache_Starred_Images extends Plugin { return false; } - private function cache_article_images($content, $site_url, $owner_uid, $article_id) { + private function cache_article_images(string $content, string $site_url, int $owner_uid, int $article_id) : bool { $status_filename = $article_id . "-" . sha1($site_url) . ".status"; /* housekeeping might run as a separate user, in this case status/media might not be writable */ if (!$this->cache->is_writable($status_filename)) { - Debug::log("status not writable: $status_filename", Debug::$LOG_VERBOSE); + Debug::log("status not writable: $status_filename", Debug::LOG_VERBOSE); return false; } - Debug::log("status: $status_filename", Debug::$LOG_VERBOSE); + Debug::log("status: $status_filename", Debug::LOG_VERBOSE); if ($this->cache->exists($status_filename)) $status = json_decode($this->cache->get($status_filename), true); @@ -170,7 +173,7 @@ class Cache_Starred_Images extends Plugin { // only allow several download attempts for article if ($status["attempt"] > $this->max_cache_attempts) { - Debug::log("too many attempts for $site_url", Debug::$LOG_VERBOSE); + Debug::log("too many attempts for $site_url", Debug::LOG_VERBOSE); return false; } @@ -194,7 +197,7 @@ class Cache_Starred_Images extends Plugin { $has_images = true; - $src = rewrite_relative_url($site_url, $entry->getAttribute('src')); + $src = UrlHelper::rewrite_relative($site_url, $entry->getAttribute('src')); if ($this->cache_url($article_id, $src)) { $success = true; @@ -210,7 +213,7 @@ class Cache_Starred_Images extends Plugin { while ($enc = $esth->fetch()) { $has_images = true; - $url = rewrite_relative_url($site_url, $enc["content_url"]); + $url = UrlHelper::rewrite_relative($site_url, $enc["content_url"]); if ($this->cache_url($article_id, $url)) { $success = true; diff --git a/plugins/no_iframes/init.php b/plugins/no_iframes/init.php index 3cfa15915..dc297b60e 100644 --- a/plugins/no_iframes/init.php +++ b/plugins/no_iframes/init.php @@ -11,7 +11,7 @@ class No_Iframes extends Plugin { $host->add_hook($host::HOOK_SANITIZE, $this); } - function hook_sanitize($doc, $site_url, $allowed_elements, $disallowed_attributes) { + function hook_sanitize($doc, $site_url, $allowed_elements, $disallowed_attributes, $article_id) { $xpath = new DOMXpath($doc); $entries = $xpath->query('//iframe'); diff --git a/plugins/note/init.php b/plugins/note/init.php index bc3df64b1..28d3c8c3a 100644 --- a/plugins/note/init.php +++ b/plugins/note/init.php @@ -21,7 +21,7 @@ class Note extends Plugin { style='cursor : pointer' title='".__('Edit article note')."'>note</i>"; } - function edit() { + function edit() : void { $id = clean($_REQUEST['id']); $sth = $this->pdo->prepare("SELECT note FROM ttrss_user_entries WHERE @@ -49,7 +49,7 @@ class Note extends Plugin { <?php } - function setNote() { + function setNote() : void { $id = (int)clean($_REQUEST["id"]); $note = clean($_REQUEST["note"]); diff --git a/plugins/nsfw/init.php b/plugins/nsfw/init.php index fc38fef71..a349ceac0 100644 --- a/plugins/nsfw/init.php +++ b/plugins/nsfw/init.php @@ -1,5 +1,7 @@ <?php class NSFW extends Plugin { + + /** @var PluginHost $host */ private $host; function about() { @@ -31,7 +33,12 @@ class NSFW extends Plugin { } } - private function rewrite_contents($article) { + /** + * @param array<string, mixed> $article + * @return array<string,mixed> + * @throws PDOException + */ + private function rewrite_contents(array $article) : array { $tags = explode(",", $this->host->get($this, "tags")); $article_tags = $article["tags"]; @@ -101,7 +108,7 @@ class NSFW extends Plugin { <?php } - function save() { + function save() : void { $tags = implode(", ", FeedItem_Common::normalize_categories(explode(",", $_POST["tags"] ?? ""))); diff --git a/plugins/share/init.php b/plugins/share/init.php index 359d86802..0b14c673b 100644 --- a/plugins/share/init.php +++ b/plugins/share/init.php @@ -1,5 +1,6 @@ <?php class Share extends Plugin { + /** @var PluginHost $host */ private $host; function about() { @@ -8,7 +9,6 @@ class Share extends Plugin { "fox"); } - /* @var PluginHost $host */ function init($host) { $this->host = $host; @@ -32,6 +32,7 @@ class Share extends Plugin { return file_get_contents(__DIR__ . "/share_prefs.js"); } + /** @return void */ function unshare() { $id = $_REQUEST['id']; @@ -42,6 +43,9 @@ class Share extends Plugin { print __("Article unshared"); } + /** + * @param string $id + * @return void */ function hook_prefs_tab_section($id) { if ($id == "prefFeedsPublishedGenerated") { ?> @@ -56,6 +60,7 @@ class Share extends Plugin { } } + /** @return void */ function clearArticleKeys() { $sth = $this->pdo->prepare("UPDATE ttrss_user_entries SET uuid = '' WHERE owner_uid = ?"); @@ -64,6 +69,7 @@ class Share extends Plugin { print __("Shared URLs cleared."); } + /** @return void */ function newkey() { $id = $_REQUEST['id']; $uuid = uniqid_short(); @@ -75,6 +81,10 @@ class Share extends Plugin { print json_encode(["link" => $uuid]); } + /** + * @param array<string,mixed> $line + * + * @return string */ function hook_article_button($line) { $icon_class = !empty($line['uuid']) ? "is-shared" : ""; @@ -83,6 +93,7 @@ class Share extends Plugin { title='".__('Share by URL')."'>link</i>"; } + /** @return void */ function get() { $uuid = clean($_REQUEST["key"] ?? ""); @@ -107,7 +118,7 @@ class Share extends Plugin { print "Article not found."; } - private function format_article($id, $owner_uid) { + private function format_article(int $id, int $owner_uid) : void { $pdo = Db::pdo(); @@ -133,7 +144,7 @@ class Share extends Plugin { $line["content"] = Sanitizer::sanitize($line["content"], $line['hide_images'], - $owner_uid, $line["site_url"], false, $line["id"]); + $owner_uid, $line["site_url"], null, $line["id"]); PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_RENDER_ARTICLE, function ($result) use (&$line) { @@ -183,10 +194,7 @@ class Share extends Plugin { strip_tags($content_decoded) ) ), 500, "...")) ?>"> - - <?php if ($og_image) { ?> - <meta property='og:image' content="<?= htmlspecialchars($og_image) ?>"> - <?php } ?> + <meta property='og:image' content="<?= htmlspecialchars($og_image) ?>"> </head> <body class='flat ttrss_utility ttrss_zoom css_loading'> @@ -231,6 +239,7 @@ class Share extends Plugin { } } + /** @return void */ function shareDialog() { $id = (int)clean($_REQUEST['id'] ?? 0); @@ -276,6 +285,7 @@ class Share extends Plugin { <?php } + /** @return int */ function api_version() { return 2; } |