UNPKG

5.43 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 _cookieSharedSecretCache = {}
64
65var getCookieSharedSecret = function(api_key){
66 return _cookieSharedSecretCache[api_key];
67}
68
69var setCookieSharedSecret = function(api_key, cookieSharedSecret){
70 _cookieSharedSecretCache[api_key] = cookieSharedSecret;
71 console.log('_cookieSharedSecretCache: ', _cookieSharedSecretCache);
72}
73
74var getCookieSharedSecretFromServer = function(requestedApiKey, cb) {
75 var urlOpts = {
76 pathname: '/bouncer/getCookieSharedSecret'
77 , query: { 'requestedApiKey': requestedApiKey }
78 }
79 API.api({ url: urlOpts }, function(err, data){
80 cb(err, data && data.cookie_shared_secret)
81 })
82}
83
84exports.validateFaasSecurity = function(req, cb_err_obj){
85 // First check if the mode is Shared Secret.
86 // In that case, the signed cookies would have been decrypted
87 // by CookieParser successfully
88 var cookieRaw = getSignedCookieRaw(req, 'faas_cookie') // this has Signature suffix, and is URI encoded
89 var cookieObj = extractFaasCookieObj(cookieRaw) // remove signature suffix, and construct JSON object
90
91 if (!cookieRaw || !cookieObj) { cb_err_obj('No cookie'); return }
92
93 var cookieObjStr = JSON.stringify(cookieObj)
94 var connectSignedCookie = req.signedCookies['faas_cookie']
95
96 if (cookieObjStr === connectSignedCookie) {
97 // Things look good, the cookies were signed with a Shared Secret
98 cb_err_obj(null, cookieObj)
99 }
100 else {
101 if (cookieObj && cookieObj.api_key) {
102 if (getCookieSharedSecret(cookieObj.api_key)) {
103 // We already have the signing secret, so just validate the signature.
104 validateFaasCookieLocal(cookieObj.api_key, cookieRaw, cb_err_obj)
105 } else {
106 // Cached secret not found. Get Cookie Shared Secret
107 getCookieSharedSecretFromServer(cookieObj.api_key, function(err, cookieSharedSecret){
108 if (err) {
109 cb_err_obj(err)
110 }
111 else {
112 // Set the cache.
113 setCookieSharedSecret(cookieObj.api_key, cookieSharedSecret);
114 // Validate.
115 validateFaasCookieLocal(cookieObj.api_key, cookieRaw, cb_err_obj);
116 }
117 })
118 }
119 } else {
120 cb_err_obj('no cookie')
121 }
122 }
123}
124
125
126///////////////////////////////////////////////////////////////////////////////////
127// Locally validate signed cookie using the Cookie Secret from faas.io
128///////////////////////////////////////////////////////////////////////////////////
129
130//connect/lib/middleware/cookieSession.js -- cookieSession()
131var getSignedCookie = function(api_key, val) {
132 faasSignedCookie = 's:' + sign(val, getCookieSharedSecret(api_key))
133 return faasSignedCookie
134}
135
136//cookie-signature/index.js
137var sign = function(val, secret){
138 if ('string' != typeof val) throw new TypeError('cookie required');
139 if ('string' != typeof secret) throw new TypeError('secret required');
140 return val + '.' + crypto
141 .createHmac('sha256', secret)
142 .update(val)
143 .digest('base64')
144 .replace(/\=+$/, '');
145};
146
147
148var validateFaasCookieLocal = function(api_key, signedCookie, cb_err_obj){
149
150 // Get the clear text portion of the signed cookie
151 var cookieObj = extractFaasCookieObj(signedCookie)
152 var cookieObjStr = JSON.stringify(cookieObj)
153 var signedCookieDecoded = decodeURIComponent(signedCookie)
154
155 // Sign the clear cookie with the secret key again.
156 var signTest = getSignedCookie(api_key, cookieObjStr)
157
158 // Match the signatures
159 if (signedCookieDecoded === signTest) {
160 cb_err_obj(null, cookieObj)
161 }
162 else {
163 cb_err_obj('invalid signature')
164 }
165}
166////////////////////////////////////////////////////////////////////////////////
167// END: Locally validate signed cookie using the Cookie Secret from faas.io
168////////////////////////////////////////////////////////////////////////////////