Commit Graph
7510 Commits
Author SHA1 Message Date
Alexandre Alapetite 7e8ef628d9 Better doc and log proxy cases (#9436)
Fix https://github.com/FreshRSS/FreshRSS/issues/9423
And strip redundant proxy scheme.
And add a few more unit tests.
2026-10-13 19:50:38 +02:00
Alexandre Alapetite 15d57cea88 Changelog 2026-10-12 12:05:56 +02:00
M. Önlük 9e53bdd223 Fix missing left outline on Mark as read button (#9426)
The hidden CSRF input was the first child of the form, directly before the
Mark as read button. Theme rules such as `.stick input + .btn` and
`.stick .btn:first-child` therefore treated the button as the second element
of an input + button group: no left border and no rounded left corners.
Move the input back inside the dropdown, as it was before #9205.

Fixes #9359

Changes proposed in this pull request:

- In `app/layout/nav_menu.phtml`, move the hidden `_csrf` input of the "Mark as read" form back inside the `#nav_menu_read` dropdown (where it was before #9205), instead of being the first child of the form right before the `read_all` button.
- Because of that input, many theme rules written for `input + .btn` groups (`.stick input + .btn`, and `.btn:first-child` no longer matching) removed the left border and the rounded left corners of the "Mark as read" button. This affected Alternative Dark, Origine and the themes built on them (Dark, Dark-pink, Origine-compact), Pafat, and gave a stray separator and square corners in Flat, Ansum and Mapco.
2026-10-12 09:21:10 +02:00
0187b15c8e Sanitizer: block data: URI scheme while keeping data:image for images (#9417)
* Sanitizer: block data: URI scheme, keep data:image for images

FreshRSS_SimplePieCustom only disallowed the `javascript` scheme, so
`data:text/html,...` URIs in feed content survived
sanitization on <a href>, <iframe src>, <audio|video|source|track src>.
The default CSP neutralises these on FreshRSS pages, but clients and
deployments without that CSP (API WebViews, extensions using amendCsp(),
proxies stripping headers) could execute them. Same class as
GHSA-3fw6-j8m4-82vj / #9272.

- Sanitize::is_allowed_uri(): element/attribute-aware check that still
  permits inert `data:image/...` on img[src], image[src], video[poster]
  while blocking `data:` elsewhere; replace_urls() now uses it.
  is_allowed_scheme() is unchanged for backward compatibility.
- SimplePieCustom: disallow_uri_schemes(['javascript','data']).
- Tests: 4 blocked-input cases, a data:image keep-alive test and an
  `unsafe:` prefix test. They fail without the patch and pass with it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Sync SimplePie
https://github.com/FreshRSS/simplepie/pull/92

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-10-11 20:36:09 +02:00
Alexandre Alapetite 308b1726ec CI/CD: Login to Docker Hub (#9433)
Fix Error: Error response from daemon: toomanyrequests: You have reached your unauthenticated pull rate limit. https://www.docker.com/increase-rate-limit
2026-10-11 10:41:18 +02:00
spa77k 9c04882cc1 Document how to use the User CSS and User JS core extensions (#9424)
Closes #9394

## Summary

The _User CSS_ and _User JS_ sections already existed in the user documentation, but they did not say where to find the settings. This explains that each extension has a gear icon (_Manage_) next to its switch, and gives the steps to use both extensions.

## Changes

- `docs/en/users/05_Configuration.md`: describe the extension list (switch, gear icon, name), add the steps for User CSS, and the same for User JS with a note that it might ask to sign in again.
- `docs/en/users/05_Configuration.md`, `docs/en/admins/11_Themes.md`, `docs/en/contributing.md`: the "CustomCSS extension" links pointed to FreshRSS/Extensions, where it is no longer available. They now point to the built-in User CSS section.
- `docs/en/admins/15_extensions.md`, `lib/core-extensions/README.md`: list the two core extensions with links to their documentation. Also fix the `.lib/core-extensions` path.
- `CREDITS.md`: add my name.

Only the English documentation is changed.
2026-10-09 23:04:22 +02:00
Alexandre Alapetite c7c53f4576 WebSub fix POST, fix warning, better message (#9420)
* WebSub fix warning and better message
Contributes to https://github.com/FreshRSS/FreshRSS/issues/9416

* Fix POST conditions
2026-10-09 22:28:18 +02:00
dependabot[bot] aa6b46ba96 chore(deps): bump source-map-js from 1.2.1 to 1.2.2 (#9425)
Bumps [source-map-js](https://github.com/7rulnik/source-map-js) from 1.2.1 to 1.2.2.
- [Release notes](https://github.com/7rulnik/source-map-js/releases)
- [Changelog](https://github.com/7rulnik/source-map-js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/7rulnik/source-map-js/compare/v1.2.1...v1.2.2)

---
updated-dependencies:
- dependency-name: source-map-js
  dependency-version: 1.2.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-09 10:19:00 +02:00
Inverle 07617c48e6 Fix SVGO zero percent filtering in CI (#9422)
Because of the environment variable `CI=true` being passed in GitHub Actions to SVGO, it outputted colored text with ANSI escape sequences, which broke the awk 0% filtering (for unchanged files).

Ref: https://github.com/FreshRSS/FreshRSS/pull/9361#discussion_r4147827482
2026-10-09 08:17:58 +02:00
Alexandre Alapetite 4a3c6b6b60 Fix PHP 8.5+ deprecation sqliteCreateFunction (#9421)
Fix https://github.com/FreshRSS/FreshRSS/issues/8525#issuecomment-6065641500
2026-10-08 22:55:00 +02:00
Alejandro Borrego 219eaf58a7 Add Alejandro Borrego to CREDITS.md (#9412)
Following #9350
Co-authored-by: Alejandro Borrego <210245044+abp002@users.noreply.github.com>
2026-10-06 08:25:51 +02:00
abp002andAlejandro Borrego 48547b4a6c Reduce memory consumption of export (#9350)
Contributes to #6139 (export part; the import will follow in another PR)

Exporting favourites was collecting the whole file in memory. With many articles, it fails with the default PHP memory limit.

## Changes
- New `Minz_View::helperToFile()`, similar to `helperToString()`, writing the output of a helper into a file by chunks of 64 KiB instead of keeping it in memory.
- `FreshRSS_Export_Service`: the `generate*()` methods now return the path of a temporary file instead of the content, and `zip()` builds the archive from those files (`ZipArchive::addFile()` instead of `addFromString()`). Temporary files are created in `TMP_PATH` (already required to be writable) and deleted at the end of the script.
- The export is sent with `readfile()`: Web UI, `cli/export-zip-for-user.php`, `cli/export-opml-for-user.php` and the OPML export of the Google Reader API.
- Note: this changes what `FreshRSS_Export_Service` returns (a path instead of the content). All callers in the repository are updated, and I could not find any public extension using this service.

## Measurements
Peak PHP memory (`memory_get_peak_usage(true)`), SQLite database with synthetic starred articles:

| Scenario | Before | After |
|---|---|---|
| Web, export your favourites, 10,000 articles (69 MB JSON) | 136 MB (fails with the default `memory_limit` of 128 MB) | 6 MB |
| Web, ZIP (OPML + favourites + labelled articles + 4 feeds), 10,000 articles | 152 MB | 6 MB |
| CLI `export-zip-for-user.php`, 10,000 articles | 189 MB (fails with 128 MB) | 8 MB |
| Web, export your favourites, 30,000 articles (208 MB JSON) | 404 MB | 10 MB |

Co-authored-by: Alejandro Borrego <210245044+abp002@users.noreply.github.com>
2026-10-05 21:47:19 +02:00
Alexandre Alapetite c7396a3a68 Update to GT\CssXPath 1.6.0 (#9411)
https://github.com/phpgt/CssXPath/releases/tag/v1.6.0
2026-10-05 21:44:57 +02:00
Alexandre Alapetite 588dd92d77 Start 1.30.2-dev 2026-10-05 21:43:00 +02:00
Alexandre Alapetite 4a810f1624 Release 1.30.1 1.30.1 2026-10-05 21:19:07 +02:00
Alexandre Alapetite 089e021bf7 Changelog + credits 2026-10-05 09:26:21 +02:00
Alexandre Alapetite da9dc448c6 Fix API custom favicon (#9409) 2026-10-05 07:59:57 +02:00
dependabot[bot] 522c560922 chore(deps-dev): bump jekyll-default-layout from 0.1.5 to 0.2.0 in /docs (#9407)
Bumps [jekyll-default-layout](https://github.com/benbalter/jekyll-default-layout) from 0.1.5 to 0.2.0.
- [Release notes](https://github.com/benbalter/jekyll-default-layout/releases)
- [Changelog](https://github.com/benbalter/jekyll-default-layout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/benbalter/jekyll-default-layout/compare/v0.1.5...v0.2.0)

---
updated-dependencies:
- dependency-name: jekyll-default-layout
  dependency-version: 0.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-05 06:10:15 +02:00
dependabot[bot] fc099016d3 chore(deps-dev): bump jekyll-relative-links from 0.7.0 to 0.8.0 in /docs (#9405)
Bumps [jekyll-relative-links](https://github.com/benbalter/jekyll-relative-links) from 0.7.0 to 0.8.0.
- [Release notes](https://github.com/benbalter/jekyll-relative-links/releases)
- [Changelog](https://github.com/benbalter/jekyll-relative-links/blob/main/CHANGELOG.md)
- [Commits](https://github.com/benbalter/jekyll-relative-links/compare/v0.7.0...v0.8.0)

---
updated-dependencies:
- dependency-name: jekyll-relative-links
  dependency-version: 0.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-05 06:09:31 +02:00
dependabot[bot] a28ae9056e chore(deps-dev): bump jekyll-readme-index from 0.3.0 to 0.4.0 in /docs (#9403)
Bumps [jekyll-readme-index](https://github.com/benbalter/jekyll-readme-index) from 0.3.0 to 0.4.0.
- [Release notes](https://github.com/benbalter/jekyll-readme-index/releases)
- [Changelog](https://github.com/benbalter/jekyll-readme-index/blob/master/CHANGELOG.md)
- [Commits](https://github.com/benbalter/jekyll-readme-index/compare/v0.3.0...v0.4.0)

---
updated-dependencies:
- dependency-name: jekyll-readme-index
  dependency-version: 0.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-04 23:03:30 +02:00
dependabot[bot] 4be1479702 chore(deps): bump ruby/setup-ruby from 1.326.0 to 1.327.0 (#9406)
Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.326.0 to 1.327.0.
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](https://github.com/ruby/setup-ruby/compare/762794c140bbeda0f1224786aa33b4b46783a6c1...14594264cd68ce8a2345dd349bc3d138a4ef85c8)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.327.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-04 22:58:53 +02:00
dependabot[bot] e03c1616c6 chore(deps-dev): bump jekyll-optional-front-matter in /docs (#9404)
Bumps [jekyll-optional-front-matter](https://github.com/benbalter/jekyll-optional-front-matter) from 0.3.2 to 0.3.3.
- [Release notes](https://github.com/benbalter/jekyll-optional-front-matter/releases)
- [Changelog](https://github.com/benbalter/jekyll-optional-front-matter/blob/main/CHANGELOG.md)
- [Commits](https://github.com/benbalter/jekyll-optional-front-matter/compare/v0.3.2...v0.3.3)

---
updated-dependencies:
- dependency-name: jekyll-optional-front-matter
  dependency-version: 0.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-04 22:57:57 +02:00
dependabot[bot] fc1b40a70a chore(deps-dev): bump jekyll-titles-from-headings in /docs (#9402)
Bumps [jekyll-titles-from-headings](https://github.com/benbalter/jekyll-titles-from-headings) from 0.5.3 to 0.5.4.
- [Release notes](https://github.com/benbalter/jekyll-titles-from-headings/releases)
- [Changelog](https://github.com/benbalter/jekyll-titles-from-headings/blob/main/CHANGELOG.md)
- [Commits](https://github.com/benbalter/jekyll-titles-from-headings/compare/v0.5.3...v0.5.4)

---
updated-dependencies:
- dependency-name: jekyll-titles-from-headings
  dependency-version: 0.5.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-04 22:56:51 +02:00
Inverle 3b60a4ac3b Bump Ruby gems automatically with Dependabot for docs (#9401)
Previous Ruby gem version bumps were only triggered for security updates (since Dependabot was left unconfigured for bundler).

See: https://github.com/FreshRSS/FreshRSS/pulls?q=is%3Apr%20state%3Aclosed%20label%3Aruby%20author%3Aapp%2Fdependabot
2026-10-04 22:54:43 +02:00
akinechanandakinechan 34c60510f2 i18n(ja): translate the remaining TODO strings (#9398)
Translate the last untranslated Japanese strings and mark the Lithuanian
endonym as IGNORE, consistent with the other language names.

Co-authored-by: akinechan <1593847+akine@users.noreply.github.com>
2026-10-04 18:35:07 +02:00
Abdelrhman Mohamed 820687e78c Keep the reader view article date on one line (#9388)
Follow-up to #9369, as discussed in https://github.com/FreshRSS/FreshRSS/pull/9369#issuecomment-5954861516

Changes proposed in this pull request:

- In the reader view, the date in the line under the article title had a fixed `width: 155px`. A long date such as "28 September 2026 at 18:30" needs about 190px, so at desktop width it broke into two lines. This was already the case before #9369.
- `.content .subtitle.horizontal-list .item.date` now uses the 155px as `min-width` and has `white-space: nowrap`, so the box grows to fit the date and the date stays on one line.
- Short dates are unchanged: they keep the 155px box and the same position.
- If the feed name, authors and date do not fit on one row, the date moves to the next line as a whole (the `flex-wrap` from #9369), instead of breaking in the middle.
- In the `max-width: 840px` block the date is reset to `min-width: 0; white-space: normal`, so nothing can overflow on very narrow screens. The phone layout from #9369 is unchanged.
- `frss.rtl.css` was regenerated with `rtlcss`.
2026-10-04 18:21:22 +02:00
Inverle 4e5e142cd0 Remove vulnerable and unused code path for displaying errors (#9395)
If we were to remove or rename `errorController`, an HTML injection could potentially be introduced due to the fallback code path, that directly echoes the logs without any escaping.

(but mainly removing it to reduce the amount of code, and since it's unused)
2026-10-03 23:28:39 +02:00
d5e13066bc Fix NAT64 feed fetching on IPv6-only hosts (#9372)
* Fix NAT64 feed fetching on IPv6-only hosts

Closes #9371
Regression from https://github.com/FreshRSS/FreshRSS/pull/9195

Changes proposed in this pull request:

* Fix feed fetching on IPv6-only hosts using NAT64.
* Preserve SSRF protection by validating the IPv4 address embedded in RFC 6052 NAT64 addresses before allowing it in `CURLOPT_RESOLVE`.
* Add regression tests for both public and private/reserved NAT64 addresses.

* Minor formating

* Add test tearDown

* RFC8215 64:ff9b:1::/48
Credits: @onurcangnc

---------

Co-authored-by: Viktor Platov <TapuGitHub@users.noreply.github.com>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-10-03 21:24:33 +02:00
Nikolai ShcheglovandAlexandre Alapetite f65d2760e3 Fix domain-wide Retry-After (#9390)
* Fix domain-wide Retry-After

- Fix the domain-wide HTTP `Retry-After` for public servers, which has not applied since #8195 (FreshRSS 1.28.0).
  - `getRetryAfterFile()` passed the bare host name to `Minz_Request::serverIsPublic()`. That function expects a URL, so it always returned `false`.
  - So a 429 or 503 paused only the URL that got it, despite the log saying "For that domain, will first retry after …", and FreshRSS went on requesting the other feeds of that server. With several Reddit feeds, for instance, each one got its own 429 in turn.
  - `serverIsPublic()` now gets the URL. Its answer is kept per host for the rest of the request, because it resolves the host name (`dns_get_record()`), and a refresh may load many feeds of the same host.
- Fix the per-URL `Retry-After` of servers on a local network (#8195), which never applied to feeds whose URL, as stored, differs from the URL as requested.
  - Stored URLs are HTML-encoded, e.g. `&amp;` in an RSS-Bridge URL, and may end with `#force_feed`.
  - `FreshRSS_Feed::load()` checked the stored URL, while the pause is stored for the URL as requested. It now checks the requested URL, as `loadJson()` and `loadHtmlXpath()` already do.

* Minor final

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-10-03 10:22:47 +02:00
Nikolai ShcheglovandAlexandre Alapetite a93bd27b7d Fix muting of feeds gone with HTTP 410 (#9391)
* Fix muting of feeds gone with HTTP 410

A feed answering HTTP 410 Gone is meant to be muted (#3561), but:

* Since #6037, FreshRSS_Feed_Exception extends Minz_Exception, which
  resets any code other than its own error levels to 0, so the check for
  410 never matched. FreshRSS_Feed_Exception now keeps the HTTP status
  code it is given.
* FreshRSS_FeedDAO::mute() mutes by negating the TTL, which leaves a feed
  with the default TTL (0) unmuted. Mute the feed the way the feed
  settings and dynamic OPML categories do instead.

* A bit of cleaning

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-10-03 09:59:51 +02:00
OrangeJuice a4dbc4240d i18n(de): follow-up to #9370 review; add Max Oberrauch to credits (#9385)
Follow-up to #9370, applying @math-GH's review:

- `latest`: „Veröffentlichte Version“ instead of „Versionierte Veröffentlichung“. I didn't go back to „Stabile Version“ because #9270 moved the English away from "stable" on purpose, as @Inverle pointed out; „Veröffentlichte Version“ pairs with „Aktueller Entwicklungsstand“ for edge.
- „berücksichtigen“ instead of „einbeziehen“, in both include labels.
- `global_hint` without „Sie“, as suggested.
2026-10-02 10:16:31 +02:00
Abdelrhman Mohamed e7cbb59c66 Wrap the reader view article subtitle on narrow screens (#9369)
In the reader view, the feed name, authors and date share one
horizontal-list row whose items are `flex: 0 0 auto` and whose date is
a fixed 155px wide. The row could neither wrap nor shrink, so a long
feed name or author list pushed the date past the article box, and on
a phone the whole page scrolled sideways.

Let the row wrap and let its items shrink, so a long feed name is
ellipsized and the authors wrap inside the box. On narrow screens the
date then sits on its own line, so drop its fixed width there.
Rows that already fit are laid out as before.

Closes #9360
2026-10-02 08:40:33 +02:00
Alexandre Alapetite b531e78ec7 Changelog
Including https://github.com/FreshRSS/FreshRSS/pull/9270#issuecomment-5941042548
2026-10-02 08:33:56 +02:00
dependabot[bot] b3090b007e chore(deps): bump ruby/setup-ruby from 1.324.0 to 1.326.0 (#9381)
Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.324.0 to 1.326.0.
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](https://github.com/ruby/setup-ruby/compare/a0102e0972be65f351c307e2d64b9314a57c8073...762794c140bbeda0f1224786aa33b4b46783a6c1)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.326.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-01 21:16:39 +02:00
dependabot[bot] 4bf9015b70 chore(deps): bump docker/setup-qemu-action from 4.3.0 to 4.4.0 (#9380)
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 4.3.0 to 4.4.0.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/1f40c72289eff860ee54a304f1438e3cff362e0a...99012661954931238ded8c8b007157a8430204e1)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-version: 4.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-01 21:11:09 +02:00
dependabot[bot] c5ce9a84af chore(deps): bump docker/setup-buildx-action from 4.3.0 to 4.4.1 (#9379)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 4.3.0 to 4.4.1.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/37fe631027851001ddb9b187196cc803df7f5f0e...f87e5991a6d7451dcb8d9637bfbc97413f497069)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: 4.4.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-01 21:04:25 +02:00
dependabot[bot] ab1c94f469 chore(deps): bump docker/build-push-action from 7.3.0 to 7.4.0 (#9378)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 7.3.0 to 7.4.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/53b7df96c91f9c12dcc8a07bcb9ccacbed38856a...c3c9e263c25d99ce0380d002d59b67737d91b0dc)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-01 20:58:12 +02:00
Alexandre Alapetite c351fb304f Changelog 2026-10-01 20:52:41 +02:00
OrangeJuice 573078baa3 i18n(de, it): translate remaining TODO strings and review DIRTY ones (#9370) 2026-10-01 20:07:32 +02:00
Nikolai Shcheglov 1f6d7853b3 Fix error when opening a label menu in sidebar (#9377)
Since #9170, opening the menu of a label in the sidebar throws
`TypeError: Cannot set properties of null (setting 'href')`, as the
menu of labels has no website link. The rest of the click handler is
then skipped, so for instance the menu does not flip upwards when there
is no room below it.

Assisted-by: Claude <noreply@anthropic.com>
2026-10-01 08:24:29 +02:00
Inverle 1f055da218 Avoid writing to log files during unit tests (#9373)
* Avoid writing to log files during unit tests

* Translate PHPDoc of `record()`

* Move environment variable into `phpunit.xml` and use tabs for indents
2026-09-30 21:50:47 +02:00
Inverle 05bfbb9f33 Move PHPUnit flags to a config file and use strictest failure mode (#9374)
See:
* https://docs.phpunit.de/en/12.5/xml-configuration-file.html#the-failonallissues-attribute
* https://docs.phpunit.de/en/12.5/xml-configuration-file.html#the-displaydetailsonallissues-attribute
2026-09-30 21:36:38 +02:00
Inverle 01afc061d7 Slightly more robust SessionTest and cleanup (#9376)
* Slightly more robust SessionTest and cleanup

Improvement of #9311

I noticed that my `/tmp` directory got filled up with random `sess_*` files and empty `frss_test_sessions_*` directories after repeatedly running PHPUnit, which means there was no proper cleanup being done in the tests.

See the first commit for changes, since I also moved the test to a more appropriate directory name (alongside `tests/lib/Minz`, `tests/app/Minz` was newly added in #9311).

Before the PR:
* Check output of `ls -lah /tmp/{frss_test_sessions_*,sess_*}; rm -r /tmp/{frss_test_sessions_*,sess_*}` to confirm there are initially no temporary files existing.
* Run `composer run phpunit`.
* Check output of the previous command again to confirm there is a new `sess_*` file and an empty `frss_test_sessions_*` directory.

After the PR:
* Check output of `ls -lah /tmp/{frss_test_sessions_*,sess_*}; rm -r /tmp/{frss_test_sessions_*,sess_*}` to confirm that no temporary files exist initially.
* Run `composer run phpunit`.
* Check output of the previous command again to confirm there are no temporary files, since they are now being cleaned up correctly.

* Move SessionTest from tests/app/Minz to tests/lib/Minz
2026-09-30 21:34:27 +02:00
Alexandre Alapetite e247edb1fb Fixes for PHPStan 2.2.16 (#9368)
Bump other dev dependencies as well, prior to upcoming release 1.30.1
2026-09-30 15:49:06 +02:00
InverleandAlexandre Alapetite 0285dc8970 Check SVG optimization in the tests CI workflow with SVGO (#9361)
* Check SVG optimization in the tests CI workflow with SVGO

Previously it was only recommended by the documentation that SVG images should be optimized using [SVGOMG](https://github.com/jakearchibald/svgomg), the web GUI version of https://github.com/svg/svgo (CLI)


Now all SVG images are optimized, and optimization is mandatory enforced by the tests CI workflow.
\+ SVGs are sanitized of potentially malicious JS code using the https://svgo.dev/docs/plugins/removeScripts/ plugin

* Output prettified SVGs instead and remove unchanged files from stdout

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>

* Use `removeScripts` SVGO plugin to reduce risk of malicious SVGs

* Move the CLI options to the JS config instead

* Disable `removeComments` plugin included in the default preset

* editorconfig, and easier config

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-09-29 16:18:01 +02:00
Antonio Santos 84023d443e Update Antonio Santos website in credits (#9367)
Update my website link in CREDITS.md from antoniosantos.io to otolock.net.
2026-09-29 16:01:49 +02:00
Alexandre Alapetite a8e5e6300b Better enforce feed limits (#9357)
E.g. when added from API
Fix https://github.com/FreshRSS/FreshRSS/issues/8822#issuecomment-5781019651
2026-09-28 10:41:29 +02:00
5a270c02b0 Rotate session ID on all authenticated transitions (CWE-384) (#9333)
* auth: rotate session ID on all authenticated transitions (session fixation)

The PHP session ID was regenerated on explicit form login, reauth, logout and
password change, but NOT when access is (re)established from a remember-me
cookie, via HTTP authentication, or on self-registration auto-login (CWE-384),
so a fixed session ID could become authenticated.

Regenerate the session ID at those transitions too: in FreshRSS_Auth::init
when accessControl() first grants access (covers remember-me restore and HTTP
auth; skipped for auth_type 'none', which has no authentication boundary), and
in the self-registration auto-login path, mirroring the existing form-login
idiom. Also enable session.use_strict_mode before session_start as defence in
depth so an uninitialised, attacker-supplied session ID is not adopted.

* auth: avoid duplicate cookie during session rotation

* Code preferences, shorten some comments

---------

Co-authored-by: Inverle <inverle@proton.me>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-09-28 10:39:21 +02:00
Yuchen Shi 818b57a9a9 Update documentation of TRUSTED_PROXY syntax and document limitations. (#9283)
* Update documentation of TRUSTED_PROXY syntax and document limitations.

Single IPs are now supported as of #9301.
Document the existing limitation of domain names, see #9210.

For IPs without `/`, I manually tested the behavior and found requests got rejected on my server before #9301. After #9301 is merged, I've tested again and found that requests are now authorized as expected. So I've updated the corresponding documentation to say "_IPs or_ ranges" where applicable.

Domain names are still silently ignored as of writing. I looked at the code, as described in #9210 investigation steps, and concluded that they are WAI (working as _implemented_ , not sure if _intended_ ). I don't particularly like the existing behavior (failures with no debuggable warnings or logs) but I try to document it as-is without judgement.

* Update TRUSTED_PROXY comments accordingly for Docker usage.

Single IPs are now supported as of #9301.
Document the existing limitation of domain names, see #9210.
2026-09-28 08:53:12 +02:00
GigiandAlexandre Alapetite cd42dc7509 Bound ZIP import against decompression bombs (CWE-409) (#9332)
* importExport: bound ZIP import against decompression bombs

ZIP import read every archive member into memory via getFromIndex() with no
limit on member count, per-member or total uncompressed size, or compression
ratio, so a small crafted upload could exhaust memory (CWE-409).

Enforce a member-count limit, per-member and aggregate uncompressed-size
limits and a compression-ratio ceiling from the central-directory metadata,
and additionally cap the real decompressed size while streaming each member
(the declared size is attacker-controlled and can under-report). Oversized or
over-compressed members are skipped and the loop stops once the budget is
reached; a realistic export (an OPML plus a few JSON files) stays well within
the limits.

* Fix lookup by name and total calculation

* Fix locateName regression
Duplicate entry name: keep only the first occurrence, but allow full paths

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-09-27 21:25:08 +02:00