This repository has been archived by the owner on Dec 16, 2023. It is now read-only.
/
cookies.js
132 lines (116 loc) · 4.27 KB
/
cookies.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// See [RFC 2109](http://tools.ietf.org/html/rfc2109.html) and
// [document.cookie](http://dev/loper.mozilla.org/en/document.cookie)
const DOM = require('./dom');
const { isArray } = require('util');
const Tough = require('tough-cookie');
const { Cookie } = Tough;
// Lists all available cookies.
module.exports = class Cookies extends Array {
constructor() {
super();
}
// Used to dump state to console (debugging)
dump(output = process.stdout) {
for (let cookie of this.sort(Tough.cookieCompare))
output.write(`${cookie}\n`);
}
// Serializes all selected cookies into a single string. Used to generate a cookies header.
//
// domain - Request hostname
// path - Request pathname
serialize(domain, path) {
return this
.select({ domain: domain, path: path })
.map(cookie => cookie.cookieString())
.join('; ');
}
// Returns all cookies that match the identifier (name, domain and path).
// This is used for retrieving cookies.
select(identifier) {
let cookies = this.filter(cookie => cookie.TTL() > 0); // eslint-disable-line new-cap
if (identifier.name)
cookies = cookies.filter(cookie => cookie.key === identifier.name);
if (identifier.path)
cookies = cookies.filter(cookie => Tough.pathMatch(identifier.path, cookie.path));
if (identifier.domain)
cookies = cookies.filter(cookie => Tough.domainMatch(identifier.domain, cookie.domain));
return cookies
.sort((a, b)=> b.domain.length - a.domain.length)
.sort(Tough.cookieCompare);
}
// Adds a new cookie, updates existing cookie (same name, domain and path), or
// deletes a cookie (if expires in the past).
set(params) {
const cookie = new Cookie({
key: params.name,
value: params.value,
domain: params.domain || 'localhost',
path: params.path || '/'
});
if (params.expires)
cookie.setExpires(params.expires);
else if (params.hasOwnProperty('max-age'))
cookie.setMaxAge(params['max-age']);
cookie.secure = !!params.secure;
cookie.httpOnly = !!params.httpOnly;
// Delete cookie before setting it, so we only store one cookie (per
// domain/path/name)
this
.filter(c => c.domain === cookie.domain)
.filter(c => c.path === cookie.path)
.filter(c => c.key === cookie.key)
.forEach(c => this.delete(c));
if (cookie.TTL() > 0) // eslint-disable-line new-cap
this.push(cookie);
}
// Delete the specified cookie.
delete(cookie) {
const index = this.indexOf(cookie);
if (~index)
this.splice(index, 1);
}
// Deletes all cookies.
deleteAll() {
this.splice(0, this.length);
}
// Update cookies with HTTP response
//
// httpHeader - Value of HTTP Set-Cookie header (string/array)
// domain - Set from hostname
// path - Set from pathname
update(httpHeader, domain, path) {
// One Set-Cookie is a string, multiple is an array
const headers = isArray(httpHeader) ? httpHeader : [httpHeader];
headers
.map(cookie => Cookie.parse(cookie))
.filter(cookie => cookie)
.forEach(cookie => {
cookie.domain = cookie.domain || domain;
cookie.path = cookie.path || Tough.defaultPath(path);
// Delete cookie before setting it, so we only store one cookie (per
// domain/path/name)
this
.filter(c => c.domain === cookie.domain)
.filter(c => c.path === cookie.path)
.filter(c => c.key === cookie.key)
.forEach(c => this.delete(c));
if (cookie.TTL() > 0) // eslint-disable-line new-cap
this.push(cookie);
});
}
};
// Returns name=value pairs
DOM.HTMLDocument.prototype.__defineGetter__('cookie', function() {
const { cookies } = this.defaultView.browser;
return cookies
.select({ domain: this.location.hostname, path: this.location.pathname })
.filter(cookie => !cookie.httpOnly)
.map(cookie => `${cookie.key}=${cookie.value}`)
.join('; ');
});
// Accepts serialized form (same as Set-Cookie header) and updates cookie from
// new values.
DOM.HTMLDocument.prototype.__defineSetter__('cookie', function(cookie) {
const { cookies } = this.defaultView.browser;
cookies.update(cookie.toString(), this.location.hostname, this.location.pathname);
});