fix(browser): abort unrepresentable cookie clears

This commit is contained in:
Brennan Benson
2026-08-13 06:27:09 -07:00
parent 4f9b61256d
commit 6e8ae17812
2 changed files with 14 additions and 6 deletions
@@ -84,7 +84,10 @@ export async function withCookieClearLock<T>(owner: object, run: () => Promise<T
}
}
function removableCookieEntries(cookies: readonly Cookie[]): { cookie: Cookie; url: string }[] {
function removableCookieEntries(
cookies: readonly Cookie[],
requireAddressable = false
): { cookie: Cookie; url: string }[] {
const removable: { cookie: Cookie; url: string }[] = []
for (const cookie of cookies) {
if (isNonTransplantableCookieDomain(cookie.domain ?? '')) {
@@ -93,6 +96,9 @@ function removableCookieEntries(cookies: readonly Cookie[]): { cookie: Cookie; u
const domain = cookie.domain ? normalizeCookieDomain(cookie.domain) : null
const url = domain ? cookieRemovalUrl(cookie, domain) : null
if (!url) {
if (requireAddressable) {
throw new Error('Could not clear existing cookies; the session was left unchanged')
}
continue
}
removable.push({ cookie, url })
@@ -154,7 +160,7 @@ export async function removeTransplantableCookies(
return
}
const initialRemovable = removableCookieEntries(initialCookies)
const initialRemovable = removableCookieEntries(initialCookies, true)
const identities = await targetSession.snapshotClearIdentities(initialRemovable)
assertClearIdentitiesCoverRemovable(initialRemovable, identities)
@@ -289,14 +289,16 @@ describe('removeTransplantableCookies', () => {
expect(remove).not.toHaveBeenCalled()
})
it('bulk clears cookies the per-cookie path could never address', async () => {
const { session, clearData } = clearSession([
it('does not mutate when a transplantable cookie cannot be represented for rollback', async () => {
const { session, clearData, remove, restoreClearIdentities } = clearSession([
{ ...cookie('.example.com', 'session'), domain: '' }
])
await removeTransplantableCookies(session)
await expect(removeTransplantableCookies(session)).rejects.toThrow(/session was left unchanged/)
expect(clearData).toHaveBeenCalledOnce()
expect(clearData).not.toHaveBeenCalled()
expect(remove).not.toHaveBeenCalled()
expect(restoreClearIdentities).not.toHaveBeenCalled()
})
it('falls back to per-cookie removal when the bulk clear rejects', async () => {