Skip to content

Commit f31dac9

Browse files
authoredDec 11, 2023
Merge pull request from GHSA-qxrj-hx23-xp82
This is a security update for the Same Origin Policy (SOP), and also a BREAKING CHANGE. closes GHSA-qxrj-hx23-xp82
1 parent 0f3f948 commit f31dac9

File tree

5 files changed

+83
-26
lines changed

5 files changed

+83
-26
lines changed
 

‎.github/workflows/nodejs.yml

+1-3
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ on:
1212
branches:
1313
- main
1414
- master
15-
schedule:
16-
- cron: '0 2 * * *'
1715

1816
jobs:
1917
build:
@@ -22,7 +20,7 @@ jobs:
2220
strategy:
2321
fail-fast: false
2422
matrix:
25-
node-version: [14, 16, 18]
23+
node-version: [14, 16, 18, 20]
2624
os: [ubuntu-latest]
2725

2826
steps:

‎README.md

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
@koa/cors
2-
=======
1+
# @koa/cors
32

43
[![NPM version][npm-image]][npm-url]
54
[![Node.js CI](https://github.com/koajs/cors/actions/workflows/nodejs.yml/badge.svg)](https://github.com/koajs/cors/actions/workflows/nodejs.yml)
@@ -43,7 +42,8 @@ app.use(cors());
4342
* CORS middleware
4443
*
4544
* @param {Object} [options]
46-
* - {String|Function(ctx)} origin `Access-Control-Allow-Origin`, default is request Origin header
45+
* - {String|Function(ctx)} origin `Access-Control-Allow-Origin`, default is '*'
46+
* If `credentials` set and return `true, the `origin` default value will set to the request `Origin` header
4747
* - {String|Array} allowMethods `Access-Control-Allow-Methods`, default is 'GET,HEAD,PUT,POST,DELETE,PATCH'
4848
* - {String|Array} exposeHeaders `Access-Control-Expose-Headers`
4949
* - {String|Array} allowHeaders `Access-Control-Allow-Headers`
@@ -57,6 +57,18 @@ app.use(cors());
5757
*/
5858
```
5959

60+
## Breaking change between 5.0 and 4.0
61+
62+
The default `origin` is set to `*`, if you want to keep the 4.0 behavior, you can set the `origin` handler like this:
63+
64+
```js
65+
app.use(cors({
66+
origin(ctx) {
67+
return ctx.get('Origin') || '*';
68+
},
69+
}));
70+
```
71+
6072
## License
6173

6274
[MIT](./LICENSE)

‎index.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
'use strict';
2-
31
const vary = require('vary');
42

53
/**
64
* CORS middleware
75
*
86
* @param {Object} [options]
9-
* - {String|Function(ctx)} origin `Access-Control-Allow-Origin`, default is request Origin header
7+
* - {String|Function(ctx)} origin `Access-Control-Allow-Origin`, default is '*'
8+
* If `credentials` set and return `true, the `origin` default value will set to the request `Origin` header
109
* - {String|Array} allowMethods `Access-Control-Allow-Methods`, default is 'GET,HEAD,PUT,POST,DELETE,PATCH'
1110
* - {String|Array} exposeHeaders `Access-Control-Expose-Headers`
1211
* - {String|Array} allowHeaders `Access-Control-Allow-Headers`
@@ -61,9 +60,11 @@ module.exports = function(options) {
6160
let origin;
6261
if (typeof options.origin === 'function') {
6362
origin = await options.origin(ctx);
64-
if (!origin) return await next();
63+
if (!origin) {
64+
return await next();
65+
}
6566
} else {
66-
origin = options.origin || requestOrigin;
67+
origin = options.origin || '*';
Has conversations. Original line has conversations.
6768
}
6869

6970
let credentials;

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"node": ">= 14.0.0"
4747
},
4848
"ci": {
49-
"version": "14, 16, 18",
49+
"version": "14, 16, 18, 20",
5050
"os": "linux"
5151
},
5252
"author": "fengmk2 <fengmk2@gmail.com> (http://github.com/fengmk2)",

‎test/cors.test.js

+60-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
'use strict';
2-
31
const assert = require('assert');
42
const Koa = require('koa');
53
const request = require('supertest');
@@ -13,22 +11,19 @@ describe('cors.test.js', function() {
1311
ctx.body = { foo: 'bar' };
1412
});
1513

16-
it('should not set `Access-Control-Allow-Origin` when request Origin header missing', function(done) {
14+
it('should set `Access-Control-Allow-Origin` to `*` when request Origin header missing', function(done) {
1715
request(app.listen())
1816
.get('/')
1917
.expect({ foo: 'bar' })
20-
.expect(200, function(err, res) {
21-
assert(!err);
22-
assert(!res.headers['access-control-allow-origin']);
23-
done();
24-
});
18+
.expect('access-control-allow-origin', '*')
19+
.expect(200, done);
2520
});
2621

27-
it('should set `Access-Control-Allow-Origin` to request origin header', function(done) {
22+
it('should set `Access-Control-Allow-Origin` to `*`', function(done) {
2823
request(app.listen())
2924
.get('/')
3025
.set('Origin', 'http://koajs.com')
31-
.expect('Access-Control-Allow-Origin', 'http://koajs.com')
26+
.expect('Access-Control-Allow-Origin', '*')
3227
.expect({ foo: 'bar' })
3328
.expect(200, done);
3429
});
@@ -38,7 +33,7 @@ describe('cors.test.js', function() {
3833
.options('/')
3934
.set('Origin', 'http://koajs.com')
4035
.set('Access-Control-Request-Method', 'PUT')
41-
.expect('Access-Control-Allow-Origin', 'http://koajs.com')
36+
.expect('Access-Control-Allow-Origin', '*')
4237
.expect('Access-Control-Allow-Methods', 'GET,HEAD,PUT,POST,DELETE,PATCH')
4338
.expect(204, done);
4439
});
@@ -87,6 +82,44 @@ describe('cors.test.js', function() {
8782
});
8883
});
8984

85+
describe('options.origin set the request Origin header', function() {
86+
const app = new Koa();
87+
app.use(cors({
88+
origin(ctx) {
89+
return ctx.get('Origin') || '*';
90+
},
91+
}));
92+
app.use(function(ctx) {
93+
ctx.body = { foo: 'bar' };
94+
});
95+
96+
it('should set `Access-Control-Allow-Origin` to request `Origin` header', function(done) {
97+
request(app.listen())
98+
.get('/')
99+
.set('Origin', 'http://koajs.com')
100+
.expect('Access-Control-Allow-Origin', 'http://koajs.com')
101+
.expect({ foo: 'bar' })
102+
.expect(200, done);
103+
});
104+
105+
it('should set `Access-Control-Allow-Origin` to request `origin` header', function(done) {
106+
request(app.listen())
107+
.get('/')
108+
.set('origin', 'http://origin.koajs.com')
109+
.expect('Access-Control-Allow-Origin', 'http://origin.koajs.com')
110+
.expect({ foo: 'bar' })
111+
.expect(200, done);
112+
});
113+
114+
it('should set `Access-Control-Allow-Origin` to `*`, even if no Origin is passed on request', function(done) {
115+
request(app.listen())
116+
.get('/')
117+
.expect('Access-Control-Allow-Origin', '*')
118+
.expect({ foo: 'bar' })
119+
.expect(200, done);
120+
});
121+
});
122+
90123
describe('options.secureContext=true', function() {
91124
const app = new Koa();
92125
app.use(cors({
@@ -651,7 +684,11 @@ describe('cors.test.js', function() {
651684
describe('options.headersKeptOnError', function() {
652685
it('should keep CORS headers after an error', function(done) {
653686
const app = new Koa();
654-
app.use(cors());
687+
app.use(cors({
688+
origin(ctx) {
689+
return ctx.get('Origin') || '*';
690+
},
691+
}));
655692
app.use(function(ctx) {
656693
ctx.body = { foo: 'bar' };
657694
throw new Error('Whoops!');
@@ -668,7 +705,11 @@ describe('cors.test.js', function() {
668705

669706
it('should not affect OPTIONS requests', function(done) {
670707
const app = new Koa();
671-
app.use(cors());
708+
app.use(cors({
709+
origin(ctx) {
710+
return ctx.get('Origin') || '*';
711+
},
712+
}));
672713
app.use(function(ctx) {
673714
ctx.body = { foo: 'bar' };
674715
throw new Error('Whoops!');
@@ -684,7 +725,11 @@ describe('cors.test.js', function() {
684725

685726
it('should not keep unrelated headers', function(done) {
686727
const app = new Koa();
687-
app.use(cors());
728+
app.use(cors({
729+
origin(ctx) {
730+
return ctx.get('Origin') || '*';
731+
},
732+
}));
688733
app.use(function(ctx) {
689734
ctx.body = { foo: 'bar' };
690735
ctx.set('X-Example', 'Value');
@@ -752,6 +797,7 @@ describe('cors.test.js', function() {
752797
.expect(200, done);
753798
});
754799
});
800+
755801
describe('other middleware has set vary header on Error', function() {
756802
it('should append `Origin to other `Vary` header', function(done) {
757803
const app = new Koa();

0 commit comments

Comments
 (0)
Please sign in to comment.