Skip to content

feat(stalker): add secure portal session compatibility - #1290

Closed
4gray wants to merge 85 commits into
masterfrom
agent/stalker-session-compatibility
Closed

feat(stalker): add secure portal session compatibility#1290
4gray wants to merge 85 commits into
masterfrom
agent/stalker-session-compatibility

Conversation

@4gray

@4gray 4gray commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • Replace the legacy renderer-owned Stalker request flow with typed, main-owned portal sessions based on the compatibility audit of Stalker-Client, MAG/Stalker behavior, and Kodi clients.
  • Harden endpoint discovery, cookies, identity/authentication, credential prompting, refresh, redirects, persistence, and native playback header isolation.
  • Add stateful replay fixtures and Electron/web coverage for real session sequences without storing real portal evidence or credentials.

Changes

Session and authentication

  • Discover and persist verified portal endpoints while treating learned recipes as invalidatable cache.
  • Keep cookie handling, tokens, optional device identity, credential attempts, and single-flight refresh in the Electron main process.
  • Support status-2 second-step authentication, bounded credential retries, terminal Retry, stale-session recovery, and route/reopen race protection.
  • Classify HTTP/status/body failures consistently and fail closed on malformed list/EPG envelopes, redirect escapes, generic HTML, oversized responses, and incompatible payloads.

Playback and persistence

  • Pass opaque playback contexts through the renderer and bind authorization only in the main process.
  • Isolate reused MPV headers by source and disable VLC RC reuse for streams carrying custom headers.
  • Redact Stalker secrets and explicit identity from backups by default while retaining portal URL/MAC; clear learned/token/account state during restore.
  • Validate incomplete local Xtream credentials during restore as part of the same backup hardening boundary.

Replay, UX, and documentation

  • Add validated, secret-scanned stateful replay fixtures for authentication, redirects, cookies, refresh, discovery, classifiers, catalog, playback, and route reopen flows.
  • Add challenge-driven credential/origin dialogs and localized terminal Retry handling.
  • Document the compatibility audit, Stalker session architecture, EPG adapter boundary, replay mock behavior, backup policy, and native playback rules.
  • Add .changes/stalker-session-compatibility.md.

Current master integration

  • Preserve the newer shared fictional marketing-poster catalog while keeping replay listeners isolated from the long-running mock server.
  • Adopt the shared createRandomId migration and the split Settings facade/spec architecture.
  • Merge the current coverage policy and dependency updates; the frozen lockfile and 41-project coverage classification validate.
  • Mark the new playlist database spec as a module so it cannot collide with the current master download-event spec in the shared TypeScript test program.

Testing

  • Stalker portal feature tests: 125/125
  • Services tests: 279/279
  • Stalker protocol tests: 114/114
  • Stalker mock tests: 64/64
  • Replay-fixture library: 35/35
  • Fixture-tool tests: 94/94; 36 committed fixtures validated
  • Targeted Electron Stalker/player tests: 200/200
  • Merge-collision database suites: 21/21
  • Playlist import tests: 45/45
  • Focused web Settings tests: 24/24
  • Electron Playwright Stalker/backup acceptance: 7/7
  • Web Stalker Playwright acceptance: 16/16
  • Affected lint, production web build, Electron E2E build, i18n, coverage-policy, fixture, diff, frozen-lockfile, and release-note gates

Known baseline failure

The fresh post-merge full Electron run exercised 115 suites: 113 passed, the independently reproducible pre-existing Xtream timing assertion still failed, and one merge-only TypeScript global-scope collision was found. The collision was fixed and its two suites now pass 21/21. The only remaining unaddressed failure is apps/electron-backend/src/app/events/xtream.events.spec.ts, where abortSignal?.aborted is undefined rather than false; it is outside this PR scope.

Deliberate follow-ups

This PR implements the approved Option B / Stage 1 foundation. Semantic SQLite/FTS caching with adaptive pagination and authenticated context consumers for web/download playback remain explicit Stage 2/3 follow-ups.

4gray added 30 commits July 27, 2026 02:28
@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown

Too many files changed for review. (282 files found, 100 file limit)

Bypass the limit by tagging @greptile-apps to review.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 27488bea90

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +168 to +170
data: episodes.episodes.map((episode) =>
compact({
id: episode.id,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve the episode discriminator in compatibility responses

For a typed full-session portal using lazy Ministra VOD is_series, fetchVodSeriesEpisodes() passes this compatibility response to with-stalker-series.feature.ts, which retains only entries where item.is_episode === true. These mapped entries omit is_episode, so every returned episode is discarded and the selected season appears empty; include the legacy discriminator when reconstructing this response.

AGENTS.md reference: AGENTS.md:L426-L429

Useful? React with 👍 / 👎.

Comment on lines +342 to +343
if (runId !== this.runId) {
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Roll back an import when persistence finishes after cancellation

If the user closes the add-playlist dialog while the persistStalkerConnection() observable is pending, ngOnDestroy() changes runId and discards the provisional attempt, but the database write can then complete and this branch merely returns. The canceled playlist consequently remains persisted without session promotion or an NgRx update and unexpectedly reappears after reload; the stale path needs to restore/delete the completed write or cancellation must be prevented once persistence begins.

Useful? React with 👍 / 👎.

Comment on lines +147 to +152
readonly form = this.formBuilder.group({
username: [
this.data.username ?? '',
[Validators.required, Validators.pattern(/\S/)],
],
password: [''],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require a password before submitting credential challenges

When a portal requests second-step credentials, this form permits a username with an empty password even though normalizeCredentials() in the main-process auth session rejects password.length === 0. Submitting consumes the one-time challenge and ends the attempt with an invalid-identity failure instead of keeping the dialog actionable; the import flow has the same mismatch because its validation button checks only the username.

Useful? React with 👍 / 👎.

@4gray

4gray commented Jul 29, 2026

Copy link
Copy Markdown
Owner Author

Stalker playback regression fix

Added focused compatibility coverage for portals that require literal / separators in create_link commands and return an exact empty error sentinel on success. Reserved query characters remain percent-encoded and non-empty errors remain fail-closed.

Validation:

  • StalkerHttpSession: 26/26
  • Stalker protocol: 115/115
  • replay fixture corpus: 9/9
  • Electron Stalker E2E: 3/3
  • affected lint, production build, release-note validation, and diff check
  • manual real-portal playback: timeline advanced, media ready, no playback error

@4gray
4gray marked this pull request as draft July 29, 2026 19:01
@4gray 4gray closed this Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant