diff --git a/README.md b/README.md index 74024335..40bcb0ed 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,7 @@ We are not aware of any other extensions to the TTRSS protocol. If you know of a #### Errors and ambiguities +- TTRSS accepts base64-encoded passwords, though this is undocumented; The Arsse accepts base64-encoded passwords as well - TTRSS sometimes returns an incorrect count from the `setArticleLabel` operation; The Arsse returns a correct count in all cases - TTRSS sometimes returns out-of-date cached information; The Arsse does not use caches as TTRSS does, so information is always current - TTRSS returns results for _feed_ ID `-3` when providing the `getHeadlines` operation with _category_ ID `-3`; The Arsse retuns the correct results diff --git a/lib/REST/TinyTinyRSS/API.php b/lib/REST/TinyTinyRSS/API.php index 6d27ad02..2a31304a 100644 --- a/lib/REST/TinyTinyRSS/API.php +++ b/lib/REST/TinyTinyRSS/API.php @@ -21,32 +21,6 @@ use JKingWeb\Arsse\Db\ResultEmpty; use JKingWeb\Arsse\Feed\Exception as FeedException; use JKingWeb\Arsse\REST\Response; -/* - -Protocol difference so far: - - Malformed JSON data returns a different error code than login failure, for clarity - - TT-RSS accepts whitespace-only names for categories, labels, and feeds; we do not - - TT-RSS allows two folders to share the same name under the same parent; we do not - - TT-RSS requires the user to choose in the face of multiple found feeds during discovery; we use the first one (picoFeed limitation) - - Session lifetime is much shorter by default - - Categories and feeds will always be sorted alphabetically (the protocol does not allow for clients to re-order) - - The "Archived" virtual feed is non-functional (the protocol does not allow archiving) - - The "Published" virtual feed is non-functional (this will not be implemented in the near term) - - setArticleLabel responds with errors for invalid labels where TT-RSS simply returns a zero result - - The result of setArticleLabel counts only records which actually changed rather than all entries attempted - - Using both limit/skip and unread_only in getFeeds produces reliable results, unlike in TT-RSS - - Top-level categories in getFeedTree have a 'parent_id' property (set to null); in TT-RSS the property is absent - - Article hashes are SHA-256 rather than SHA-1. - - Articles have at most one attachment (enclosure), whereas TTRSS allows for several; there is also significantly less detail. These are limitations of picoFeed which should be addressed - - IDs for enclosures are always 0 as we don't give them IDs - - Searching in getHeadlines is not yet implemented - - Category -3 (all non-special feeds) is handled correctly in getHeadlines; TT-RSS returns results for feed -3 (Fresh) - - Sorting of headlines does not match TT-RSS: special feeds are not sorted specially like they should be - - The 'sanitize', 'force_update', and 'has_sandbox' parameters of getHeadlines are ignored -*/ - - - class API extends \JKingWeb\Arsse\REST\AbstractHandler { const LEVEL = 14; // emulated API level const VERSION = "17.4"; // emulated TT-RSS version @@ -194,7 +168,8 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { } public function opLogin(array $data): array { - if (Arsse::$user->auth((string) $data['user'], (string) $data['password'])) { + // both cleartext and base64 passwords are accepted + if (Arsse::$user->auth($data['user'], $data['password']) || Arsse::$user->auth($data['user'], base64_decode($data['password']))) { $id = Arsse::$db->sessionCreate($data['user']); return [ 'session_id' => $id, diff --git a/tests/REST/TinyTinyRSS/TestTinyTinyAPI.php b/tests/REST/TinyTinyRSS/TestTinyTinyAPI.php index ee71d775..2f7f66a8 100644 --- a/tests/REST/TinyTinyRSS/TestTinyTinyAPI.php +++ b/tests/REST/TinyTinyRSS/TestTinyTinyAPI.php @@ -192,7 +192,8 @@ LONG_STRING; } public function testLogIn() { - Phake::when(Arsse::$user)->auth(Arsse::$user->id, "superman")->thenReturn(false); + Phake::when(Arsse::$user)->auth(Arsse::$user->id, $this->anything())->thenReturn(false); + Phake::when(Arsse::$user)->auth(Arsse::$user->id, "secret")->thenReturn(true); Phake::when(Arsse::$db)->sessionCreate->thenReturn("PriestsOfSyrinx")->thenReturn("SolarFederation"); $data = [ 'op' => "login", @@ -201,6 +202,8 @@ LONG_STRING; ]; $exp = $this->respGood(['session_id' => "PriestsOfSyrinx", 'api_level' => \JKingWeb\Arsse\REST\TinyTinyRSS\API::LEVEL]); $this->assertResponse($exp, $this->req($data)); + // base64 passwords are also accepted + $data['password'] = base64_encode($data['password']); $exp = $this->respGood(['session_id' => "SolarFederation", 'api_level' => \JKingWeb\Arsse\REST\TinyTinyRSS\API::LEVEL]); $this->assertResponse($exp, $this->req($data)); // test a failed log-in