|
"use strict"; |
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { |
|
if (k2 === undefined) k2 = k; |
|
var desc = Object.getOwnPropertyDescriptor(m, k); |
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { |
|
desc = { enumerable: true, get: function() { return m[k]; } }; |
|
} |
|
Object.defineProperty(o, k2, desc); |
|
}) : (function(o, m, k, k2) { |
|
if (k2 === undefined) k2 = k; |
|
o[k2] = m[k]; |
|
})); |
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { |
|
Object.defineProperty(o, "default", { enumerable: true, value: v }); |
|
}) : function(o, v) { |
|
o["default"] = v; |
|
}); |
|
var __importStar = (this && this.__importStar) || function (mod) { |
|
if (mod && mod.__esModule) return mod; |
|
var result = {}; |
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); |
|
__setModuleDefault(result, mod); |
|
return result; |
|
}; |
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
exports.Cookie = void 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getPublicSuffix_1 = require("../getPublicSuffix"); |
|
const validators = __importStar(require("../validators")); |
|
const utils_1 = require("../utils"); |
|
const formatDate_1 = require("./formatDate"); |
|
const parseDate_1 = require("./parseDate"); |
|
const canonicalDomain_1 = require("./canonicalDomain"); |
|
|
|
|
|
const COOKIE_OCTETS = /^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]+$/; |
|
|
|
|
|
const PATH_VALUE = /[\x20-\x3A\x3C-\x7E]+/; |
|
|
|
const CONTROL_CHARS = /[\x00-\x1F]/; |
|
|
|
|
|
|
|
const TERMINATORS = ['\n', '\r', '\0']; |
|
function trimTerminator(str) { |
|
if (validators.isEmptyString(str)) |
|
return str; |
|
for (let t = 0; t < TERMINATORS.length; t++) { |
|
const terminator = TERMINATORS[t]; |
|
const terminatorIdx = terminator ? str.indexOf(terminator) : -1; |
|
if (terminatorIdx !== -1) { |
|
str = str.slice(0, terminatorIdx); |
|
} |
|
} |
|
return str; |
|
} |
|
function parseCookiePair(cookiePair, looseMode) { |
|
cookiePair = trimTerminator(cookiePair); |
|
let firstEq = cookiePair.indexOf('='); |
|
if (looseMode) { |
|
if (firstEq === 0) { |
|
|
|
cookiePair = cookiePair.substring(1); |
|
firstEq = cookiePair.indexOf('='); |
|
} |
|
} |
|
else { |
|
|
|
if (firstEq <= 0) { |
|
|
|
return undefined; |
|
} |
|
} |
|
let cookieName, cookieValue; |
|
if (firstEq <= 0) { |
|
cookieName = ''; |
|
cookieValue = cookiePair.trim(); |
|
} |
|
else { |
|
cookieName = cookiePair.slice(0, firstEq).trim(); |
|
cookieValue = cookiePair.slice(firstEq + 1).trim(); |
|
} |
|
if (CONTROL_CHARS.test(cookieName) || CONTROL_CHARS.test(cookieValue)) { |
|
return undefined; |
|
} |
|
const c = new Cookie(); |
|
c.key = cookieName; |
|
c.value = cookieValue; |
|
return c; |
|
} |
|
function parse(str, options) { |
|
if (validators.isEmptyString(str) || !validators.isString(str)) { |
|
return undefined; |
|
} |
|
str = str.trim(); |
|
|
|
const firstSemi = str.indexOf(';'); |
|
const cookiePair = firstSemi === -1 ? str : str.slice(0, firstSemi); |
|
const c = parseCookiePair(cookiePair, options?.loose ?? false); |
|
if (!c) { |
|
return undefined; |
|
} |
|
if (firstSemi === -1) { |
|
return c; |
|
} |
|
|
|
|
|
|
|
const unparsed = str.slice(firstSemi + 1).trim(); |
|
|
|
|
|
if (unparsed.length === 0) { |
|
return c; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const cookie_avs = unparsed.split(';'); |
|
while (cookie_avs.length) { |
|
const av = (cookie_avs.shift() ?? '').trim(); |
|
if (av.length === 0) { |
|
|
|
continue; |
|
} |
|
const av_sep = av.indexOf('='); |
|
let av_key, av_value; |
|
if (av_sep === -1) { |
|
av_key = av; |
|
av_value = null; |
|
} |
|
else { |
|
av_key = av.slice(0, av_sep); |
|
av_value = av.slice(av_sep + 1); |
|
} |
|
av_key = av_key.trim().toLowerCase(); |
|
if (av_value) { |
|
av_value = av_value.trim(); |
|
} |
|
switch (av_key) { |
|
case 'expires': |
|
if (av_value) { |
|
const exp = (0, parseDate_1.parseDate)(av_value); |
|
|
|
|
|
if (exp) { |
|
|
|
|
|
c.expires = exp; |
|
} |
|
} |
|
break; |
|
case 'max-age': |
|
if (av_value) { |
|
|
|
|
|
|
|
if (/^-?[0-9]+$/.test(av_value)) { |
|
const delta = parseInt(av_value, 10); |
|
|
|
|
|
c.setMaxAge(delta); |
|
} |
|
} |
|
break; |
|
case 'domain': |
|
|
|
|
|
if (av_value) { |
|
|
|
|
|
const domain = av_value.trim().replace(/^\./, ''); |
|
if (domain) { |
|
|
|
c.domain = domain.toLowerCase(); |
|
} |
|
} |
|
break; |
|
case 'path': |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
c.path = av_value && av_value[0] === '/' ? av_value : null; |
|
break; |
|
case 'secure': |
|
|
|
|
|
|
|
|
|
|
|
c.secure = true; |
|
break; |
|
case 'httponly': |
|
c.httpOnly = true; |
|
break; |
|
case 'samesite': |
|
switch (av_value ? av_value.toLowerCase() : '') { |
|
case 'strict': |
|
c.sameSite = 'strict'; |
|
break; |
|
case 'lax': |
|
c.sameSite = 'lax'; |
|
break; |
|
case 'none': |
|
c.sameSite = 'none'; |
|
break; |
|
default: |
|
c.sameSite = undefined; |
|
break; |
|
} |
|
break; |
|
default: |
|
c.extensions = c.extensions || []; |
|
c.extensions.push(av); |
|
break; |
|
} |
|
} |
|
return c; |
|
} |
|
function fromJSON(str) { |
|
if (!str || validators.isEmptyString(str)) { |
|
return undefined; |
|
} |
|
let obj; |
|
if (typeof str === 'string') { |
|
try { |
|
obj = JSON.parse(str); |
|
} |
|
catch { |
|
return undefined; |
|
} |
|
} |
|
else { |
|
|
|
obj = str; |
|
} |
|
const c = new Cookie(); |
|
Cookie.serializableProperties.forEach((prop) => { |
|
if (obj && typeof obj === 'object' && (0, utils_1.inOperator)(prop, obj)) { |
|
const val = obj[prop]; |
|
if (val === undefined) { |
|
return; |
|
} |
|
if ((0, utils_1.inOperator)(prop, cookieDefaults) && val === cookieDefaults[prop]) { |
|
return; |
|
} |
|
switch (prop) { |
|
case 'key': |
|
case 'value': |
|
case 'sameSite': |
|
if (typeof val === 'string') { |
|
c[prop] = val; |
|
} |
|
break; |
|
case 'expires': |
|
case 'creation': |
|
case 'lastAccessed': |
|
if (typeof val === 'number' || |
|
typeof val === 'string' || |
|
val instanceof Date) { |
|
c[prop] = obj[prop] == 'Infinity' ? 'Infinity' : new Date(val); |
|
} |
|
else if (val === null) { |
|
c[prop] = null; |
|
} |
|
break; |
|
case 'maxAge': |
|
if (typeof val === 'number' || |
|
val === 'Infinity' || |
|
val === '-Infinity') { |
|
c[prop] = val; |
|
} |
|
break; |
|
case 'domain': |
|
case 'path': |
|
if (typeof val === 'string' || val === null) { |
|
c[prop] = val; |
|
} |
|
break; |
|
case 'secure': |
|
case 'httpOnly': |
|
if (typeof val === 'boolean') { |
|
c[prop] = val; |
|
} |
|
break; |
|
case 'extensions': |
|
if (Array.isArray(val) && |
|
val.every((item) => typeof item === 'string')) { |
|
c[prop] = val; |
|
} |
|
break; |
|
case 'hostOnly': |
|
case 'pathIsDefault': |
|
if (typeof val === 'boolean' || val === null) { |
|
c[prop] = val; |
|
} |
|
break; |
|
} |
|
} |
|
}); |
|
return c; |
|
} |
|
const cookieDefaults = { |
|
|
|
key: '', |
|
value: '', |
|
expires: 'Infinity', |
|
maxAge: null, |
|
domain: null, |
|
path: null, |
|
secure: false, |
|
httpOnly: false, |
|
extensions: null, |
|
|
|
hostOnly: null, |
|
pathIsDefault: null, |
|
creation: null, |
|
lastAccessed: null, |
|
sameSite: undefined, |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
class Cookie { |
|
|
|
|
|
|
|
|
|
|
|
constructor(options = {}) { |
|
this.key = options.key ?? cookieDefaults.key; |
|
this.value = options.value ?? cookieDefaults.value; |
|
this.expires = options.expires ?? cookieDefaults.expires; |
|
this.maxAge = options.maxAge ?? cookieDefaults.maxAge; |
|
this.domain = options.domain ?? cookieDefaults.domain; |
|
this.path = options.path ?? cookieDefaults.path; |
|
this.secure = options.secure ?? cookieDefaults.secure; |
|
this.httpOnly = options.httpOnly ?? cookieDefaults.httpOnly; |
|
this.extensions = options.extensions ?? cookieDefaults.extensions; |
|
this.creation = options.creation ?? cookieDefaults.creation; |
|
this.hostOnly = options.hostOnly ?? cookieDefaults.hostOnly; |
|
this.pathIsDefault = options.pathIsDefault ?? cookieDefaults.pathIsDefault; |
|
this.lastAccessed = options.lastAccessed ?? cookieDefaults.lastAccessed; |
|
this.sameSite = options.sameSite ?? cookieDefaults.sameSite; |
|
this.creation = options.creation ?? new Date(); |
|
|
|
Object.defineProperty(this, 'creationIndex', { |
|
configurable: false, |
|
enumerable: false, |
|
writable: true, |
|
value: ++Cookie.cookiesCreated, |
|
}); |
|
|
|
this.creationIndex = Cookie.cookiesCreated; |
|
} |
|
[Symbol.for('nodejs.util.inspect.custom')]() { |
|
const now = Date.now(); |
|
const hostOnly = this.hostOnly != null ? this.hostOnly.toString() : '?'; |
|
const createAge = this.creation && this.creation !== 'Infinity' |
|
? `${String(now - this.creation.getTime())}ms` |
|
: '?'; |
|
const accessAge = this.lastAccessed && this.lastAccessed !== 'Infinity' |
|
? `${String(now - this.lastAccessed.getTime())}ms` |
|
: '?'; |
|
return `Cookie="${this.toString()}; hostOnly=${hostOnly}; aAge=${accessAge}; cAge=${createAge}"`; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
toJSON() { |
|
const obj = {}; |
|
for (const prop of Cookie.serializableProperties) { |
|
const val = this[prop]; |
|
if (val === cookieDefaults[prop]) { |
|
continue; |
|
} |
|
switch (prop) { |
|
case 'key': |
|
case 'value': |
|
case 'sameSite': |
|
if (typeof val === 'string') { |
|
obj[prop] = val; |
|
} |
|
break; |
|
case 'expires': |
|
case 'creation': |
|
case 'lastAccessed': |
|
if (typeof val === 'number' || |
|
typeof val === 'string' || |
|
val instanceof Date) { |
|
obj[prop] = |
|
val == 'Infinity' ? 'Infinity' : new Date(val).toISOString(); |
|
} |
|
else if (val === null) { |
|
obj[prop] = null; |
|
} |
|
break; |
|
case 'maxAge': |
|
if (typeof val === 'number' || |
|
val === 'Infinity' || |
|
val === '-Infinity') { |
|
obj[prop] = val; |
|
} |
|
break; |
|
case 'domain': |
|
case 'path': |
|
if (typeof val === 'string' || val === null) { |
|
obj[prop] = val; |
|
} |
|
break; |
|
case 'secure': |
|
case 'httpOnly': |
|
if (typeof val === 'boolean') { |
|
obj[prop] = val; |
|
} |
|
break; |
|
case 'extensions': |
|
if (Array.isArray(val)) { |
|
obj[prop] = val; |
|
} |
|
break; |
|
case 'hostOnly': |
|
case 'pathIsDefault': |
|
if (typeof val === 'boolean' || val === null) { |
|
obj[prop] = val; |
|
} |
|
break; |
|
} |
|
} |
|
return obj; |
|
} |
|
|
|
|
|
|
|
|
|
clone() { |
|
return fromJSON(this.toJSON()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
validate() { |
|
if (!this.value || !COOKIE_OCTETS.test(this.value)) { |
|
return false; |
|
} |
|
if (this.expires != 'Infinity' && |
|
!(this.expires instanceof Date) && |
|
!(0, parseDate_1.parseDate)(this.expires)) { |
|
return false; |
|
} |
|
if (this.maxAge != null && |
|
this.maxAge !== 'Infinity' && |
|
(this.maxAge === '-Infinity' || this.maxAge <= 0)) { |
|
return false; |
|
} |
|
if (this.path != null && !PATH_VALUE.test(this.path)) { |
|
return false; |
|
} |
|
const cdomain = this.cdomain(); |
|
if (cdomain) { |
|
if (cdomain.match(/\.$/)) { |
|
return false; |
|
} |
|
const suffix = (0, getPublicSuffix_1.getPublicSuffix)(cdomain); |
|
if (suffix == null) { |
|
|
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setExpires(exp) { |
|
if (exp instanceof Date) { |
|
this.expires = exp; |
|
} |
|
else { |
|
this.expires = (0, parseDate_1.parseDate)(exp) || 'Infinity'; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setMaxAge(age) { |
|
if (age === Infinity) { |
|
this.maxAge = 'Infinity'; |
|
} |
|
else if (age === -Infinity) { |
|
this.maxAge = '-Infinity'; |
|
} |
|
else { |
|
this.maxAge = age; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
cookieString() { |
|
const val = this.value || ''; |
|
if (this.key) { |
|
return `${this.key}=${val}`; |
|
} |
|
return val; |
|
} |
|
|
|
|
|
|
|
|
|
toString() { |
|
let str = this.cookieString(); |
|
if (this.expires != 'Infinity') { |
|
if (this.expires instanceof Date) { |
|
str += `; Expires=${(0, formatDate_1.formatDate)(this.expires)}`; |
|
} |
|
} |
|
if (this.maxAge != null && this.maxAge != Infinity) { |
|
str += `; Max-Age=${String(this.maxAge)}`; |
|
} |
|
if (this.domain && !this.hostOnly) { |
|
str += `; Domain=${this.domain}`; |
|
} |
|
if (this.path) { |
|
str += `; Path=${this.path}`; |
|
} |
|
if (this.secure) { |
|
str += '; Secure'; |
|
} |
|
if (this.httpOnly) { |
|
str += '; HttpOnly'; |
|
} |
|
if (this.sameSite && this.sameSite !== 'none') { |
|
if (this.sameSite.toLowerCase() === |
|
Cookie.sameSiteCanonical.lax.toLowerCase()) { |
|
str += `; SameSite=${Cookie.sameSiteCanonical.lax}`; |
|
} |
|
else if (this.sameSite.toLowerCase() === |
|
Cookie.sameSiteCanonical.strict.toLowerCase()) { |
|
str += `; SameSite=${Cookie.sameSiteCanonical.strict}`; |
|
} |
|
else { |
|
str += `; SameSite=${this.sameSite}`; |
|
} |
|
} |
|
if (this.extensions) { |
|
this.extensions.forEach((ext) => { |
|
str += `; ${ext}`; |
|
}); |
|
} |
|
return str; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TTL(now = Date.now()) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this.maxAge != null && typeof this.maxAge === 'number') { |
|
return this.maxAge <= 0 ? 0 : this.maxAge * 1000; |
|
} |
|
const expires = this.expires; |
|
if (expires === 'Infinity') { |
|
return Infinity; |
|
} |
|
return (expires?.getTime() ?? now) - (now || Date.now()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expiryTime(now) { |
|
|
|
if (this.maxAge != null) { |
|
const relativeTo = now || this.lastAccessed || new Date(); |
|
const maxAge = typeof this.maxAge === 'number' ? this.maxAge : -Infinity; |
|
const age = maxAge <= 0 ? -Infinity : maxAge * 1000; |
|
if (relativeTo === 'Infinity') { |
|
return Infinity; |
|
} |
|
return relativeTo.getTime() + age; |
|
} |
|
if (this.expires == 'Infinity') { |
|
return Infinity; |
|
} |
|
return this.expires ? this.expires.getTime() : undefined; |
|
} |
|
|
|
|
|
|
|
|
|
isPersistent() { |
|
|
|
return this.maxAge != null || this.expires != 'Infinity'; |
|
} |
|
|
|
|
|
|
|
|
|
canonicalizedDomain() { |
|
|
|
return (0, canonicalDomain_1.canonicalDomain)(this.domain); |
|
} |
|
|
|
|
|
|
|
|
|
cdomain() { |
|
return (0, canonicalDomain_1.canonicalDomain)(this.domain); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static parse(str, options) { |
|
return parse(str, options); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static fromJSON(str) { |
|
return fromJSON(str); |
|
} |
|
} |
|
exports.Cookie = Cookie; |
|
Cookie.cookiesCreated = 0; |
|
|
|
|
|
|
|
Cookie.sameSiteLevel = { |
|
strict: 3, |
|
lax: 2, |
|
none: 1, |
|
}; |
|
|
|
|
|
|
|
Cookie.sameSiteCanonical = { |
|
strict: 'Strict', |
|
lax: 'Lax', |
|
}; |
|
|
|
|
|
|
|
|
|
Cookie.serializableProperties = [ |
|
'key', |
|
'value', |
|
'expires', |
|
'maxAge', |
|
'domain', |
|
'path', |
|
'secure', |
|
'httpOnly', |
|
'extensions', |
|
'hostOnly', |
|
'pathIsDefault', |
|
'creation', |
|
'lastAccessed', |
|
'sameSite', |
|
]; |
|
|