From cbb44ac3c0a3f8d700936069c1e52d2e8f651cc4 Mon Sep 17 00:00:00 2001 From: Dmitry Nizovtsev Date: Thu, 2 Apr 2015 18:12:49 +0300 Subject: [PATCH] new version with fixes --- README.md | 4 +- index.js | 71 ++++++++++++++++--- package.json | 7 +- test/cookies.txt | 18 +++++ test/file-store.test.js | 148 ++++++++++++++++++++++++++++++++++++++-- 5 files changed, 230 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index d6352dd..473ffb7 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Library allow parallel access to the cookies file based on [lockfile](https://gi ``` javascript var FileCookieStore = require('file-cookie-store'); -var CookieJar = require("tough-cookie2").CookieJar; //note: it use tough-cookie2 by default, it's available for use with tough-cookie +var CookieJar = require("tough-cookie").CookieJar; var jar = new CookieJar(new FileCookieStore("./cookie.txt", {lockfile : true})); ``` @@ -39,7 +39,7 @@ Example of using FileCookieStore without auto_sync mode: ``` javascript var Q = require('q'); var FileCookieStore = require('file-cookie-store'); -var TOUGH = require("tough-cookie2"); +var TOUGH = require("tough-cookie"); var cookies_store = new FileCookieStore("./cookie.txt", {auto_sync : false}); var jar = new TOUGH.CookieJar(cookies_store); diff --git a/index.js b/index.js index 328bf18..5262097 100644 --- a/index.js +++ b/index.js @@ -3,7 +3,7 @@ var FS = require('fs'), UTIL = require('util'), Q = require('q'), - TOUGH = require('tough-cookie2'), + TOUGH = require('tough-cookie'), canonicalDomain = TOUGH.canonicalDomain, permuteDomain = TOUGH.permuteDomain, permutePath = TOUGH.permutePath, @@ -36,6 +36,8 @@ function FileCookieStore(file, opt) { : 200; this.auto_sync = opt.hasOwnProperty('auto_sync') ? opt.auto_sync : true; + this.no_file_error = opt.hasOwnProperty('no_file_error') ? opt.no_file_error + : false; if (!this.file || !isString(this.file)) { throw new Error("Unknown file for read/write cookies"); @@ -65,7 +67,7 @@ FileCookieStore.prototype._readFile = function (cb) { cb(null, self); }). catch(function(err){ - if ( ! (err.code && err.code === 'ENOENT') ) + if ( ! (err.code && err.code === 'ENOENT' && ! self.no_file_error ) ) cb(err); else cb(); @@ -155,9 +157,12 @@ FileCookieStore.prototype.serialize = function(idx) { 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", + var cookie_domain = cookie.domain; + if ( ! cookie.hostOnly) { + cookie_domain = '.' + cookie_domain; + } + var line = [ this.http_only_extension && cookie.httpOnly ? '#HttpOnly_' + cookie_domain : cookie_domain, + /^\./.test(cookie_domain) ? "TRUE" : "FALSE", cookie.path, cookie.secure ? "TRUE" : "FALSE", cookie.expires && cookie.expires != 'Infinity' ? Math.round(cookie.expires.getTime() / 1000) : 0, @@ -211,7 +216,9 @@ FileCookieStore.prototype.deserialize = function (raw_data) { else return; - var can_domain = canonicalDomain(parsed[0]); + var domain = parsed[0], + can_domain = canonicalDomain(domain); + var cookie = new TOUGH.Cookie({ domain : can_domain, path : parsed[2], @@ -219,9 +226,10 @@ FileCookieStore.prototype.deserialize = function (raw_data) { expires : parseInt(parsed[4]) ? new Date(parsed[4] * 1000) : undefined, key : decodeURIComponent(parsed[5]), value : decodeURIComponent(parsed[6]), - httpOnly : http_only + httpOnly : http_only, + hostOnly : /^\./.test(domain) ? false : true }); - cookie.original_domain = parsed[0]; + self._addCookie(cookie); } }); @@ -368,4 +376,51 @@ FileCookieStore.prototype.removeCookies = function(domain, path, cb) { }; +FileCookieStore.prototype.export = function(file_store, cb) { + var self = this; + if ( arguments.length < 2) { + cb = file_store; + file_store = null; + } + if (! file_store) { + file_store = []; + } + this._read(function (err) { + var fns = []; + var idx = self.idx; + 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) { + if (file_store instanceof TOUGH.Store) { + var func = Q.nbind(file_store.putCookie, file_store); + fns.push(func(cookie)); + } else { + file_store.push(cookie); + } + } + } + } + } + + if (fns.length) { + Q.all(fns).then(function(){ + cb(null, file_store); + }). + catch(function (err){ + cb(err); + }). + done(); + } else { + cb(null, file_store); + } + }); + + return file_store; +}; + module.exports = FileCookieStore; diff --git a/package.json b/package.json index 6a009a5..1a5f675 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "file-cookie-store", - "version": "0.1.1", + "version": "0.2.0", "description": "Store cookies in Netscape's file", "main": "index.js", "repository": { @@ -17,20 +17,19 @@ "Netscape file", "cookiejar", "tough-cookie", - "tough-cookie2", "file cookie", "cookie store" ], "devDependencies": { "expect.js": "~0.2.0", - "mocha": "~1.20.0", + "mocha": "~2.2.1", "grunt": "~0.4", "grunt-cli": "~0.1.13", "grunt-mocha-test": "~0.12.2", "grunt-contrib-jshint": "~0.10.0" }, "dependencies": { - "tough-cookie2": "~0.12.0", + "tough-cookie": "~0.12.0", "punycode": "~1.2.3", "lockfile": "~1.0.0", "q": "~1.0.1" diff --git a/test/cookies.txt b/test/cookies.txt index 637211a..b0682b4 100644 --- a/test/cookies.txt +++ b/test/cookies.txt @@ -27,3 +27,21 @@ www.alibaba.com FALSE / FALSE 0 JSESSIONID DeS9eUwHYSUF2NLJhkm-pb5P .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 +aff.store.com FALSE / FALSE 3455118043 A a7ee73682a47529054ed7f89104fd5fdsde +aff.store.com FALSE / FALSE 3455118043 A_auth bb5fdfdlfd +aff.store.com FALSE / FALSE 0 A_pap_sid a7ee73682a47529054ed7f89104fd5de +www.google.com FALSE /calendar TRUE 2485022944 CAL DQAAAFoBAAAqB4qdsfdsVFHoj4XZK96upRZqYLQAcIOod4KSHcXgOzfQXn5nlqnxBjPRy11g3Dsf3e66zuVRdZa5G_RkDGRjFTcQud7ZYXrcCwT_l2QB9B01OVfgX-2Q6J46HYfGg829p6D-qlG43sQUoexJdI4X7jIUV4MBWCRmST_d61lhszPBDz1cPnenPFpkvj7ZzXqZJ8qfnh5tDzyIvw8hiGMTC8xYliW2Kbrfc68vRQuoaPH6DKrlPvgSysuFkHF3aVTq2M7vCUchRrVNvKbHVkztj5AWtrecmSDS7tgJAHnRfzcumj77cOiJov1oKgYyVgSgX9eiANrSF87Tj81SA2MC_gBuubfReQD0IURvPC0LSqTS9g82_WWfaiQKQ2VyPOOe20aoueEhBjBlLkaLC9pVNpfwW_o8JSpu2MSe7K0IO18yP63h5wDBJIiZCMB74HQeZvdu3RLHFq1Ac62Y0PIjKmsoj +www.google.com FALSE /a TRUE 2487269054 GAPS 1:grbVtyKFbPy0AZMDvJr2n46PDyfsDQ8g:pqs_0kI0xaSWXy2Z +www.google.com FALSE /accounts FALSE 2484997631 GAPS 1:qq4L6m3VxZfe4S9aSynYdfd23do_FK9kQ:uhoqRlo7QmaG36ZB +.google.com TRUE / FALSE 0 GMAIL_RTT 667 +www.google.com FALSE / FALSE 0 GoogleAccountsLocale_session ru +.google.com TRUE / FALSE 2487430420 HSID AdvWK2t48hBsdfPfLE_e +www.google.com FALSE /trends FALSE 2455611239 I4SUserLocale en_US +.google.com TRUE / FALSE 2438508299 NID 67=P3HLqYBOi6-6ox-3xuDg5Wo8wnlEoCjKs_ClfMBgLXB0yCOmuSCLLhHEFEPZCod2n5ReXRqrG1qJqSX6EpQM4KqybItyakoNhtgbFfilnVF6TwdOMsX_vbBV8KmYqPRtQdFhZCw2q6cenHgKDerhGztnWo3DdRuoQX2iWW6RD7IODxLB_0_fIFSe_htilwZ07jR4NYHVQqmwds6JiQj-Z5RRDX4QTglJTKmr9MxEy3AmQB8U +.google.com TRUE / FALSE 2424530050 OGPC 4061155-25: +store.com FALSE / FALSE 2734273447 Id 982f38a31d8e92b7d3 +.store.com TRUE / FALSE 2734273447 VisitorId 9439ee6f63767329 +.aff.store.com TRUE / FALSE 2739632121 Id 8ds98e959ef6982f38a31d8e92b7 +.www.edical.com TRUE / FALSE 2484725151 __utma 1.1534491830.1418284963.1418917050.1421653151.3 +.www.edical.com TRUE / FALSE 2437421151 __utmz 1.1418284963.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none) +aff.store.com FALSE / FALSE 2444440653 gpf_language en-US diff --git a/test/file-store.test.js b/test/file-store.test.js index 10c043b..600352f 100644 --- a/test/file-store.test.js +++ b/test/file-store.test.js @@ -1,6 +1,8 @@ var expect = require('expect.js'), FS = require('fs'), - TOUGH = require('tough-cookie2'), + util = require('util'), + TOUGH = require('tough-cookie'), + MemoryCookieStore = require('tough-cookie/lib/memstore').MemoryCookieStore, Q = require('q'); describe('Test file cookie store', function() { @@ -72,6 +74,13 @@ describe('Test file cookie store', function() { done(); }); }); + + it('should throw exception if file not found', function (done) { + new FileCookieStore(COOKIES_TEST_FILE_NEW,{no_file_error: true}).findCookies('.ebay.com', null, function (err,cookies) { + 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) { @@ -211,6 +220,12 @@ describe('Test file cookie store', function() { done(); }); }); + + + + it ('should not find host only cookies', function (done) { + done(); + }); it ('wrong arguments', function (done) { cookie_store.findCookies(undefined, null, function (err, cookies) { @@ -244,7 +259,7 @@ describe('Test file cookie store', function() { expect(cookies).to.have.length(5); var fns = [], - cookie_store2 = new FileCookieStore(COOKIES_TEST_FILE_NEW) + cookie_store2 = new FileCookieStore(COOKIES_TEST_FILE_NEW); cookies.forEach(function (cookie) { var func = Q.nbind(cookie_store2.putCookie, cookie_store2); @@ -531,7 +546,14 @@ describe('Test file cookie store', function() { cookie_jar = new TOUGH.CookieJar(new FileCookieStore(COOKIES_TEST_FILE2)); done(); }); - + + afterEach(function(done){ + try { + FS.unlinkSync(COOKIES_TEST_FILE_NEW); + } catch (err) {}; + done(); + }); + it ('should create CookieJar object', function (done) { expect(cookie_jar).to.be.a(TOUGH.CookieJar); done(); @@ -622,6 +644,32 @@ describe('Test file cookie store', function() { }). done(); }); + + it ('should find "host only" cookies', function (done) { + Q.nbind(cookie_jar.getCookies, cookie_jar)('http://www.aff.store.com/'). + then(function (cookies){ + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(2); + done(); + }). + catch(function (){ + done(err); + }). + done(); + }); + + it ('should find "host only" cookies and domain cookies', function (done) { + Q.nbind(cookie_jar.getCookies, cookie_jar)('http://aff.store.com/'). + then(function (cookies){ + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(6); + done(); + }). + catch(function (){ + done(err); + }). + done(); + }); it('should put cookie in CookieJar', function (done) { @@ -654,6 +702,7 @@ describe('Test file cookie store', function() { }). done(); }); + it('should save cookie into file from CookieJar', function (done) { var expire = new Date(); @@ -679,6 +728,7 @@ describe('Test file cookie store', function() { 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) { @@ -761,6 +811,96 @@ describe('Test file cookie store', function() { }). done(); }); - + + + it('should save "host only" cookies correctly', function (done) { + var cookies_urls = ['http://aff.store.com/', 'http://www.aff.store.com/', + 'http://store.com', 'http://www.store.com'], + fns = []; + for (i = 0; i < cookies_urls.length; i++) { + var func = Q.nbind(cookie_jar.getCookies, cookie_jar); + fns.push(func(cookies_urls[i])); + } + + var cookie_store2 = new FileCookieStore(COOKIES_TEST_FILE_NEW), + cookie_jar2 = new TOUGH.CookieJar(new FileCookieStore(COOKIES_TEST_FILE_NEW)); + + Q.all(fns).spread(function(cookies1,cookies2,cookies3,cookies4){ + expect(cookies1).to.be.a(Array); + expect(cookies1).to.have.length(6); + expect(cookies2).to.be.a(Array); + expect(cookies2).to.have.length(2); + expect(cookies3).to.be.a(Array); + expect(cookies3).to.have.length(2); + expect(cookies4).to.be.a(Array); + expect(cookies4).to.have.length(1); + + var all_cookies = cookies1.concat(cookies1, cookies2, cookies3,cookies4), + put_fns = []; + + for (i = 0; i < all_cookies.length; i++) { + var func = Q.nbind(cookie_store2.putCookie, cookie_store2); + put_fns.push(func(all_cookies[i])); + } + + return Q.all(put_fns); + }).then(function () { + return Q.nbind(cookie_jar2.getCookies, cookie_jar2)('http://aff.store.com/'); + }).then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(6); + return Q.nbind(cookie_jar2.getCookies, cookie_jar2)('http://store.com/'); + }).then(function (cookies) { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(2); + done(); + }). + catch(function (err){ + done(err); + }). + done(); + }); }); + + describe("#export", function () { + it('should export cookies to the array', function (done) { + cookie_store.export(function (err, cookies) { + if (err) { + done(err); + } else { + expect(cookies).to.be.a(Array); + expect(cookies).to.have.length(43); + done(); + } + }); + }); + + it('should export cookies to the other store', function (done) { + var memory_cookie_store = new MemoryCookieStore(); + cookie_store.export(memory_cookie_store, function (err, cookies) { + if (err) { + done(err); + } else { + var idx = memory_cookie_store.idx, + cookies_num = 0; + 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) { + ++cookies_num; + } + } + } + } + expect(cookies_num).to.be(43); + done(); + } + }); + }); + }); + }); \ No newline at end of file