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)) throw new TypeError('cookie name is invalid');
|
25 |
|
26 | const content = encode(value);
|
27 | if (content && !CookieCutter.test(content)) throw new TypeError('cookie value is invalid');
|
28 |
|
29 | let cookie = `${name}=${content}`;
|
30 |
|
31 | if (maxAge) {
|
32 | if (!Number.isInteger(maxAge)) throw new Error('maxAge must be a number');
|
33 |
|
34 | cookie += `; Max-Age=${Math.floor(maxAge)}`;
|
35 | }
|
36 |
|
37 | if (domain) {
|
38 | if (!CookieCutter.test(domain)) throw new TypeError('domain is invalid');
|
39 |
|
40 | cookie += `; Domain=${domain}`;
|
41 | }
|
42 |
|
43 | if (path) {
|
44 | if (!CookieCutter.test(path)) throw new TypeError('path is invalid');
|
45 |
|
46 | cookie += `; Path=${path}`;
|
47 | }
|
48 |
|
49 | if (expires) {
|
50 | if (typeof expires.toUTCString !== 'function') throw new TypeError('expires is invalid');
|
51 |
|
52 | cookie += `; Expires=${expires.toUTCString()}`;
|
53 | }
|
54 |
|
55 | if (httpOnly) cookie += '; HttpOnly';
|
56 | if (secure) cookie += '; Secure';
|
57 |
|
58 | if (sameSite) {
|
59 | let _sameSite = typeof sameSite === 'string' ? sameSite.toLowerCase() : sameSite;
|
60 |
|
61 | if (_sameSite === true) cookie += '; SameSite=Strict';
|
62 | else if (_sameSite === 'lax') cookie += '; SameSite=Lax';
|
63 | else if (_sameSite === 'strict') cookie += '; SameSite=Strict';
|
64 | else throw new TypeError('sameSite is invalid');
|
65 | }
|
66 |
|
67 | return cookie;
|
68 | }
|
69 |
|
70 | static destroy(name) {
|
71 | return name;
|
72 | }
|
73 | }
|
74 |
|
75 | module.exports = Cookie;
|