UNPKG

tough-cookie-file-store

Version:
163 lines 6.8 kB
import * as tough from 'tough-cookie'; const HttpOnlyPrefix = '#HttpOnly_'; const AllWhitespaceRegex = /^\s*$/; const CommentRegex = /^\s*#/; const LeadingDotRegex = /^\./; /** * Parses the text of a netscape cookies.txt file line-by-line, yielding each cookie and its canonical domain. * @param {string} data - The string content of the cookies file. * @param {object} options - Options for loading the cookies file. * @returns {Generator} a generator that yields each cookie */ export function* parseNetscapeCookiesTxtLineByLine(data, options) { // code adapted from https://github.com/JSBizon/file-cookie-store/blob/61795ac4806504e1baaa3b459bcdaa1517ccad1f/index.js#L188 var _a, _b; // if file is empty, dont bother parsing if (!data) { return; } // split file into separate lines const lines = data.split(/\r\n|\n/); // ensure file is actually a cookie file const magic = lines[0]; if ((!magic || !/^#(?: Netscape)? HTTP Cookie File/.test(magic)) && !(options === null || options === void 0 ? void 0 : options.forceParse)) { throw new Error(`${(options === null || options === void 0 ? void 0 : options.filePath) || 'File'} does not look like a netscape cookies file`); } // parse file line by line const httpOnlyExtension = (_a = options === null || options === void 0 ? void 0 : options.httpOnlyExtension) !== null && _a !== void 0 ? _a : true; let lineNum = 0; for (let line of lines) { lineNum++; // ignore if line is blank if (AllWhitespaceRegex.test(line)) { continue; } // ignore if line is a comment const httpOnly = line.startsWith(HttpOnlyPrefix); if (CommentRegex.test(line) && (!httpOnly || !httpOnlyExtension)) { continue; } // remove #HttpOnly_ prefix if (httpOnly) { line = line.substring(HttpOnlyPrefix.length); } // split line parts const parsed = line.split(/\t/); if (parsed.length !== 7) { if (!(options === null || options === void 0 ? void 0 : options.forceParse)) { const filePathDescr = (options === null || options === void 0 ? void 0 : options.filePath) ? ` in cookies file ${options.filePath}` : ''; throw new Error(`Line ${lineNum} is not valid${filePathDescr}`); } else { (_b = options.onLineError) === null || _b === void 0 ? void 0 : _b.call(options, line, lineNum); continue; } } // create cookie object const domain = parsed[0]; const canDomain = tough.canonicalDomain(domain); // istanbul ignore next if (!canDomain) { console.warn(`Empty canonical domain for ${domain}`); continue; } // const flag = parsed[1].toUpperCase() // flag is legacy and should be ignored const expireSeconds = parseInt(parsed[4]); const cookie = new tough.Cookie({ httpOnly, domain: canDomain, hostOnly: !LeadingDotRegex.test(domain), path: parsed[2], secure: (parsed[3].toUpperCase() === 'TRUE'), expires: expireSeconds ? new Date(expireSeconds * 1000) : 'Infinity', key: decodeURIComponent(parsed[5]), value: decodeURIComponent(parsed[6]) }); yield cookie; } } /** * Parses the text of a netscape cookies.txt file into an array of cookies * @param {string} data - The string content of the cookies file. * @param {object} options - Options for loading the cookies file. * @returns {Cookie[]} the parsed cookies */ export function parseNetscapeCookiesTxtToIndex(data, options) { const cookies = {}; for (const cookie of parseNetscapeCookiesTxtLineByLine(data, options)) { if (cookie.domain && cookie.path && cookie.key) { let domainVal = cookies[cookie.domain]; if (!domainVal) { domainVal = {}; cookies[cookie.domain] = domainVal; } let pathVal = domainVal[cookie.path]; if (!pathVal) { pathVal = {}; domainVal[cookie.path] = pathVal; } pathVal[cookie.key] = cookie; } } return cookies; } /** * Serializes the text of a netscape cookies.txt file from a cookies index. * @param {CookiesIndex} cookies - The object containing all the cookies. * @param {object} options - Options for serializing the cookies file. * @returns {string} the serialized netscape cookies file. */ export function stringifyNetscapeCookiesTxt(cookies, options) { // code adapted from https://github.com/JSBizon/file-cookie-store/blob/61795ac4806504e1baaa3b459bcdaa1517ccad1f/index.js#L146 const lines = [ '# 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 (const domain of Object.keys(cookies)) { const domainVal = cookies[domain]; for (const path of Object.keys(domainVal)) { const pathVal = domainVal[path]; for (const key of Object.keys(pathVal)) { const cookie = pathVal[key]; if (cookie) { lines.push(stringifyNetscapeCookiesTxtLine(cookie, options) + '\n'); } } } } return lines.join(''); } /** * Serializes a Cookie object into a line for a cookies.txt file. This does not include the trailing newline. * @param {Cookie} cookie - The cookie to serialize * @param {object} options - Options for serializing the cookie * @returns {string} the serialized netscape cookies.txt line. */ export function stringifyNetscapeCookiesTxtLine(cookie, options) { let cookieDomain = cookie.domain; if (!cookie.hostOnly) { cookieDomain = '.' + cookieDomain; } return [ // domain (((options === null || options === void 0 ? void 0 : options.httpOnlyExtension) && cookie.httpOnly) ? `${HttpOnlyPrefix}${cookieDomain}` : cookieDomain), // flag ((cookieDomain && LeadingDotRegex.test(cookieDomain)) ? 'TRUE' : 'FALSE'), // hostOnly is legacy and should be determined from the domain // path cookie.path, // secure (cookie.secure ? 'TRUE' : 'FALSE'), // expires (cookie.expires && cookie.expires !== 'Infinity') ? Math.round(cookie.expires.getTime() / 1000) : 0, // key encodeURIComponent(cookie.key), // value encodeURIComponent(cookie.value) ].join('\t'); } //# sourceMappingURL=netscape-cookies-txt.js.map