|
export default { cookieJar, signCookies, validateCookies } |
|
|
|
function cookieJar(r) { |
|
// Replace Set-Cookie response headers with an opaque reference |
|
if (r.headersOut['Set-Cookie'].length) { |
|
var kvs = []; |
|
r.headersOut['Set-Cookie'].forEach(c => kvs.push(c.split(';')[0])); // Omit cookie flags |
|
r.variables.new_session = kvs.join('; '); // Store in keyval cookie jar |
|
r.headersOut['Set-Cookie'] = "session=" + r.variables.request_id + "; " + r.variables.session_cookie_flags; |
|
} |
|
} |
|
|
|
function signCookies(r) { |
|
var c = require('crypto'); |
|
var kv, sc = []; |
|
if (r.headersOut['Set-Cookie'].length) { |
|
r.headersOut['Set-Cookie'].forEach(function(cookie){ |
|
kv = cookie.split('='); |
|
sc.push("sig." + kv[0] + '=' + c.createHmac('sha256', r.variables.signing_key).update(kv[1].split(';')[0]).digest('base64url')); |
|
sc.push(cookie); // This is inefficient but cannot find a way to append to r.headersOut['Set-Cookie'] object |
|
}); |
|
r.headersOut['Set-Cookie'] = sc; |
|
} |
|
} |
|
|
|
function validateCookies(r) { |
|
if (typeof(r.headersIn['Cookie']) == "undefined") { |
|
r.log("NO COOKIES TO VALIDATE"); |
|
return ''; |
|
} else { |
|
var fail = false, kv = [], raw = {}, signed = {}; |
|
// Convert Cookie header into matching objects of raw and signed cookies |
|
var cookies = r.headersIn['Cookie'].split('; '); |
|
cookies.forEach(function(cookie){ |
|
r.log("FOUND " + cookie); |
|
kv = cookie.split('='); |
|
if (kv[0].startsWith('sig.')) { |
|
r.log("ADDING " + kv[0] + " TO SIGNED OBJECT"); |
|
signed[kv[0].slice(4)] = kv[1]; |
|
} else { |
|
r.log("ADDING " + kv[0] + " TO RAW OBJECT"); |
|
raw[kv[0]] = kv[1]; |
|
} |
|
}); |
|
// Loop through each raw cookie and ensure there is a corresponding signature |
|
var c = require('crypto'); |
|
Object.keys(raw).forEach(function(cookie){ |
|
r.log("CHECKING " + cookie + ": " + raw[cookie] + " == " + signed[cookie]); |
|
if (typeof(signed[cookie]) == "undefined") { |
|
r.warn("COOKIE " + cookie + " has no signature"); |
|
fail = true; |
|
} else { |
|
if (signed[cookie] != c.createHmac('sha256', r.variables.signing_key).update(raw[cookie]).digest('base64url')) { |
|
r.warn("COOKIE " + cookie + " has invalid signature"); |
|
fail = true; |
|
} |
|
} |
|
}); |
|
if (fail) { |
|
return ''; |
|
} else { |
|
// Return raw cookies ready to be proxied |
|
return Object.keys(raw).map(key => `${key}=${raw[key]}`).join('; '); |
|
} |
|
} |
|
} |