Skip to content

Commit

Permalink
fix: issue where path needed to be explicit on cookie filters
Browse files Browse the repository at this point in the history
  • Loading branch information
AtofStryker committed Mar 4, 2025
1 parent 4381baa commit a7c7f64
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 8 deletions.
4 changes: 2 additions & 2 deletions packages/server/lib/automation/util.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type playwright from 'playwright-webkit'
import { domainMatch } from 'tough-cookie'
import { domainMatch, pathMatch } from 'tough-cookie'

// @ts-ignore
export type CyCookie = Pick<chrome.cookies.Cookie, 'name' | 'value' | 'expirationDate' | 'hostOnly' | 'domain' | 'path' | 'secure' | 'httpOnly'> & {
Expand All @@ -17,7 +17,7 @@ export const cookieMatches = (cookie: CyCookie | playwright.Cookie, filter?: CyC
return false
}

if (filter?.path && filter?.path !== cookie.path) {
if (filter?.path && !pathMatch(filter.path, cookie.path)) {
return false
}

Expand Down
34 changes: 28 additions & 6 deletions packages/server/lib/browsers/bidi_automation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ import type { CyCookie } from './webkit-automation'

const BIDI_DEBUG_NAMESPACE = 'cypress:server:browsers:bidi_automation'
const BIDI_COOKIE_DEBUG_NAMESPACE = `${BIDI_DEBUG_NAMESPACE}:cookies`
const BIDI_SCREENSHOT_DEBUG_NAMESPACE = `${BIDI_DEBUG_NAMESPACE}:screenshot`

const debug = debugModule(BIDI_DEBUG_NAMESPACE)
const debugCookies = debugModule(BIDI_COOKIE_DEBUG_NAMESPACE)
const debugScreenshot = debugModule(BIDI_SCREENSHOT_DEBUG_NAMESPACE)

// if the filter is not an exact match OR, if looselyMatchCookiePath is enabled, doesn't include the path.
// ex: /foo/bar/baz path should include cookies for /foo/bar/baz, /foo/bar, /foo, and /
// this is shipped in remoteTypes within webdriver but it isn't exported, so we need to redefine the type
interface StoragePartialCookie extends Record<string, unknown> {
name: string
Expand Down Expand Up @@ -392,11 +396,6 @@ export class BidiAutomation {
path?: string
url?: string
}) {
// filter for BiDI storageGetCookies gets the EXACT domain of the cookie.
// Cypress expects all cookies that apply to that domain to be returned
// For instance, domain www.foobar.com would have cookies with .foobar.com applied,
// but sending domain=www.foobar.com to storageGetCookies would not return cookies with .foobar.com domain.

let secure: boolean | undefined = undefined

if (filter?.url) {
Expand All @@ -408,8 +407,29 @@ export class BidiAutomation {
if (url.protocol === 'http:') {
secure = false
}

if (url.pathname) {
filter.path = url.pathname
}
}

/**
*
* filter for BiDI storageGetCookies gets the EXACT domain / path of the cookie.
* Cypress expects all cookies that apply to that domain / path hierarchy to be returned.
*
* Domain example:
* For instance, domain www.foobar.com would have cookies with .foobar.com applied,
* but sending domain=www.foobar.com to storageGetCookies would not return cookies with .foobar.com domain.
*
* Path example
* For instance, given everything equal except path, given 3 cookies paths:
* /
* /cookies
* /cookies/foo
*
* passing path=/cookies/foo will ONLY return cookies matching the exact path of cookies/foo and not its parent hierarchy
*/
const BiDiCookieFilter = {
...(filter?.name !== undefined ? {
name: filter.name,
Expand All @@ -430,6 +450,8 @@ export class BidiAutomation {
// and filter out all cookies that apply to the given domain, path, and name (which should already be done)
const filteredCookies = normalizedCookies.filter((cookie) => cookieMatches(cookie, filter))

debugCookies(`filtered additional cookies based on domain, path, or name: %o`, filteredCookies)

// print additional information if additional filtering was performed and differs from that returned from BiDi
if (debugModule.enabled(BIDI_COOKIE_DEBUG_NAMESPACE) && filteredCookies.length !== normalizedCookies.length) {
debugCookies(`filtered additional cookies based on domain, path, or name: %o`, filteredCookies)
Expand Down Expand Up @@ -563,7 +585,7 @@ export class BidiAutomation {
},
})

debug(`take:screenshot base64 encoded value of context %s: %s`, contexts[0].context, base64EncodedScreenshot)
debugScreenshot(`take:screenshot base64 encoded value of context %s: %s`, contexts[0].context, base64EncodedScreenshot)

return `data:image/png;base64,${base64EncodedScreenshot}`
}
Expand Down
102 changes: 102 additions & 0 deletions packages/server/test/unit/browsers/bidi_automation_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,108 @@ describe('lib/browsers/bidi_automation', () => {
} })
})

it('data.url / path', async () => {
mockWebdriverClient.storageGetCookies = sinon.stub().resolves({
cookies: [{
domain: '.www.foobar.com',
expiry: 123456789,
httpOnly: false,
name: 'key1',
path: '/',
sameSite: 'lax',
secure: false,
size: 10,
value: {
type: 'string',
value: 'value1',
},
}, {
domain: '.app.www.foobar.com',
expiry: 123456789,
httpOnly: false,
name: 'key2',
path: '/foo',
sameSite: 'lax',
secure: false,
size: 10,
value: {
type: 'string',
value: 'value2',
},
},
{
domain: '.foobar.com',
expiry: 123456789,
httpOnly: false,
name: 'key3',
path: '/foo/bar',
sameSite: 'lax',
secure: false,
size: 10,
value: {
type: 'string',
value: 'value3',
},
},
{
// this cookie should be filtered out
domain: 'www.foobar.com',
expiry: 123456789,
httpOnly: false,
name: 'key4',
path: '/baz',
sameSite: 'lax',
secure: false,
size: 10,
value: {
type: 'string',
value: 'value4',
},
}],
})

const cookies = await bidiAutomationInstance.onRequest('get:cookies', {
url: 'http://app.www.foobar.com:3500/foo/bar/index.html',
})

expect(cookies).to.deep.equal([{
domain: '.www.foobar.com',
expirationDate: 123456789,
httpOnly: false,
hostOnly: false,
name: 'key1',
path: '/',
sameSite: 'lax',
secure: false,
value: 'value1',
}, {
domain: '.app.www.foobar.com',
expirationDate: 123456789,
httpOnly: false,
hostOnly: false,
name: 'key2',
path: '/foo',
sameSite: 'lax',
secure: false,
value: 'value2',
}, {
domain: '.foobar.com',
expirationDate: 123456789,
httpOnly: false,
hostOnly: false,
name: 'key3',
path: '/foo/bar',
sameSite: 'lax',
secure: false,
value: 'value3',
}])

expect(mockWebdriverClient.storageGetCookies).to.have.been.calledWith({ filter: {
// this would filter out secure cookies and prevent sending them in a secure context
secure: false,
} })
})

it('cookie name', async () => {
mockWebdriverClient.storageGetCookies = sinon.stub().resolves({
cookies: [{
Expand Down

0 comments on commit a7c7f64

Please sign in to comment.