Skip to content

Commit

Permalink
feat: support function to set domain
Browse files Browse the repository at this point in the history
  • Loading branch information
onlylovermb committed Aug 4, 2023
1 parent d98e1c1 commit f057f3f
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 26 deletions.
9 changes: 7 additions & 2 deletions lib/cookie.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,20 @@ const fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/; // eslint-di
const sameSiteRegExp = /^(?:none|lax|strict)$/i;

class Cookie {
constructor(name, value, attrs) {
constructor(ctx, name, value, attrs) {
assert(fieldContentRegExp.test(name), 'argument name is invalid');
assert(!value || fieldContentRegExp.test(value), 'argument value is invalid');

this.ctx = ctx;
this.name = name;
this.value = value || '';
this.attrs = mergeDefaultAttrs(attrs);
assert(!this.attrs.path || fieldContentRegExp.test(this.attrs.path), 'argument option path is invalid');
assert(!this.attrs.domain || fieldContentRegExp.test(this.attrs.domain), 'argument option domain is invalid');
assert(!this.attrs.domain || typeof this.attrs.domain === 'string' || typeof this.attrs.domain === 'function', 'argument option domain is invalid');
if (typeof this.attrs.domain === 'function') {
this.attrs.domain = this.attrs.domain(this.ctx);
}
assert(fieldContentRegExp.test(this.attrs.domain), 'argument option domain is invalid');
assert(!this.attrs.sameSite || this.attrs.sameSite === true || sameSiteRegExp.test(this.attrs.sameSite), 'argument option sameSite is invalid');
if (!value) {
this.attrs.expires = new Date(0);
Expand Down
2 changes: 1 addition & 1 deletion lib/cookies.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ class Cookies {
}
}

const cookie = new Cookie(name, value, opts);
const cookie = new Cookie(this.ctx, name, value, opts);

// if user not set secure, reset secure to ctx.secure
if (opts.secure === undefined) cookie.attrs.secure = this.secure;
Expand Down
58 changes: 35 additions & 23 deletions test/lib/cookie.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,25 @@ function assertExceptionCheck(expectedMsg) {
}
describe('test/lib/cookie.test.js', () => {
it('create cookies contains invalid string error should throw', () => {
assert.throws(() => new Cookie('中文', 'value'), assertExceptionCheck('argument name is invalid'));
assert.throws(() => new Cookie('name', '中文'), assertExceptionCheck('argument value is invalid'));
assert.throws(() => new Cookie('name', 'value', { path: '中文' }), assertExceptionCheck('argument option path is invalid'));
assert.throws(() => new Cookie('name', 'value', { domain: '中文' }), assertExceptionCheck('argument option domain is invalid'));
assert.throws(() => new Cookie({}, '中文', 'value'), assertExceptionCheck('argument name is invalid'));
assert.throws(() => new Cookie({}, 'name', '中文'), assertExceptionCheck('argument value is invalid'));
assert.throws(() => new Cookie({}, 'name', 'value', { path: '中文' }), assertExceptionCheck('argument option path is invalid'));
assert.throws(() => new Cookie({}, 'name', 'value', { domain: '中文' }), assertExceptionCheck('argument option domain is invalid'));
});

it('set expires to 0 if value not present', () => {
assert(new Cookie('name', null).attrs.expires.getTime() === 0);
assert(new Cookie({}, 'name', null).attrs.expires.getTime() === 0);
});

describe('toString()', () => {
it('return name=vaule', () => {
assert(new Cookie('name', 'value').toString() === 'name=value');
assert(new Cookie({}, 'name', 'value').toString() === 'name=value');
});
});

describe('toHeader()', () => {
it('return name=vaule;params', () => {
assert(new Cookie('name', 'value', {
assert(new Cookie({}, 'name', 'value', {
secure: true,
maxAge: 1000,
domain: 'eggjs.org',
Expand All @@ -37,15 +37,27 @@ describe('test/lib/cookie.test.js', () => {
}).toHeader().match(/^name=value; path=\/; max-age=1; expires=(.*?)GMT; domain=eggjs\.org; secure; httponly$/));
});

it('set domain when domain is a function', () => {
assert(new Cookie({
hostname: 'eggjs.org',
}, 'name', 'value', {
secure: true,
maxAge: 1000,
domain: ctx => ctx.hostname,
path: '/',
httpOnly: true,
}).toHeader().match(/^name=value; path=\/; max-age=1; expires=(.*?)GMT; domain=eggjs\.org; secure; httponly$/));
});

it('donnot set path when set path to null', () => {
const header = new Cookie('name', 'value', {
const header = new Cookie({}, 'name', 'value', {
path: null,
}).toHeader();
assert(!header.match(/path=/));
});

it('donnot set httponly when set httpOnly to false', () => {
const header = new Cookie('name', 'value', {
const header = new Cookie({}, 'name', 'value', {
httpOnly: false,
}).toHeader();
assert(!header.match(/httponly/));
Expand All @@ -55,15 +67,15 @@ describe('test/lib/cookie.test.js', () => {
describe('maxAge', () => {
it('maxAge overwrite expires', () => {
const expires = new Date('2020-01-01');
let header = new Cookie('name', 'value', {
let header = new Cookie({}, 'name', 'value', {
secure: true,
expires,
domain: 'eggjs.org',
path: '/',
httpOnly: true,
}).toHeader();
assert(header.match(/expires=Wed, 01 Jan 2020 00:00:00 GMT/));
header = new Cookie('name', 'value', {
header = new Cookie({}, 'name', 'value', {
secure: true,
maxAge: 1000,
expires,
Expand All @@ -75,7 +87,7 @@ describe('test/lib/cookie.test.js', () => {
});

it('ignore maxage NaN', () => {
const header = new Cookie('name', 'value', {
const header = new Cookie({}, 'name', 'value', {
secure: true,
maxAge: 'session',
domain: 'eggjs.org',
Expand All @@ -88,7 +100,7 @@ describe('test/lib/cookie.test.js', () => {

it('ignore maxage 0', () => {
// In previous implementations, maxAge = 0 was considered unnecessary to set this header
const header = new Cookie('name', 'value', {
const header = new Cookie({}, 'name', 'value', {
secure: true,
maxAge: 0,
domain: 'eggjs.org',
Expand All @@ -102,21 +114,21 @@ describe('test/lib/cookie.test.js', () => {

describe('sameSite', () => {
it('should default to false', () => {
const cookie = new Cookie('foo', 'bar');
const cookie = new Cookie({}, 'foo', 'bar');
assert.equal(cookie.attrs.sameSite, false);
});

it('should throw on invalid value', () => {
assert.throws(() => {
new Cookie('foo', 'bar', { sameSite: 'foo' });
new Cookie({}, 'foo', 'bar', { sameSite: 'foo' });
}, /argument option sameSite is invalid/);
});

describe('when set to falsy values', () => {
it('should not add "samesite" attribute in header', () => {
const falsyValues = [ false, 0, '', null, undefined, NaN ];
falsyValues.forEach(falsy => {
const cookie = new Cookie('foo', 'bar', { sameSite: falsy });
const cookie = new Cookie({}, 'foo', 'bar', { sameSite: falsy });
assert.ok(Object.is(cookie.attrs.sameSite, falsy));
assert.equal(cookie.toHeader(), 'foo=bar; path=/; httponly');
});
Expand All @@ -125,7 +137,7 @@ describe('test/lib/cookie.test.js', () => {

describe('when set to "true"', () => {
it('should set "samesite=strict" attribute in header', () => {
const cookie = new Cookie('foo', 'bar', { sameSite: true });
const cookie = new Cookie({}, 'foo', 'bar', { sameSite: true });
assert.equal(cookie.attrs.sameSite, true);
assert.equal(cookie.toHeader(), 'foo=bar; path=/; samesite=strict; httponly');
});
Expand All @@ -134,11 +146,11 @@ describe('test/lib/cookie.test.js', () => {
describe('when set to "none"', () => {
it('should set "samesite=none" attribute in header', () => {
{
const cookie = new Cookie('foo', 'bar', { sameSite: 'none' });
const cookie = new Cookie({}, 'foo', 'bar', { sameSite: 'none' });
assert.equal(cookie.toHeader(), 'foo=bar; path=/; samesite=none; httponly');
}
{
const cookie = new Cookie('foo', 'bar', { sameSite: 'None' });
const cookie = new Cookie({}, 'foo', 'bar', { sameSite: 'None' });
assert.equal(cookie.toHeader(), 'foo=bar; path=/; samesite=none; httponly');
}
});
Expand All @@ -147,11 +159,11 @@ describe('test/lib/cookie.test.js', () => {
describe('when set to "lax"', () => {
it('should set "samesite=lax" attribute in header', () => {
{
const cookie = new Cookie('foo', 'bar', { sameSite: 'lax' });
const cookie = new Cookie({}, 'foo', 'bar', { sameSite: 'lax' });
assert.equal(cookie.toHeader(), 'foo=bar; path=/; samesite=lax; httponly');
}
{
const cookie = new Cookie('foo', 'bar', { sameSite: 'Lax' });
const cookie = new Cookie({}, 'foo', 'bar', { sameSite: 'Lax' });
assert.equal(cookie.toHeader(), 'foo=bar; path=/; samesite=lax; httponly');
}
});
Expand All @@ -160,11 +172,11 @@ describe('test/lib/cookie.test.js', () => {
describe('when set to "strict"', () => {
it('should set "samesite=strict" attribute in header', () => {
{
const cookie = new Cookie('foo', 'bar', { sameSite: 'strict' });
const cookie = new Cookie({}, 'foo', 'bar', { sameSite: 'strict' });
assert.equal(cookie.toHeader(), 'foo=bar; path=/; samesite=strict; httponly');
}
{
const cookie = new Cookie('foo', 'bar', { sameSite: 'Strict' });
const cookie = new Cookie({}, 'foo', 'bar', { sameSite: 'Strict' });
assert.equal(cookie.toHeader(), 'foo=bar; path=/; samesite=strict; httponly');
}
});
Expand Down
11 changes: 11 additions & 0 deletions test/lib/cookies.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ describe('test/lib/cookies.test.js', () => {
assert(cookie.indexOf('secure') > 0);
});

it('should work with domain ok, when domain is a function', () => {
const cookies = Cookies({
host: 'foo.com',
}, {
secure: true,
});
cookies.set('foo', 'bar', { encrypt: true, domain: ctx => ctx.request.host });
const cookie = cookies.ctx.response.headers['set-cookie'][0];
assert(cookie.indexOf('domain=foo.com') > 0);
});

it('should signed work fine', () => {
const cookies = Cookies();
cookies.set('foo', 'bar', { signed: true });
Expand Down

0 comments on commit f057f3f

Please sign in to comment.