Commit Graph

7296 Commits

Author SHA1 Message Date
IEEE-754
4cb2bb5be0 i18n: Improve Traditional Chinese translations (#9037)
**Change(s)**
- Add missing punctuation
- Add missing spaces in the date format
- Add some new translations

**File(s) changed**
`app/i18n/zh-TW/{admin,conf,gen,install,sub}.php`
`README.md`
`README.fr.md`
2026-07-12 22:42:13 +02:00
Christos Longros
9f40a9b7f8 Add Christos Longros to CREDITS.md (#9040)
Adding myself to the contributors list, following #9038 (Greek translation improvements).
2026-07-12 14:13:24 +02:00
Christos Longros
4b378ebea0 Improve Greek (el) translation (#9038)
* Improve Greek (el) translation

Complete install.php and translate reading-view sorting and
menu strings in index.php.

* Update translation completion tables
2026-07-12 12:36:23 +02:00
Gerard Alvear Porras
e24ac6f21c Sort labels with locale-aware collation (#9023)
Labels (tags) were sorted by the database's raw byte/ASCII collation
via ORDER BY name, so accented or non-Latin label names sorted after
all ASCII names instead of near their base letter.

Apply the same FreshRSS_Context::localeCompare() sort used for
categories, feeds, and shares (#8985) to TagDAO::listTags(), fixing
the last remaining sub-item of this issue; the others were already
resolved by #6212.

Fixes #6211

Co-authored-by: Gerard Alvear <gerard.alvear@logiqd.me>
2026-07-11 17:35:33 +02:00
Gerard Alvear Porras
e95243ae68 Document OIDC token endpoint authentication method (#9027)
Explain that mod_auth_openidc defaults to client_secret_basic since
our reference Apache configuration does not set
OIDCProviderTokenEndpointAuth. If the identity provider's discovery
metadata advertises a token_endpoint_auth_methods_supported array
instead, mod_auth_openidc picks the first mutually supported method
from that array rather than falling back to client_secret_basic.
Also point to the .htaccess override for administrators who need
something else.

This only addresses the token-endpoint-auth-method part of #6102;
the redirect-URI-port question raised in that issue is out of scope
here.

Addresses the token-endpoint-auth-method part of #6102

Co-authored-by: Gerard Alvear <gerard.alvear@logiqd.me>
2026-07-11 17:35:01 +02:00
Inverle
0f0b696cdf Display slider after submit for all buttons in feed/update.phtml (#8999)
Slight improvement of https://github.com/FreshRSS/FreshRSS/pull/8612
2026-07-11 17:04:12 +02:00
TowyTowy
ad78838ffc Keep search and state filters when marking articles as read (#9007)
* Keep search and state filters when marking articles as read

Marking articles as read (e.g. "mark all as read") POSTs to
entry?a=read and, for non-AJAX requests, redirects back to the index.
That redirect rebuilt its parameters without the current `search` and
`state`, so the view fell back to the default state and the active
search was dropped, forcing the user to re-apply their filter.

Carry `search` and `state` through the redirect, mirroring the existing
handling for `order`/`sort`, so the filtered view is preserved.

Fixes #8671

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

* Reduce comments a bit

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-07-09 21:13:14 +02:00
Jam Balaya
3d04c8ef49 Prefer OS-bundled Japanese fonts when UI language is Japanese (#9002)
Add a :lang(ja)-scoped font-family in the shared frss.css so kanji/kana
render with Japanese glyphs on Japanese UIs, without affecting Chinese
(zh-CN/zh-TW) users. Revives the intent of PR #5671 with a
cross-platform font list. frss.rtl.css is regenerated via rtlcss.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 21:01:53 +02:00
TowyTowy
f7c4fbeeed Redirect after saving user CSS/JS so changes apply immediately (#9006)
Saving custom CSS/JS rendered the response from the pre-save state (no
Post/Redirect/Get), so the stylesheet cache-busting URL was stale and
the change only appeared after a manual reload, which reads as erratic
behavior. Redirect back to the extension config after save, matching
the pattern used elsewhere in the codebase.

Fixes #8795

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 16:37:49 +02:00
Inverle
143cb09418 Minz: Skip loading JS/CSS asset if it's already in the list (#9000)
Fixes `Uncaught SyntaxError: redeclaration of const freshrssSliderLoadEvent` error shown in console on e.g. `/i/?c=subscription&id=1` due to https://github.com/FreshRSS/FreshRSS/pull/8973
2026-07-09 11:22:37 +02:00
Jam Balaya
7744f1fed9 WebSub: ignore http/https scheme difference in Self URL comparison (#9005)
* WebSub: ignore http/https scheme difference in Self URL comparison

The PubSubHubbub endpoint logged 'Self URL does not match registered
canonical URL' whenever a feed's self URL differed from the registered
canonical URL only by http vs https (common with http->https redirects),
spamming the log. Compare the URLs ignoring the http/https scheme while
still requiring host/path/query to match exactly.

Closes #3087

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Stylistic preferences

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-07-09 07:50:42 +02:00
Inverle
6908d998d4 Fix .dockerignore being ignored during build in CI (#9001)
For example:

f201061345/.dockerignore (L6)

`/docs/` is included in `.dockerignore`, but currently if you check `docker exec freshrss ls -la`, you'll notice `/docs/` is being listed despite that.

This is because we are using git context for the build instead of path context, see: https://github.com/docker/build-push-action#git-context

Compare the runs https://github.com/Inverle/FreshRSS/actions/runs/28884689769/job/85681744466 and https://github.com/Inverle/FreshRSS/actions/runs/28885427454/job/85684280287 by CTRL+F'ing for `.dockerignore` in the `Build and push Docker images` step.
In the second run, a line `#5 [internal] load .dockerignore` is printed, but not in the first run without `context: .`

Additionally, it can be confirmed this fix is working by checking the `ghcr.io/inverle/freshrss:docker-testing-alpine` image for the `/docs/` directory.
2026-07-08 20:46:35 +02:00
Cactus
0b018adfc2 Clariffied netnews wire podcast compatibility (#8991)
* Clariffied netnews wire podcast compatibility

Netnewswire is unable to play podcasts.

* Update Netnewswire status in README.fr.md

* Fix Unicode

---------

Co-authored-by: Inverle <inverle@proton.me>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-07-07 21:10:53 +02:00
Jam Balaya
f201061345 Feeds tree: sort feed names with locale-aware collation (#8985)
## Problem

The feed **tree** (left sidebar) and the **feed-title view** (main body) order feeds differently for names with accents or symbols. As reported in #8300, a Spanish feed starting with `Ú` appears **last** in the tree, after every ASCII-named feed.

The tree is sorted in PHP by `FreshRSS_Category::sortFeeds()` with `strnatcasecmp()`, which compares raw UTF-8 **bytes** — so any name starting with a non-ASCII character (`0xC3…` for `Á`, `Ñ`, `Ú`, …) sorts after `A–Z`. The main view is sorted by the database according to its collation, which orders accented letters near their base letter — hence the mismatch (as @Alkarex noted in the issue).

Closes #8300.

## Change

`sortFeeds()` now compares with a `Collator` (`ext-intl`, already a hard requirement) for the user's language, falling back to the previous `strnatcasecmp()` if a collator cannot be created:

```php
$collator = \Collator::create(FreshRSS_Context::hasUserConf() ? FreshRSS_Context::userConf()->language : '');
```

Sorting a Spanish set, before / after:

```
old: banana, Manzana, nube, Zorro, Ábaco, Ñandú, Úlcera, árbol
new: Ábaco, árbol, banana, Manzana, nube, Ñandú, Úlcera, Zorro
```

This makes the tree order locale-aware and much closer to the main view. Exact parity with the main view still depends on the database collation (which is admin/DB-specific and cannot be reproduced generically in PHP), but the "accented names sort last" problem is gone.

* Feeds tree: sort feed names with locale-aware collation

The feed tree sorted names byte-wise with strnatcasecmp(), which places
names starting with a non-ASCII character (e.g. an accented capital such
as "U-acute") after every ASCII name. Use a Collator for the user's
language so accented and non-ASCII names sort near their base letter,
closer to the database collation used on the main feed-title view.

For https://github.com/FreshRSS/FreshRSS/issues/8300

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Guard Collator with class_exists() so intl stays optional

The intl extension is only a recommended (not required) dependency, but
sortFeeds() called \Collator::create() unconditionally when a user language
was set. On installs without intl the \Collator class does not exist, so the
call raised a fatal "Class \"Collator\" not found" — effectively promoting
intl from recommended to required.

Guard the call with class_exists('Collator'): when intl is absent, fall back
to the previous byte-wise strnatcasecmp() sort. Locale-aware ordering stays a
progressive enhancement and the listed requirements are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Shorten the sortFeeds() collation comment per review

Trim the rationale comment to a concise four lines as suggested in review,
keeping the locale-aware/fallback and class_exists() reasoning.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Stylistic preference

* Factorise localeCompare

* Minor code preference

* Preserve natural locale sort behaviour

* Avoid repeated locale lookup in comparator

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-07-07 15:42:12 +02:00
Jam Balaya
ce7a196034 Remove unused simple layout (#8998)
Closes #6223.
Supersedes the investigation draft in #6765.

## Summary
- Removed the remaining explicit uses of the `simple` layout from the email-validation flows.
- Deleted `app/layout/simple.phtml` so those pages now use the shared `layout.phtml`.
- Kept the existing `disable_aside` behavior for the profile page while an email validation token is pending.

## Notes
The replacement for `simple.phtml` is the normal shared layout. Access while email validation is pending is still constrained by the existing `FreshRSS::checkEmailValidated()` route guard, which allows the validation/profile/logout paths and forwards other routes to `user#validateEmail`.
2026-07-07 15:04:11 +02:00
Jam Balaya
5014915c40 Fix article hover date visibility (#8997)
- Keep the article title in its own grid area on hover when the article row also shows a date.
- Restore a small spacing between the hovered title and the date.
- Regenerate the RTL stylesheet counterpart.

Fixes #8994

## Screenshots

![FreshRSS #8994 hover date comparison](https://raw.githubusercontent.com/JamBalaya56562/FreshRSS/assets-8994-hover-date/docs/screenshots/freshrss-8994-hover-date-comparison.png)

The comparison uses a synthetic hover fixture with FreshRSS article-row DOM and theme CSS, so no local feed data is included.
2026-07-07 13:59:25 +02:00
i @man
2188070aa6 Add option to keep or reset article sort order when navigating (#8969)
* Add option to keep or reset article sort order when navigating

Adds a new per-user reading option, "Keep the current sort order when
navigating between categories and feeds" (config key: sticky_sort), under
Settings > Reading > "Left navigation: Categories". It defaults to enabled,
which reproduces the current behaviour exactly.

Background (addresses #8953)
----------------------------
Once a sort/order was active in one view, it was propagated to every sidebar
link and to the "mark all as read" redirect. Opening another category then
ignored that category's own defaultSort/defaultOrder, because FreshRSS_Context
only applies those defaults when sort/order are absent from the request. As a
result the current view's sort (whether chosen manually or resolved from that
view's default) "bled" into the next category/feed.

Behaviour of the new option
---------------------------
- ON (default): unchanged. The current sort/order stays sticky while
  navigating, exactly as before.
- OFF: sidebar links and the "mark all as read" redirect no longer carry
  sort/order, so each target resolves its own order in FreshRSS_Context:
  feed/category defaultSort/defaultOrder, falling back to the global Reading
  sort criterion when none is configured.

order/sort propagation across the UI (for reference)
----------------------------------------------------
- Categories & feeds (sidebar): now gated by sticky_sort (app/layout/aside_feed.phtml).
- "Mark all as read" -> next category, both the top navigation button and the
  stream-footer button: now gated by sticky_sort
  (app/Controllers/entryController.php::readAction, non-AJAX redirect).
- Custom user queries: unaffected. A query's link is a self-contained URL built
  from that query's own saved parameters, so switching query A -> B never
  carried A's sort; no option is needed there.
- Stream transition links when sorting by category/feed name: intentionally
  left unchanged (out of scope; the sort is intrinsic to that grouping).

Compatibility
-------------
- Not a breaking change: the default (true) reproduces the previous behaviour.
- No database migration. The setting is a standard user configuration value
  with its default declared in config-user.default.php, so existing users keep
  the previous behaviour transparently.
- The read/unread state filter still persists across navigation regardless of
  this option.

i18n
----
English strings authored; en-US marked as IGNORE. Translations for the other
25 languages were produced with an automated (AI) translation service and
should be reviewed by native speakers.

* Update app/i18n/en/conf.php

Co-authored-by: Frans de Jonge <fransdejonge@gmail.com>

* Comments preference

* Update app/i18n/en/conf.php

Co-authored-by: Frans de Jonge <fransdejonge@gmail.com>

* i18n updates and comment

* Update translations to match reworded sticky_sort strings

Re-applies the 24 non-English/French translations of the "sticky_sort"
reading option after the English and French wording was updated to
"Keep manual sort order during navigation".

* improve Dutch

* i18n DIRTY

* i18n en: custom sort order

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Co-authored-by: Frans de Jonge <fransdejonge@gmail.com>
2026-07-07 11:04:31 +02:00
Jam Balaya
271257be42 Fix statistics repartition averages (#8996)
* Fix statistics repartition averages

* Minor code preference

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-07-07 10:42:53 +02:00
Jam Balaya
310bcb5e90 Add read status hook for entries (#8995)
- Add a new `EntriesRead` / `entries_read` hook for extensions.
- Trigger the hook when `markRead()` changes entry read/unread state for explicit entry IDs.
- Cover both the default DAO path and the SQLite/PGSQL DAO path.
- Add Minz hook tests for the new hook signature and argument passing.

## Why

Extensions can already react to favorite/bookmark changes through `EntriesFavorite`. This adds the matching read/unread hook requested in #4051 for extensions that need to collect stats or react to manual read state changes.

Closes #4051
2026-07-07 09:04:32 +02:00
Inverle
cb13091b37 Fix GH issue links with label filter in docs (#8993)
The "good first issue" and "help wanted" links under https://freshrss.github.io/FreshRSS/en/contributing.html#fix-a-bug aren't working.
2026-07-06 13:22:52 +02:00
Jam Balaya
241c7fb425 Respect simplepie_syslog_enabled for cache-hit debug logs (#8986)
Two "uses cache" LOG_DEBUG syslog() calls were emitted on every feed
refresh regardless of the simplepie_syslog_enabled setting, so users who
disabled it still saw "FreshRSS SimplePie uses cache for ..." spam in
syslog (issue #8540). Guard both with simplepie_syslog_enabled, like the
neighbouring SimplePie GET logs already are. Real error and fatal logs
are left untouched.

For https://github.com/FreshRSS/FreshRSS/issues/8540

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:19:33 +02:00
Inverle
c3d0bd5b55 Clarify in docs favicons/ should not be skipped during backup (#8992)
Alternative for https://github.com/FreshRSS/FreshRSS/pull/8972, at least until the migration system is improved to support rollbacks.
2026-07-06 11:16:56 +02:00
Frans de Jonge
612ac4f117 Notifications: pluralize the "new articles" count message (#8988)
* Generate new articles notification string in PHP

Closes #6470

Changes proposed in this pull request:

- Generate notifications string  in PHP
- Use plurals support

* New articles notification: switch to plural forms

* README status

* fix paramInt invocation

* i18n

* make fix-all

* Apply suggestion from @Frenzie

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-07-06 11:16:29 +02:00
utkutibet
56d31c53de Improve turkish translation 3 (#8989)
* Translate remaining Turkish strings

* Translate remaining Turkish strings

---------

Co-authored-by: Utku Tibet <utkutibet@Utkus-MacBook-Pro.local>
2026-07-05 14:20:15 +02:00
Jam Balaya
ffc5a966c3 Migrate markdownlint-cli to markdownlint-cli2 (single config file) (#8987)
* Migrate markdownlint-cli to markdownlint-cli2

Replace markdownlint-cli with markdownlint-cli2 and consolidate the three
separate configuration points (.markdownlint.json rules, .markdownlintignore
excludes, and the '**/*.md' glob in the npm scripts) into a single
.markdownlint-cli2.jsonc holding config + globs + ignores.

The npm script names (markdownlint / markdownlint_fix) are unchanged, so the
CI step and the test/fix compound scripts need no change. markdownlint-cli2
v0.23.0 bundles the same markdownlint v0.41.0, so linting behaviour is
identical (112 files, 0 errors).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Add JSONC to .editorconfig

* Reduce obvious comments

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-07-05 14:18:49 +02:00
Jam Balaya
cf2ceafca1 OPML: include each feed's refresh interval (TTL) in export/import (#8982)
Feeds moved between instances via OPML lost their refresh interval,
forcing manual reconfiguration. Add a 'frss:ttl' attribute (signed, so a
negative value also carries the muted state) to the OPML export, and read
it back on import. Documented in docs/en/developers/OPML.md.

For https://github.com/FreshRSS/FreshRSS/issues/5914

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 21:55:13 +02:00
Jam Balaya
988c678634 Fever API: log the client IP address on authentication failure (#8981)
A failed Fever API auth returns {"auth":0} with HTTP 200, so from the web
server log a failure is indistinguishable from a success and fail2ban
cannot act. The failure was already logged to API_LOG, but without the
client IP. Append the remote IP (Minz_Request::connectionRemoteAddress())
so a fail2ban filter watching data/users/_/log_api.txt can ban repeated
attempts.

For https://github.com/FreshRSS/FreshRSS/issues/6814

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 21:33:09 +02:00
Jam Balaya
6351a71938 cli/health.php: output a diagnostic when the health check fails (#8980)
Previously the Docker healthcheck script exited with a bare die(1) /
die(2) and no message, so users only saw 'unhealthy' with no clue why.
Print an informative reason to STDERR before each failing exit (a
connection/HTTP error, or a response that is not a FreshRSS page),
without changing the exit codes relied on by Docker HEALTHCHECK.

For https://github.com/FreshRSS/FreshRSS/issues/8026

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:59:30 +02:00
Jam Balaya
c90e48fd62 Report new articles count per feed in actualize_script output (#8948)
* feat: report new articles count per feed in actualize_script output

Closes #8291

## Changes proposed in this pull request

`app/actualize_script.php` now reports, for each feed that received new articles, how many new articles were fetched — in addition to the existing per-user summary. This makes batch refreshes (cron / systemd timers) much more informative.

Example output:

```
FreshRSS actualize admin…
	10 new article(s) from feed: FreshRSS releases
	3 new article(s) from feed: Some other blog
```

The feature is implemented **entirely within the CLI script**, reusing the existing extension-hook mechanism that the script already uses for the actualization mutex — no change to `feedController` or to any other behaviour:

- `FeedBeforeActualize` records each feed's name.
- `EntryBeforeAdd` counts new entries per feed. This hook fires only in the "genuinely new GUID" branch of the actualization loop (updated articles go through `EntryBeforeUpdate`), so the count matches the controller's own `$nbNewArticles` counter. Because the counting hook is registered after `$app->init()`, it runs last in the chain and is skipped for entries dropped by another extension — i.e. it counts only articles that are actually added.

Counts are printed through the script's existing `notice()` helper, so they reach STDOUT regardless of the `environment` setting (unlike `Minz_Log::notice`, which is suppressed in `production`).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Minor

* Remove tab
The tab character is escaped in some logs, e.g.

```
 [notice] --- \x091 new article(s) from feed: L’Express
```

* Sort per-feed output and also report updated articles

Addresses review feedback on #8948:
- Sort the per-feed report by descending article count, then feed name.
- Also count updated articles (via EntryBeforeUpdate) and report them
  alongside new ones, e.g. '10 new, 2 updated article(s) from feed: X'.
  EntryBeforeAdd fires only for new articles (new-GUID branch), so
  updated articles need the separate EntryBeforeUpdate hook.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Reduced code

* Do not report feeds with no new or updated articles

FeedBeforeActualize initializes every actualized feed in $feedStatistics
and fires before the TTL/mute skips, so skipped or unchanged feeds would
otherwise print an empty count ('  article(s) from feed: X'). Skip them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Minor code logic preference

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-07-04 17:38:40 +02:00
Inverle
13c2b68806 Keep scroll position of slider after form submit (#8974)
Follow-up of https://github.com/FreshRSS/FreshRSS/pull/8612#issuecomment-4078560064

Depends on https://github.com/FreshRSS/FreshRSS/pull/8973
2026-07-04 13:32:52 +02:00
Harry Andreolas
44b5c132b8 i18n: Update el (Greek) translations (#8977)
* Update el (i18n)

* Update CREDITS.md
2026-07-04 12:26:51 +02:00
utkutibet
da52ac4ee0 Translated remaining Turkish strings (#8970)
* Translate remaining Turkish strings

* Trigger CI re-run

* Update translation status

---------

Co-authored-by: Utku Tibet <utkutibet@Utkus-MacBook-Pro.local>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-07-04 12:22:20 +02:00
Inverle
9b43639c88 Fix slider not reinitializing after form submit (#8973)
"Follow-up" of https://github.com/FreshRSS/FreshRSS/pull/8612 (not fixing a regression, just a bug)

Some features like URL observers and custom favicon JS (e.g. *Reset to default* button) wouldn't work, due to `extra.js` not being loaded properly on pages where the slider content was already included in the HTML.
2026-07-04 12:14:05 +02:00
Inverle
8a5f7d24b6 Remove .DS_Store files and update .gitignore (#8971)
The `.DS_Store` files were accidentally added in #8966
2026-07-03 13:28:36 +02:00
utkutibet
2e6e571b91 Worked on Turkish translation (#8966)
* Worked on Turkish translation

* Add my name to CREDITS.md

* Run make fix-all

* Fix credits

---------

Co-authored-by: Utku Tibet <utkutibet@Utkus-MacBook-Pro.local>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-07-03 10:03:55 +02:00
Alexandre Alapetite
339d5c7ef1 Minor Minz_Extension typing (#8952)
Declare some accessors as non-empty-string, to make some extension code slightly nicer, e.g. https://github.com/FreshRSS/Extensions/pull/470
2026-07-02 15:09:07 +02:00
Inverle
a3badc2d2e Fix bad header filtering bypass (#8964)
* Fix bad header filtering bypass

* Sanitize every save using `_attribute('curl_params')`

* Sanitize every read using `attributeArray('curl_params')`
2026-07-02 15:08:32 +02:00
dependabot[bot]
c90c86a5c0 chore(deps-dev): bump phpstan/phpstan-phpunit from 2.0.16 to 2.0.17 (#8960)
Bumps [phpstan/phpstan-phpunit](https://github.com/phpstan/phpstan-phpunit) from 2.0.16 to 2.0.17.
- [Release notes](https://github.com/phpstan/phpstan-phpunit/releases)
- [Commits](https://github.com/phpstan/phpstan-phpunit/compare/2.0.16...2.0.17)

---
updated-dependencies:
- dependency-name: phpstan/phpstan-phpunit
  dependency-version: 2.0.17
  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>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-07-01 21:38:02 +02:00
dependabot[bot]
93e83943a3 chore(deps-dev): bump phpstan/phpstan from 2.2.2 to 2.2.3 (#8962)
* chore(deps-dev): bump phpstan/phpstan from 2.2.2 to 2.2.3

Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan-phar-composer-source) from 2.2.2 to 2.2.3.
- [Commits](https://github.com/phpstan/phpstan-phar-composer-source/commits)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-version: 2.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Ignore a could of redundant tests, for keeping additional safety

---------

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>
2026-07-01 21:35:39 +02:00
dependabot[bot]
abd683e8a0 chore(deps-dev): bump the stylelint group with 2 updates (#8958)
Bumps the stylelint group with 2 updates: [stylelint](https://github.com/stylelint/stylelint) and [@stylistic/stylelint-plugin](https://github.com/stylelint-stylistic/stylelint-stylistic).


Updates `stylelint` from 17.12.0 to 17.14.0
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/17.12.0...17.14.0)

Updates `@stylistic/stylelint-plugin` from 5.2.0 to 5.2.1
- [Release notes](https://github.com/stylelint-stylistic/stylelint-stylistic/releases)
- [Changelog](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint-stylistic/stylelint-stylistic/compare/v5.2.0...v5.2.1)

---
updated-dependencies:
- dependency-name: stylelint
  dependency-version: 17.14.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: stylelint
- dependency-name: "@stylistic/stylelint-plugin"
  dependency-version: 5.2.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: stylelint
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-01 20:58:01 +02:00
dependabot[bot]
e8bcb4021d chore(deps): bump ruby/setup-ruby from 1.310.0 to 1.315.0 (#8959)
Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.310.0 to 1.315.0.
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](afeafc3d1a...0dafeac902)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.315.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-07-01 20:57:35 +02:00
dependabot[bot]
334796d1c4 chore(deps): bump actions/cache from 5 to 6 (#8961)
Bumps [actions/cache](https://github.com/actions/cache) from 5 to 6.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-01 20:57:09 +02:00
dependabot[bot]
ddf2976e83 chore(deps): bump actions/checkout from 6 to 7 (#8963)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-01 20:56:45 +02:00
Inverle
6984c22b5c Fix feed dropdown bugs due to hash desync (#8949)
Fixes regression caused by https://github.com/FreshRSS/FreshRSS/pull/8335
To reproduce it, open any dropdown in the aside, reload the page, and try to open the same dropdown - it will disappear

To explain the issue more clearly, the dropdown menu wouldn't show because earlier its opacity is set to 0%, and after clicking the same dropdown after a page reload, the hashchange event wouldn't trigger to restore the previous opacity, and also the second listener would trigger to remove the dropdown if you opened it again.

Maybe https://github.com/FreshRSS/FreshRSS/issues/6156 is relevant here

Also a CSS change to stop showing the dropdown toggle icon of the previously opened dropdown after a page reload while the dropdown was open.
2026-06-28 21:38:37 +02:00
Inverle
dcec27c69d Add SSRF mitigations using filter_var and CURLOPT_RESOLVE (#8400)
* Add SSRF mitigations using `filter_var` and `CURLOPT_RESOLVE`
The idea is to prevent FreshRSS from sending any HTTP requests to internal services, except for the ones that are explicitly allowed in the config.

Based on 6e82b46a48/lib/filelib.php (L3818) and https://github.com/symfony/symfony/blob/8.1/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php

https://github.com/FreshRSS/simplepie/pull/76
https://github.com/FreshRSS/simplepie/pull/78

* Add allowlist setting in Web UI

* make readme

* Update app/i18n/fr/admin.php

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

* make readme again

* make readme

* Further work

Still WIP and needs testing etc.

* Readd previous if check for domain combination allowlist

* Turn POST to GET after redirect

* Improve

* Update config.default.php

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

* make readme

* Skip SSRF check if `CURLOPT_PROXY` is set

* make readme

* Fix `!empty()` mistake

* Respect max redirects feed option when fetching with `httpGet()`

* Respect max redirects during SimplePie fetching + fix bypass

bypass fix: `CURLOPT_FOLLOWLOCATION` was moved below so that emulated redirects are enforced.

* Avoid FreshRSS and Minz code in SimplePie
https://github.com/FreshRSS/FreshRSS/pull/8400#discussion_r2935375980

* Corrected hook code

* phpdoc wrong return type

* Add CIDR support in allowlist

* Implement simple DNS caching

* Suppress `dns_get_record()` warnings

* A bit of proof-reading

* Minor typo

* Fix proxy logic

* Fix HTTP POST redirect logic

* Proofread checkCIDR
Add fixes for several situations

* Remove credentials from URL in logs

* Ensure `CURLOPT_FOLLOWLOCATION` is `false` by setting it at the end

* Fix codesniffer long line

* Fix potential bypass due to wrong return value

If there were no records returned by `dns_get_record()`, no overrides to `CURLOPT_RESOLVE` would get passed,
and a potential bypass could occur, when cURL would try to resolve the domain by itself.

* Put the URL at the end in logs

* Add documentation and environment variable support

* make readme

* Fix wrong behavior in case of IP

* Fix duplicate selector in CSS

* Minor type check change

* i18n fr, en

* Minor type check change

* Fix whitespace i18n fr

* make fix-all

* Fix `$ips_ok` not being returned after domain records were cached

* make readme

* PHPStan fix

* make readme

* Minor syntax in SimplePie

* Only return `null` if no allowed IPs were found

* Add wildcard *, help message

* Consistent docs with help message

* i18n: pl

* SimplePie compatibility PHP 7.2

* make fix-all

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

* 💥 Breaking change in the Changelog

* Document `INTERNAL_HOST_ALLOWLIST` in Docker docs

* Remove `Cookie` and `Authorization` headers in `httpGet()` during cross-origin redirect

* Minor whitespace
And same comment convention than below

* Remove authentication headers and change POST to GET on redirect in SimplePie

* Remove .local in Docker example

* Fill in default ports when comparing URL origins

* Remove .local from other places than the Docker example

* Rewrite WebSub subscribe to use `httpGet()`

* make fix-all

* Also unset `CURLOPT_USERPWD` during redirects

* phpcs fix

* Always unset `CURLOPT_FOLLOWLOCATION`

* Bump SimplePie
https://github.com/FreshRSS/simplepie/pull/78

* Update logic for CURLOPT_FOLLOWLOCATION

* Fix PHPStan

* Changelog fix security section

* Update most common RSS Bridge case
https://hub.docker.com/r/rssbridge/rss-bridge

* Replace misleading 127.0.0.1:8080 example for Docker
This does not make sense for a Docker container

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-06-28 18:51:04 +02:00
Alexandre Alapetite
d9dc140a11 Minor bump SimplePie (#8947) 2026-06-27 22:14:25 +02:00
Thomas Vermeer
3161fd1333 fix: move disable button before remove button in user management (#8944)
* fix: move disable button before remove button in user management

The order of action buttons when modifying a user was inconsistent.
The "disable" button appeared after the "remove" button, which is
counterintuitive since disabling a user is a less destructive action
than removing one.

This commit reorders the buttons in `details.phtml` to reflect the
severity of each action, from least to most destructive:
update → purge → promote/demote → disable/enable → delete

Closes #8877

* Remove blank lines

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
2026-06-27 14:29:48 +02:00
Inverle
931d62ab08 Use timing safe comparison for tokens everywhere (#8945)
I already changed some places that were using normal string comparison to hash_equals before, but didn't check other places.

Now the checks should be consistent.
2026-06-27 14:02:20 +02:00
dependabot[bot]
69eff07d92 chore(deps): bump concurrent-ruby (#8940)
Bumps the bundler group with 1 update in the /docs directory: [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby).


Updates `concurrent-ruby` from 1.3.6 to 1.3.7
- [Release notes](https://github.com/ruby-concurrency/concurrent-ruby/releases)
- [Changelog](https://github.com/ruby-concurrency/concurrent-ruby/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ruby-concurrency/concurrent-ruby/compare/v1.3.6...v1.3.7)

---
updated-dependencies:
- dependency-name: concurrent-ruby
  dependency-version: 1.3.7
  dependency-type: indirect
  dependency-group: bundler
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 22:00:22 +02:00
dependabot[bot]
6f1b66eb2b chore(deps-dev): bump faraday (#8939)
Bumps the bundler group with 1 update in the /docs directory: [faraday](https://github.com/lostisland/faraday).


Updates `faraday` from 2.14.2 to 2.14.3
- [Release notes](https://github.com/lostisland/faraday/releases)
- [Changelog](https://github.com/lostisland/faraday/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lostisland/faraday/compare/v2.14.2...v2.14.3)

---
updated-dependencies:
- dependency-name: faraday
  dependency-version: 2.14.3
  dependency-type: indirect
  dependency-group: bundler
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 21:45:35 +02:00