mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-05 06:20:44 -05:00
Rename uses of term 'whitelist' (#7782)
* Rename non-user facing instances of whitelist * Rename server option 'whitelist' to 'ignore' * Update use of whitelist with server to throw instead of warn * Rename Cypress.Cookies.defaults 'whitelist' option to 'preserve' * fix circle yml parameter parsing consistent * compose cloning an external repo and switching to the NEXT_DEV_VERSION branch consistently * add cypress org to repo parameter * cd into the right dir before switching branches * one line git checkout * simplify passing repo * cd into the right dir * clone into the right dir * oh my cd 101 * replace kitchen sink strings for 5.0.0 Co-authored-by: Brian Mann <brian.mann86@gmail.com>
This commit is contained in:
+71
-67
@@ -77,14 +77,14 @@ commands:
|
||||
- run:
|
||||
name: Install latest Google Chrome (stable)
|
||||
command: |
|
||||
if [ << parameters.browser >> == "chrome" ]; then
|
||||
if [ <<parameters.browser>> == "chrome" ]; then
|
||||
echo "**** Running Chrome tests. Installing latest stable version of Google Chrome. ****"
|
||||
apt-get update
|
||||
apt-get install google-chrome-stable -y
|
||||
echo "**** Location of Google Chrome Installation: "`which google-chrome`" ****"
|
||||
echo "**** Google Chrome Version: "`google-chrome --version`" ****"
|
||||
else
|
||||
echo "**** Not updating Chrome. Running tests in '<< parameters.browser >>' ****"
|
||||
echo "**** Not updating Chrome. Running tests in '<<parameters.browser>>' ****"
|
||||
fi
|
||||
|
||||
run-driver-integration-tests:
|
||||
@@ -105,7 +105,7 @@ commands:
|
||||
if [[ -v PACKAGES_RECORD_KEY ]]; then
|
||||
# internal PR
|
||||
CYPRESS_RECORD_KEY=$PACKAGES_RECORD_KEY \
|
||||
yarn cypress:run --record --parallel --group 5x-driver-<< parameters.browser >> --browser << parameters.browser >>
|
||||
yarn cypress:run --record --parallel --group 5x-driver-<<parameters.browser>> --browser <<parameters.browser>>
|
||||
else
|
||||
# external PR
|
||||
TESTFILES=$(circleci tests glob "cypress/integration/**/*_spec.*" | circleci tests split --total=$CIRCLE_NODE_TOTAL)
|
||||
@@ -114,7 +114,7 @@ commands:
|
||||
if [[ -z "$TESTFILES" ]]; then
|
||||
echo "Empty list of test files"
|
||||
fi
|
||||
yarn cypress:run --browser << parameters.browser >> --spec $TESTFILES
|
||||
yarn cypress:run --browser <<parameters.browser>> --spec $TESTFILES
|
||||
fi
|
||||
working_directory: packages/driver
|
||||
- verify-mocha-results
|
||||
@@ -136,7 +136,7 @@ commands:
|
||||
command: |
|
||||
CYPRESS_KONFIG_ENV=production \
|
||||
CYPRESS_RECORD_KEY=$PACKAGES_RECORD_KEY \
|
||||
yarn workspace @packages/runner cypress:run --record --parallel --group runner-integration-<< parameters.browser >> --browser <<parameters.browser>>
|
||||
yarn workspace @packages/runner cypress:run --record --parallel --group runner-integration-<<parameters.browser>> --browser <<parameters.browser>>
|
||||
- store_test_results:
|
||||
path: /tmp/cypress
|
||||
- store_artifacts:
|
||||
@@ -156,7 +156,7 @@ commands:
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run:
|
||||
command: yarn workspace @packages/server test ./test/e2e/<< parameters.chunk >>*spec* --browser << parameters.browser >>
|
||||
command: yarn workspace @packages/server test ./test/e2e/<<parameters.chunk>>*spec* --browser <<parameters.browser>>
|
||||
- verify-mocha-results
|
||||
- store_test_results:
|
||||
path: /tmp/cypress
|
||||
@@ -194,15 +194,30 @@ commands:
|
||||
## by default, assert that at least 1 test ran
|
||||
default: 0
|
||||
steps:
|
||||
- run: yarn verify:mocha:results << parameters.expectedResultCount >>
|
||||
- run: yarn verify:mocha:results <<parameters.expectedResultCount>>
|
||||
|
||||
clone-repo-and-checkout-release-branch:
|
||||
description: |
|
||||
Clones an external repo and then checks out the branch that matches NEXT_DEV_VERSION otherwise uses 'master' branch.
|
||||
parameters:
|
||||
repo:
|
||||
description: "Name of the github repo to clone like: cypress-example-kitchensink"
|
||||
type: string
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run:
|
||||
name: "Cloning test project: <<parameters.repo>>"
|
||||
command: |
|
||||
git clone --depth 1 --no-single-branch https://github.com/cypress-io/<<parameters.repo>>.git /tmp/<<parameters.repo>>
|
||||
cd /tmp/<<parameters.repo>> && (git checkout $NEXT_DEV_VERSION || true)
|
||||
test-binary-against-repo:
|
||||
description: |
|
||||
Takes the built binary and NPM package, clones given example repo
|
||||
and runs the new version of Cypress against it.
|
||||
parameters:
|
||||
repo:
|
||||
description: Name of the repo like "cypress-example-kitchensink"
|
||||
description: "Name of the github repo to clone like: cypress-example-kitchensink"
|
||||
type: string
|
||||
browser:
|
||||
description: Name of the browser to use, like "electron", "chrome", "firefox"
|
||||
@@ -232,18 +247,17 @@ commands:
|
||||
# make sure the binary and NPM package files are present
|
||||
- run: ls -l
|
||||
- run: ls -l cypress.zip cypress.tgz
|
||||
- run:
|
||||
name: Cloning project <<parameters.repo>>
|
||||
command: git clone --depth 1 https://github.com/cypress-io/<<parameters.repo>>.git /tmp/<<parameters.repo>>
|
||||
- clone-repo-and-checkout-release-branch:
|
||||
repo: <<parameters.repo>>
|
||||
- when:
|
||||
condition: << parameters.pull_request_id >>
|
||||
condition: <<parameters.pull_request_id>>
|
||||
steps:
|
||||
- run:
|
||||
name: Check out PR << parameters.pull_request_id >>
|
||||
name: Check out PR <<parameters.pull_request_id>>
|
||||
working_directory: /tmp/<<parameters.repo>>
|
||||
command: |
|
||||
git fetch origin pull/<< parameters.pull_request_id >>/head:pr-<< parameters.pull_request_id >>
|
||||
git checkout pr-<< parameters.pull_request_id >>
|
||||
git fetch origin pull/<<parameters.pull_request_id>>/head:pr-<<parameters.pull_request_id>>
|
||||
git checkout pr-<<parameters.pull_request_id>>
|
||||
git log -n 2
|
||||
- run:
|
||||
command: npm install
|
||||
@@ -266,42 +280,42 @@ commands:
|
||||
command: npm start --if-present
|
||||
background: true
|
||||
- when:
|
||||
condition: << parameters.folder >>
|
||||
condition: <<parameters.folder>>
|
||||
steps:
|
||||
- when:
|
||||
condition: << parameters.browser >>
|
||||
condition: <<parameters.browser>>
|
||||
steps:
|
||||
- run:
|
||||
name: Run tests using browser "<< parameters.browser >>"
|
||||
working_directory: /tmp/<<parameters.repo>>/<< parameters.folder >>
|
||||
name: Run tests using browser "<<parameters.browser>>"
|
||||
working_directory: /tmp/<<parameters.repo>>/<<parameters.folder>>
|
||||
command: |
|
||||
<<parameters.command>> -- --browser <<parameters.browser>>
|
||||
- unless:
|
||||
condition: << parameters.browser >>
|
||||
condition: <<parameters.browser>>
|
||||
steps:
|
||||
- run:
|
||||
name: Run tests using command
|
||||
working_directory: /tmp/<<parameters.repo>>/<< parameters.folder >>
|
||||
working_directory: /tmp/<<parameters.repo>>/<<parameters.folder>>
|
||||
command: <<parameters.command>>
|
||||
|
||||
- store_artifacts:
|
||||
name: screenshots
|
||||
path: /tmp/<<parameters.repo>>/<< parameters.folder >>/cypress/screenshots
|
||||
path: /tmp/<<parameters.repo>>/<<parameters.folder>>/cypress/screenshots
|
||||
- store_artifacts:
|
||||
name: videos
|
||||
path: /tmp/<<parameters.repo>>/<< parameters.folder >>/cypress/videos
|
||||
path: /tmp/<<parameters.repo>>/<<parameters.folder>>/cypress/videos
|
||||
- unless:
|
||||
condition: << parameters.folder >>
|
||||
condition: <<parameters.folder>>
|
||||
steps:
|
||||
- when:
|
||||
condition: << parameters.browser >>
|
||||
condition: <<parameters.browser>>
|
||||
steps:
|
||||
- run:
|
||||
name: Run tests using browser "<< parameters.browser >>"
|
||||
name: Run tests using browser "<<parameters.browser>>"
|
||||
working_directory: /tmp/<<parameters.repo>>
|
||||
command: <<parameters.command>> -- --browser <<parameters.browser>>
|
||||
- unless:
|
||||
condition: << parameters.browser >>
|
||||
condition: <<parameters.browser>>
|
||||
steps:
|
||||
- run:
|
||||
name: Run tests using command
|
||||
@@ -904,45 +918,39 @@ jobs:
|
||||
test-kitchensink:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run:
|
||||
name: Cloning test project
|
||||
command: git clone https://github.com/cypress-io/cypress-example-kitchensink.git /tmp/repo
|
||||
- clone-repo-and-checkout-release-branch:
|
||||
repo: cypress-example-kitchensink
|
||||
- run:
|
||||
name: Install prod dependencies
|
||||
command: yarn --production
|
||||
working_directory: /tmp/repo
|
||||
working_directory: /tmp/cypress-example-kitchensink
|
||||
- run:
|
||||
name: Example server
|
||||
command: yarn start
|
||||
working_directory: /tmp/repo
|
||||
working_directory: /tmp/cypress-example-kitchensink
|
||||
background: true
|
||||
- run:
|
||||
name: Run Kitchensink example project
|
||||
command: yarn cypress:run --project /tmp/repo
|
||||
command: yarn cypress:run --project /tmp/cypress-example-kitchensink
|
||||
- store_artifacts:
|
||||
path: /tmp/repo/cypress/screenshots
|
||||
path: /tmp/cypress-example-kitchensink/cypress/screenshots
|
||||
- store_artifacts:
|
||||
path: /tmp/repo/cypress/videos
|
||||
path: /tmp/cypress-example-kitchensink/cypress/videos
|
||||
- store-npm-logs
|
||||
|
||||
"test-kitchensink-against-staging":
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run:
|
||||
name: Cloning test project
|
||||
command: git clone https://github.com/cypress-io/cypress-example-kitchensink.git /tmp/repo
|
||||
- clone-repo-and-checkout-release-branch:
|
||||
repo: cypress-example-kitchensink
|
||||
- run:
|
||||
name: Install prod dependencies
|
||||
command: yarn --production
|
||||
working_directory: /tmp/repo
|
||||
working_directory: /tmp/cypress-example-kitchensink
|
||||
- run:
|
||||
name: Example server
|
||||
command: yarn start
|
||||
working_directory: /tmp/repo
|
||||
working_directory: /tmp/cypress-example-kitchensink
|
||||
background: true
|
||||
- run:
|
||||
name: Run Kitchensink example project
|
||||
@@ -951,24 +959,21 @@ jobs:
|
||||
CYPRESS_RECORD_KEY=$TEST_KITCHENSINK_RECORD_KEY \
|
||||
CYPRESS_INTERNAL_ENV=staging \
|
||||
CYPRESS_video=false \
|
||||
yarn cypress:run --project /tmp/repo --record
|
||||
yarn cypress:run --project /tmp/cypress-example-kitchensink --record
|
||||
- store-npm-logs
|
||||
|
||||
"test-against-staging":
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run:
|
||||
name: Cloning test project
|
||||
command: git clone https://github.com/cypress-io/cypress-test-tiny.git /tmp/repo
|
||||
- clone-repo-and-checkout-release-branch:
|
||||
repo: cypress-test-tiny
|
||||
- run:
|
||||
name: Run test project
|
||||
command: |
|
||||
CYPRESS_PROJECT_ID=$TEST_TINY_PROJECT_ID \
|
||||
CYPRESS_RECORD_KEY=$TEST_TINY_RECORD_KEY \
|
||||
CYPRESS_INTERNAL_ENV=staging \
|
||||
yarn cypress:run --project /tmp/repo --record
|
||||
yarn cypress:run --project /tmp/cypress-example-kitchensink --record
|
||||
- store-npm-logs
|
||||
|
||||
build-npm-package:
|
||||
@@ -1164,16 +1169,16 @@ jobs:
|
||||
# make sure we have cypress.zip received
|
||||
- run: ls -l
|
||||
- run: ls -l cypress.zip cypress.tgz
|
||||
- run: mkdir << parameters.wd >>
|
||||
- run: mkdir <<parameters.wd>>
|
||||
- run: node --version
|
||||
- run: npm --version
|
||||
- run:
|
||||
name: Create new NPM package ⚗️
|
||||
working_directory: << parameters.wd >>
|
||||
working_directory: <<parameters.wd>>
|
||||
command: npm init -y
|
||||
- run:
|
||||
name: Install dependencies 📦
|
||||
working_directory: << parameters.wd >>
|
||||
working_directory: <<parameters.wd>>
|
||||
environment:
|
||||
CYPRESS_INSTALL_BINARY: /root/cypress/cypress.zip
|
||||
# let's install Cypress, Jest and any other package that might conflict
|
||||
@@ -1183,7 +1188,7 @@ jobs:
|
||||
typescript jest @types/jest enzyme @types/enzyme
|
||||
- run:
|
||||
name: Test types clash ⚔️
|
||||
working_directory: << parameters.wd >>
|
||||
working_directory: <<parameters.wd>>
|
||||
command: |
|
||||
echo "console.log('hello world')" > hello.ts
|
||||
npx tsc hello.ts --noEmit
|
||||
@@ -1207,16 +1212,16 @@ jobs:
|
||||
# make sure we have cypress.zip received
|
||||
- run: ls -l
|
||||
- run: ls -l cypress.zip cypress.tgz
|
||||
- run: mkdir << parameters.wd >>
|
||||
- run: mkdir <<parameters.wd>>
|
||||
- run: node --version
|
||||
- run: npm --version
|
||||
- run:
|
||||
name: Create new NPM package ⚗️
|
||||
working_directory: << parameters.wd >>
|
||||
working_directory: <<parameters.wd>>
|
||||
command: npm init -y
|
||||
- run:
|
||||
name: Install dependencies 📦
|
||||
working_directory: << parameters.wd >>
|
||||
working_directory: <<parameters.wd>>
|
||||
environment:
|
||||
CYPRESS_INSTALL_BINARY: /root/cypress/cypress.zip
|
||||
# let's install Cypress, Jest and any other package that might conflict
|
||||
@@ -1226,7 +1231,7 @@ jobs:
|
||||
typescript jest @types/jest enzyme @types/enzyme
|
||||
- run:
|
||||
name: Scaffold and test examples 🏗
|
||||
working_directory: << parameters.wd >>
|
||||
working_directory: <<parameters.wd>>
|
||||
environment:
|
||||
CYPRESS_INTERNAL_FORCE_SCAFFOLD: "1"
|
||||
command: |
|
||||
@@ -1250,27 +1255,27 @@ jobs:
|
||||
# make sure we have cypress.zip received
|
||||
- run: ls -l
|
||||
- run: ls -l cypress.zip cypress.tgz
|
||||
- run: mkdir << parameters.wd >>
|
||||
- run: mkdir <<parameters.wd>>
|
||||
- run: node --version
|
||||
- run: npm --version
|
||||
- run:
|
||||
name: Create new NPM package ⚗️
|
||||
working_directory: << parameters.wd >>
|
||||
working_directory: <<parameters.wd>>
|
||||
command: npm init -y
|
||||
- run:
|
||||
name: Install dependencies 📦
|
||||
working_directory: << parameters.wd >>
|
||||
working_directory: <<parameters.wd>>
|
||||
environment:
|
||||
CYPRESS_INSTALL_BINARY: /root/cypress/cypress.zip
|
||||
command: |
|
||||
npm install /root/cypress/cypress.tgz typescript
|
||||
- run:
|
||||
name: Scaffold full TypeScript project 🏗
|
||||
working_directory: << parameters.wd >>
|
||||
working_directory: <<parameters.wd>>
|
||||
command: npx @bahmutov/cly@1 init --typescript
|
||||
- run:
|
||||
name: Run project tests 🗳
|
||||
working_directory: << parameters.wd >>
|
||||
working_directory: <<parameters.wd>>
|
||||
command: npx cypress run
|
||||
|
||||
# install NPM + binary zip and run against staging API
|
||||
@@ -1282,9 +1287,8 @@ jobs:
|
||||
- run: ls -l
|
||||
# make sure we have the binary and NPM package
|
||||
- run: ls -l cypress.zip cypress.tgz
|
||||
- run:
|
||||
name: Cloning test project
|
||||
command: git clone https://github.com/cypress-io/cypress-test-tiny.git /tmp/cypress-test-tiny
|
||||
- clone-repo-and-checkout-release-branch:
|
||||
repo: cypress-test-tiny
|
||||
- run:
|
||||
name: Install Cypress
|
||||
working_directory: /tmp/cypress-test-tiny
|
||||
|
||||
Vendored
+3
-3
@@ -2130,7 +2130,7 @@ declare namespace Cypress {
|
||||
type Agent<T extends sinon.SinonSpy> = SinonSpyAgent<T> & T
|
||||
|
||||
interface CookieDefaults {
|
||||
whitelist: string | string[] | RegExp | ((cookie: any) => boolean)
|
||||
preserve: string | string[] | RegExp | ((cookie: any) => boolean)
|
||||
}
|
||||
|
||||
interface Failable {
|
||||
@@ -2616,7 +2616,7 @@ declare namespace Cypress {
|
||||
enable: boolean
|
||||
force404: boolean
|
||||
urlMatchingOptions: object
|
||||
whitelist(xhr: Request): void
|
||||
ignore(xhr: Request): void
|
||||
onAnyRequest(route: RouteOptions, proxy: any): void
|
||||
onAnyResponse(route: RouteOptions, proxy: any): void
|
||||
onAnyAbort(route: RouteOptions, proxy: any): void
|
||||
@@ -4806,7 +4806,7 @@ declare namespace Cypress {
|
||||
|
||||
interface Server extends RouteOptions {
|
||||
enable: boolean
|
||||
whitelist: (xhr: any) => boolean
|
||||
ignore: (xhr: any) => boolean
|
||||
}
|
||||
|
||||
interface Viewport {
|
||||
|
||||
@@ -35,7 +35,7 @@ cy.visit('https://www.acme.com/', {
|
||||
|
||||
const serverOptions: Partial<Cypress.ServerOptions> = {
|
||||
delay: 100,
|
||||
whitelist: () => true
|
||||
ignore: () => true
|
||||
}
|
||||
|
||||
cy.server(serverOptions)
|
||||
|
||||
@@ -1246,4 +1246,18 @@ describe('src/cy/commands/cookies', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('Cypress.cookies.defaults', () => {
|
||||
it('throws error on use of renamed whitelist option', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.include('`Cypress.Cookies.defaults` `whitelist` option has been renamed to `preserve`. Please rename `whitelist` to `preserve`.')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
Cypress.Cookies.defaults({
|
||||
whitelist: 'session_id',
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -305,39 +305,6 @@ describe('src/cy/commands/xhr', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// FIXME: I have no idea why this is skipped, this test is rly old
|
||||
describe.skip('filtering requests', () => {
|
||||
beforeEach(() => {
|
||||
cy.server()
|
||||
})
|
||||
|
||||
const extensions = {
|
||||
html: 'ajax html',
|
||||
js: '{foo: "bar"}',
|
||||
css: 'body {}',
|
||||
}
|
||||
|
||||
_.each(extensions, (val, ext) => {
|
||||
it(`filters out non ajax requests by default for extension: .${ext}`, (done) => {
|
||||
cy.state('window').$.get(`/fixtures/app.${ext}`).done((res) => {
|
||||
expect(res).to.eq(val)
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('can disable default filtering', (done) => {
|
||||
// this should throw since it should return 404 when no
|
||||
// route matches it
|
||||
cy.server({ ignore: false }).window().then((w) => {
|
||||
Promise.resolve(w.$.get('/fixtures/app.html')).catch(() => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('url rewriting', () => {
|
||||
it('has a FQDN absolute-relative url', () => {
|
||||
cy
|
||||
@@ -1139,6 +1106,14 @@ describe('src/cy/commands/xhr', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('sets ignore as function by default', () => {
|
||||
cy.server()
|
||||
cy.route('*', {})
|
||||
.then(() => {
|
||||
expect(cy.state('server').getRoutes()[0].ignore).to.be.a('function')
|
||||
})
|
||||
})
|
||||
|
||||
it('passes down options.delay to routes', () => {
|
||||
cy
|
||||
.server({ delay: 100 })
|
||||
@@ -1243,110 +1218,6 @@ describe('src/cy/commands/xhr', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// FIXME: I have no idea why this is skipped, this test is rly old
|
||||
context.skip('#server', () => {
|
||||
beforeEach(function () {
|
||||
const defaults = {
|
||||
ignore: true,
|
||||
respond: true,
|
||||
delay: 10,
|
||||
beforeRequest () {},
|
||||
afterResponse () {},
|
||||
onAbort () {},
|
||||
onError () {},
|
||||
onFilter () {},
|
||||
}
|
||||
|
||||
this.options = (obj) => {
|
||||
return _.extend(obj, defaults)
|
||||
}
|
||||
|
||||
this.create = cy.spy(this.Cypress.Server, 'create')
|
||||
})
|
||||
|
||||
it('can accept an onRequest and onResponse callback', function (done) {
|
||||
const onRequest = () => {}
|
||||
const onResponse = () => {}
|
||||
|
||||
cy.on('end', () => {
|
||||
expect(this.create.getCall(0).args[1]).to.have.keys(_.keys(this.options({ onRequest, onResponse })))
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.server(onRequest, onResponse)
|
||||
})
|
||||
|
||||
it('can accept onRequest and onRespond through options', function (done) {
|
||||
const onRequest = () => {}
|
||||
const onResponse = () => {}
|
||||
|
||||
cy.on('end', () => {
|
||||
expect(this.create.getCall(0).args[1]).to.have.keys(_.keys(this.options({ onRequest, onResponse })))
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.server({ onRequest, onResponse })
|
||||
})
|
||||
|
||||
describe('without sinon present', () => {
|
||||
beforeEach(() => {
|
||||
// force us to start from blank window
|
||||
cy.state('$autIframe').prop('src', 'about:blank')
|
||||
})
|
||||
|
||||
it('can start server with no errors', () => {
|
||||
cy
|
||||
.server()
|
||||
.visit('http://localhost:3500/fixtures/sinon.html')
|
||||
})
|
||||
|
||||
it('can add routes with no errors', () => {
|
||||
cy
|
||||
.server()
|
||||
.route(/foo/, {})
|
||||
.visit('http://localhost:3500/fixtures/sinon.html')
|
||||
})
|
||||
|
||||
it('routes xhr requests', () => {
|
||||
cy
|
||||
.server()
|
||||
.route(/foo/, { foo: 'bar' })
|
||||
.visit('http://localhost:3500/fixtures/sinon.html')
|
||||
.window().then((w) => {
|
||||
return w.$.get('/foo')
|
||||
})
|
||||
.then((resp) => {
|
||||
expect(resp).to.deep.eq({ foo: 'bar' })
|
||||
})
|
||||
})
|
||||
|
||||
it('works with aliases', () => {
|
||||
cy
|
||||
.server()
|
||||
.route(/foo/, { foo: 'bar' }).as('getFoo')
|
||||
.visit('http://localhost:3500/fixtures/sinon.html')
|
||||
.window().then((w) => {
|
||||
return w.$.get('/foo')
|
||||
})
|
||||
.wait('@getFoo').then((xhr) => {
|
||||
expect(xhr.responseText).to.eq(JSON.stringify({ foo: 'bar' }))
|
||||
})
|
||||
})
|
||||
|
||||
it('prevents XHR\'s from going out from sinon.html', () => {
|
||||
cy
|
||||
.server()
|
||||
.route(/bar/, { bar: 'baz' }).as('getBar')
|
||||
.visit('http://localhost:3500/fixtures/sinon.html')
|
||||
.wait('@getBar').then((xhr) => {
|
||||
expect(xhr.responseText).to.eq(JSON.stringify({ bar: 'baz' }))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#route', () => {
|
||||
beforeEach(function () {
|
||||
this.expectOptionsToBe = (opts) => {
|
||||
@@ -1909,6 +1780,16 @@ describe('src/cy/commands/xhr', () => {
|
||||
cy.route()
|
||||
})
|
||||
|
||||
it('throws on use of whitelist option', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.include('The `cy.server()` `whitelist` option has been renamed to `ignore`. Please rename `whitelist` to `ignore`.')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.server({ whitelist: () => { } })
|
||||
})
|
||||
|
||||
it('url must be a string or regexp', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.include('`cy.route()` was called with an invalid `url`. `url` must be either a string or regular expression.')
|
||||
@@ -2285,8 +2166,8 @@ describe('src/cy/commands/xhr', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('whitelisting', () => {
|
||||
it('does not send back 404s on whitelisted routes', () => {
|
||||
describe('ignored routes', () => {
|
||||
it('does not send back 404s on allowed routes', () => {
|
||||
cy
|
||||
.server()
|
||||
.window().then((win) => {
|
||||
@@ -2298,7 +2179,7 @@ describe('src/cy/commands/xhr', () => {
|
||||
})
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/7280
|
||||
it('ignores query params when whitelisting routes', () => {
|
||||
it('ignores query params when filtering routes', () => {
|
||||
cy.server()
|
||||
cy.route(/url-with-query-param/, { foo: 'bar' }).as('getQueryParam')
|
||||
cy.window().then((win) => {
|
||||
@@ -2312,7 +2193,7 @@ describe('src/cy/commands/xhr', () => {
|
||||
})
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/7280
|
||||
it('ignores hashes when whitelisting routes', () => {
|
||||
it('ignores hashes when filtering routes', () => {
|
||||
cy.server()
|
||||
cy.route(/url-with-hash/, { foo: 'bar' }).as('getHash')
|
||||
cy.window().then((win) => {
|
||||
@@ -2324,6 +2205,30 @@ describe('src/cy/commands/xhr', () => {
|
||||
cy.wait('@getHash').its('response.body')
|
||||
.should('deep.equal', { foo: 'bar' })
|
||||
})
|
||||
|
||||
it('overrides ignoring resources when passed as option', () => {
|
||||
cy.server({ ignore: () => false })
|
||||
cy.route('app.js', { foo: 'bar' }).as('getJSResource')
|
||||
cy.route('index.html', '<html></html>').as('getHTMLResource')
|
||||
cy.route('style.css', 'body: {color: red;}').as('getCSSResource')
|
||||
cy.window().then((win) => {
|
||||
win.$.get('/fixtures/app.js')
|
||||
win.$.get('/fixtures/style.css')
|
||||
|
||||
return win.$.get('/fixtures/index.html')
|
||||
})
|
||||
|
||||
// normally these resources would be ignored
|
||||
// but overwriting ignore to return false allows all resources
|
||||
cy.wait('@getJSResource').its('response.body')
|
||||
.should('deep.equal', { foo: 'bar' })
|
||||
|
||||
cy.wait('@getHTMLResource').its('response.body')
|
||||
.should('deep.equal', '<html></html>')
|
||||
|
||||
cy.wait('@getCSSResource').its('response.body')
|
||||
.should('deep.equal', 'body: {color: red;}')
|
||||
})
|
||||
})
|
||||
|
||||
describe('route setup', () => {
|
||||
|
||||
@@ -95,7 +95,7 @@ module.exports = function (Commands, Cypress, cy, state, config) {
|
||||
return resp
|
||||
}
|
||||
|
||||
// iterate over all of these and ensure none are whitelisted
|
||||
// iterate over all of these and ensure none are allowed
|
||||
// or preserved
|
||||
const cookies = Cypress.Cookies.getClearableCookies(resp)
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@ const shouldUpdateValue = (el: HTMLElement, key: KeyDetails, options: typeOption
|
||||
|
||||
if (!(numberRe.test(potentialValue))) {
|
||||
debug('skipping inserting value since number input would be invalid', key.text, potentialValue)
|
||||
// when typing in a number input, only certain whitelisted chars will insert text
|
||||
// when typing in a number input, only certain allowed chars will insert text
|
||||
if (!key.text.match(isValidNumberInputChar)) {
|
||||
// https://github.com/cypress-io/cypress/issues/6055
|
||||
// Should not remove old valid values when a new one is not a valid number char, just dismiss it with return
|
||||
|
||||
@@ -9,7 +9,13 @@ let isDebuggingVerbose = false
|
||||
const preserved = {}
|
||||
|
||||
const defaults = {
|
||||
whitelist: null,
|
||||
preserve: null,
|
||||
}
|
||||
|
||||
const warnOnWhitelistRenamed = (obj, type) => {
|
||||
if (obj.whitelist) {
|
||||
return $errUtils.throwErrByPath('cookies.whitelist_renamed', { args: { type } })
|
||||
}
|
||||
}
|
||||
|
||||
const $Cookies = (namespace, domain) => {
|
||||
@@ -17,8 +23,8 @@ const $Cookies = (namespace, domain) => {
|
||||
return _.startsWith(name, namespace)
|
||||
}
|
||||
|
||||
const isWhitelisted = (cookie) => {
|
||||
const w = defaults.whitelist
|
||||
const isAllowed = (cookie) => {
|
||||
const w = defaults.preserve
|
||||
|
||||
if (w) {
|
||||
if (_.isString(w)) {
|
||||
@@ -76,7 +82,7 @@ const $Cookies = (namespace, domain) => {
|
||||
|
||||
getClearableCookies (cookies = []) {
|
||||
return _.filter(cookies, (cookie) => {
|
||||
return !isWhitelisted(cookie) && !removePreserved(cookie.name)
|
||||
return !isAllowed(cookie) && !removePreserved(cookie.name)
|
||||
})
|
||||
},
|
||||
|
||||
@@ -132,6 +138,8 @@ const $Cookies = (namespace, domain) => {
|
||||
},
|
||||
|
||||
defaults (obj = {}) {
|
||||
warnOnWhitelistRenamed(obj, 'Cypress.Cookies.defaults')
|
||||
|
||||
// merge obj into defaults
|
||||
return _.extend(defaults, obj)
|
||||
},
|
||||
|
||||
@@ -301,6 +301,11 @@ module.exports = {
|
||||
- \`cy.clearCookie()\`
|
||||
- \`cy.clearCookies()\``,
|
||||
},
|
||||
whitelist_renamed (obj) {
|
||||
return {
|
||||
message: `\`${obj.type}\` \`whitelist\` option has been renamed to \`preserve\`. Please rename \`whitelist\` to \`preserve\`.`,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
dom: {
|
||||
@@ -1286,6 +1291,7 @@ module.exports = {
|
||||
},
|
||||
xhrurl_not_set: '`Server.options.xhrUrl` has not been set',
|
||||
unavailable: 'The XHR server is unavailable or missing. This should never happen and likely is a bug. Open an issue if you see this message.',
|
||||
whitelist_renamed: `The ${cmd('server')} \`whitelist\` option has been renamed to \`ignore\`. Please rename \`whitelist\` to \`ignore\`.`,
|
||||
},
|
||||
|
||||
setCookie: {
|
||||
|
||||
@@ -65,7 +65,13 @@ const warnOnForce404Default = (obj) => {
|
||||
}
|
||||
}
|
||||
|
||||
const whitelist = (xhr) => {
|
||||
const warnOnWhitelistRenamed = (obj, type) => {
|
||||
if (obj.whitelist) {
|
||||
return $errUtils.throwErrByPath('server.whitelist_renamed', { args: { type } })
|
||||
}
|
||||
}
|
||||
|
||||
const ignore = (xhr) => {
|
||||
const url = new URL(xhr.url)
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/7280
|
||||
@@ -74,7 +80,7 @@ const whitelist = (xhr) => {
|
||||
url.search = ''
|
||||
url.hash = ''
|
||||
|
||||
// whitelist if we're GET + looks like we're fetching regular resources
|
||||
// allow if we're GET + looks like we're fetching regular resources
|
||||
return xhr.method === 'GET' && regularResourcesRe.test(url.href)
|
||||
}
|
||||
|
||||
@@ -95,7 +101,7 @@ const serverDefaults = {
|
||||
urlMatchingOptions: { matchBase: true },
|
||||
stripOrigin: _.identity,
|
||||
getUrlOptions: _.identity,
|
||||
whitelist, // function whether to allow a request to go out (css/js/html/templates) etc
|
||||
ignore, // function whether to allow a request to go out (css/js/html/templates) etc
|
||||
onOpen () {},
|
||||
onSend () {},
|
||||
onXhrAbort () {},
|
||||
@@ -209,8 +215,8 @@ const create = (options = {}) => {
|
||||
return routes
|
||||
},
|
||||
|
||||
isWhitelisted (xhr) {
|
||||
return options.whitelist(xhr)
|
||||
isIgnored (xhr) {
|
||||
return options.ignore(xhr)
|
||||
},
|
||||
|
||||
shouldApplyStub (route) {
|
||||
@@ -257,9 +263,9 @@ const create = (options = {}) => {
|
||||
// return the 404 stub if we dont have any stubs
|
||||
// but we are stubbed - meaning we havent added any routes
|
||||
// but have started the server
|
||||
// and this request shouldnt be whitelisted
|
||||
// and this request shouldnt be allowed
|
||||
if (!routes.length && hasEnabledStubs &&
|
||||
options.force404 !== false && !server.isWhitelisted(xhr)) {
|
||||
options.force404 !== false && !server.isIgnored(xhr)) {
|
||||
return get404Route()
|
||||
}
|
||||
|
||||
@@ -268,8 +274,8 @@ const create = (options = {}) => {
|
||||
return nope()
|
||||
}
|
||||
|
||||
// bail if this xhr matches our whitelist
|
||||
if (server.isWhitelisted(xhr)) {
|
||||
// bail if this xhr matches our ignore list
|
||||
if (server.isIgnored(xhr)) {
|
||||
return nope()
|
||||
}
|
||||
|
||||
@@ -414,6 +420,7 @@ const create = (options = {}) => {
|
||||
set (obj) {
|
||||
warnOnStubDeprecation(obj, 'server')
|
||||
warnOnForce404Default(obj)
|
||||
warnOnWhitelistRenamed(obj, 'server')
|
||||
|
||||
// handle enable=true|false
|
||||
if (obj.enable != null) {
|
||||
@@ -648,8 +655,8 @@ const create = (options = {}) => {
|
||||
proxy._setRequestBody(requestBody)
|
||||
|
||||
// log this out now since it's being sent officially
|
||||
// unless its been whitelisted
|
||||
if (!server.isWhitelisted(this)) {
|
||||
// unless its not been ignored
|
||||
if (!server.isIgnored(this)) {
|
||||
options.onSend(proxy, sendStack, route)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@ function replaceStringsIn (file) {
|
||||
replace(eslintRe, "")
|
||||
replace("imgSrcToDataURL('/assets", "imgSrcToDataURL('https://example.cypress.io/assets")
|
||||
|
||||
// temporary for 5.0.0
|
||||
// TODO: remove this
|
||||
replace("whitelist: 'session_id'", "preserve: 'session_id'")
|
||||
replace("server.whitelist", "server.ignore")
|
||||
|
||||
fs.writeFile(file, str, function (err) {
|
||||
if (err) throw err
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ exports['e2e cookies with baseurl'] = `
|
||||
|
||||
|
||||
cookies
|
||||
with whitelist
|
||||
with preserve
|
||||
✓ can get all cookies
|
||||
✓ resets cookies between tests correctly
|
||||
✓ should be only two left now
|
||||
✓ handles undefined cookies
|
||||
without whitelist
|
||||
without preserve
|
||||
✓ sends set cookies to path
|
||||
✓ handles expired cookies secure
|
||||
✓ issue: #224 sets expired cookies between redirects
|
||||
@@ -122,12 +122,12 @@ exports['e2e cookies with no baseurl'] = `
|
||||
|
||||
|
||||
cookies
|
||||
with whitelist
|
||||
with preserve
|
||||
✓ can get all cookies
|
||||
✓ resets cookies between tests correctly
|
||||
✓ should be only two left now
|
||||
✓ handles undefined cookies
|
||||
without whitelist
|
||||
without preserve
|
||||
✓ sends cookies to localhost:2121
|
||||
✓ handles expired cookies secure
|
||||
✓ issue: #224 sets expired cookies between redirects
|
||||
|
||||
@@ -83,7 +83,7 @@ firefoxGcInterval\
|
||||
`)
|
||||
|
||||
// NOTE: If you add a config value, make sure to update the following
|
||||
// - cli/types/index.d.ts (including whitelisted config options on TestOptions)
|
||||
// - cli/types/index.d.ts (including allowed config options on TestOptions)
|
||||
// - cypress.schema.json
|
||||
|
||||
// experimentalComponentTesting
|
||||
@@ -372,7 +372,7 @@ module.exports = {
|
||||
return _.includes(names, value)
|
||||
},
|
||||
|
||||
whitelist (obj = {}) {
|
||||
allowed (obj = {}) {
|
||||
const propertyNames = configKeys
|
||||
.concat(breakingConfigKeys)
|
||||
.concat(systemConfigKeys)
|
||||
@@ -427,7 +427,7 @@ module.exports = {
|
||||
debug('merged config with options, got %o', config)
|
||||
|
||||
_
|
||||
.chain(this.whitelist(options))
|
||||
.chain(this.allowed(options))
|
||||
.omit('env')
|
||||
.omit('browsers')
|
||||
.each((val, key) => {
|
||||
|
||||
@@ -173,10 +173,10 @@ class Project extends EE {
|
||||
|
||||
_initPlugins (cfg, options) {
|
||||
// only init plugins with the
|
||||
// whitelisted config values to
|
||||
// allowed config values to
|
||||
// prevent tampering with the
|
||||
// internals and breaking cypress
|
||||
cfg = config.whitelist(cfg)
|
||||
cfg = config.allowed(cfg)
|
||||
|
||||
return plugins.init(cfg, {
|
||||
projectRoot: this.projectRoot,
|
||||
|
||||
@@ -9,7 +9,7 @@ const fs = require('./util/fs')
|
||||
|
||||
const stateFiles = {}
|
||||
|
||||
const whitelist = `
|
||||
const allowed = `
|
||||
appWidth
|
||||
appHeight
|
||||
appX
|
||||
@@ -64,7 +64,7 @@ const formStatePath = (projectRoot) => {
|
||||
})
|
||||
}
|
||||
|
||||
const normalizeAndWhitelistSet = (set, key, value) => {
|
||||
const normalizeAndAllowSet = (set, key, value) => {
|
||||
const valueObject = (() => {
|
||||
if (_.isString(key)) {
|
||||
const tmp = {}
|
||||
@@ -78,15 +78,15 @@ const normalizeAndWhitelistSet = (set, key, value) => {
|
||||
})()
|
||||
|
||||
const invalidKeys = _.filter(_.keys(valueObject), (key) => {
|
||||
return !_.includes(whitelist, key)
|
||||
return !_.includes(allowed, key)
|
||||
})
|
||||
|
||||
if (invalidKeys.length) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`WARNING: attempted to save state for non-whitelisted key(s): ${invalidKeys.join(', ')}. All keys must be whitelisted in server/lib/saved_state.js`)
|
||||
console.error(`WARNING: attempted to save state for non-allowed key(s): ${invalidKeys.join(', ')}. All keys must be allowed in server/lib/saved_state.js`)
|
||||
}
|
||||
|
||||
return set(_.pick(valueObject, whitelist))
|
||||
return set(_.pick(valueObject, allowed))
|
||||
}
|
||||
|
||||
const create = (projectRoot, isTextTerminal) => {
|
||||
@@ -110,7 +110,7 @@ const create = (projectRoot, isTextTerminal) => {
|
||||
path: fullStatePath,
|
||||
})
|
||||
|
||||
stateFile.set = _.wrap(stateFile.set.bind(stateFile), normalizeAndWhitelistSet)
|
||||
stateFile.set = _.wrap(stateFile.set.bind(stateFile), normalizeAndAllowSet)
|
||||
|
||||
stateFiles[fullStatePath] = stateFile
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ const appData = require('./util/app_data')
|
||||
const statusCode = require('./util/status_code')
|
||||
const headersUtil = require('./util/headers')
|
||||
const allowDestroy = require('./util/server_destroy')
|
||||
const { SocketWhitelist } = require('./util/socket_whitelist')
|
||||
const { SocketAllowed } = require('./util/socket_allowed')
|
||||
const errors = require('./errors')
|
||||
const logger = require('./logger')
|
||||
const Socket = require('./socket')
|
||||
@@ -59,7 +59,7 @@ const _forceProxyMiddleware = function (clientRoute) {
|
||||
const trimmedUrl = _.trimEnd(req.proxiedUrl, '/')
|
||||
|
||||
if (_isNonProxiedRequest(req) && !ALLOWED_PROXY_BYPASS_URLS.includes(trimmedUrl) && (trimmedUrl !== trimmedClientRoute)) {
|
||||
// this request is non-proxied and non-whitelisted, redirect to the runner error page
|
||||
// this request is non-proxied and non-allowed, redirect to the runner error page
|
||||
return res.redirect(clientRoute)
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ class Server {
|
||||
return new Server()
|
||||
}
|
||||
|
||||
this._socketWhitelist = new SocketWhitelist()
|
||||
this._socketAllowed = new SocketAllowed()
|
||||
this._request = null
|
||||
this._middleware = null
|
||||
this._server = null
|
||||
@@ -278,7 +278,7 @@ class Server {
|
||||
this._server.on('connect', (req, socket, head) => {
|
||||
debug('Got CONNECT request from %s', req.url)
|
||||
|
||||
socket.once('upstream-connected', this._socketWhitelist.add)
|
||||
socket.once('upstream-connected', this._socketAllowed.add)
|
||||
|
||||
return this._httpsProxy.connect(req, socket, head, {
|
||||
onDirectConnection: (req) => {
|
||||
@@ -761,7 +761,7 @@ class Server {
|
||||
let host; let remoteOrigin
|
||||
|
||||
if (req.url.startsWith(socketIoRoute)) {
|
||||
if (!this._socketWhitelist.isRequestWhitelisted(req)) {
|
||||
if (!this._socketAllowed.isRequestAllowed(req)) {
|
||||
socket.write('HTTP/1.1 400 Bad Request\r\n\r\nRequest not made via a Cypress-launched browser.')
|
||||
socket.end()
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ const nestedObjectsInCurlyBracesRe = /\{(.+?)\}/g
|
||||
const nestedArraysInSquareBracketsRe = /\[(.+?)\]/g
|
||||
const everythingAfterFirstEqualRe = /=(.*)/
|
||||
|
||||
const whitelist = 'appPath apiKey browser ci ciBuildId clearLogs config configFile cwd env execPath exit exitWithCode generateKey getKey group headed inspectBrk key logs mode outputPath parallel ping port project proxySource quiet record reporter reporterOptions returnPkg runMode runProject smokeTest spec tag updating version'.split(' ')
|
||||
const allowList = 'appPath apiKey browser ci ciBuildId clearLogs config configFile cwd env execPath exit exitWithCode generateKey getKey group headed inspectBrk key logs mode outputPath parallel ping port project proxySource quiet record reporter reporterOptions returnPkg runMode runProject smokeTest spec tag updating version'.split(' ')
|
||||
// returns true if the given string has double quote character "
|
||||
// only at the last position.
|
||||
const hasStrayEndQuote = (s) => {
|
||||
@@ -189,14 +189,14 @@ module.exports = {
|
||||
alias,
|
||||
})
|
||||
|
||||
const whitelisted = _.pick(argv, whitelist)
|
||||
const allowed = _.pick(argv, allowList)
|
||||
|
||||
// were we invoked from the CLI or directly?
|
||||
const invokedFromCli = Boolean(options.cwd)
|
||||
|
||||
options = _
|
||||
.chain(options)
|
||||
.defaults(whitelisted)
|
||||
.defaults(allowed)
|
||||
.omit(_.keys(alias)) // remove aliases
|
||||
.extend({ invokedFromCli })
|
||||
.defaults({
|
||||
@@ -320,11 +320,11 @@ module.exports = {
|
||||
toArray (obj = {}) {
|
||||
// goes in reverse, takes an object
|
||||
// and converts to an array by picking
|
||||
// only the whitelisted properties and
|
||||
// only the allowed properties and
|
||||
// mapping them to include the argument
|
||||
return _
|
||||
.chain(obj)
|
||||
.pick(...whitelist)
|
||||
.pick(...allowList)
|
||||
.mapValues((val, key) => {
|
||||
return `--${key}=${stringify(val)}`
|
||||
}).values()
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import _ from 'lodash'
|
||||
import Debug from 'debug'
|
||||
import net from 'net'
|
||||
import { Request } from 'express'
|
||||
|
||||
const debug = Debug('cypress:server:util:socket_allowed')
|
||||
|
||||
/**
|
||||
* Utility to validate incoming, local socket connections against a list of
|
||||
* expected client TCP ports.
|
||||
*/
|
||||
export class SocketAllowed {
|
||||
allowedLocalPorts: number[] = []
|
||||
|
||||
/**
|
||||
* Add a socket to the allowed list.
|
||||
*/
|
||||
add = (socket: net.Socket) => {
|
||||
const { localPort } = socket
|
||||
|
||||
debug('allowing socket %o', { localPort })
|
||||
this.allowedLocalPorts.push(localPort)
|
||||
|
||||
socket.once('close', () => {
|
||||
debug('allowed socket closed, removing %o', { localPort })
|
||||
this._remove(socket)
|
||||
})
|
||||
}
|
||||
|
||||
_remove (socket: net.Socket) {
|
||||
_.pull(this.allowedLocalPorts, socket.localPort)
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this socket that this request originated allowed?
|
||||
*/
|
||||
isRequestAllowed (req: Request) {
|
||||
const { remotePort, remoteAddress } = req.socket
|
||||
const isAllowed = this.allowedLocalPorts.includes(remotePort!)
|
||||
&& ['127.0.0.1', '::1'].includes(remoteAddress!)
|
||||
|
||||
debug('is incoming request allowed? %o', { isAllowed, reqUrl: req.url, remotePort, remoteAddress })
|
||||
|
||||
return isAllowed
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import _ from 'lodash'
|
||||
import Debug from 'debug'
|
||||
import net from 'net'
|
||||
import { Request } from 'express'
|
||||
|
||||
const debug = Debug('cypress:server:util:socket_whitelist')
|
||||
|
||||
/**
|
||||
* Utility to validate incoming, local socket connections against a list of
|
||||
* expected client TCP ports.
|
||||
*/
|
||||
export class SocketWhitelist {
|
||||
whitelistedLocalPorts: number[] = []
|
||||
|
||||
/**
|
||||
* Add a socket to the whitelist.
|
||||
*/
|
||||
add = (socket: net.Socket) => {
|
||||
const { localPort } = socket
|
||||
|
||||
debug('whitelisting socket %o', { localPort })
|
||||
this.whitelistedLocalPorts.push(localPort)
|
||||
|
||||
socket.once('close', () => {
|
||||
debug('whitelisted socket closed, removing %o', { localPort })
|
||||
this._remove(socket)
|
||||
})
|
||||
}
|
||||
|
||||
_remove (socket: net.Socket) {
|
||||
_.pull(this.whitelistedLocalPorts, socket.localPort)
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this socket that this request originated from whitelisted?
|
||||
*/
|
||||
isRequestWhitelisted (req: Request) {
|
||||
const { remotePort, remoteAddress } = req.socket
|
||||
const isWhitelisted = this.whitelistedLocalPorts.includes(remotePort!)
|
||||
&& ['127.0.0.1', '::1'].includes(remoteAddress!)
|
||||
|
||||
debug('is incoming request whitelisted? %o', { isWhitelisted, reqUrl: req.url, remotePort, remoteAddress })
|
||||
|
||||
return isWhitelisted
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
Cypress.Cookies.defaults({
|
||||
whitelist: "foo1"
|
||||
preserve: "foo1"
|
||||
})
|
||||
|
||||
describe "Cookies", ->
|
||||
@@ -84,3 +84,4 @@ describe "Cookies", ->
|
||||
domain: "brian.dev.local"
|
||||
})
|
||||
.its("body").should("deep.eq", {wow: "bob"})
|
||||
|
||||
+4
-4
@@ -35,10 +35,10 @@ describe "cookies", ->
|
||||
beforeEach ->
|
||||
cy.wrap({foo: "bar"})
|
||||
|
||||
context "with whitelist", ->
|
||||
context "with preserve", ->
|
||||
before ->
|
||||
Cypress.Cookies.defaults({
|
||||
whitelist: "foo1"
|
||||
preserve: "foo1"
|
||||
})
|
||||
|
||||
it "can get all cookies", ->
|
||||
@@ -104,10 +104,10 @@ describe "cookies", ->
|
||||
it "handles undefined cookies", ->
|
||||
cy.visit("/cookieWithNoName")
|
||||
|
||||
context "without whitelist", ->
|
||||
context "without preserve", ->
|
||||
before ->
|
||||
Cypress.Cookies.defaults({
|
||||
whitelist: []
|
||||
preserve: []
|
||||
})
|
||||
|
||||
it "sends set cookies to path", ->
|
||||
|
||||
+4
-4
@@ -5,10 +5,10 @@ describe "cookies", ->
|
||||
beforeEach ->
|
||||
cy.wrap({foo: "bar"})
|
||||
|
||||
context "with whitelist", ->
|
||||
context "with preserve", ->
|
||||
before ->
|
||||
Cypress.Cookies.defaults({
|
||||
whitelist: "foo1"
|
||||
preserve: "foo1"
|
||||
})
|
||||
|
||||
it "can get all cookies", ->
|
||||
@@ -79,10 +79,10 @@ describe "cookies", ->
|
||||
it "handles undefined cookies", ->
|
||||
cy.visit("#{httpUrl}/cookieWithNoName")
|
||||
|
||||
context "without whitelist", ->
|
||||
context "without preserve", ->
|
||||
before ->
|
||||
Cypress.Cookies.defaults({
|
||||
whitelist: []
|
||||
preserve: []
|
||||
})
|
||||
|
||||
it "sends cookies to localhost:2121", ->
|
||||
|
||||
@@ -270,7 +270,7 @@ describe('lib/util/args', () => {
|
||||
expect(options.config).to.deep.eq(config)
|
||||
})
|
||||
|
||||
it('whitelists config properties', function () {
|
||||
it('allows config properties', function () {
|
||||
const options = this.setup('--config', 'foo=bar,port=1111,supportFile=path/to/support_file')
|
||||
|
||||
expect(options.config.port).to.eq(1111)
|
||||
|
||||
@@ -62,7 +62,7 @@ describe('lib/saved_state', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('only saves whitelisted keys', () => {
|
||||
it('only saves allowed keys', () => {
|
||||
return savedState.create()
|
||||
.then((state) => {
|
||||
return state.set({ foo: 'bar', appWidth: 20 })
|
||||
@@ -81,7 +81,7 @@ describe('lib/saved_state', () => {
|
||||
.then((state) => {
|
||||
return state.set({ foo: 'bar', baz: 'qux' })
|
||||
}).then(() => {
|
||||
expect(console.error).to.be.calledWith('WARNING: attempted to save state for non-whitelisted key(s): foo, baz. All keys must be whitelisted in server/lib/saved_state.js')
|
||||
expect(console.error).to.be.calledWith('WARNING: attempted to save state for non-allowed key(s): foo, baz. All keys must be allowed in server/lib/saved_state.js')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -679,7 +679,7 @@ describe('lib/screenshots', () => {
|
||||
return sinon.stub(plugins, 'execute')
|
||||
})
|
||||
|
||||
it('resolves whitelisted details if no after:screenshot plugin registered', function () {
|
||||
it('resolves allowed details if no after:screenshot plugin registered', function () {
|
||||
plugins.has.returns(false)
|
||||
|
||||
return screenshots.afterScreenshot(this.data, this.details).then((result) => {
|
||||
|
||||
@@ -338,7 +338,7 @@ describe('lib/server', () => {
|
||||
remoteAddress: '127.0.0.1',
|
||||
}
|
||||
|
||||
this.server._socketWhitelist.add({
|
||||
this.server._socketAllowed.add({
|
||||
localPort: socket.remotePort,
|
||||
once: _.noop,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import '../../spec_helper'
|
||||
|
||||
import { expect } from 'chai'
|
||||
import { Request } from 'express'
|
||||
import { SocketAllowed } from '../../../lib/util/socket_allowed'
|
||||
import { EventEmitter } from 'events'
|
||||
import { Socket } from 'net'
|
||||
|
||||
describe('lib/util/socket_allowed', function () {
|
||||
let sw: SocketAllowed
|
||||
|
||||
beforeEach(() => {
|
||||
sw = new SocketAllowed()
|
||||
})
|
||||
|
||||
context('#add', () => {
|
||||
it('adds localPort to allowed list and removes it when closed', () => {
|
||||
const socket = new EventEmitter as Socket
|
||||
|
||||
// @ts-ignore readonly
|
||||
socket.localPort = 12345
|
||||
|
||||
const req = {
|
||||
socket: {
|
||||
remotePort: socket.localPort,
|
||||
remoteAddress: '127.0.0.1',
|
||||
},
|
||||
} as Request
|
||||
|
||||
expect(sw.allowedLocalPorts).to.deep.eq([])
|
||||
expect(sw.isRequestAllowed(req)).to.be.false
|
||||
|
||||
sw.add(socket)
|
||||
expect(sw.allowedLocalPorts).to.deep.eq([socket.localPort])
|
||||
expect(sw.isRequestAllowed(req)).to.be.true
|
||||
|
||||
socket.emit('close')
|
||||
expect(sw.allowedLocalPorts).to.deep.eq([])
|
||||
expect(sw.isRequestAllowed(req)).to.be.false
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,42 +0,0 @@
|
||||
import '../../spec_helper'
|
||||
|
||||
import { expect } from 'chai'
|
||||
import { Request } from 'express'
|
||||
import { SocketWhitelist } from '../../../lib/util/socket_whitelist'
|
||||
import { EventEmitter } from 'events'
|
||||
import { Socket } from 'net'
|
||||
|
||||
describe('lib/util/socket_whitelist', function () {
|
||||
let sw: SocketWhitelist
|
||||
|
||||
beforeEach(() => {
|
||||
sw = new SocketWhitelist()
|
||||
})
|
||||
|
||||
context('#add', () => {
|
||||
it('adds localPort to whitelist and removes it when closed', () => {
|
||||
const socket = new EventEmitter as Socket
|
||||
|
||||
// @ts-ignore readonly
|
||||
socket.localPort = 12345
|
||||
|
||||
const req = {
|
||||
socket: {
|
||||
remotePort: socket.localPort,
|
||||
remoteAddress: '127.0.0.1',
|
||||
},
|
||||
} as Request
|
||||
|
||||
expect(sw.whitelistedLocalPorts).to.deep.eq([])
|
||||
expect(sw.isRequestWhitelisted(req)).to.be.false
|
||||
|
||||
sw.add(socket)
|
||||
expect(sw.whitelistedLocalPorts).to.deep.eq([socket.localPort])
|
||||
expect(sw.isRequestWhitelisted(req)).to.be.true
|
||||
|
||||
socket.emit('close')
|
||||
expect(sw.whitelistedLocalPorts).to.deep.eq([])
|
||||
expect(sw.isRequestWhitelisted(req)).to.be.false
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user