From b28134e7709c803eb7a7ed071a25bac8a28e3d1f Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Sat, 7 Dec 2019 11:53:16 +0800 Subject: [PATCH] feat: add application level Cookie options (#4086) * test: fix doctools path on windows --- .travis.yml | 1 + app/extend/context.js | 2 +- config/config.default.js | 12 ++++++++ docs/source/en/basics/controller.md | 23 +++++++++++++++ docs/source/zh-cn/basics/controller.md | 23 +++++++++++++++ package.json | 2 +- test/doc.test.js | 8 ++++-- .../app-config-cookies/app/controller/home.js | 4 +++ .../apps/app-config-cookies/app/router.js | 3 ++ .../config/config.default.js | 7 +++++ .../apps/app-config-cookies/package.json | 3 ++ test/lib/core/config/config.cookies.test.js | 28 +++++++++++++++++++ 12 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 test/fixtures/apps/app-config-cookies/app/controller/home.js create mode 100644 test/fixtures/apps/app-config-cookies/app/router.js create mode 100644 test/fixtures/apps/app-config-cookies/config/config.default.js create mode 100644 test/fixtures/apps/app-config-cookies/package.json create mode 100644 test/lib/core/config/config.cookies.test.js diff --git a/.travis.yml b/.travis.yml index 7273bd8066..c22a733287 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ node_js: - '8' - '10' - '12' + - '13' before_install: - npm install -g npminstall install: diff --git a/app/extend/context.js b/app/extend/context.js index 87b0b7d9e9..a2ed967196 100644 --- a/app/extend/context.js +++ b/app/extend/context.js @@ -19,7 +19,7 @@ const proto = module.exports = { */ get cookies() { if (!this[COOKIES]) { - this[COOKIES] = new this.app.ContextCookies(this, this.app.keys); + this[COOKIES] = new this.app.ContextCookies(this, this.app.keys, this.app.config.cookies); } return this[COOKIES]; }, diff --git a/config/config.default.js b/config/config.default.js index eb9fe868c9..1b2a657492 100644 --- a/config/config.default.js +++ b/config/config.default.js @@ -38,6 +38,18 @@ module.exports = appInfo => { */ keys: '', + /** + * default cookie options + * + * @member Config#cookies + * @property {String} sameSite - SameSite property, defaults is '' + * @property {Boolean} httpOnly - httpOnly property, defaults is true + */ + cookies: { + // httpOnly: true | false, + // sameSite: 'none|lax|strict', + }, + /** * Whether application deployed after a reverse proxy, * when true proxy header fields will be trusted diff --git a/docs/source/en/basics/controller.md b/docs/source/en/basics/controller.md index 39a322d531..387b590345 100644 --- a/docs/source/en/basics/controller.md +++ b/docs/source/en/basics/controller.md @@ -631,6 +631,29 @@ Although Cookie is only a header in HTTP, multiple key-value pairs can be set in In Web applications, Cookie is usually used to send the identity information of the client, so it has many safety related configurations which can not be ignored, [Cookie](../core/cookie-and-session.md#cookie) explains the usage and safety related configurations of Cookie in detail and is worth being read in depth. +#### Configuration + +There are mainly these attributes below can be used to configure default Cookie options in `config.default.js`: + +```js +module.exports = { + cookies: { + // httpOnly: true | false, + // sameSite: 'none|lax|strict', + }, +}; +``` + +e.g.: Configured application level Cookie [SameSite](https://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html) property to `Lax`. + +```js +module.exports = { + cookies: { + sameSite: 'lax', + }, +}; +``` + ### Session By using Cookie, we can create an individual Session specific to every user to store user identity information, which will be encrypted then stored in Cookie to perform session persistence across requests. diff --git a/docs/source/zh-cn/basics/controller.md b/docs/source/zh-cn/basics/controller.md index 437f574ece..8217ba7893 100644 --- a/docs/source/zh-cn/basics/controller.md +++ b/docs/source/zh-cn/basics/controller.md @@ -631,6 +631,29 @@ Cookie 虽然在 HTTP 中只是一个头,但是通过 `foo=bar;foo1=bar1;` 的 Cookie 在 Web 应用中经常承担了传递客户端身份信息的作用,因此有许多安全相关的配置,不可忽视,[Cookie](../core/cookie-and-session.md#cookie) 文档中详细介绍了 Cookie 的用法和安全相关的配置项,可以深入阅读了解。 +#### 配置 + +对于 Cookie 来说,主要有下面几个属性可以在 `config.default.js` 中进行配置: + +```js +module.exports = { + cookies: { + // httpOnly: true | false, + // sameSite: 'none|lax|strict', + }, +}; +``` + +举例: 配置应用级别的 Cookie [SameSite](https://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html) 属性等于 `Lax`。 + +```js +module.exports = { + cookies: { + sameSite: 'lax', + }, +}; +``` + ### Session 通过 Cookie,我们可以给每一个用户设置一个 Session,用来存储用户身份相关的信息,这份信息会加密后存储在 Cookie 中,实现跨请求的用户身份保持。 diff --git a/package.json b/package.json index f775a3e7b2..56c83a055f 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "debug": "^4.1.1", "delegates": "^1.0.0", "egg-cluster": "^1.23.0", - "egg-cookies": "^2.2.6", + "egg-cookies": "^2.3.0", "egg-core": "^4.16.1", "egg-development": "^2.4.2", "egg-i18n": "^2.0.0", diff --git a/test/doc.test.js b/test/doc.test.js index f41f94d75f..6cca1d3c94 100644 --- a/test/doc.test.js +++ b/test/doc.test.js @@ -7,11 +7,13 @@ const runscript = require('runscript'); const utils = require('./utils'); describe('test/doc.test.js', () => { - let app; before(async () => { - const doctools = path.join(process.cwd(), 'node_modules/.bin', 'doctools'); - await runscript(`${doctools} build`, { cwd: path.dirname(__dirname) }); + const cwd = path.dirname(__dirname); + const doctools = path.join(cwd, 'node_modules', '.bin', 'doctools'); + const cmd = `${doctools} build`; + console.log('Runing %j on %j', cmd, cwd); + await runscript(cmd, { cwd }); }); before(async () => { app = utils.cluster({ diff --git a/test/fixtures/apps/app-config-cookies/app/controller/home.js b/test/fixtures/apps/app-config-cookies/app/controller/home.js new file mode 100644 index 0000000000..2813ff1f7f --- /dev/null +++ b/test/fixtures/apps/app-config-cookies/app/controller/home.js @@ -0,0 +1,4 @@ +module.exports = async ctx => { + ctx.cookies.set('foo', 'bar'); + ctx.body = 'hello'; +}; diff --git a/test/fixtures/apps/app-config-cookies/app/router.js b/test/fixtures/apps/app-config-cookies/app/router.js new file mode 100644 index 0000000000..a7bbaa97d5 --- /dev/null +++ b/test/fixtures/apps/app-config-cookies/app/router.js @@ -0,0 +1,3 @@ +module.exports = app => { + app.get('home', '/', 'home'); +}; diff --git a/test/fixtures/apps/app-config-cookies/config/config.default.js b/test/fixtures/apps/app-config-cookies/config/config.default.js new file mode 100644 index 0000000000..98f2c2c290 --- /dev/null +++ b/test/fixtures/apps/app-config-cookies/config/config.default.js @@ -0,0 +1,7 @@ +'use strict'; + +exports.keys = 'test key'; + +exports.cookies = { + sameSite: 'lax', +}; diff --git a/test/fixtures/apps/app-config-cookies/package.json b/test/fixtures/apps/app-config-cookies/package.json new file mode 100644 index 0000000000..861b24f925 --- /dev/null +++ b/test/fixtures/apps/app-config-cookies/package.json @@ -0,0 +1,3 @@ +{ + "name": "app-config-cookies" +} diff --git a/test/lib/core/config/config.cookies.test.js b/test/lib/core/config/config.cookies.test.js new file mode 100644 index 0000000000..4b84004138 --- /dev/null +++ b/test/lib/core/config/config.cookies.test.js @@ -0,0 +1,28 @@ +'use strict'; + +const assert = require('assert'); +const mm = require('egg-mock'); +const utils = require('../../../utils'); + +describe('test/lib/core/config/config.cookies.test.js', () => { + let app; + before(() => { + app = utils.app('apps/app-config-cookies'); + return app.ready(); + }); + after(() => app.close()); + + afterEach(mm.restore); + + it('should auto set sameSite cookie', async () => { + const res = await app.httpRequest() + .get('/'); + assert(res.status === 200); + assert(res.text === 'hello'); + const cookies = res.headers['set-cookie']; + assert(cookies.length >= 1); + for (const cookie of cookies) { + assert(cookie.includes('; samesite=lax')); + } + }); +});