UNPKG

4.95 kBJavaScriptView Raw
1var API = require('./api')
2
3var crypto = require('crypto')
4
5
6var getSignedCookieRaw = function(req, cookieName) {
7 var signedCookieRaw = null
8
9 var rawCookies = req.headers.cookie
10 if (rawCookies) {
11 // Cookies key/val pairs are separted by ;
12 var split1 = rawCookies.split(';')
13
14 for (var i=0; i<split1.length; i++) {
15 // Look for the cookie with the input cookieName
16 if (split1[i].indexOf(cookieName) > -1) {
17 // key/val pairs are separated by =
18 var split2 = split1[i].split('=')
19 //The cookie's value is 2nd index of the split array
20 signedCookieRaw = split2[1]
21 }
22 }
23 }
24
25 return signedCookieRaw
26}
27
28var extractFaasCookieObj = function(faas_cookie_signed) {
29 var method_name = "faas.io: extractFaasCookieObj";
30
31 if (faas_cookie_signed) {
32 //console.log(method_name+": faas_cookie_signed: "+faas_cookie_signed);
33
34 try
35 {
36 faas_cookie_signed = decodeURIComponent(faas_cookie_signed);
37 }
38 catch (err) {
39 //console.log(method_name+": error decoding faas_cookie_signed");
40 return null;
41 }
42 //console.log(method_name+": decoded faas_cookie_signed: "+faas_cookie_signed);
43
44 if (faas_cookie_signed) {
45 // Signed Cookie Format (node.js Connect):
46 // "s:" + {key: val, faas_session_id: xxxxxxxxxx} + "." + signature
47
48 var split1 = (faas_cookie_signed.split('s:'))[1];
49 //console.log("split1: "+split1);
50
51 var faas_cookie_object_str = (split1.split('}.'))[0] + "}";
52 //console.log("faas_cookie_object_str: "+faas_cookie_object_str);
53
54 return JSON.parse(faas_cookie_object_str);
55 } else {
56 return null;
57 }
58 } else {
59 return null;
60 }
61}
62
63var _cookieSharedSecret = null
64
65var getCookieSharedSecret = function(){
66 return _cookieSharedSecret
67}
68
69var setCookieSharedSecret = function(cookieSharedSecret){
70 _cookieSharedSecret = cookieSharedSecret
71}
72
73var getCookieSharedSecretFromServer = function(cb) {
74 var urlOpts = {
75 pathname: '/bouncer/getCookieSharedSecret'
76 }
77 API.api({ url: urlOpts }, function(err, data){
78 cb(err, data && data.cookie_shared_secret)
79 })
80}
81
82exports.validateFaasSecurity = function(req, cb_err_obj){
83 // First check if the mode is Shared Secret.
84 // In that case, the signed cookies would have been decrypted
85 // by CookieParser successfully
86 var cookieRaw = getSignedCookieRaw(req, 'faas_cookie') // this has Signature suffix, and is URI encoded
87 var cookieObj = extractFaasCookieObj(cookieRaw) // remove signature suffix, and construct JSON object
88
89 if (!cookieRaw || !cookieObj) { cb_err_obj('No cookie'); return }
90
91 var cookieObjStr = JSON.stringify(cookieObj)
92 var connectSignedCookie = req.signedCookies['faas_cookie']
93
94 if (cookieObjStr === connectSignedCookie) {
95 // Things look good, the cookies were signed with a Shared Secret
96 cb_err_obj(null, cookieObj)
97 }
98 else if (getCookieSharedSecret()) {
99 // We already have the signing secret, so just validate the signature.
100 validateFaasCookieLocal(cookieRaw, cb_err_obj)
101 }
102 else {
103 // Cached secret not found. Get Cookie Shared Secret
104 getCookieSharedSecretFromServer(function(err, cookieSharedSecret){
105 if (err) {
106 cb_err_obj(err)
107 }
108 else {
109 // Set the cache.
110 setCookieSharedSecret(cookieSharedSecret)
111 // Validate.
112 validateFaasCookieLocal(cookieRaw, cb_err_obj)
113 }
114 })
115 }
116}
117
118
119///////////////////////////////////////////////////////////////////////////////////
120// Locally validate signed cookie using the Cookie Secret from faas.io
121///////////////////////////////////////////////////////////////////////////////////
122
123//connect/lib/middleware/cookieSession.js -- cookieSession()
124var getSignedCookie = function(val) {
125 faasSignedCookie = 's:' + sign(val, getCookieSharedSecret())
126 return faasSignedCookie
127}
128
129//cookie-signature/index.js
130var sign = function(val, secret){
131 if ('string' != typeof val) throw new TypeError('cookie required');
132 if ('string' != typeof secret) throw new TypeError('secret required');
133 return val + '.' + crypto
134 .createHmac('sha256', secret)
135 .update(val)
136 .digest('base64')
137 .replace(/\=+$/, '');
138};
139
140
141var validateFaasCookieLocal = function(signedCookie, cb_err_obj){
142
143 // Get the clear text portion of the signed cookie
144 var cookieObj = extractFaasCookieObj(signedCookie)
145 var cookieObjStr = JSON.stringify(cookieObj)
146 var signedCookieDecoded = decodeURIComponent(signedCookie)
147
148 // Sign the clear cookie with the secret key again.
149 var signTest = getSignedCookie(cookieObjStr)
150
151 // Match the signatures
152 if (signedCookieDecoded === signTest) {
153 cb_err_obj(null, cookieObj)
154 }
155 else {
156 cb_err_obj('invalid signature')
157 }
158}
159////////////////////////////////////////////////////////////////////////////////
160// END: Locally validate signed cookie using the Cookie Secret from faas.io
161////////////////////////////////////////////////////////////////////////////////