368 lines
10 KiB
JavaScript
368 lines
10 KiB
JavaScript
const CookieJar = require('tough-cookie').CookieJar,
|
|
ToughCookie = require('tough-cookie').Cookie,
|
|
PostmanCookie = require('postman-collection').Cookie,
|
|
PostmanCookieList = require('postman-collection').CookieList,
|
|
Url = require('postman-collection').Url,
|
|
|
|
FUNCTION = 'function',
|
|
OBJECT = 'object',
|
|
STRING = 'string',
|
|
|
|
/**
|
|
* Convert PostmanCookie Cookie instance to ToughCookie instance.
|
|
*
|
|
* @private
|
|
* @param {PostmanCookie} cookie - Postman Cookie instance
|
|
* @returns {ToughCookie} Tough Cookie instance
|
|
*/
|
|
serialize = function (cookie) {
|
|
if (!cookie) {
|
|
return;
|
|
}
|
|
|
|
return ToughCookie.fromJSON({
|
|
key: cookie.name || cookie.key,
|
|
value: cookie.value,
|
|
expires: cookie.expires,
|
|
maxAge: cookie.maxAge,
|
|
domain: cookie.domain,
|
|
path: cookie.path,
|
|
secure: cookie.secure,
|
|
httpOnly: cookie.httpOnly,
|
|
hostOnly: cookie.hostOnly,
|
|
extensions: cookie.extensions
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Convert Tough Cookie instance to Electron Cookie instance.
|
|
*
|
|
* @private
|
|
* @param {ToughCookie} cookie - Tough Cookie instance
|
|
* @returns {ElectronCookie} Electron Cookie instance
|
|
*/
|
|
deserialize = function (cookie) {
|
|
if (!cookie) {
|
|
return;
|
|
}
|
|
|
|
return new PostmanCookie({
|
|
name: cookie.key,
|
|
value: cookie.value,
|
|
expires: cookie.expires === 'Infinity' ? null : cookie.expires,
|
|
maxAge: cookie.maxAge,
|
|
domain: cookie.domain,
|
|
path: cookie.path,
|
|
secure: cookie.secure,
|
|
httpOnly: cookie.httpOnly,
|
|
hostOnly: cookie.hostOnly,
|
|
extensions: cookie.extensions
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Sanitize url object or string to Postman Url instance.
|
|
*
|
|
* @private
|
|
* @param {Object|String} url -
|
|
* @returns {Url|Null}
|
|
*/
|
|
sanitizeURL = function (url) {
|
|
if (Url.isUrl(url)) {
|
|
return url;
|
|
}
|
|
|
|
if (url && typeof url === STRING) {
|
|
return new Url(url);
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
/**
|
|
* Executes a provided function once for each array element.
|
|
*
|
|
* @note not completely asynchronous, don't compare with async.each
|
|
*
|
|
* @private
|
|
* @param {Array} items - Array of items to iterate over
|
|
* @param {Function} fn - An async function to apply to each item in items
|
|
* @param {Function} cb - A callback which is called when all iteratee functions have finished,
|
|
* or an error occurs
|
|
*/
|
|
forEachWithCallback = function (items, fn, cb) {
|
|
!cb && (cb = function () { /* (ಠ_ಠ) */ });
|
|
|
|
if (!(Array.isArray(items) && fn)) { return cb(); }
|
|
|
|
var index = 0,
|
|
totalItems = items.length,
|
|
next = function (err) {
|
|
if (err || index >= totalItems) {
|
|
return cb(err);
|
|
}
|
|
|
|
try {
|
|
fn.call(items, items[index++], next);
|
|
}
|
|
catch (error) {
|
|
return cb(error);
|
|
}
|
|
};
|
|
|
|
if (!totalItems) {
|
|
return cb();
|
|
}
|
|
|
|
next();
|
|
},
|
|
|
|
/**
|
|
* Helper function to handle callback.
|
|
*
|
|
* @private
|
|
* @param {Function} callback - Callback function
|
|
* @param {Error|String} err - Error or Error message
|
|
* @param {*} result -
|
|
*/
|
|
callbackHandler = function (callback, err, result) {
|
|
if (typeof callback !== FUNCTION) {
|
|
return;
|
|
}
|
|
|
|
if (err) {
|
|
return callback(err instanceof Error ? err : new Error(err));
|
|
}
|
|
|
|
callback(null, result);
|
|
},
|
|
|
|
/**
|
|
* Helper function to fetch a cookie with given name.
|
|
*
|
|
* @private
|
|
* @todo add CookieJar~getCookie to avoid this
|
|
*
|
|
* @param {CookieJar} jar - ToughCookie jar instance
|
|
* @param {String} url - Url string
|
|
* @param {String} name - Cookie name
|
|
* @param {Function} callback - Callback function
|
|
*/
|
|
getCookie = function (jar, url, name, callback) {
|
|
jar.getCookies(url, function (err, cookies) {
|
|
var i,
|
|
ii;
|
|
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
|
|
if (!(cookies && cookies.length)) {
|
|
return callback(null, null);
|
|
}
|
|
|
|
for (i = 0, ii = cookies.length; i < ii; i++) {
|
|
if (cookies[i].key === name) {
|
|
return callback(null, cookies[i]);
|
|
}
|
|
}
|
|
|
|
callback(null, null);
|
|
});
|
|
};
|
|
|
|
class PostmanCookieJar {
|
|
/**
|
|
* @param {Object} cookieStore -
|
|
*/
|
|
constructor (cookieStore) {
|
|
this.store = cookieStore;
|
|
this.jar = new CookieJar(cookieStore, {
|
|
rejectPublicSuffixes: false,
|
|
looseMode: true
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get the cookie value with the given name.
|
|
*
|
|
* @param {String} url -
|
|
* @param {String} name -
|
|
* @param {Function} callback -
|
|
*/
|
|
get (url, name, callback) {
|
|
url = sanitizeURL(url);
|
|
|
|
if (!url) {
|
|
throw new TypeError('CookieJar.get() requires a valid url');
|
|
}
|
|
|
|
if (typeof callback !== FUNCTION) {
|
|
throw new TypeError('CookieJar.get() requires a callback function');
|
|
}
|
|
|
|
if (typeof name !== STRING) {
|
|
throw new TypeError('CookieJar.get() requires cookie name to be a string');
|
|
}
|
|
|
|
getCookie(this.jar, url.toString(true), name, function (err, cookie) {
|
|
if (err || !cookie) {
|
|
return callbackHandler(callback, err, null);
|
|
}
|
|
|
|
cookie = deserialize(cookie);
|
|
|
|
return callbackHandler(callback, null, cookie.valueOf());
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get all the cookies for the given URL.
|
|
*
|
|
* @param {String} url -
|
|
* @param {Object} [options] -
|
|
* @param {Function} callback -
|
|
*/
|
|
getAll (url, options, callback) {
|
|
url = sanitizeURL(url);
|
|
|
|
if (!url) {
|
|
throw new TypeError('CookieJar.getAll() requires a valid url');
|
|
}
|
|
|
|
if (typeof options === FUNCTION && !callback) {
|
|
callback = options;
|
|
options = {};
|
|
}
|
|
|
|
if (typeof callback !== FUNCTION) {
|
|
throw new TypeError('CookieJar.getAll() requires a callback function');
|
|
}
|
|
|
|
if (typeof options !== OBJECT) {
|
|
throw new TypeError('CookieJar.getAll() requires options to be an object');
|
|
}
|
|
|
|
options = {
|
|
// return HttpOnly cookies by default
|
|
http: Object.hasOwnProperty.call(options, 'http') ? Boolean(options.http) : true,
|
|
// if undefined, auto-detect from url
|
|
secure: Object.hasOwnProperty.call(options, 'secure') ? Boolean(options.secure) : undefined
|
|
};
|
|
|
|
this.jar.getCookies(url.toString(true), options, function (err, cookies) {
|
|
if (err) {
|
|
return callbackHandler(callback, err);
|
|
}
|
|
|
|
callbackHandler(callback, null, new PostmanCookieList(null, cookies && cookies.map(deserialize)));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Set or update a cookie.
|
|
*
|
|
* @param {String} url -
|
|
* @param {String|Object} name -
|
|
* @param {String|Function} [value] -
|
|
* @param {Function} [callback] -
|
|
*/
|
|
set (url, name, value, callback) {
|
|
url = sanitizeURL(url);
|
|
|
|
if (!url) {
|
|
throw new TypeError('CookieJar.set() requires a valid url');
|
|
}
|
|
|
|
if (typeof value === FUNCTION && !callback) {
|
|
callback = value;
|
|
value = null;
|
|
}
|
|
|
|
var cookie;
|
|
|
|
// @todo avoid else-if to reduce cyclomatic complexity
|
|
if (name && value) {
|
|
cookie = serialize({ name, value });
|
|
}
|
|
else if (typeof name === OBJECT) {
|
|
cookie = serialize(name);
|
|
}
|
|
else if (typeof name === STRING) {
|
|
cookie = name;
|
|
}
|
|
else {
|
|
throw new TypeError('CookieJar.set() requires a valid set cookie arguments');
|
|
}
|
|
|
|
this.jar.setCookie(cookie, url.toString(true), function (err, cookie) {
|
|
if (err) {
|
|
return callbackHandler(callback, err);
|
|
}
|
|
|
|
callbackHandler(callback, null, deserialize(cookie));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Remove single cookie with the given name.
|
|
*
|
|
* @param {String} url -
|
|
* @param {String} name -
|
|
* @param {Function} [callback] -
|
|
*/
|
|
unset (url, name, callback) {
|
|
url = sanitizeURL(url);
|
|
|
|
if (!url) {
|
|
throw new TypeError('CookieJar.unset() requires a valid url');
|
|
}
|
|
|
|
if (typeof name !== STRING) {
|
|
throw new TypeError('CookieJar.unset() requires cookie name to be a string');
|
|
}
|
|
|
|
var store = this.store;
|
|
|
|
getCookie(this.jar, url.toString(true), name, function (err, cookie) {
|
|
if (err || !cookie) {
|
|
return callbackHandler(callback, err);
|
|
}
|
|
|
|
store.removeCookie(cookie.domain, cookie.path, cookie.key, function (err) {
|
|
callbackHandler(callback, err);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Remove all the cookies for the given URL.
|
|
*
|
|
* @param {String} url -
|
|
* @param {Function} [callback] -
|
|
*/
|
|
clear (url, callback) {
|
|
url = sanitizeURL(url);
|
|
|
|
if (!url) {
|
|
throw new TypeError('CookieJar.clear() requires a valid url');
|
|
}
|
|
|
|
var store = this.store;
|
|
|
|
this.jar.getCookies(url.toString(true), function (err, cookies) {
|
|
if (err || !cookies) {
|
|
return callbackHandler(callback, err);
|
|
}
|
|
|
|
forEachWithCallback(cookies, function (cookie, next) {
|
|
store.removeCookie(cookie.domain, cookie.path, cookie.key, next);
|
|
}, function (err) {
|
|
callbackHandler(callback, err);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = PostmanCookieJar;
|