1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | const encode = encodeURIComponent;
|
15 |
|
16 | const CookieCutter = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
|
17 |
|
18 | class Cookie {
|
19 | static create(
|
20 | name,
|
21 | value,
|
22 | { maxAge, domain, path, expires, httpOnly, secure, sameSite } = {}
|
23 | ) {
|
24 | if (name && !CookieCutter.test(name))
|
25 | throw new TypeError('cookie name is invalid');
|
26 |
|
27 | const content = encode(value);
|
28 | if (content && !CookieCutter.test(content))
|
29 | throw new TypeError('cookie value is invalid');
|
30 |
|
31 | let cookie = `${name}=${content}`;
|
32 |
|
33 | if (maxAge) {
|
34 | if (!Number.isInteger(maxAge)) throw new Error('maxAge must be a number');
|
35 |
|
36 | cookie += `; Max-Age=${Math.floor(maxAge)}`;
|
37 | }
|
38 |
|
39 | if (domain) {
|
40 | if (!CookieCutter.test(domain)) throw new TypeError('domain is invalid');
|
41 |
|
42 | cookie += `; Domain=${domain}`;
|
43 | }
|
44 |
|
45 | if (path) {
|
46 | if (!CookieCutter.test(path)) throw new TypeError('path is invalid');
|
47 |
|
48 | cookie += `; Path=${path}`;
|
49 | }
|
50 |
|
51 | if (expires) {
|
52 | if (typeof expires.toUTCString !== 'function')
|
53 | throw new TypeError('expires is invalid');
|
54 |
|
55 | cookie += `; Expires=${expires.toUTCString()}`;
|
56 | }
|
57 |
|
58 | if (httpOnly) cookie += '; HttpOnly';
|
59 | if (secure) cookie += '; Secure';
|
60 |
|
61 | if (sameSite) {
|
62 | let _sameSite =
|
63 | typeof sameSite === 'string' ? sameSite.toLowerCase() : sameSite;
|
64 |
|
65 | if (_sameSite === true) cookie += '; SameSite=Strict';
|
66 | else if (_sameSite === 'lax') cookie += '; SameSite=Lax';
|
67 | else if (_sameSite === 'strict') cookie += '; SameSite=Strict';
|
68 | else throw new TypeError('sameSite is invalid');
|
69 | }
|
70 |
|
71 | return cookie;
|
72 | }
|
73 |
|
74 | static destroy(name) {
|
75 | return name;
|
76 | }
|
77 | }
|
78 |
|
79 | module.exports = Cookie;
|