Skip to content

Commit 8be4b82

Browse files
authored
Loosen cookie name/value validation (#210)
1 parent 94ba436 commit 8be4b82

File tree

2 files changed

+90
-95
lines changed

2 files changed

+90
-95
lines changed

src/index.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
* tchar = "!" / "#" / "$" / "%" / "&" / "'" /
99
* "*" / "+" / "-" / "." / "^" / "_" /
1010
* "`" / "|" / "~" / DIGIT / ALPHA
11+
*
12+
* Note: Allowing more characters - https://github.com/jshttp/cookie/issues/191
13+
* Allow same range as cookie value, except `=`, which delimits end of name.
1114
*/
12-
const cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
15+
const cookieNameRegExp = /^[\u0021-\u003A\u003C\u003E-\u007E]+$/;
1316

1417
/**
1518
* RegExp to match cookie-value in RFC 6265 sec 4.1.1
@@ -19,9 +22,11 @@ const cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
1922
* ; US-ASCII characters excluding CTLs,
2023
* ; whitespace DQUOTE, comma, semicolon,
2124
* ; and backslash
25+
*
26+
* Allowing more characters: https://github.com/jshttp/cookie/issues/191
27+
* Comma, backslash, and DQUOTE are not part of the parsing algorithm.
2228
*/
23-
const cookieValueRegExp =
24-
/^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/;
29+
const cookieValueRegExp = /^[\u0021-\u003A\u003C-\u007E]*$/;
2530

2631
/**
2732
* RegExp to match domain-value in RFC 6265 sec 4.1.1

src/serialize.spec.ts

+82-92
Original file line numberDiff line numberDiff line change
@@ -14,91 +14,80 @@ describe("cookie.serialize(name, value)", function () {
1414
expect(cookie.serialize("foo", "")).toEqual("foo=");
1515
});
1616

17-
it("should serialize valid name", function () {
18-
var validNames = [
19-
"foo",
20-
"foo!bar",
21-
"foo#bar",
22-
"foo$bar",
23-
"foo'bar",
24-
"foo*bar",
25-
"foo+bar",
26-
"foo-bar",
27-
"foo.bar",
28-
"foo^bar",
29-
"foo_bar",
30-
"foo`bar",
31-
"foo|bar",
32-
"foo~bar",
33-
"foo7bar",
34-
];
35-
36-
validNames.forEach(function (name) {
37-
expect(cookie.serialize(name, "baz")).toEqual(name + "=baz");
38-
});
17+
it.each([
18+
["foo"],
19+
["foo,bar"],
20+
["foo!bar"],
21+
["foo#bar"],
22+
["foo$bar"],
23+
["foo'bar"],
24+
["foo*bar"],
25+
["foo+bar"],
26+
["foo-bar"],
27+
["foo.bar"],
28+
["foo^bar"],
29+
["foo_bar"],
30+
["foo`bar"],
31+
["foo|bar"],
32+
["foo~bar"],
33+
["foo7bar"],
34+
["foo/bar"],
35+
["foo@bar"],
36+
["foo[bar"],
37+
["foo]bar"],
38+
["foo:bar"],
39+
["foo{bar"],
40+
["foo}bar"],
41+
['foo"bar'],
42+
["foo<bar"],
43+
["foo>bar"],
44+
["foo?bar"],
45+
["foo\\bar"],
46+
])("should serialize name: %s", (name) => {
47+
expect(cookie.serialize(name, "baz")).toEqual(`${name}=baz`);
3948
});
4049

41-
it("should throw for invalid name", function () {
42-
var invalidNames = [
43-
"foo\n",
44-
"foo\u280a",
45-
"foo/foo",
46-
"foo,foo",
47-
"foo;foo",
48-
"foo@foo",
49-
"foo[foo]",
50-
"foo?foo",
51-
"foo:foo",
52-
"foo{foo}",
53-
"foo foo",
54-
"foo\tfoo",
55-
'foo"foo',
56-
"foo<script>foo",
57-
];
58-
59-
invalidNames.forEach(function (name) {
60-
expect(cookie.serialize.bind(cookie, name, "bar")).toThrow(
61-
/argument name is invalid/,
62-
);
63-
});
50+
it.each([
51+
["foo\n"],
52+
["foo\u280a"],
53+
["foo=bar"],
54+
["foo;bar"],
55+
["foo bar"],
56+
["foo\tbar"],
57+
])("should throw for invalid name: %s", (name) => {
58+
expect(() => cookie.serialize(name, "bar")).toThrow(
59+
/argument name is invalid/,
60+
);
6461
});
6562
});
6663

6764
describe("cookie.serialize(name, value, options)", function () {
6865
describe('with "domain" option', function () {
69-
it("should serialize valid domain", function () {
70-
var validDomains = [
71-
"example.com",
72-
"sub.example.com",
73-
".example.com",
74-
"localhost",
75-
".localhost",
76-
"my-site.org",
77-
"localhost",
78-
];
79-
80-
validDomains.forEach(function (domain) {
81-
expect(cookie.serialize("foo", "bar", { domain: domain })).toEqual(
82-
"foo=bar; Domain=" + domain,
83-
);
84-
});
66+
it.each([
67+
["example.com"],
68+
["sub.example.com"],
69+
[".example.com"],
70+
["localhost"],
71+
[".localhost"],
72+
["my-site.org"],
73+
["localhost"],
74+
])("should serialize domain: %s", (domain) => {
75+
expect(cookie.serialize("foo", "bar", { domain })).toEqual(
76+
`foo=bar; Domain=${domain}`,
77+
);
8578
});
8679

87-
it("should throw for invalid domain", function () {
88-
var invalidDomains = [
89-
"example.com\n",
90-
"sub.example.com\u0000",
91-
"my site.org",
92-
"domain..com",
93-
"example.com; Path=/",
94-
"example.com /* inject a comment */",
95-
];
96-
97-
invalidDomains.forEach(function (domain) {
98-
expect(
99-
cookie.serialize.bind(cookie, "foo", "bar", { domain: domain }),
100-
).toThrow(/option domain is invalid/);
101-
});
80+
it.each([
81+
["example.com\n"],
82+
["sub.example.com\u0000"],
83+
["my site.org"],
84+
["domain..com"],
85+
["example.com; Path=/"],
86+
["example.com /* inject a comment */"],
87+
])("should throw for invalid domain: %s", (domain) => {
88+
expect(() => cookie.serialize("foo", "bar", { domain })).toThrow(
89+
/option domain is invalid/,
90+
);
10291
});
10392
});
10493

@@ -113,22 +102,23 @@ describe("cookie.serialize(name, value, options)", function () {
113102
).toEqual("foo=YmFy");
114103
});
115104

116-
it("should throw when returned value is invalid", function () {
117-
expect(
118-
cookie.serialize.bind(cookie, "foo", "+ \n", {
119-
encode: function (v) {
120-
return v;
121-
},
122-
}),
123-
).toThrow(/argument val is invalid/);
124-
expect(
125-
cookie.serialize.bind(cookie, "foo", "foo bar", {
126-
encode: function (v) {
127-
return v;
128-
},
129-
}),
130-
).toThrow(/argument val is invalid/);
131-
});
105+
it.each(["foo=bar", 'foo"bar', "foo,bar", "foo\\bar", "foo$bar"])(
106+
"should serialize value: %s",
107+
(value) => {
108+
expect(cookie.serialize("foo", value, { encode: (x) => x })).toEqual(
109+
`foo=${value}`,
110+
);
111+
},
112+
);
113+
114+
it.each([["+\n"], ["foo bar"], ["foo\tbar"], ["foo;bar"], ["foo\u280a"]])(
115+
"should throw for invalid value: %s",
116+
(value) => {
117+
expect(() =>
118+
cookie.serialize("foo", value, { encode: (x) => x }),
119+
).toThrow(/argument val is invalid/);
120+
},
121+
);
132122
});
133123

134124
describe('with "expires" option', function () {

0 commit comments

Comments
 (0)