'use strict'; var urllib = require('url'); module.exports.CookieJar = CookieJar; function CookieJar(options) { this.options = options || {}; this.options.sessionTimeout = this.options.sessionTimeout || 1800; // 30min this.cookies = {}; } CookieJar.prototype.addCookie = function (cookie) { if (!cookie || !cookie.name) { return; } var lcookie; if (!this.cookies[cookie.name]) { this.cookies[cookie.name] = []; } // overwrite if has same params for (var i = 0, len = this.cookies[cookie.name].length; i < len; i++) { lcookie = this.cookies[cookie.name][i]; if ( lcookie.path === cookie.path && lcookie.domain === cookie.domain && lcookie.secure === cookie.secure && lcookie.httponly === cookie.httponly ) { this.cookies[cookie.name][i] = cookie; return; } } this.cookies[cookie.name].push(cookie); }; CookieJar.prototype.getCookies = function (url) { var keys = Object.keys(this.cookies), cookie, cookies = []; for (var i = 0, len = keys.length; i < len; i++) { if (Array.isArray(this.cookies[keys[i]])) { for (var j = 0, lenj = this.cookies[keys[i]].length; j < lenj; j++) { cookie = this.cookies[keys[i]][j]; if (this.matchCookie(cookie, url)) { cookies.push(cookie.name + '=' + cookie.value); } } } } return cookies.join('; '); }; CookieJar.prototype.matchCookie = function (cookie, url) { var urlparts = urllib.parse(url || '', false, true), path; // check expire if (cookie.expire) { if (cookie.expire.getTime() < Date.now()) { return; } } // check if hostname matches if (urlparts.hostname && cookie._domain) { if (!(urlparts.hostname === cookie._domain || urlparts.hostname.substr(-(cookie._domain.length + 1)) === '.' + cookie._domain)) { return false; } } // check if path matches if (cookie.path && urlparts.pathname) { path = (urlparts.pathname || '/').split('/'); path.pop(); path = path.join('/').trim(); if (path.substr(0, 1) !== '/') { path = '/' + path; } if (path.substr(-1) !== '/') { path += '/'; } if (path.substr(0, cookie.path.length) !== cookie.path) { return false; } } // check secure if (cookie.secure && urlparts.protocol) { if (urlparts.protocol !== 'https:') { return false; } } // check httponly if (cookie.httponly && urlparts.protocol) { if (urlparts.protocol !== 'http:') { return false; } } return true; }; CookieJar.prototype.setCookie = function (cookie_str, url) { var parts = (cookie_str || '').split(';'), cookie = {}, urlparts = urllib.parse(url || '', false, true), path; parts.forEach((function (part) { var key, val; part = part.split('='); key = part.shift().trim(); val = part.join('=').trim(); if (!key) { return; } switch (key.toLowerCase()) { case 'expires': cookie.expires = new Date(val); break; case 'path': cookie.path = val.trim(); break; case 'domain': cookie.domain = val.toLowerCase(); break; case 'max-age': cookie.expires = new Date(Date.now() + (Number(val) || 0) * 1000); break; case 'secure': cookie.secure = true; break; case 'httponly': cookie.httponly = true; break; default: if (!cookie.name) { cookie.name = key; cookie.value = val; } } }).bind(this)); // use current path when path is not specified if (!cookie.path) { path = (urlparts.pathname || '/').split('/'); path.pop(); cookie.path = path.join('/').trim(); if (cookie.path.substr(0, 1) !== '/') { cookie.path = '/' + cookie.path; } if (cookie.path.substr(-1) !== '/') { cookie.path += '/'; } } // if no expire date, then use sessionTimeout value if (!cookie.expires) { cookie._expires = new Date(Date.now() + (Number(this.options.sessionTimeout) || 0) * 1000); } else { cookie._expires = cookie.expires; } if (!cookie.domain) { if (urlparts.hostname) { cookie._domain = urlparts.hostname; } } else { cookie._domain = cookie.domain; } this.addCookie(cookie); };