Skip to content

Commit

Permalink
chore: enforce strict origin spec bridges
Browse files Browse the repository at this point in the history
chore: refactor spec bridges to strictly enforce same origin

fix: wrap fullCrossOrigin injection around feature flag inside buffered response
  • Loading branch information
AtofStryker committed Sep 27, 2022
1 parent 443a887 commit 62fc3ea
Show file tree
Hide file tree
Showing 69 changed files with 696 additions and 682 deletions.
8 changes: 4 additions & 4 deletions packages/app/src/runner/aut-iframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ export class AutIframe {
}

/**
* If the AUT is cross origin relative to top, a security error is thrown and the method returns false
* If the AUT is cross origin relative to top and chromeWebSecurity is false, origins of the AUT and top need to be compared and returns false
* Otherwise, if top and the AUT match origins, the method returns true.
* If the AUT is cross super domain origin relative to top, a security error is thrown and the method returns false
* If the AUT is cross super domain origin relative to top and chromeWebSecurity is false, origins of the AUT and top need to be compared and returns false
* Otherwise, if top and the AUT match super domain origins, the method returns true.
* If the AUT origin is "about://blank", that means the src attribute has been stripped off the iframe and is adhering to same origin policy
*/
doesAUTMatchTopSuperDomainOrigin = () => {
Expand Down Expand Up @@ -163,7 +163,7 @@ export class AutIframe {
})

// The iframe is in a cross origin state.
// Remove the src attribute to adhere to same super domain origin policy so we can interact with the frame. NOTE: This should only be done ONCE.
// Remove the src attribute to adhere to same super domain origin so we can interact with the frame. NOTE: This should only be done ONCE.
this.removeSrcAttribute()

return
Expand Down
20 changes: 10 additions & 10 deletions packages/app/src/runner/event-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -611,8 +611,8 @@ export class EventManager {
})

// Reflect back to the requesting origin the status of the 'duringUserTestExecution' state
Cypress.primaryOriginCommunicator.on('sync:during:user:test:execution', ({ specBridgeResponseEvent }, superDomainOrigin) => {
Cypress.primaryOriginCommunicator.toSpecBridge(superDomainOrigin, specBridgeResponseEvent, cy.state('duringUserTestExecution'))
Cypress.primaryOriginCommunicator.on('sync:during:user:test:execution', ({ specBridgeResponseEvent }, origin) => {
Cypress.primaryOriginCommunicator.toSpecBridge(origin, specBridgeResponseEvent, cy.state('duringUserTestExecution'))
})

Cypress.on('request:snapshot:from:spec:bridge', ({ log, name, options, specBridge, addSnapshot }: {
Expand Down Expand Up @@ -653,22 +653,22 @@ export class EventManager {
Cypress.primaryOriginCommunicator.toAllSpecBridges('before:unload', origin)
})

Cypress.primaryOriginCommunicator.on('expect:origin', (superDomainOrigin) => {
this.localBus.emit('expect:origin', superDomainOrigin)
Cypress.primaryOriginCommunicator.on('expect:origin', (origin) => {
this.localBus.emit('expect:origin', origin)
})

Cypress.primaryOriginCommunicator.on('viewport:changed', (viewport, superDomainOrigin) => {
Cypress.primaryOriginCommunicator.on('viewport:changed', (viewport, origin) => {
const callback = () => {
Cypress.primaryOriginCommunicator.toSpecBridge(superDomainOrigin, 'viewport:changed:end')
Cypress.primaryOriginCommunicator.toSpecBridge(origin, 'viewport:changed:end')
}

Cypress.primaryOriginCommunicator.emit('sync:viewport', viewport)
this.localBus.emit('viewport:changed', viewport, callback)
})

Cypress.primaryOriginCommunicator.on('before:screenshot', (config, superDomainOrigin) => {
Cypress.primaryOriginCommunicator.on('before:screenshot', (config, origin) => {
const callback = () => {
Cypress.primaryOriginCommunicator.toSpecBridge(superDomainOrigin, 'before:screenshot:end')
Cypress.primaryOriginCommunicator.toSpecBridge(origin, 'before:screenshot:end')
}

handleBeforeScreenshot(config, callback)
Expand Down Expand Up @@ -861,9 +861,9 @@ export class EventManager {
this.ws.emit('spec:changed', specFile)
}

notifyCrossOriginBridgeReady (superDomainOrigin) {
notifyCrossOriginBridgeReady (origin) {
// Any multi-origin event appends the origin as the third parameter and we do the same here for this short circuit
Cypress.primaryOriginCommunicator.emit('bridge:ready', undefined, superDomainOrigin)
Cypress.primaryOriginCommunicator.emit('bridge:ready', undefined, origin)
}

snapshotUnpinned () {
Expand Down
6 changes: 3 additions & 3 deletions packages/app/src/runner/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,11 @@ export async function teardown () {
* Add a cross origin iframe for cy.origin support
*/
export function addCrossOriginIframe (location) {
const id = `Spec Bridge: ${location.superDomainOrigin}`
const id = `Spec Bridge: ${location.origin}`

// if it already exists, don't add another one
if (document.getElementById(id)) {
getEventManager().notifyCrossOriginBridgeReady(location.superDomainOrigin)
getEventManager().notifyCrossOriginBridgeReady(location.origin)

return
}
Expand All @@ -209,7 +209,7 @@ export function addCrossOriginIframe (location) {
// container since it needs to match the size of the top window for screenshots
$container: document.body,
className: 'spec-bridge-iframe',
src: `${location.superDomainOrigin}/${getRunnerConfigFromWindow().namespace}/spec-bridge-iframes`,
src: `${location.origin}/${getRunnerConfigFromWindow().namespace}/spec-bridge-iframes`,
})
}

Expand Down
8 changes: 4 additions & 4 deletions packages/driver/cypress/e2e/commands/navigation.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -1553,7 +1553,7 @@ describe('src/cy/commands/navigation', () => {
${experimentalMessage}
\`cy.visit('http://localhost:3500/fixtures/generic.html')\`
\`<commands targeting http://localhost:3500 go here>\`\n
\`cy.origin('http://foobar.com:3500', () => {\`
\`cy.origin('http://www.foobar.com:3500', () => {\`
\` cy.visit('http://www.foobar.com:3500/fixtures/generic.html')\`
\` <commands targeting http://www.foobar.com:3500 go here>\`
\`})\`\n
Expand Down Expand Up @@ -2241,10 +2241,10 @@ describe('src/cy/commands/navigation', () => {
expect(err.message).to.contain(stripIndent`\
Cypress detected a cross origin error happened on page load:\n
> ${error}\n
Before the page load, you were bound to the origin policy:\n
Before the page load, you were bound to the origin:\n
> http://localhost:3500\n
A cross origin error happens when your application navigates to a new URL which does not match the origin policy above.\n
A new URL does not match the origin policy if the 'protocol', 'port' (if specified), and/or 'host' (unless of the same superdomain) are different.\n
A cross origin error happens when your application navigates to a new URL which does not match the origin above.\n
A new URL does not match the origin if the 'protocol', 'port' (if specified), and/or 'host' are different.\n
Cypress does not allow you to navigate to a different origin URL within a single test.\n
You may need to restructure some of your test code to avoid this problem.\n
Alternatively you can also disable Chrome Web Security in Chromium-based browsers which will turn off this restriction by setting { chromeWebSecurity: false }`)
Expand Down
34 changes: 17 additions & 17 deletions packages/driver/cypress/e2e/e2e/origin/basic_login.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ describe('basic login', () => {
it('logs in with idp redirect', () => {
cy.visit('/fixtures/auth/index.html') // Establishes primary origin
cy.get('[data-cy="login-idp"]').click() // Takes you to idp.com
cy.origin('http://idp.com:3500', () => {
cy.origin('http://www.idp.com:3500', () => {
cy.get('[data-cy="username"]').type('BJohnson')
cy.get('[data-cy="login"]').click()
})
Expand All @@ -23,7 +23,7 @@ describe('basic login', () => {
win.location.href = 'http://www.idp.com:3500/fixtures/auth/idp.html'
})

cy.origin('http://idp.com:3500', () => {
cy.origin('http://www.idp.com:3500', () => {
cy.get('[data-cy="username"]').type('FJohnson')
cy.get('[data-cy="login"]').click()
})
Expand All @@ -37,7 +37,7 @@ describe('basic login', () => {
it('visits foobar first', () => {
cy.visit('http://www.foobar.com:3500/fixtures/auth/index.html') // Establishes primary origin
cy.get('[data-cy="login-idp"]').click() // Takes you to idp.com
cy.origin('http://idp.com:3500', () => {
cy.origin('http://www.idp.com:3500', () => {
cy.get('[data-cy="username"]').type('BJohnson')
cy.get('[data-cy="login"]').click()
})
Expand All @@ -60,7 +60,7 @@ describe('basic login', () => {
// Primary established via base url
// TODO: baseUrl does not establish primary without a visit
it.skip('logs in with primary set via baseurl', { baseUrl: 'http://localhost:3500' }, () => {
cy.origin('http://idp.com:3500', () => { // primary origin is localhost
cy.origin('http://www.idp.com:3500', () => { // primary origin is localhost
cy.visit('http://www.idp.com:3500/fixtures/auth/idp.html')
cy.get('[data-cy="username"]').type('FJohnson')
cy.get('[data-cy="login"]').click()
Expand All @@ -77,7 +77,7 @@ describe('basic login', () => {

it('logs in with primary set via visit', () => {
cy.visit('/fixtures/auth/index.html')
cy.origin('http://idp.com:3500', () => { // primary origin is localhost
cy.origin('http://www.idp.com:3500', () => { // primary origin is localhost
cy.visit('http://www.idp.com:3500/fixtures/auth/idp.html')
cy.get('[data-cy="username"]').type('FJohnson')
cy.get('[data-cy="login"]').click()
Expand All @@ -94,7 +94,7 @@ describe('basic login', () => {
const login = (name) => {
cy.session(name, () => {
// Note, this assumes localhost is the primary origin, ideally we'd be able to specify this directly.
cy.origin('http://idp.com:3500', { args: name }, (name) => {
cy.origin('http://www.idp.com:3500', { args: name }, (name) => {
cy.visit('http://www.idp.com:3500/fixtures/auth/idp.html')
cy.get('[data-cy="username"]').type(name)
cy.get('[data-cy="login"]').click()
Expand Down Expand Up @@ -154,9 +154,9 @@ describe('Multi-step Auth', () => {
cy.visit('/fixtures/auth/index.html')
cy.get('[data-cy="login-with-approval"]').click() // takes you to foobar.com.../approval
cy.url() //fail
cy.origin('http://foobar.com:3500', () => { // Parent origin is localhost
cy.origin('http://www.foobar.com:3500', () => { // Parent origin is localhost
cy.get('[data-cy="approve-orig"]').click() // takes you to idp.com
cy.origin('http://idp.com:3500', () => { // Parent origin is foobar.com
cy.origin('http://www.idp.com:3500', () => { // Parent origin is foobar.com
cy.get('[data-cy="username"]').type('MarkyMark')
cy.get('[data-cy="login"]').click() // Takes you back to localhost
}) // Does not wait on foobar.com because there are no subsequent commands (would wait forever)
Expand All @@ -172,11 +172,11 @@ describe('Multi-step Auth', () => {
it.skip('final-auth redirects back to localhost - flat', () => {
cy.visit('/fixtures/auth/index.html')
cy.get('[data-cy="login-with-approval"]').click() // takes you to foobar.com.../approval
cy.origin('http://foobar.com:3500', () => { // Parent origin is localhost
cy.origin('http://www.foobar.com:3500', () => { // Parent origin is localhost
cy.get('[data-cy="approve-orig"]').click() // takes you to idp.com
}) // Exits and moves on to the next command

cy.origin('http://idp.com:3500', () => { // Parent origin is localhost
cy.origin('http://www.idp.com:3500', () => { // Parent origin is localhost
cy.get('[data-cy="username"]').type('MarkyMark')
cy.get('[data-cy="login"]').click() // Takes you back to localhost
}) // Exits and moves on to the next command
Expand All @@ -189,10 +189,10 @@ describe('Multi-step Auth', () => {

// TODO: cy.origin does not work in cy.origin yet.
it.skip('final auth redirects back to localhost - nested - approval first', () => {
cy.origin('http://foobar.com:3500', () => { // parent origin is localhost
cy.origin('http://www.foobar.com:3500', () => { // parent origin is localhost
cy.visit('http://www.foobar.com:3500/fixtures/auth/approval.html')
cy.get('[data-cy="approve-orig"]').click() // takes you to idp.com
cy.origin('http://idp.com:3500', () => { // parent origin is foobar.com
cy.origin('http://www.idp.com:3500', () => { // parent origin is foobar.com
cy.get('[data-cy="username"]').type('MarkyMark')
cy.get('[data-cy="login"]').click() // Takes you back to localhost
}) // Does not wait on foobar.com because there are no subsequent commands (would wait forever)
Expand All @@ -208,9 +208,9 @@ describe('Multi-step Auth', () => {
it.skip('final auth redirects back to approval page - nested', () => {
cy.visit('/fixtures/auth/index.html')
cy.get('[data-cy="login-with-approval"]').click() // takes you to foobar.com.../approval
cy.origin('http://foobar.com:3500', () => { // parent origin is localhost
cy.origin('http://www.foobar.com:3500', () => { // parent origin is localhost
cy.get('[data-cy="approve-me"]').click() // takes you to idp.com
cy.origin('http://idp.com:3500', () => { // parent origin is foobar.com
cy.origin('http://www.idp.com:3500', () => { // parent origin is foobar.com
cy.get('[data-cy="username"]').type('MarkyMark')
cy.get('[data-cy="login"]').click() // Takes you back to foobar.com.../approval
}) // Exits and moves on to the next command
Expand All @@ -227,16 +227,16 @@ describe('Multi-step Auth', () => {
it('final auth redirects back to approval page - flat', () => {
cy.visit('/fixtures/auth/index.html')
cy.get('[data-cy="login-with-approval"]').click() // takes you to foobar.com.../approval
cy.origin('http://foobar.com:3500', () => { // parent origin is localhost
cy.origin('http://www.foobar.com:3500', () => { // parent origin is localhost
cy.get('[data-cy="approve-me"]').click() // takes you to idp.com
}) // waits on localhost forever, this breaks

cy.origin('http://idp.com:3500', () => { // parent origin is localhost
cy.origin('http://www.idp.com:3500', () => { // parent origin is localhost
cy.get('[data-cy="username"]').type('MarkyMark')
cy.get('[data-cy="login"]').click() // Takes you back to foobar.com.../approval
}) // Exits and moves on to the next command

cy.origin('http://foobar.com:3500', () => { // parent origin is localhost
cy.origin('http://www.foobar.com:3500', () => { // parent origin is localhost
cy.get('[data-cy="login-success"]').click() // Takes you back to localhost
}) // Exits and moves on to the next command

Expand Down
Loading

0 comments on commit 62fc3ea

Please sign in to comment.