aboutsummaryrefslogtreecommitdiff
path: root/lib
AgeCommit message (Collapse)Author
2025-08-07PHPStan: finalise strictArrayFilter (#7794)Gravatar Alexandre Alapetite
As well as reportPossiblyNonexistentConstantArrayOffset. And disable PHPStan-next from GitHub Action, since the work is completed for now.
2025-08-01Bump SimplePie with PHPStan Level 8 (#7775)Gravatar Alexandre Alapetite
* Bump SimplePie with PHPStan Level 8 * https://github.com/FreshRSS/simplepie/pull/45 SimplePie increased to PHPStan Level 8: * https://github.com/simplepie/simplepie/pull/857 * Merge upstream Including my two PRs: * https://github.com/simplepie/simplepie/pull/932 * https://github.com/simplepie/simplepie/pull/933 * Resolve upstream sync of Expose HTTP status * https://github.com/FreshRSS/simplepie/pull/47 Finalise merge, following: * https://github.com/simplepie/simplepie/pull/905#issuecomment-3007605779 * https://github.com/simplepie/simplepie/pull/909 * https://github.com/FreshRSS/FreshRSS/issues/7038
2025-08-01composer update + corresponding PHPStan fixes (#7781)Gravatar Alexandre Alapetite
Replacing failing Dependabot PRs: * https://github.com/FreshRSS/FreshRSS/pull/7779 * https://github.com/FreshRSS/FreshRSS/pull/7780 * https://github.com/FreshRSS/FreshRSS/pull/7778
2025-08-01Rework fetch favicons (#7767)Gravatar Alexandre Alapetite
* Use main function `httpGet()` instead of local one; * Use HTTP cache, also between users; * Do not default to feed URL when there is no website URL TODO for later: consider supporting Atom's `<icon>` and RSS 2.0's `<image>` https://github.com/FreshRSS/FreshRSS/issues/7774
2025-07-31Strip more unsafe attributes e.g. `referrerpolicy` (#7770)Gravatar Inverle
2025-07-31Implement sudo mode / reauthentication (#7753)Gravatar Inverle
* Implement sudo mode / reauthentication * i18n: fr * generate flags * Improvements * Remove HMAC check * Don't require reauth to access logs when signed in as admin * Notify user of bad login via notification instead --------- Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2025-07-31Fix regression Minz_Configuration (#7765)Gravatar Alexandre Alapetite
Follow-up of https://github.com/FreshRSS/FreshRSS/pull/7761 Partially avoid calls to deprecated functions. Avoid warnings: ``` [warning] --- old_entries does not exist in configuration [warning] --- keep_history_default does not exist in configuration ```
2025-07-31Implement support for HTTP 429 Too Many Requests (#7760)Gravatar Alexandre Alapetite
* Implement support for HTTP 429 Too Many Requests Will obey the corresponding HTTP `Retry-After` header at domain level. * Implement 503 Service Unavailable * Sanitize Retry-After * Reduce default value when Retry-After is absent And make configuration parameter * Retry-After also for favicons
2025-07-30`before_login_btn` hook + system conf attributes (#7761)Gravatar Inverle
* `before_login_btn` hook + system conf attributes * phpstan fix * Refactoring --------- Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2025-07-17Call DOMNode::insertBefore() on the parent of it's $child (#7741)Gravatar Sam Edwards
Follow-up to https://github.com/FreshRSS/FreshRSS/pull/7654#discussion_r2208901108 Changes proposed in this pull request: - `DOMNode::insertBefore()` needs to be called on an element that is the parent of the `$child` param being passed - Update code to call this on `$doc->documentElement` instead of directly on the `$doc` (`DOMDocument`) How to test the feature manually: 1. Set up an HTML + XPath feed for a URL that contains partial HTML content (eg. https://victoria.citified.ca/modules/blog/news.php?n=7&c=8) 1. Observe that the feed is processed successfully without error, and that the `<base>` is still inserted
2025-07-03SimplePie: sync upstream (#7706)Gravatar Alexandre Alapetite
https://github.com/FreshRSS/simplepie/pull/43
2025-06-30Implement custom feed favicons (#7646)Gravatar Inverle
Closes #3789, #6503 Icon setting when no custom icon is set yet: ![image](https://github.com/user-attachments/assets/28b07dd0-7dac-4c76-b1d7-77035f91a87a) - `Change...` button opens a file dialog, and after selecting a file shows the chosen icon in the preview on the left. `Submit` must be clicked after selecting the icon. - `Reset to default` changes the preview icon to the default one, and also requires `Submit` to be clicked to apply the changes. Full list of changes: - CSP now includes `blob:` in `img-src` for - `indexAction()` and `feedAction()` in `subscriptionController.php` - all of the view actions in `indexController.php` - Introduce new attribute `customFavicon (boolean)` for feeds that indicates if the feed has a custom favicon - `hashFavicon()` in `Feed.php` is dependent on this attribute - `hashFavicon()` has a new parameter called `skipCache (boolean)` that allows the reset of the favicon hash for the Feed object - `resetFaviconHash()` just calls `hashFavicon(skipCache: true)` - `f.php` URLs now have the format of `/f.php?h=XXXXX&t=cachebuster`, where the `t` parameter is only used for serving custom favicons - if `t` parameter is set, `f.php` returns a `Cache-Control: immutable` header - `stripos` and `strpos` were changed to `str_contains` in various places (refactor) - JS for handling the custom favicon configuration logic is in `extra.js` inside `init_update_feed()` which is called when feed configuration is opened from the aside or when the subscription management page with the feed is loaded - Server-side code for uploading the icon in `subscriptionController.php` under `feedAction()` - Errors that may occur during the setting of a custom favicon: - Unsupported image file type (handled only server-side with `isImgMime()`) - When the file is bigger than 1 MiB (default), handled both client-side and server-side - Standard feed error when `updateFeed()` fails - JS vars `javascript_vars.phtml` are no longer escaped with `htmlspecialchars()`, instead with json encoding, - CSS for disabled buttons was added - Max favicon file size is configurable with the `max_favicon_upload_size` option in `config.php` (not exposed via UI) - Custom favicons are currently deleted only when they are either reset to the default icon, or the feed gets deleted. They do not get deleted when the user deletes their account without removing their feeds first. - ` faviconPrepare()` and `faviconRebuild()` are not allowed to be called when the `customFavicon` attribute is `true` - New i18n strings: - `'sub.feed.icon' => 'Icon'` - `'sub.feed.change_favicon' => 'Change…'` - `'sub.feed.reset_favicon' => 'Reset to default'` - `'sub.feed.favicon_changed_by_ext' => 'The icon has been set by the <b>%s</b> extension.'` - `'feedback.sub.feed.favicon.too_large' => 'Uploaded icon is too large. The maximum file size is <em>%s</em>.'` - `'feedback.sub.feed.favicon.unsupported_format' => 'Unsupported image file format!'` - Extension hook `custom_favicon_hash` - `setCustomFavicon()` method - `resetCustomFavicon()` method - `customFaviconExt` and `customFaviconDisallowDel` attributes - example of usage: https://github.com/FreshRSS/Extensions/pull/337 - Extension hook `custom_favicon_btn_url` - Allows extensions to implement a button for setting a custom favicon for individual feeds by providing an URL. The URL will be sent a POST request with the `extAction` field set to either `query_icon_info` or `update_icon`, along with an `id` field which describes the feed's ID.
2025-06-30Fix multiple auth headers bug (#7703)Gravatar Inverle
Fix https://github.com/FreshRSS/FreshRSS/issues/7699
2025-06-25Fix feeds encoded in UTF-16LE (#7691)Gravatar Alexandre Alapetite
* Fix feeds encoded in UTF-16LE Fix https://github.com/FreshRSS/FreshRSS/issues/7690 https://github.com/FreshRSS/simplepie/pull/40 The final character `>` of a feed is encoded as `3E00` in UTF-16LE, so calling `trim()` was removing the `\x00`, breaking the multibyte encoding and making the feed invalid. Upstream PR https://github.com/simplepie/simplepie/pull/916 * Trim body for all paths https://github.com/FreshRSS/simplepie/pull/42 https://github.com/simplepie/simplepie/pull/917 Slight refactor of https://github.com/simplepie/simplepie/pull/916 (https://github.com/FreshRSS/simplepie/pull/40) to cover all paths. Missing paths included the fsock method without gzip (e.g. deflate or plain).
2025-06-24Fix support for XML feeds with HTML entities (#7689)Gravatar Alexandre Alapetite
fix https://github.com/FreshRSS/FreshRSS/issues/7687 https://github.com/FreshRSS/simplepie/pull/37 Upstream: https://github.com/simplepie/simplepie/pull/915 Partial revert of https://github.com/FreshRSS/FreshRSS/pull/7515 HTML entities are normally only allowed in XML when there is a DTD declaring them. SimplePie is even allowing Atom documents with undeclared HTML entities - which I am not sure is on purpose.
2025-06-22Exposed the reading modes for extensions through Minz (#7668)Gravatar Stefan
* + Exposed the reading modes for extensions through Minz. Now extensions can add a custom view mode. Graceful fallback to normal view in case the extension was disabled without resetting the view_mode through the uninstall method. In that case the user will be informed via Minz_Request::setBadNotification that the view has been reset to normal. + Added translation strings for de, en and en-us for the notification * + Added missing, generated translations * Simplify indexAction, performance * Minor settings htmlspecialchars * i18n: fr * Minor wording * Doc * Fix i18n --------- Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2025-06-22Handle redirects when scraping feed from HTML (#7654)Gravatar Inverle
* Handle redirects when scraping feed from HTML * pass codesniffer * pass PHPStan * Optimize * Another approach relying on HTML base Standard way to save an HTML document with relative references * Fix case of existing HTML base which should not be overriden --------- Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2025-06-18frame-ancestors CSP (#7677)Gravatar Inverle
2025-06-15SimplePie: Fix propagation of HTTP error codes (#7670)Gravatar Alexandre Alapetite
* SimplePie: Fix propagation of HTTP error codes fix https://github.com/FreshRSS/FreshRSS/issues/7038 https://github.com/FreshRSS/simplepie/pull/36 upstream https://github.com/simplepie/simplepie/pull/905 Co-authored-by: Edgar Alvarado <15692727+pe1uca@users.noreply.github.com>
2025-06-06Install: add test PDO typing (#7651)Gravatar Alexandre Alapetite
fix https://github.com/FreshRSS/FreshRSS/issues/7647
2025-06-03Add API endpoint for extensions (#7576)Gravatar Alexandre Alapetite
* Add API endpoint for extensions Useful for https://github.com/FreshRSS/FreshRSS/issues/7572 * Support PATH_INFO Now also support being invoked like `/api/misc.php/Extension%20Name/` * More documentation
2025-06-03Include remaining tags/attributes for lazy loading (#7636)Gravatar Inverle
* Include remaining tags/attributes for lazy loading * Suggested change
2025-05-23Strip more styles attributes (#7606)Gravatar Alexandre Alapetite
Strip `bgcolor`, `text`, `background`, `link`, `alink`, `vlink` fix https://github.com/FreshRSS/FreshRSS/issues/7604
2025-05-10Fix newest articles not shown (#7577)Gravatar Alexandre Alapetite
* Fix newest articles not shown Case when processing was faster than 1 second. fix https://github.com/FreshRSS/FreshRSS/issues/7412 Regression from https://github.com/FreshRSS/FreshRSS/pull/7149 * Simplify uTimeString() PHPStan has become a bit smarter
2025-05-07Move PHP minimum version check (#7560)Gravatar Alexandre Alapetite
It is too late to check for minimum version check in `lib_rss.php` because that file already contains some relatively new PHP language constructs, which will lead to a syntax error - when running with an old PHP version - instead of the expected error message. Moved to `constants.php` for now. Example of syntax error with PHP 7.4: ``` PHP Parse error: syntax error, unexpected '|', expecting '{' in /var/www/FreshRSS/lib/lib_rss.php on line 166 ``` Should help users like in: * https://github.com/FreshRSS/FreshRSS/discussions/7539 * https://github.com/FreshRSS/FreshRSS/issues/7557
2025-05-03PHPMailer 6.10.0 (#7542)Gravatar Alexandre Alapetite
Supplement to https://github.com/FreshRSS/FreshRSS/pull/7541
2025-05-02Fix file serving for symlinked extensions (#7545)Gravatar Inverle
* Fix file serving for symlinked extensions from ext.php * Don't resolve symlink when deleting extension * Minor syntax --------- Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2025-05-01Update phpmailer/phpmailer requirement from 6.9.3 to 6.10.0 in /lib (#7541)Gravatar dependabot[bot]
Updates the requirements on [phpmailer/phpmailer](https://github.com/PHPMailer/PHPMailer) to permit the latest version. - [Release notes](https://github.com/PHPMailer/PHPMailer/releases) - [Changelog](https://github.com/PHPMailer/PHPMailer/blob/master/changelog.md) - [Commits](https://github.com/PHPMailer/PHPMailer/compare/v6.9.3...v6.10.0) --- updated-dependencies: - dependency-name: phpmailer/phpmailer dependency-version: 6.10.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-01Bump phpstan/phpstan from 2.1.11 to 2.1.13 (#7534)Gravatar dependabot[bot]
* Bump phpstan/phpstan from 2.1.11 to 2.1.13 Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 2.1.11 to 2.1.13. - [Release notes](https://github.com/phpstan/phpstan/releases) - [Changelog](https://github.com/phpstan/phpstan/blob/2.1.x/CHANGELOG.md) - [Commits](https://github.com/phpstan/phpstan/compare/2.1.11...2.1.13) --- updated-dependencies: - dependency-name: phpstan/phpstan dependency-version: 2.1.13 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Bump phpstan/phpstan from 2.1.11 to 2.1.13 Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 2.1.11 to 2.1.13. - [Release notes](https://github.com/phpstan/phpstan/releases) - [Changelog](https://github.com/phpstan/phpstan/blob/2.1.x/CHANGELOG.md) - [Commits](https://github.com/phpstan/phpstan/compare/2.1.11...2.1.13) --- updated-dependencies: - dependency-name: phpstan/phpstan dependency-version: 2.1.13 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Fix PHPStan --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2025-04-28HTTP Auth disallow multiple headers (#7528)Gravatar Alexandre Alapetite
When using HTTP Auth methods (including OpenID Connect), exactly 1 HTTP header should be received, not more.
2025-04-18SimplePie: Fix support for feeds with XML preample + DTD (#7515)Gravatar Alexandre Alapetite
Regression from https://github.com/FreshRSS/FreshRSS/pull/4374 fix: https://github.com/FreshRSS/FreshRSS/issues/7514 https://github.com/FreshRSS/simplepie/pull/35 Upstream PR: https://github.com/simplepie/simplepie/pull/914
2025-04-13SimplePie forbit formaction attribute (#7506)Gravatar Alexandre Alapetite
Sanitize buttons with a form or formaction attribute.
2025-04-07Secure serving of user files from extensions (#7495)Gravatar Alexandre Alapetite
* Secure serving of user files from extensions fix https://github.com/FreshRSS/FreshRSS/issues/4930 * More fixes * Typo
2025-04-07Web scraping forbid security headers in cURL (#7496)Gravatar Alexandre Alapetite
Prevent using `Remote-User`, `X-WebAuth-User` during Web scraping.
2025-04-06Disallow iframe srcdoc for now (#7494)Gravatar Alexandre Alapetite
We do not sanitize this attribute well enough, so striped for now. It is rarely used: I have not seen any use of it in any of my many test feeds. Can be added back when we can handle its inherent security issues better.
2025-04-01Catch extension exceptions in override (#7475)Gravatar Alexandre Alapetite
* Catch extension exceptions in override https://github.com/FreshRSS/Extensions/pull/300#issuecomment-2768578464 * Fix error message
2025-04-01Referrer-Policy: same-origin (#6303)Gravatar maTh
* Referrer-Policy: same-origin * same-origin for our own images --------- Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2025-03-15Update PHPStan 2.1.8 (#7431)Gravatar Alexandre Alapetite
Fixing minor breaking changes
2025-03-15SimplePie sync upstream (#7434)Gravatar Alexandre Alapetite
https://github.com/FreshRSS/simplepie/pull/34
2025-03-08Back-compatibility cURL 7.51 (#7409)Gravatar Alexandre Alapetite
* Back-compatibility cURL 7.51 fix https://github.com/FreshRSS/FreshRSS/issues/7381 And add cURL version to system info. Do not require a specific version of cURL for now, but maybe later. * Fix CI * make fix-all * Add TODOs * Add ssl_version * Update app/i18n/it/index.php Co-authored-by: UserRoot-Luca <55756898+UserRoot-Luca@users.noreply.github.com> --------- Co-authored-by: UserRoot-Luca <55756898+UserRoot-Luca@users.noreply.github.com>
2025-03-05Fix Minz_Request::paramArray (#7400)Gravatar Alexandre Alapetite
fix https://github.com/FreshRSS/FreshRSS/issues/7371 Regression from https://github.com/FreshRSS/FreshRSS/pull/7131
2025-03-05Fix regression cURL HTTP headers (#7403)Gravatar Alexandre Alapetite
* Fix regression cURL HTTP headers fix https://github.com/FreshRSS/FreshRSS/issues/6712#issuecomment-2697961491 We would sometimes wrongly override the default HTTP headers of SimplePie https://github.com/FreshRSS/simplepie/pull/33 https://github.com/simplepie/simplepie/pull/912 * Sync SimplePie https://github.com/FreshRSS/simplepie/pull/33
2025-02-21Update dev tools (#7347)Gravatar Alexandre Alapetite
In particular those not covered by Dependabot
2025-02-02Improve notifications: notificationName (#7287)Gravatar maTh
* notificationID * 3 first examples * fix * notificationID -> notificationName * Update lib/Minz/Request.php Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr> --------- Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2025-01-26Doc force-https (#7259)Gravatar Alexandre Alapetite
* Doc force-https https://github.com/FreshRSS/FreshRSS/discussions/7252#discussioncomment-11951183 * Forgotten ^ * More proper support for comments
2025-01-25Improve cURL proxy options (#7231)Gravatar Alexandre Alapetite
3 is now used for CURLPROXY_HTTPS2 https://github.com/curl/curl/blob/f07612cd9ae1ec50b9bedd749171ad75203c9e7e/include/curl/curl.h#L789 Related to https://github.com/FreshRSS/FreshRSS/issues/7209
2025-01-11CssXPath 1.3.0 (#7211)Gravatar Alexandre Alapetite
No change https://github.com/PhpGt/CssXPath/pull/227#issuecomment-2580589055
2025-01-10Reduce undeeded use of elvis operator ?: (#7204)Gravatar Alexandre Alapetite
2025-01-08Add some missing PHP native types (#7191)Gravatar Alexandre Alapetite
* Add some missing PHP native types Replaces https://github.com/FreshRSS/FreshRSS/pull/7184 * Clean some types
2025-01-06Implement custom order-by (#7149)Gravatar Alexandre Alapetite
Add option to sort results by received date (existing, default), publication date, title, URL (link), random. fix https://github.com/FreshRSS/FreshRSS/issues/1771 fix https://github.com/FreshRSS/FreshRSS/issues/2083 fix https://github.com/FreshRSS/FreshRSS/issues/2119 fix https://github.com/FreshRSS/FreshRSS/issues/2596 fix https://github.com/FreshRSS/FreshRSS/issues/3204 fix https://github.com/FreshRSS/FreshRSS/issues/4405 fix https://github.com/FreshRSS/FreshRSS/issues/5529 fix https://github.com/FreshRSS/FreshRSS/issues/5864 fix https://github.com/FreshRSS/Extensions/issues/161 URL parameters: * `&sort=id` (current behaviour, sorting according to newest received articles) * `&sort=date` (publication date, which is not indicative of how new an article is) * `&sort=title` * `&sort=link` * `&sort=rand` (random order - which disables infinite scrolling, at least for now) combined with `&order=ASC` or `&order=DESC` ![image](https://github.com/user-attachments/assets/2de5aef1-604e-4a73-a147-569f6f42a1be) ## Implementation notes The sorting criteria by *received date* (id), which is the default, and which was the only one before this PR, is the one that has the best sorting characteristics: * *uniqueness*: no entries have the exact same received date * *monotonicity*: new entries always have a higher received date * *performance*: this field is efficiently indexed in database for fast usage, including for paging (indexing could also be done to other fields, but with lower effective performance) In contrary, sorting criteria such as by *publication date*, by *title*, or by *link* are neither unique nor monotonic. In particular, multiple articles may share the same *publication date*, and we may receive articles with a *publication date* far in the future, and then later some new articles with a *publication date* far in the past. To understand why sorting by *publication date* is problematic, it helps to think about sorting by *title* or by *link*, as sorting by *title* and by *publication date* share more or less the same characteristics. ### Problem 1: new articles New articles may be received in the background after what is shown on screen, and before the next user action such as *mark all as read*. Due to the lack of *monotonicity* when sorting by e.g. *publication date* or *title*, users risk marking as read a batch of articles containing some fresh articles without seeing them. Mitigation: A parameter `idMax` tracks the maximum ID related to a batch of actions such as *mark all as read* to exclude articles received after those that are displayed. ### Problem 2: paging / pagination When navigating articles, only a few articles are displayed, and a new "page" of articles needs to be received from the database when scrolling down or when clicking the button to show more articles. When sorting by e.g. *publication date* or *title*, it is not trivial to show the next page without re-showing some of the same articles, and without skipping any. Indeed, views are often with additional criteria such as showing only unread articles, and users may mark some articles as read while viewing them, hereby removing some articles from the previous pages. And like for *Problem 1*, new articles may have been received in the background. Consequently, it is not possible to use `OFFSET` to implement pagination (so the patches suggested by a few users were wrong due to that, in particular). Mitigation: `idMax` is also used (just like for *Problem 1*) and a *Keyset Pagination* approach is used, combining an unstable sorting criterion such as *publication date* or *title*, together with *id* to ensure stable sorting. (So, 2 sorting criteria + 1 filter criteria) See e.g. https://www.alwaysdeveloping.net/dailydrop/2022/07/01-keyset-pagination/ ### Problem 3: performance Sorting by anything else than *received date* (id) is doomed to be slow(er) due to the combination of 3 criteria (see *Problem 2*). An `OFFSET` approach (which is not possible anyway as explained) would be even slower. Furthermore, we have no SQL index at the moment, but they would not necessarily help much due to the multiple sorting criteria needed and involving some `OR` logic which is difficult to optimise for databases. The nicest syntax would be using tuples and corresponding indexes, but that is poorly supported by MySQL https://bugs.mysql.com/bug.php?id=104128 Mitigation: a compatibility SQL syntax is used to implement *Keyset Pagination* ### Problem 4: user confusion Several users have shown that they do not fully understand the difference between *received date* and *publication date*, and particularly not the pitfalls of *publication date*. Mitigation: the menus to mark-as-read *before 1 day* and *before 1 week* are disabled when sorting by anything else than *received date*. Likewise, the separation headers *Today* and *Yesterday* and *Before yesterday* are only shown when sorting by *received date*. Again here, to better understand why, it helps to think about sorting by *title* or by *link*, as sorting by *title* and by *publication date* share more or less the same characteristics. * [ ] We should write a Q&A and/or documentation about the problems associated to *sorting by publication date*: risks of not noticing new publication, of inadvertently marking them as read, of having some articles with a date in the future hanging at the top of the views (vice versa when sorting in ascending order), performance, etc. ### Problem 5: APIs Sorting by anything else than *received date* breaks the guarantees needed for a successful synchronisation via API. Mitigation: sorting by *received date* is ensured for all API calls.