Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.12.0] - 2026-08-05

### Added
- **`GET /api/version` reports the running build.** Returns `version`, `revision` (git SHA), `revisionShort`, `buildDate` and `environment`, so you can confirm what a deployment is actually serving with a single request. The image's OCI labels already carried this, but labels are only readable via `docker inspect` on the host — no help for checking an instance from outside, and absent entirely from locally-built images. CI now passes `BUILD_VERSION` / `BUILD_REVISION` / `BUILD_DATE` as Docker build args from the same metadata that produces the labels; builds without them report `unknown` rather than failing. The endpoint is anonymous by design (the repository is public, so the commit SHA is not sensitive, and no configuration or secret is exposed).
- **Generic external SSO / OIDC login provider** ([#327](https://github.com/PGAN-Dev/PoracleWeb.NET/issues/327)): PoracleWeb can now delegate login to any external OAuth2/OpenID Connect provider, in addition to the built-in Discord and Telegram methods. This enables single sign-on — e.g. pointing PoracleWeb (`alerts.pogoalerts.net`) at the PogoAlerts OAuth2 server so a user who is already signed into the main site lands in PoracleWeb without re-authenticating — but it is fully **provider-agnostic**: any self-hoster can configure their own IdP. The implementation is a configurable twin of the existing Discord flow. Two new endpoints (`GET /api/auth/oidc/login` and `GET /api/auth/oidc/callback`) handle the authorization-code exchange with **PKCE** (state + verifier persisted in HttpOnly cookies, same CSRF protection as the Discord path), then read a configurable **identity claim** (default `discord_id`, falling back to the standard `sub`) from the provider's UserInfo response and look it up in the Poracle `human` table exactly as a direct Discord login would — so existing admin resolution (`GetRolesAsync`), Discord guild-role gating, and the per-user enable/disable all apply unchanged, and PoracleWeb still mints and validates **its own** JWT (no change to token issuance). Provider config (provider name, authorize/token/userinfo URLs, client id/secret, scopes, claim mapping, PKCE flag) comes from `OIDC_*` env vars / `appsettings` — the secret is never stored in the database — and `OIDC_ENABLED` is auto-inferred when the client id and three URLs are all present (same first-time-setup safeguard as Telegram). A separate `enable_oidc` site setting gives admins a runtime on/off toggle (Features → *External SSO* group on the admin settings page; carried by `SettingsMigrationService`), while admins can always log in even when it's disabled so they can re-enable it. The login page renders a "Sign in with {provider}" button (with the same disabled-by-admin hint pattern as Discord/Telegram) whenever the provider is configured, driven by a new `oidc` block on `GET /api/auth/providers`; a new `/auth/oidc/callback` route reuses the existing token-fragment callback handler. New `OIDC_*` keys documented in `.env.example`, new `AUTH.SIGN_IN_OIDC` / `AUTH.ERR_OIDC_*` and `ADMIN_SETTINGS.*_OIDC` / `GROUP_OIDC` i18n keys added to English (other locales fall back to English until translated). Backend tests cover the `providers` oidc block (configured / not-configured / admin-disabled) and the `/oidc/login` redirect (state + PKCE cookies, provider URL + params); frontend tests cover the OIDC button visibility and click delegation. Wiring ReactMap and the PogoAlerts main site to the same provider, and PogoAlerts-side cross-subdomain session cookies, are separate follow-up work.
Expand All @@ -26,6 +28,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Gym-picker images no longer send a `Referer` header to third-party hosts** ([#242](https://github.com/PGAN-Dev/PoracleWeb.NET/issues/242)): the gym picker renders two kinds of remote image — the scanner DB's `gym.url` photo (a Niantic CDN URL in stock Golbat/RDM deployments, though an operator can rewrite the column to point at a self-hosted mirror) and the team-icon fallback from `raw.githubusercontent.com`. Neither carried a referrer policy, so every image request told the remote host which PoracleWeb instance the user was browsing. All four `<img>` tags in `gym-picker.component.html` now set `referrerpolicy="no-referrer"`. Modern browsers already default to `strict-origin-when-cross-origin`, so the pre-existing leak was the origin rather than the full URL — this closes the remainder. Presentation-only: no API, model, or scanner-query change, and `GymSearchResult.Url` still carries the raw scanner URL as before. The photo-proxy endpoint floated in the original issue was **not** implemented: server-side fetching of a URL supplied by a database PoracleWeb does not own would turn a passive disclosure into an authenticated outbound-request primitive from a host that can reach Poracle, Koji, Golbat, and both MySQL servers. A host allowlist applied at projection remains the cheaper option if a deployment ever needs the mirror case handled.
- **App-wide `Referrer-Policy` tightened to `same-origin`, so no remote host learns the instance origin** ([#383](https://github.com/PGAN-Dev/PoracleWeb.NET/issues/383)): the per-element fix above covered the gym picker, but the same leak existed everywhere else the SPA loads a remote resource — uicons from `raw.githubusercontent.com` (`icon.service.ts`, operator-overridable, so possibly a self-hosted mirror) across the Pokémon/raid/egg/lure/invasion/gym/quick-pick lists and dialogs, Discord avatars from `cdn.discordapp.com`, and the Google Fonts stylesheets in `index.html`. Each request disclosed the origin of the PoracleWeb instance being browsed, which for a private or invite-only deployment is the part worth withholding. The security-headers middleware previously sent `strict-origin-when-cross-origin` (the browser default, which sends the origin cross-origin); it now sends `same-origin` — full referrer within the site, nothing at all to third parties — fixing every case in one place rather than annotating tags individually. `no-referrer` was considered and rejected: `AuthController` reads the `Referer` header on `DiscordLogin`, the OIDC login path, and OIDC RP-initiated logout to recover which frontend origin the user came from, validate it against the configured CORS origins, and redirect back there after the provider callback — blanking the same-origin referrer would degrade all three to this host's own origin and bounce users to the wrong place. The header values moved out of the inline lambda in `Program.cs` into a `SecurityHeaders` class so they're assertable without booting the app; the CSP is carried over byte-identical (a test pins it against the original literal). Tests cover the policy value, a guard that it never becomes `no-referrer` or any of the origin-leaking values, and the previously untested `AuthController` origin recovery it depends on (allowed referer honored, disallowed and non-absolute referers rejected, absent referer falling back to self). The per-element `referrerpolicy` attributes from #242 are left in place as defence-in-depth.

### Dependencies
- Bump Microsoft.AspNetCore.Authentication.JwtBearer and 6 others ([#363](https://github.com/PGAN-Dev/PoracleWeb.NET/pull/363))
- Bump Microsoft.EntityFrameworkCore and 4 others ([#366](https://github.com/PGAN-Dev/PoracleWeb.NET/pull/366))
- Bump Microsoft.NET.Test.Sdk from 18.6.0 to 18.8.1 ([#365](https://github.com/PGAN-Dev/PoracleWeb.NET/pull/365))
- Bump jest-preset-angular ([#344](https://github.com/PGAN-Dev/PoracleWeb.NET/pull/344))
- Bump the angular group across 1 directory with 13 updates ([#338](https://github.com/PGAN-Dev/PoracleWeb.NET/pull/338))
- Bump the angular group across 1 directory with 9 updates ([#359](https://github.com/PGAN-Dev/PoracleWeb.NET/pull/359))
- Bump the eslint group across 1 directory with 5 updates ([#349](https://github.com/PGAN-Dev/PoracleWeb.NET/pull/349))
- Upgrade @ngx-translate to v18 and migrate off TranslateModule ([#377](https://github.com/PGAN-Dev/PoracleWeb.NET/pull/377))

## [2.11.1] - 2026-06-05

### Fixed
Expand Down Expand Up @@ -607,7 +619,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Rate limiting (per-IP) on auth endpoints
- Docker deployment with Watchtower auto-updates

[Unreleased]: https://github.com/PGAN-Dev/PoracleWeb.NET/compare/v2.11.1...HEAD
[Unreleased]: https://github.com/PGAN-Dev/PoracleWeb.NET/compare/v2.12.0...HEAD
[2.12.0]: https://github.com/PGAN-Dev/PoracleWeb.NET/compare/v2.11.1...v2.12.0
[2.11.1]: https://github.com/PGAN-Dev/PoracleWeb.NET/compare/v2.11.0...v2.11.1
[2.11.0]: https://github.com/PGAN-Dev/PoracleWeb.NET/compare/v2.10.0...v2.11.0
[2.10.0]: https://github.com/PGAN-Dev/PoracleWeb.NET/compare/v2.9.0...v2.10.0
Expand Down
Loading