Migrate Hyper Core simulator to first-party credentials - #7
Conversation
cb880fc to
ada03d9
Compare
| let base_url = session_url.origin().unicode_serialization(); | ||
| let cookie = cookie_manager.give_cookie(&base_url); | ||
| let name = cookie.as_ref().map(BorrowedCookie::username); | ||
| let credentials = credentials_manager.give_credentials(&session_url); |
There was a problem hiding this comment.
P2: Skip Core credential borrowing for local Hyper Lite participants
When Core credentials are cached for the same origin, this path gives a Lite participant the cached username. FrontendAuth::for_kind then drops the credentials immediately because Lite does not use them. The next spawn can borrow the same entry and get the same name. ParticipantStore::add uses that name as its map key, so it replaces the earlier participant and drops its task handle.
I reproduced two local /m/ spawns leaving only one participant in the store. Only borrow credentials when the frontend is Hyper Core, as the Device Farm path already does. The remote stub path also borrows a name and immediately returns the credentials, so it should skip borrowing too.
There was a problem hiding this comment.
Yep, good catch — fixed in f74e5cb. Local participants now only borrow credentials for Core, and the remote stub does not borrow them at all. Added a regression test for two Lite/stub spawns with cached Core credentials on the same origin; both participants now stay in the store.
| fn drop(&mut self) { | ||
| self.manager.return_cookie(self.domain.clone(), self.cookie.clone()); | ||
| self.manager | ||
| .return_credentials(self.server_url.clone(), self.credentials.clone()); |
There was a problem hiding this comment.
P2: Retain credentials renewed in the browser before returning the identity
The new expiry checks fix repeated reuse of an expired cache entry, but this still returns the original envelope. Hyper Core writes renewed credentials to browser storage, and no path copies them back into BorrowedCredentials or the disk stash.
If a browser runs past the original renewal token's 24-hour lifetime, it can hold valid replacement credentials while return_credentials discards its original pair. The next run creates a new guest even though the previous identity was still renewable. Restarting the simulator also loses the replacement because the stash only records the initial fetch.
Read the current browser envelope before closing the session, then update the pool and persisted entry. In the original browser probe, storage held renewed-final before shutdown, but the next checkout returned issued-access.
There was a problem hiding this comment.
Yep, the expiry check alone was only half the fix. f74e5cb now reads the browser envelope before teardown and copies the renewed pair back into the borrowed credentials and disk stash. This covers local Chromium and Device Farm, including cleanup after a failed join. Added regression coverage for reuse and persistence after the original pair expires; a failed read/save logs a warning without preventing shutdown. All 185 workspace tests pass.
| let key = serde_json::to_string(STORAGE_KEY).context("failed to encode credential storage key")?; | ||
| let credentials = serde_json::to_string(credentials).context("failed to encode first-party credentials")?; | ||
| Ok(format!( | ||
| "if (globalThis.location.origin === {realm} && globalThis.localStorage.getItem({key}) === null) {{ globalThis.localStorage.setItem({key}, {credentials}); }}" |
There was a problem hiding this comment.
P2: Install credentials before the first local room navigation
The new empty-storage guard can prevent the intended identity from ever reaching local Chromium. LocalChromiumSession::start_inner still calls create_page_retry before building authentication, and create_page opens the room URL. Hyper Core's lobby requests a permit during startup, so that first document can create and store its own guest. When join_session finally installs this script and navigates again, the key already exists and the script skips the borrowed credentials. Cleanup then saves that other guest back into the pool and stash.
I reproduced this with the real local driver and a page that models the lobby's initial credential write. The room never observed the simulator-issued token. The separate renewal and Lite-name probes now pass.
Open a blank page first, install the credentials, and only then navigate to the room. Keep the empty-storage guard for later navigations so SDK renewals survive.
There was a problem hiding this comment.
Yep, you were right — we missed that first navigation. Fixed in 164613c: both new and reused tabs now open about:blank, then the frontend installs the credentials before navigating to the room. Removed the HTTP-response wait for the blank page and kept the empty-storage guard. Added a real-Chromium regression that reproduced the page-created guest before the fix; it now checks the intended identity on first load, preserves renewals on later navigation, and returns the renewed credentials to the pool. All 186 workspace tests pass.
Summary
Depends on hypervideo/cloudflare-browser-simulator#5. Merge and deploy that worker change before releasing this simulator change.
Verification
cargo fmtcargo clippy --all-targets --all-features -- -D warningscargo clippy -p client-simulator-browser --lib --all-features -- -D warningscargo nextest run --workspace --no-tests warn --no-fail-fast(178 tests)