blackbird-server
Version:
HTTP for JavaScript
513 lines (512 loc) • 16.5 kB
HTML
<html lang="en">
<head>
<title>Code coverage report for modules/middleware/session.js</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="../../index.html">all files</a> / <a href="index.html">modules/middleware/</a> session.js
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">90.38% </span>
<span class="quiet">Statements</span>
<span class='fraction'>47/52</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">72.5% </span>
<span class="quiet">Branches</span>
<span class='fraction'>29/40</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Functions</span>
<span class='fraction'>9/9</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">90.38% </span>
<span class="quiet">Lines</span>
<span class='fraction'>47/52</span>
</div>
</div>
</div>
<div class='status-line high'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet">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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150</td><td class="line-coverage quiet"><span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">16×</span>
<span class="cline-any cline-yes">16×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">16×</span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">16×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">5×</span>
<span class="cline-any cline-yes">5×</span>
<span class="cline-any cline-yes">5×</span>
<span class="cline-any cline-yes">5×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">5×</span>
<span class="cline-any cline-yes">5×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">21×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">16×</span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">16×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">16×</span>
<span class="cline-any cline-yes">16×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">16×</span>
<span class="cline-any cline-yes">16×</span>
<span class="cline-any cline-yes">16×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">16×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">13×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">const mach = require("../index");
const Promise = require("../utils/Promise");
const decodeBase64 = require("../utils/decodeBase64");
const encodeBase64 = require("../utils/encodeBase64");
const makeHash = require("../utils/makeHash");
const CookieStore = require("./session/CookieStore");
const {is} = require("ramda");
mach.extend(
require("../extensions/server")
);
/**
* The maximum size of an HTTP cookie.
*/
const MAX_COOKIE_SIZE = 4096;
/**
* Stores the given session and returns a promise for a value that should be stored
* in the session cookie to retrieve the session data again on the next request.
*/
function encodeSession(session, store, secret) {
return store.save(session).then(function (data) {
const cookie = encodeBase64(`${data}--${makeHashWithSecret(data, secret)}`);
<span class="missing-if-branch" title="if path not taken" >I</span>if (cookie.length > MAX_COOKIE_SIZE) {
<span class="cstat-no" title="statement not covered" > throw new Error("Cookie data size exceeds 4kb; content dropped");</span>
}
return cookie;
});
}
/**
* Decodes the given cookie value and returns a promise for the corresponding session
* data from the store. Also verifies the hash value to ensure the cookie has not been
* tampered with. If it has, returns null.
*/
function decodeCookie(cookie, store, secret) {
const value = decodeBase64(cookie);
const index = value.lastIndexOf("--");
const data = value.substring(0, index);
const hash = value.substring(index + 2);
// Verify the cookie has not been tampered with.
<span class="missing-if-branch" title="else path not taken" >E</span>if (hash === makeHashWithSecret(data, secret)) {
return store.load(data);
}
<span class="cstat-no" title="statement not covered" > return null;</span>
}
function makeHashWithSecret(data, secret) {
return makeHash(secret ? data + secret : <span class="branch-1 cbranch-no" title="branch not covered" >data)</span>;
}
/**
* A middleware that provides support for HTTP sessions using cookies.
*
* Options may be any of the following:
*
* - secret A cryptographically secure secret key that will be used to verify
* the integrity of session data that is received from the client
* - name The name of the cookie. Defaults to "_session"
* - path The path of the cookie. Defaults to "/"
* - domain The cookie's domain. Defaults to null
* - secure True to only send this cookie over HTTPS. Defaults to false
* - expireAfter The number of seconds after which sessions expire. Defaults
* to 0 (no expiration)
* - httpOnly True to restrict access to this cookie to HTTP(S) APIs.
* Defaults to true
* - store An instance of MemoryStore, CookieStore, or RedisStore that
* is used to store session data. Defaults to a new CookieStore
*
* Example:
*
* app.use(mach.session, {
* secret: 'the-secret',
* secure: true
* });
*
* Hint: A great way to generate a cryptographically secure session secret from
* the command line:
*
* $ node -p "require('crypto').randomBytes(64).toString('hex')"
*
* Note: Since cookies are only able to reliably store about 4k of data, if the
* session cookie payload exceeds that the session will be dropped.
*/
function session(app, options) {
options = options || <span class="branch-1 cbranch-no" title="branch not covered" >{};</span>
<span class="missing-if-branch" title="if path not taken" >I</span>if (is(String, options)) {
<span class="cstat-no" title="statement not covered" > options = {secret: options};</span>
}
const secret = options.secret;
const name = options.name || "_session";
const path = options.path || "/";
const domain = options.domain;
const expireAfter = options.expireAfter || 0;
const httpOnly = "httpOnly" in options ? <span class="branch-0 cbranch-no" title="branch not covered" >options.httpOnly || false </span>: true;
const secure = options.secure || false;
const store = options.store || new CookieStore(options);
<span class="missing-if-branch" title="if path not taken" >I</span>if (!secret) {
<span class="cstat-no" title="statement not covered" > console.warn([</span>
"WARNING: There was no \"secret\" option provided to mach.session! This poses",
"a security vulnerability because session data will be stored on clients without",
"any server-side verification that it has not been tampered with. It is strongly",
"recommended that you set a secret to prevent exploits that may be attempted using",
"carefully crafted cookies."
].join("\n"));
}
return function (conn) {
<span class="missing-if-branch" title="if path not taken" >I</span>if (conn.session) {
<span class="cstat-no" title="statement not covered" > return conn.call(app); </span>// Don't overwrite the existing session.
}
const cookie = conn.request.cookies[name];
return Promise.resolve(cookie && decodeCookie(cookie, store, secret)).then(function (object) {
conn.session = object || {};
return conn.call(app).then(function () {
return Promise.resolve(conn.session && encodeSession(conn.session, store, secret)).then(function (newCookie) {
const expires = expireAfter && <span class="branch-1 cbranch-no" title="branch not covered" >new Date(Date.now() + expireAfter * 1000);</span>
// Don't bother setting the cookie if its value
// hasn't changed and there is no expires date.
if (newCookie === cookie && !expires) {
return;
}
conn.response.setCookie(name, {
value: newCookie,
path,
domain,
expires,
httpOnly,
secure
});
}, conn.onError);
});
}, conn.onError);
};
}
module.exports = session;
</pre></td></tr>
</table></pre>
<div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Wed Jul 06 2016 20:37:18 GMT-0500 (CDT)
</div>
</div>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="../../sorter.js"></script>
</body>
</html>