source: node_modules/nodemailer/lib/fetch/cookies.js@ 81bc7da

finki-main main
Last change on this file since 81bc7da was 81bc7da, checked in by Klimentina Efremova <klimentina08642@…>, 3 months ago

Initial commit

  • Property mode set to 100644
File size: 7.9 KB
Line 
1'use strict';
2
3// module to handle cookies
4
5const urllib = require('url');
6
7const SESSION_TIMEOUT = 1800; // 30 min
8
9/**
10 * Creates a biskviit cookie jar for managing cookie values in memory
11 *
12 * @constructor
13 * @param {Object} [options] Optional options object
14 */
15class Cookies {
16 constructor(options) {
17 this.options = options || {};
18 this.cookies = [];
19 }
20
21 /**
22 * Stores a cookie string to the cookie storage
23 *
24 * @param {String} cookieStr Value from the 'Set-Cookie:' header
25 * @param {String} url Current URL
26 */
27 set(cookieStr, url) {
28 let urlparts = urllib.parse(url || '');
29 let cookie = this.parse(cookieStr);
30 let domain;
31
32 if (cookie.domain) {
33 domain = cookie.domain.replace(/^\./, '');
34
35 // do not allow cross origin cookies
36 if (
37 // can't be valid if the requested domain is shorter than current hostname
38 urlparts.hostname.length < domain.length ||
39 // prefix domains with dot to be sure that partial matches are not used
40 ('.' + urlparts.hostname).substr(-domain.length + 1) !== '.' + domain
41 ) {
42 cookie.domain = urlparts.hostname;
43 }
44 } else {
45 cookie.domain = urlparts.hostname;
46 }
47
48 if (!cookie.path) {
49 cookie.path = this.getPath(urlparts.pathname);
50 }
51
52 // if no expire date, then use sessionTimeout value
53 if (!cookie.expires) {
54 cookie.expires = new Date(Date.now() + (Number(this.options.sessionTimeout || SESSION_TIMEOUT) || SESSION_TIMEOUT) * 1000);
55 }
56
57 return this.add(cookie);
58 }
59
60 /**
61 * Returns cookie string for the 'Cookie:' header.
62 *
63 * @param {String} url URL to check for
64 * @returns {String} Cookie header or empty string if no matches were found
65 */
66 get(url) {
67 return this.list(url)
68 .map(cookie => cookie.name + '=' + cookie.value)
69 .join('; ');
70 }
71
72 /**
73 * Lists all valied cookie objects for the specified URL
74 *
75 * @param {String} url URL to check for
76 * @returns {Array} An array of cookie objects
77 */
78 list(url) {
79 let result = [];
80 let i;
81 let cookie;
82
83 for (i = this.cookies.length - 1; i >= 0; i--) {
84 cookie = this.cookies[i];
85
86 if (this.isExpired(cookie)) {
87 this.cookies.splice(i, i);
88 continue;
89 }
90
91 if (this.match(cookie, url)) {
92 result.unshift(cookie);
93 }
94 }
95
96 return result;
97 }
98
99 /**
100 * Parses cookie string from the 'Set-Cookie:' header
101 *
102 * @param {String} cookieStr String from the 'Set-Cookie:' header
103 * @returns {Object} Cookie object
104 */
105 parse(cookieStr) {
106 let cookie = {};
107
108 (cookieStr || '')
109 .toString()
110 .split(';')
111 .forEach(cookiePart => {
112 let valueParts = cookiePart.split('=');
113 let key = valueParts.shift().trim().toLowerCase();
114 let value = valueParts.join('=').trim();
115 let domain;
116
117 if (!key) {
118 // skip empty parts
119 return;
120 }
121
122 switch (key) {
123 case 'expires':
124 value = new Date(value);
125 // ignore date if can not parse it
126 if (value.toString() !== 'Invalid Date') {
127 cookie.expires = value;
128 }
129 break;
130
131 case 'path':
132 cookie.path = value;
133 break;
134
135 case 'domain':
136 domain = value.toLowerCase();
137 if (domain.length && domain.charAt(0) !== '.') {
138 domain = '.' + domain; // ensure preceeding dot for user set domains
139 }
140 cookie.domain = domain;
141 break;
142
143 case 'max-age':
144 cookie.expires = new Date(Date.now() + (Number(value) || 0) * 1000);
145 break;
146
147 case 'secure':
148 cookie.secure = true;
149 break;
150
151 case 'httponly':
152 cookie.httponly = true;
153 break;
154
155 default:
156 if (!cookie.name) {
157 cookie.name = key;
158 cookie.value = value;
159 }
160 }
161 });
162
163 return cookie;
164 }
165
166 /**
167 * Checks if a cookie object is valid for a specified URL
168 *
169 * @param {Object} cookie Cookie object
170 * @param {String} url URL to check for
171 * @returns {Boolean} true if cookie is valid for specifiec URL
172 */
173 match(cookie, url) {
174 let urlparts = urllib.parse(url || '');
175
176 // check if hostname matches
177 // .foo.com also matches subdomains, foo.com does not
178 if (
179 urlparts.hostname !== cookie.domain &&
180 (cookie.domain.charAt(0) !== '.' || ('.' + urlparts.hostname).substr(-cookie.domain.length) !== cookie.domain)
181 ) {
182 return false;
183 }
184
185 // check if path matches
186 let path = this.getPath(urlparts.pathname);
187 if (path.substr(0, cookie.path.length) !== cookie.path) {
188 return false;
189 }
190
191 // check secure argument
192 if (cookie.secure && urlparts.protocol !== 'https:') {
193 return false;
194 }
195
196 return true;
197 }
198
199 /**
200 * Adds (or updates/removes if needed) a cookie object to the cookie storage
201 *
202 * @param {Object} cookie Cookie value to be stored
203 */
204 add(cookie) {
205 let i;
206 let len;
207
208 // nothing to do here
209 if (!cookie || !cookie.name) {
210 return false;
211 }
212
213 // overwrite if has same params
214 for (i = 0, len = this.cookies.length; i < len; i++) {
215 if (this.compare(this.cookies[i], cookie)) {
216 // check if the cookie needs to be removed instead
217 if (this.isExpired(cookie)) {
218 this.cookies.splice(i, 1); // remove expired/unset cookie
219 return false;
220 }
221
222 this.cookies[i] = cookie;
223 return true;
224 }
225 }
226
227 // add as new if not already expired
228 if (!this.isExpired(cookie)) {
229 this.cookies.push(cookie);
230 }
231
232 return true;
233 }
234
235 /**
236 * Checks if two cookie objects are the same
237 *
238 * @param {Object} a Cookie to check against
239 * @param {Object} b Cookie to check against
240 * @returns {Boolean} True, if the cookies are the same
241 */
242 compare(a, b) {
243 return a.name === b.name && a.path === b.path && a.domain === b.domain && a.secure === b.secure && a.httponly === a.httponly;
244 }
245
246 /**
247 * Checks if a cookie is expired
248 *
249 * @param {Object} cookie Cookie object to check against
250 * @returns {Boolean} True, if the cookie is expired
251 */
252 isExpired(cookie) {
253 return (cookie.expires && cookie.expires < new Date()) || !cookie.value;
254 }
255
256 /**
257 * Returns normalized cookie path for an URL path argument
258 *
259 * @param {String} pathname
260 * @returns {String} Normalized path
261 */
262 getPath(pathname) {
263 let path = (pathname || '/').split('/');
264 path.pop(); // remove filename part
265 path = path.join('/').trim();
266
267 // ensure path prefix /
268 if (path.charAt(0) !== '/') {
269 path = '/' + path;
270 }
271
272 // ensure path suffix /
273 if (path.substr(-1) !== '/') {
274 path += '/';
275 }
276
277 return path;
278 }
279}
280
281module.exports = Cookies;
Note: See TracBrowser for help on using the repository browser.