Reading the path only as decoded parts misplaced the account when the
user name itself held an encoded slash (`/live/joe%2Fx/hunter2/1.ts`):
the password segment stayed on screen and in logs. `findXtreamAccount`
now scans both readings, each raw segment decoded whole and the decoded
path split on every separator, and drops what either finds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- An Xtream account could hide behind encoded separators
(`live%2Fjoe%2Fhunter2%2F1.ts` is one raw segment). `findXtreamAccount`
reads the path as decoded parts, maps them back to raw segments, and is
the one scanner for the log redactor, the on-screen URL and the name
check. Account segments go whole, joined ones included.
- The name check required a minimum length only of the raw secret, so a
decoded form as short as one letter (`%2542` is `B`) hid ordinary
names. Each form must now be long enough on its own.
- The decoding helpers move to `url-credential-parts.ts`, which keeps the
redactor under the line limit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each check decoded its input once, so one more encoding layer slipped a
secret past it: `?%2570assword=…` kept its value, and `/%256Cive/…`
kept its account segments, both on screen and in logs.
`decodeFully` (shared logging) undoes up to four percent-encoding layers
and is now the one form every name check reads: the redactor's key
normaliser and Xtream marker check, the display key predicate and path
check, and the name check's secret values. Logs and the Sources lists
gain the fix together.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Strip and redact the account segments after `/LIVE/`, `/Movie/` or an
encoded marker such as `/%6Cive/`, as after `/live/`. The display-name
check also treats an Xtream path password as a URL secret.
- A source cannot be removed while a switcher refresh clears and refills
it: the removal service ignores the request, the switcher disables
Remove, and the Sources page shows the refresh as busy.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PR #1932 CI:
- CodeQL (polynomial regular expression on uncontrolled data): the
embedded-URL and keyed-pair patterns in stripUrlCredentials could retry
from every position of a long run of letters. Matches now start only
where a name can start (lookbehinds) and every name part is bounded, as
is the bare-userinfo pattern; a spec times 50,000-character runs. The
preceding "wip: linear URL-cleaning regexes" commit holds that change.
- Initial bytes ratchet (+135 B over after master's #1928 lowered the
baseline): stripUrlCredentials sat behind the shared logging barrel,
which startup code imports, so esbuild placed it in an initial chunk
although only the lazy Sources page and switcher use it. It now lives
beside its only consumer in playlist/shared/util source-display, and the
logging barrel exports the two redaction helpers it needs. Measured
locally on the merge with master: 1,537,497 bytes, within 1,538,700.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex bot (PR review, P1): stripUrlCredentials copied every non-sensitive
parameter value unchanged, so a URL nested in one (a proxy's
?url=http%3A%2F%2Fjoe%3Ahunter2%40origin.test%2F…) kept its userinfo and
password and reached the Sources row through sourceDisplayUrl.
Kept query and fragment values and path segments are now cleaned
recursively, up to four levels: a nested URL loses its credentials the
same way, a nested parameter list loses its sensitive keys, and a part
that still names a secret (joe:hunter2@host, token=…) is dropped. Deeper
nesting is dropped rather than shown.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One app-source-row (regular for the Sources page, compact for the
playlist switcher) with an app-source-tile, built on pure helpers:
- resolvePlaylistSourceKind: one provider rule for icons, filters and
counts (the list filter and the panel counts used to disagree).
- sourceDisplayName / sourceDisplayUrl: a name or URL never shows a
password, token or MAC. URL imports that stored
"get.php?username=…&password=…" as the title now show the host.
- stripUrlCredentials (shared/logging): drops what the log redactor
would mask, plus short user/pass keys.
- formatSourceDate / sourceMetaParts / sourceStatusTag: one meta line
order and Intl dates and durations in the UI language.
- SourceStatusService + SourceHealthHistoryService: one status per
source (desktop health check, browser Xtream portal status) and the
last conclusive result kept across restarts, so "not responding for
3 days" survives a relaunch. No URL or credential is stored.
Also fixes playlistNameHasCredentials answering differently on repeated
calls (global regex lastIndex), and adds the UI-kit button, menu and
segmented-control mixins (libs/ui/styles/_app-controls.scss); menus opt
in with class="app-menu", styled by the components that use them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tier A coverage runs projects a few at a time (largest first, bounded Jest workers, buffered output, fail-fast kept) and ts-jest transpiles with isolatedModules instead of type-checking per process; five type re-exports become export type, two decorated inputs use import type. Unit Tests and Typechecks job: 26 min -> 9 min (Tier A step 23 min -> 6.5 min).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore(deps): upgrade Angular to 22.1 and Nx to 23.2
* fix(deps): complete Angular migrations after rebasing on master
* fix(ci): use the Node pin for Windows runtime refresh
* docs(deps): synchronize the workspace-shell Node requirements
Extra libmpv options (Settings > Playback) reach every embedded engine off the command line (createSession array on Windows/macOS, a 0600 --include file on Linux native-view, a stdin preamble for the frame-copy helper); the keys the embed depends on are refused, and keys libmpv rejects are reported once per session. Dropped streams reload automatically (error, or ended on live) with 2 s -> 30 s backoff, six attempts per outage and a 30 s stability reset, only for a load that already played; engine failures stay terminal, a running recording is filed as interrupted and restarted after the reload, and an external subtitle file is re-added. Settings.embeddedMpvAutoReconnect (default on) opts out; the player shows 'Reconnecting... attempt N of M'.
Started by Bpl5966 in #1515 and finished by the maintainers in the same PR.
Co-authored-by: Bpl5966 <amine.b1959@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>