From e64d9a3db0945bc33d4f74c06118a52216afc74a Mon Sep 17 00:00:00 2001 From: Dmitry Nizovtsev Date: Tue, 16 Dec 2014 18:12:40 +0200 Subject: [PATCH] add travis --- .travis.yml | 7 + Gruntfile.js | 23 ++ README.md | 35 +++ index.js | 394 ++++++++++++++++++++++++ package.json | 35 +++ test/cookies-bad.txt | 11 + test/cookies.txt | 29 ++ test/file-store.test.js | 657 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 1191 insertions(+) create mode 100644 .travis.yml create mode 100644 Gruntfile.js create mode 100644 README.md create mode 100644 index.js create mode 100644 package.json create mode 100644 test/cookies-bad.txt create mode 100644 test/cookies.txt create mode 100644 test/file-store.test.js diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..ae00f37 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +language: node_js +node_js: +- "0.10" +- "0.11" +before_install: npm install -g grunt-cli +install: npm install +before_script: grunt build \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..6c735e1 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,23 @@ +module.exports = function(grunt) { + + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-mocha-test'); + + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + jshint: { + options: { + node: true + }, + main : ["index.js"] + }, + mochaTest: { + options: { + reporter: 'spec' + }, + src: ['test/*.test.js'] + } + }); + + grunt.registerTask('default', 'jshint:main', 'mochaTest'); +}; \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8348d94 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# node-cookiejar-storefile + +## Objective + + + +## Usage + +## Netscape's cookie.txt file +http://www.cookiecentral.com/faq/#3.5 + +The layout of Netscape's cookies.txt file is such that each line contains one name-value pair. An example cookies.txt file may have an entry that looks like this: + +.netscape.com TRUE / FALSE 946684799 NETSCAPE_ID 100103 + +Each line represents a single piece of stored information. A tab is inserted between each of the fields. + +From left-to-right, here is what each field represents: + +domain - The domain that created AND that can read the variable. +flag - A TRUE/FALSE value indicating if all machines within a given domain can access the variable. This value is set automatically by the browser, depending on the value you set for domain. +path - The path within the domain that the variable is valid for. +secure - A TRUE/FALSE value indicating if a secure connection with the domain is needed to access the variable. +expiration - The UNIX time that the variable will expire on. UNIX time is defined as the number of seconds since Jan 1, 1970 00:00:00 GMT. +name - The name of the variable. +value - The value of the variable. + + + +## Developing + + + +### Tools + diff --git a/index.js b/index.js new file mode 100644 index 0000000..2ef991b --- /dev/null +++ b/index.js @@ -0,0 +1,394 @@ +"use strict"; + +var FS = require('fs'), + UTIL = require('util'), + Q = require('q'), + TOUGH = require('tough-cookie'), + canonicalDomain = TOUGH.canonicalDomain, + permuteDomain = TOUGH.permuteDomain, + permutePath = TOUGH.permutePath, + LOCKFILE = require('lockfile'); + +function isString (str) { + return typeof str === 'string' || str instanceof String; +} + +function noop() {} + +var qStop = Q.promise(function () {}); + +function lockFileName (file_name) { + return file_name + '.lock'; +} + +function FileCookieStore(file, opt) { + FileCookieStore.super_.call(this); + + opt = opt || {}; + this.file = file; + this.force_parse = opt.hasOwnProperty('force_parse') ? opt.force_parse + : false; + this.lockfile = opt.hasOwnProperty('lockfile') ? opt.lockfile + : true; + this.mode = opt.hasOwnProperty('mode') ? opt.mode + : 438; + this.http_only_extension = opt.hasOwnProperty('http_only_extension') ? opt.http_only_extension + : true; + this.lockfile_retries = opt.hasOwnProperty('lockfile_retries') ? opt.lockfile_retries + : 200; + this.auto_sync = opt.hasOwnProperty('auto_sync') ? opt.auto_sync + : true; + + if (!this.file || !isString(this.file)) + throw new Error("Unknown file for read/write cookies"); + + this.idx = {}; +} + +UTIL.inherits(FileCookieStore, TOUGH.Store); + +FileCookieStore.prototype.idx = null; +FileCookieStore.prototype.synchronous = false; + + +FileCookieStore.prototype.inspect = function() { + return "{ idx: "+util.inspect(this.idx, false, 2)+' }'; +}; + + +FileCookieStore.prototype._readFile = function (cb) { + var self = this; + Q.nfcall(FS.readFile, self.file, 'utf8'). + then(function (data) { + self.readed = true; + if ( ! data ) return cb(null, self); + self.deserialize(data); + cb(null, self); + }). + catch(function(err){ + if ( ! (err.code && err.code == 'ENOENT') ) + cb(err); + else + cb(); + }).done(); +}; + + +FileCookieStore.prototype._read = function (cb) { + var self = this; + self._readFile(cb); +}; + +/* +function lock_decorator (lock_file, options, cb) { + LOCKFILE.lock(lock_file, options, function (err, release) { + cb(err,release); + }); +} + +function unlock_decorator (lock_file, cb) { + LOCKFILE.unlock(lock_file, function (err) { + cb(err); + }); +} +*/ + +FileCookieStore.prototype._get_lock_func = function (disable_lock) { + var lock_file = lockFileName(this.file); + + return ! disable_lock && this.lockfile ? Q.nfcall(LOCKFILE.lock, lock_file, { + retries : this.lockfile_retries, + retryWait : 50 + }) : new Q(); + + /* + return ! disable_lock && this.lockfile ? Q.nfcall(lock_decorator, lock_file, { + retries : this.lockfile_retries, + retryWait : 50 + }) : new Q(); + */ +}; + + + +FileCookieStore.prototype._get_unlock_func = function (disable_lock) { + var lock_file = lockFileName(this.file); + return ! disable_lock && this.lockfile ? Q.nfcall(LOCKFILE.unlock, lock_file) + : new Q(); + /* + return ! disable_lock && this.lockfile ? Q.nfcall(unlock_decorator, lock_file) + : new Q(); + */ +}; + + +FileCookieStore.prototype._write = function (options, cb) { + var self = this, + data = this.serialize(this.idx); + options = options || {}; + cb = cb || noop; + self._get_lock_func(options.disable_lock). + then(function () { + console.log("For write: ", data); + return Q.nfcall(FS.writeFile, self.file, data, {}); + }). + then(function () { + cb(); + }). + catch(function (err) { + cb(err); + }). + fin(function() { + return self._get_unlock_func(options.disable_lock); + }). + done(); +}; + + +FileCookieStore.prototype._update = function (updateFunc, cb) { + var self = this; + self._get_lock_func( ! self.auto_sync ). + then(function () { + return Q.nbind(self._read, self)(); + }). + then(function () { + updateFunc(); + return self.auto_sync ? Q.nbind(self._write, self)({disable_lock : true}) : new Q(); + }). + then(function () { + cb(); + }). + catch(function (err) { + cb(err); + }). + fin(function () { + return self._get_unlock_func(! self.auto_sync ); + }). + done(); +}; + + +FileCookieStore.prototype.serialize = function(idx) { + var data = "# Netscape HTTP Cookie File\n" + + "# http://www.netscape.com/newsref/std/cookie_spec.html\n" + + "# This is a generated file! Do not edit.\n\n"; + + for (var domain in idx) { + if ( ! idx.hasOwnProperty(domain) ) continue; + for ( var path in idx[domain] ) { + if ( ! idx[domain].hasOwnProperty(path) ) continue; + for ( var key in idx[domain][path] ) { + if ( ! idx[domain][path].hasOwnProperty(key) ) continue; + var cookie = idx[domain][path][key]; + if (cookie) { + + var original_domain = cookie.original_domain || cookie.domain; + var line = [ cookie.httpOnly && this.http_only_extension ? '#HttpOnly_' + original_domain : original_domain, + /^\./.test(original_domain) ? "TRUE" : "FALSE", + cookie.path, + cookie.secure ? "TRUE" : "FALSE", + cookie.expires && cookie.expires != 'Infinity' ? Math.round(cookie.expires.getTime() / 1000) : 0, + encodeURIComponent(cookie.key), + encodeURIComponent(cookie.value), + ].join("\t")+ "\n"; + data += line; + + //console.log("L: ", line); + } + } + } + } + return data; +}; + + +/** + * + * @param {String} raw_data + * @throws {Error} will throw error if file invalid and force_parse - false + * @returns {Array} + */ +FileCookieStore.prototype.deserialize = function (raw_data) { + var data_by_line = raw_data.split(/\r\n|\n/), + self = this, + line_num = 0, + parsed, + http_only = false, + magic = data_by_line.length ? data_by_line[0] : ''; + + if ( (! magic || ! /^\#(?: Netscape)? HTTP Cookie File/.test(magic) ) && ! self.force_parse) + throw new Error(this.file + " does not look like a netscape cookies file"); + + data_by_line.forEach(function (line) { + ++line_num; + if (! ( /^\s*$/.test(line) || (/^\s*\#/.test(line) && + ! /^#HttpOnly_/.test(line) ) ) ) { + + if (self.http_only_extension && /^#HttpOnly_/.test(line)) { + http_only = true; + line = line.replace(/^#HttpOnly_(.*)/,"$1"); + } else { + http_only = false; + } + + parsed = line.split(/\t/); + if (parsed.length != 7) + if (! self.force_parse) { + throw new Error("Line " + line_num + " is not valid"); + } + else + return; + + var can_domain = canonicalDomain(parsed[0]); + var cookie = new TOUGH.Cookie({ + domain : can_domain, + path : parsed[2], + secure : parsed[3] == 'TRUE' ? true : false, + expires : parseInt(parsed[4]) ? new Date(parsed[4] * 1000) : undefined, + key : decodeURIComponent(parsed[5]), + value : decodeURIComponent(parsed[6]), + httpOnly : http_only + }); + cookie.original_domain = parsed[0]; + self._addCookie(cookie); + } + }); +}; + + +FileCookieStore.prototype.save = function(cb) { + this._write(null, cb); +}; + + +FileCookieStore.prototype.findCookie = function(domain, path, key, cb) { + var self = this; + this._read(function (err) { + if (err) return cb(err); + var can_domain = canonicalDomain(domain); + + if ( ! self.idx[can_domain] ) { + return cb(null,undefined); + } + + if ( ! self.idx[can_domain][path] ) { + return cb(null,undefined); + } + + return cb(null,self.idx[can_domain][path][key] || null); + }); +}; + + +FileCookieStore.prototype.findCookies = function (domain, path, cb) { + var self = this, + results = [], + pathMatcher; + if (! domain ) return cb(null,[]); + + var can_domain = canonicalDomain(domain); + this._read(function (err) { + if (err) return cb(err); + + var pathMatcher; + if (!path) { + // null or '/' means "all paths" + pathMatcher = function matchAll(domainIndex) { + for (var curPath in domainIndex) { + var pathIndex = domainIndex[curPath]; + for (var key in pathIndex) { + results.push(pathIndex[key]); + } + } + }; + } else if (path === '/') { + pathMatcher = function matchSlash(domainIndex) { + var pathIndex = domainIndex['/']; + if (!pathIndex) { + return; + } + for (var key in pathIndex) { + results.push(pathIndex[key]); + } + }; + } else { + var paths = permutePath(path) || [path]; + pathMatcher = function matchRFC(domainIndex) { + paths.forEach(function(curPath) { + var pathIndex = domainIndex[curPath]; + if (!pathIndex) { + return; + } + for (var key in pathIndex) { + results.push(pathIndex[key]); + } + }); + }; + } + + var domains = permuteDomain(can_domain) || [can_domain]; + var idx = self.idx; + domains.forEach(function(curDomain) { + var domainIndex = idx[curDomain]; + if (!domainIndex) { + return; + } + pathMatcher(domainIndex); + }); + cb(null,results); + }); +}; + + +FileCookieStore.prototype._addCookie = function (cookie) { + var domain = cookie.canonicalizedDomain(); + if (!this.idx[domain]) { + this.idx[domain] = {}; + } + if (!this.idx[domain][cookie.path]) { + this.idx[domain][cookie.path] = {}; + } + this.idx[domain][cookie.path][cookie.key] = cookie; +}; + + +FileCookieStore.prototype.putCookie = function (cookie, cb) { + var self = this; + this._update( function () { + self._addCookie(cookie); + }, cb); +}; + + +FileCookieStore.prototype.updateCookie = function(oldCookie, newCookie, cb) { + this.putCookie(newCookie, cb); +}; + + +FileCookieStore.prototype.removeCookie = function(domain, path, key, cb) { + var self = this; + this._update( function () { + var can_domain = canonicalDomain(domain); + if (self.idx[can_domain] && self.idx[can_domain][path] && self.idx[can_domain][path][key]) { + delete self.idx[can_domain][path][key]; + } + }, cb); +}; + + +FileCookieStore.prototype.removeCookies = function(domain, path, cb) { + var self = this; + this._update( function () { + var can_domain = canonicalDomain(domain); + if ( self.idx[can_domain] ) { + if (path) { + delete self.idx[can_domain][path]; + } else { + delete self.idx[can_domain]; + } + } + }, cb); +}; + + +module.exports = FileCookieStore; diff --git a/package.json b/package.json new file mode 100644 index 0000000..e798250 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "file-cookie-store", + "version": "0.1.0", + "description": "Store cookies in Netscape's file", + "main": "index.js", + "repository": { + "type" : "git", + "url" : "https://github.com/JSBizon/file-cookie-store.git" + }, + "keywords": [ + "Netscape", + "cookie", + "cookiejar", + "tough-cookie", + "file cookie", + "cookie store" + ], + "devDependencies" : { + "expect.js" : "~0.2.0", + "mocha" : "~1.20.0", + "grunt": "~0.4", + "grunt-cli": "~0.1.13", + "grunt-mocha-test" : "~0.12.2", + "grunt-contrib-jshint" : "~0.10.0" + }, + "dependencies": { + "tough-cookie" : "~0.12.0", + "punycode" : "~1.2.3", + "lockfile" : "~1.0.0", + "q" : "~1.0.1" + }, + "author": "Dmitry Nizovtsev (https://github.com/JSBizon)", + "license": "MIT", + "readmeFilename": "README.md" +} \ No newline at end of file diff --git a/test/cookies-bad.txt b/test/cookies-bad.txt new file mode 100644 index 0000000..b2637d4 --- /dev/null +++ b/test/cookies-bad.txt @@ -0,0 +1,11 @@ +# Netscape HTTP Cookie File +# http://www.netscape.com/newsref/std/cookie_spec.html# This is a generated file! Do not edit. + +.ebay.com TRUE / FALSE 0 ebay %5Esbf%3D%23%5E +.ebay.com TRUE / FALSE 1474129249000000 dp1 bu1p%2FQEBfX0BAX19AQA**55fc39e1%5Ebl%2FUA57dd6d61%5E +99 +#HttpOnly_.ebay.com TRUE / FALSE 0 s CgAD4ACBUHFfhODk5MGVkM2QxNDgwYTVlNjgzMzg0MDRkZmZmMDFhMTKDyRtR +.ebay.com TRUE / FALSE 1442593249000000 nonsessionCgADLAAFUGw1pMQDKACBdgQfhODk5MGVkM2QxNDgwYTVlNjgzMzg0MDRkZmZmMDFhMTIBfArp +.ebay.com TRUE / FALSE 1442593249000000 nonsession CgADLAAFUGw1pMQDKACBdgQfhODk5MGVkM2QxNDgwYTVlNjgzMzg0MDRkZmZmMDFhMTIBfArp +.ebay.com TRUE / FALSE 1568737249000 lucky9 5018099 +99 diff --git a/test/cookies.txt b/test/cookies.txt new file mode 100644 index 0000000..637211a --- /dev/null +++ b/test/cookies.txt @@ -0,0 +1,29 @@ +# Netscape HTTP Cookie File +# http://curl.haxx.se/rfc/cookie_spec.html +# This file was generated by libcurl! Edit at your own risk. + +.amazon.com TRUE / FALSE 0 skin noskin +.google.com.ua TRUE / FALSE 1474129028 PREF ID=b7bf0b7ae32f68f5:FF=0:TM=1411057028:LM=1411057028:S=6XSM7-cTBDMTB9tV +#HttpOnly_.google.com.ua TRUE / FALSE 1426868228 NID 67=JgS7DSq4xRuOIIFfU2pL_CqxASaDJT8XmuLDWDCcaPgcZqdvm37KF8xPqmfsnAfQuWDpKMmYgnOSBm1VW1TSYv_UaFLZkoNdlkYCd04XQxA3kAmnHmv2wTtXUAWB3Z0m +#HttpOnly_www.ebay.com FALSE / FALSE 0 JSESSIONID 1E8940733514EBBCD2A3D607486C0713 +.ebay.com TRUE / FALSE 0 ebay %5Esbf%3D%23%5E +.ebay.com TRUE / FALSE 1474129249 dp1 bu1p/QEBfX0BAX19AQA**55fc39e1^bl/UA57dd6d61^ +#HttpOnly_.ebay.com TRUE / FALSE 0 s CgAD4ACBUHFfhODk5MGVkM2QxNDgwYTVlNjgzMzg0MDRkZmZmMDFhMTKDyRtR +.ebay.com TRUE / FALSE 1442593249 nonsession CgADLAAFUGw1pMQDKACBdgQfhODk5MGVkM2QxNDgwYTVlNjgzMzg0MDRkZmZmMDFhMTIBfArp +.ebay.com TRUE / FALSE 1568737249 lucky9 5018099 +.alibaba.com TRUE / FALSE 3626384461 ali_apache_id 188.163.96.241.1411057268767.977318.9 +www.alibaba.com FALSE / FALSE 0 JSESSIONID DeS9eUwHYSUF2NLJhkm-pb5P +.alibaba.com TRUE / FALSE 3558540915 ali_apache_track "" +.alibaba.com TRUE / FALSE 0 ali_apache_tracktmp "" +.alibaba.com TRUE / FALSE 3558540915 xman_us_f x_l=0 +#HttpOnly_.alibaba.com TRUE / FALSE 0 xman_t CmkWb1wFgqTeb8VKJV3/NMYzISZQjBr/vjMNiCyhSxznYe9GYtWox+CKBVofDGEk +.alibaba.com TRUE / FALSE 0 acs_usuc_t acs_rt=bc8c5f5003ce43818c67d1c254435e91 +#HttpOnly_.alibaba.com TRUE / FALSE 0 acs_t 4hMum6oA3AKjUkEJfy3m8xQSFwWuFCO1lqikMh99Hib7P/ioSBI39mjWXZlMQy8W +#HttpOnly_.alibaba.com TRUE /path/test FALSE 3558540915 xman_f fUW2oGT39LOjTSJEvoSq+tfDjwQ1hO+QEEvx+D0eUDjWGotyXIFKVtj1DJi+k50tivsK3bmd8VlLjNm1XbmORTf/Xylom0EWEyPMtJuOqjqKUnkBr3cyww== +.www.ya.ru TRUE / FALSE 1726417289 yandexuid 1503552661411057290 +#HttpOnly_.facebook.com TRUE / FALSE 1474129312 datr oAYbVDrOuMrYKlXqFXeCv__b +.facebook.com TRUE / FALSE 1411057312 reg_ext_ref deleted +.facebook.com TRUE / FALSE 0 reg_fb_ref https%3A%2F%2Fwww.facebook.com%2Funsupportedbrowser +.facebook.com TRUE / FALSE 0 reg_fb_gate https%3A%2F%2Fwww.facebook.com%2Funsupportedbrowser +.twitter.com TRUE / FALSE 1474129332 guest_id v1%3A141105733211768497 +#HttpOnly_.twitter.com TRUE / TRUE 0 _twitter_sess BAh7CSIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo%250ASGFzaHsABjoKQHVzZWR7ADoHaWQiJTU5MmFhMGQ1MjkzYTg3NmJlNTBlZWVh%250AN2M3YzI0YzY0Ogxjc3JmX2lkIiU4ODgwNjFkMmI2NzMyNjkwZmYyMjYwODUz%250AOTI4ZDQzNzoPY3JlYXRlZF9hdGwrCHsykolIAQ%253D%253D--0e8cfdd2ca30c75f02ac5984be7c8e2583e8922b2c11 diff --git a/test/file-store.test.js b/test/file-store.test.js new file mode 100644 index 0000000..19310a0 --- /dev/null +++ b/test/file-store.test.js @@ -0,0 +1,657 @@ +var expect = require('expect.js'), + FS = require('fs'), + TOUGH = require('tough-cookie'), + Q = require('q'); + +describe('Test file cookie store', function() { + + var FileCookieStore, + COOKIES_TEST_FILE = __dirname + '/cookies.txt', + COOKIES_EMPTY_FILE = __dirname + '/cookies-not-found.txt', + COOKIES_BAD_FILE = __dirname + '/cookies-bad.txt', + COOKIES_TEST_FILE2 = __dirname + '/cookies2.txt', + COOKIES_TEST_FILE_NEW = __dirname + '/cookies2-new.txt', + PARALLEL_WRITES = 20, + cookie_store; + + before(function(done) { + FileCookieStore = require('../index'); + try { + FS.unlinkSync(COOKIES_TEST_FILE2); + } catch (err) {}; + + try { + FS.unlinkSync(COOKIES_TEST_FILE2 + '.lock'); + } catch (err) {}; + + done(); + }); + + beforeEach(function(done){ + FS.writeFileSync(COOKIES_TEST_FILE2, FS.readFileSync(COOKIES_TEST_FILE) ); + cookie_store = new FileCookieStore(COOKIES_TEST_FILE2); + console.log("beforeEach"); + done(); + }); + + afterEach(function(done){ + try { + FS.unlinkSync(COOKIES_TEST_FILE2); + } catch (err) {}; + console.log("afterEach"); + done(); + }); + + + after(function (done) { + try { + FS.unlinkSync(COOKIES_TEST_FILE2 + '.lock'); + } catch (err) {}; + done(); + }); + + + describe("load", function() { + it('should have a FileCookieStore class', function () { + expect(FileCookieStore).to.be.ok(); + }); + }); + + describe("#constructor", function () { + it('should not allow create object without file name', function () { + expect(function () { new FileCookieStore()} ).to.throwError(); + }); + + it('should create object of FileCookieStoreClass', function () { + expect(new FileCookieStore(COOKIES_TEST_FILE)).to.be.ok(); + }); + + it('should not open bad formatted file', function (done) { + new FileCookieStore(COOKIES_BAD_FILE).findCookies('.ebay.com', null, function (err) { + + expect(err).to.be.ok(); + + done(); + }); + }); + + it('should parse bad formatted file', function (done) { + new FileCookieStore(COOKIES_BAD_FILE,{force_parse : true }).findCookies('.ebay.com', null, function (err, cookies) { + + expect(err).not.to.be.ok(); + expect(cookies).to.have.length(5); + + done(); + }); + }); + }); + + + describe("#findCookie", function () { + + it ('should find amazon cookie', function (done) { + + cookie_store.findCookie('.amazon.com', '/', 'skin', function (err, cookie) { + + expect(err).not.to.be.ok(); + expect(cookie).to.be.a(TOUGH.Cookie); + expect(cookie.key).to.be('skin'); + expect(cookie.value).to.be('noskin'); + expect(cookie.expires).to.be('Infinity'); + expect(cookie.secure).not.to.be.ok(); + expect(cookie.path).to.be('/'); + expect(cookie.httpOnly).not.to.be.ok(); + + done(); + }); + }); + + it ('should find httpOnly cookie', function (done) { + + cookie_store.findCookie('.alibaba.com', '/path/test', 'xman_f', function (err, cookie) { + + expect(err).not.to.be.ok(); + expect(cookie).to.be.a(TOUGH.Cookie); + expect(cookie.key).to.be('xman_f'); + expect(cookie.value).to.be('fUW2oGT39LOjTSJEvoSq+tfDjwQ1hO+QEEvx+D0eUDjWGotyXIFKVtj1DJi+k50tivsK3bmd8VlLjNm1XbmORTf/Xylom0EWEyPMtJuOqjqKUnkBr3cyww=='); + expect(cookie.expires.getFullYear()).to.be(2082); + expect(cookie.path).to.be('/path/test'); + expect(cookie.httpOnly).to.be.ok(); + + done(); + }); + }); + + it ('should not find cookie', function (done) { + cookie_store.findCookie('.alibaba.com', '/', 'xman_f', function (err, cookie) { + + expect(err).not.to.be.ok(); + expect(cookie).not.to.be.ok(); + + done(); + }); + }); + + it('should not find cookie(file not found)', function (done) { + var cookie_empty_store = new FileCookieStore(COOKIES_EMPTY_FILE); + cookie_empty_store.findCookie('.amazon.com', '/', 'skin', function (err, cookie) { + + expect(err).not.to.be.ok(); + expect(cookie).not.to.be.ok(); + + done(); + }); + }); + }); + + + describe("#findCookies", function () { + + it ('should find cookies for ebay.com', function (done) { + + cookie_store.findCookies('.ebay.com', null, function (err, cookies) { + + expect(err).not.to.be.ok(); + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(5); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + expect(cookies[0].domain).to.be('ebay.com'); + + done(); + }); + }); + + it ('should find cookies for top level domain', function (done) { + cookie_store.findCookies('www.facebook.com', null, function (err, cookies) { + + expect(err).not.to.be.ok(); + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(4); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + expect(cookies[0].domain).to.be('facebook.com'); + + done(); + }); + }); + }); + + + describe("#putCookie", function () { + + afterEach(function(done){ + try { + FS.unlinkSync(COOKIES_TEST_FILE_NEW); + } catch (err) {}; + done(); + }); + + + it ('should save cookie', function (done) { + cookie_store.findCookies('.ebay.com', null, function (err, cookies) { + + expect(err).not.to.be.ok(); + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(5); + + var fns = [], + cookie_store2 = new FileCookieStore(COOKIES_TEST_FILE_NEW) + + cookies.forEach(function (cookie) { + var func = Q.nbind(cookie_store2.putCookie, cookie_store2); + fns.push(func(cookie)); + }); + + var new_cookie_store = new FileCookieStore(COOKIES_TEST_FILE_NEW), + findCookies = Q.nbind(new_cookie_store.findCookies, new_cookie_store ,'.ebay.com', null); + + Q.all(fns). + then(function () { return findCookies() }). + then(function(cookies){ + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(5); + + done(); + }). + catch(function (err) { + done(err); + }). + done(); + }); + }); + + + it ('should update cookie', function (done) { + + var findCookie = Q.nbind(cookie_store.findCookie, cookie_store,'.twitter.com', '/', 'guest_id'); + + findCookie(). + then(function (cookie) { + + expect(cookie.key).to.be('guest_id'); + expect(cookie.value).to.be('v1:141105733211768497'); + + cookie.value = 'test value'; + + return Q.nbind(cookie_store.putCookie, cookie_store)(cookie); + }). + then(function () { + var cookie_store2 = new FileCookieStore(COOKIES_TEST_FILE2); + + return Q.nbind(cookie_store2.findCookie, cookie_store2,'.twitter.com', '/', 'guest_id')(); + }). + then(function (cookie) { + + expect(cookie.key).to.be('guest_id'); + expect(cookie.value).to.be('test value'); + + done(); + }). + catch(function (err){ + done(err); + }). + done(); + + }); + + it('should insert new cookie', function (done) { + + var domain = 'putcookie.test.com', + path = '/', + key = 'key 1 , . !@#$%^&*()', + expire = new Date(); + + expire.setDate(expire.getDate() + 2); + + var cookie = new TOUGH.Cookie({ + domain : domain, + path : path, + secure : true, + expires : expire, + key : key, + value : '[]{}!@#$%%^&*()_+?', + httpOnly: true + }); + + Q.nbind(cookie_store.putCookie, cookie_store)(cookie). + then(function () { + var cookie_store2 = new FileCookieStore(COOKIES_TEST_FILE2); + var findCookies = Q.nbind(cookie_store2.findCookies, cookie_store2); + return findCookies(domain, null); + }). + then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(1); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + }). + then(function () { + var cookie_store2 = new FileCookieStore(COOKIES_TEST_FILE2); + var findCookie = Q.nbind(cookie_store2.findCookie, cookie_store2); + return findCookie(domain,path,key); + }). + then(function (cookie) { + + expect(cookie).to.be.a(TOUGH.Cookie); + expect(cookie.domain).to.be(domain); + expect(Math.round(cookie.expires.getTime() / 1000)).to.be(Math.round(expire.getTime() / 1000)); + + done(); + }). + catch(function(err) { + done(err); + }). + done(); + }); + + it('should mass cookies store update', function (done) { + + var i=0, + stores_num = PARALLEL_WRITES, + keys = [], + cookies = [], + fns = [], + expire = new Date(), + test_domain = 'masstest.com'; + + expire.setDate(expire.getDate() + 2); + + for (i = 0; i < stores_num; i++) { + var key = 'key ' + i; + var cookie_store = new FileCookieStore(COOKIES_TEST_FILE2); + var cookie = new TOUGH.Cookie({ + domain : test_domain, + path : '/', + secure : true, + expires : expire, + key : key, + value : 'value ' + i, + httpOnly : false + }); + + var func = Q.nbind(cookie_store.putCookie, cookie_store); + fns.push(func(cookie)); + keys.push(key); + } + + Q.all(fns) + .then(function () { + var cookie_store = new FileCookieStore(COOKIES_TEST_FILE2); + return Q.nbind(cookie_store.findCookies, cookie_store)(test_domain,null); + }) + .then(function(cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(PARALLEL_WRITES); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + + var map_key_cookie = {}; + + cookies.forEach(function (cookie) { + map_key_cookie[cookie.key] = cookie; + }); + + keys.forEach(function (key) { + expect(map_key_cookie[key]).to.be.a(TOUGH.Cookie); + }); + + done(); + }) + .catch(function (err){ + done(err); + }). + done(); + }); + }); + + + describe("#removeCookie", function () { + it ('should remove cookie', function (done) { + + var removeCookie = Q.nbind(cookie_store.removeCookie, cookie_store,'.twitter.com', '/', 'guest_id'); + + removeCookie(). + then(function (cookie) { + var cookie_store2 = new FileCookieStore(COOKIES_TEST_FILE2); + + return Q.nbind(cookie_store2.findCookie, cookie_store2)('.twitter.com', '/', 'guest_id'); + }). + then(function (cookie) { + expect(cookie).not.to.be.ok(); + done(); + }). + catch(function (err){ + done(err); + }). + done(); + }); + }); + + + describe("#removeCookies", function () { + it ('should remove all domain cookies', function (done) { + + var test_domain = '.twitter.com'; + + Q.nbind(cookie_store.findCookies, cookie_store)(test_domain, null). + then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(2); + return Q.nbind(cookie_store.removeCookies, cookie_store)(test_domain, null); + }). + then(function () { + var cookie_store2 = new FileCookieStore(COOKIES_TEST_FILE2); + return Q.nbind(cookie_store2.findCookies, cookie_store2)(test_domain, null); + }). + then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(0); + done(); + }). + catch(function (err){ + done(err); + }). + done(); + }); + }); + + + describe("#CookieJar", function () { + var cookie_jar; + + beforeEach(function(done){ + cookie_jar = new TOUGH.CookieJar(new FileCookieStore(COOKIES_TEST_FILE2)); + done(); + }); + + it ('should create CookieJar object', function (done) { + expect(cookie_jar).to.be.a(TOUGH.CookieJar); + done(); + }); + + it('should find cookie in CookieJar', function (done) { + + Q.nbind(cookie_jar.getCookies, cookie_jar)('http://facebook.com') + .then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(3); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + return Q.nbind(cookie_jar.getCookies, cookie_jar)('http://www.facebook.com'); + }). + then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(3); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + return Q.nbind(cookie_jar.getCookies, cookie_jar)('http://aaa.bbb.facebook.com'); + }). + then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(3); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + return Q.nbind(cookie_jar.getCookies, cookie_jar)('https://aaa.bbb.facebook.com'); + }). + then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(3); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + return Q.nbind(cookie_jar.getCookies, cookie_jar)('http://alibaba.com'); + }). + then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(7); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + return Q.nbind(cookie_jar.getCookies, cookie_jar)('http://www.alibaba.com'); + }). + then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(8); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + return Q.nbind(cookie_jar.getCookies, cookie_jar)('http://www.alibaba.com/path/test'); + }). + then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(9); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + return Q.nbind(cookie_jar.getCookies, cookie_jar)('https://www.alibaba.com/'); + }). + then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(8); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + return Q.nbind(cookie_jar.getCookies, cookie_jar)('https://www.ya.ru/super/path'); + }). + then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(1); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + }). + then(function () { + done(); + }). + catch(function (err){ + done(err); + }). + done(); + }); + /* + it('should not find cookie in CookieJar', function (done) { + + Q.nbind(cookie_jar.getCookies, cookie_jar)('http://www.thefacebook.com/'). + then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(0); + return Q.nbind(cookie_jar.getCookies, cookie_jar)('https://ya.ru/'); + }). + then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(0); + }). + then(function () { + done(); + }). + catch(function (err){ + done(err); + }). + done(); + }); + + it('should put cookie in CookieJar', function (done) { + + var expire = new Date(); + + expire.setDate(expire.getDate() + 2); + + var cookie = new TOUGH.Cookie({ + expires : expire, + key : 'key111', + value : 'value222', + httpOnly : false + }); + + Q.nbind(cookie_jar.setCookie, cookie_jar)(cookie, 'http://setcookietest.com/'). + then( function (cookie) { + expect(cookie).to.be.a(TOUGH.Cookie); + return Q.nbind(cookie_jar.getCookies, cookie_jar)('http://setcookietest.com/test/path'); + }). + then( function (cookies) { + console.log("aaa"); + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(1); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + }). + then(function () { + done(); + }). + catch(function (err){ + done(err); + }). + done(); + }); + + it('should save cookie into file from CookieJar', function (done) { + var expire = new Date(); + + expire.setDate(expire.getDate() + 2); + + var cookie = new TOUGH.Cookie({ + path : '/test/path', + expires : expire, + key : 'key312', + value : 'value333', + httpOnly : false + }); + console.log("qqq"); + Q.nbind(cookie_jar.setCookie, cookie_jar)(cookie, 'http://setcookietest.com/'). + then( function (cookie) { + expect(cookie).to.be.a(TOUGH.Cookie); + var cookie_jar2 = new TOUGH.CookieJar(new FileCookieStore(COOKIES_TEST_FILE2)); + return Q.nbind(cookie_jar2.getCookies, cookie_jar2)('http://setcookietest.com/test/path'); + }). + then( function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(1); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + + var cookie_jar2 = new TOUGH.CookieJar(new FileCookieStore(COOKIES_TEST_FILE2)); + return Q.nbind(cookie_jar2.getCookies, cookie_jar2)('http://setcookietest.com/'); + }). + then( function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(0); + }). + then(function () { + done(); + }). + catch(function (err){ + done(err); + }). + done(); + }); + + it('should use secure cookie for https only', function (done) { + var expire = new Date(); + + expire.setDate(expire.getDate() + 2); + + var cookie = new TOUGH.Cookie({ + expires : expire, + secure: true, + key : 'key232', + value : 'value212', + httpOnly : false + }); + + Q.nbind(cookie_jar.setCookie, cookie_jar)(cookie, 'http://setcookietest.com/'). + then( function (cookie) { + expect(cookie).to.be.a(TOUGH.Cookie); + return Q.nbind(cookie_jar.getCookies, cookie_jar)('https://setcookietest.com/test/path'); + }). + then( function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(1); + expect(cookies[0]).to.be.a(TOUGH.Cookie); + + return Q.nbind(cookie_jar.getCookies, cookie_jar)('http://setcookietest.com/test/path'); + }). + then( function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(0); + }). + then(function () { + done(); + }). + catch(function (err){ + done(err); + }). + done(); + }); + + it('should remove expired Cookie from CookieJar', function (done) { + var expire = new Date(); + + expire.setDate(expire.getDate() - 2); + + var cookie = new TOUGH.Cookie({ + expires : expire, + key : 'key', + value : 'value', + httpOnly : false + }); + + Q.nbind(cookie_jar.setCookie, cookie_jar)(cookie, 'http://setcookietest.com/'). + then( function (cookie) { + expect(cookie).to.be.a(TOUGH.Cookie); + return Q.nbind(cookie_jar.getCookies, cookie_jar)('http://setcookietest.com/'); + }). + then( function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(0); + }). + then(function () { + done(); + }). + catch(function (err){ + done(err); + }). + done(); + }); + */ + }); +}); \ No newline at end of file