cookiejar.js 4.84 KB
'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);
};