tsoa
This commit is contained in:
186
node_modules/@hapi/statehood/lib/index.d.ts
generated
vendored
Normal file
186
node_modules/@hapi/statehood/lib/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
import type { Boom } from '@hapi/boom';
|
||||
import { SealOptions, SealOptionsSub } from '@hapi/iron';
|
||||
|
||||
export { SealOptions, SealOptionsSub };
|
||||
|
||||
export type SameSitePolicy = false | 'None' | 'Lax' | 'Strict';
|
||||
|
||||
export interface StateOptions<HapiRequest> {
|
||||
/**
|
||||
* If `false`, allows any cookie value including values in violation of [RFC 6265](https://tools.ietf.org/html/rfc6265).
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
strictHeader?: boolean | undefined;
|
||||
|
||||
/**
|
||||
* If `true`, errors are ignored and treated as missing cookies.
|
||||
*/
|
||||
ignoreErrors?: boolean | undefined;
|
||||
|
||||
/**
|
||||
* Sets the `Secure` flag.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
isSecure?: boolean | undefined;
|
||||
|
||||
/**
|
||||
* Sets the `HttpOnly` flag.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
isHttpOnly?: boolean | undefined;
|
||||
|
||||
/**
|
||||
* Sets the `SameSite` flag. The value must be one of:
|
||||
*
|
||||
* - `false` - no flag.
|
||||
* - `Strict` - sets the value to `Strict`.
|
||||
* - `Lax` - sets the value to `Lax`.
|
||||
* - `None` - sets the value to `None`.
|
||||
*
|
||||
* @default 'Strict'
|
||||
*/
|
||||
isSameSite?: SameSitePolicy | undefined;
|
||||
|
||||
/**
|
||||
* Sets the `Partitioned` flag. For more information, please access https://developers.google.com/privacy-sandbox/3pcd/chips
|
||||
*/
|
||||
isPartitioned?: boolean | undefined;
|
||||
|
||||
/**
|
||||
* The path scope.
|
||||
*
|
||||
* @default null (no path)
|
||||
*/
|
||||
path?: string | null | undefined;
|
||||
|
||||
/**
|
||||
* The domain scope.
|
||||
*
|
||||
* @default null (no domain)
|
||||
*/
|
||||
domain?: string | null | undefined;
|
||||
|
||||
/**
|
||||
* Time-to-live in milliseconds.
|
||||
*
|
||||
* @default null (session time-life - cookies are deleted when the browser is closed)
|
||||
*/
|
||||
ttl?: number | null | undefined;
|
||||
|
||||
/**
|
||||
* Encoding performs on the provided value before serialization. Options are:
|
||||
*
|
||||
* - `none` - no encoding. When used, the cookie value must be a string.
|
||||
* - `base64` - string value is encoded using Base64.
|
||||
* - `base64json` - object value is JSON-stringified then encoded using Base64.
|
||||
* - `form` - object value is encoded using the x-www-form-urlencoded method.
|
||||
* - `iron` - Encrypts and sign the value using iron.
|
||||
*
|
||||
* @default 'none'
|
||||
*/
|
||||
encoding?: 'none' | 'base64' | 'base64json' | 'form' | 'iron' | undefined;
|
||||
|
||||
/**
|
||||
* An object used to calculate an HMAC for cookie integrity validation. This does not provide privacy, only a mean
|
||||
* to verify that the cookie value was generated by the server. Redundant when 'iron' encoding is used. Options are:
|
||||
* - integrity -
|
||||
* - password -
|
||||
*/
|
||||
sign?:
|
||||
| {
|
||||
/**
|
||||
* Algorithm options.
|
||||
*/
|
||||
integrity?: SealOptionsSub | undefined;
|
||||
|
||||
/**
|
||||
* Password used for HMAC key generation (must be at least 32 characters long).
|
||||
*/
|
||||
password: string;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
/**
|
||||
* Options for 'iron' encoding.
|
||||
*/
|
||||
iron?: SealOptions | undefined;
|
||||
|
||||
/**
|
||||
* Password used for 'iron' encoding (must be at least 32 characters long).
|
||||
*/
|
||||
password?: string | undefined;
|
||||
|
||||
/**
|
||||
* A function using the signature `async function(definition, request)` used to override a request-specific cookie settings.
|
||||
*/
|
||||
contextualize?(
|
||||
/**
|
||||
* A copy of the options to be used for formatting the cookie that can be manipulated by the function to customize
|
||||
* the request cookie header. Note that changing the `definition.contextualize` property will be ignored.
|
||||
*/
|
||||
definition: this,
|
||||
/**
|
||||
* The request object.
|
||||
*/
|
||||
request: HapiRequest
|
||||
): void | Promise<void>;
|
||||
|
||||
/**
|
||||
* If true, automatically instruct the client to remove invalid cookies.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
clearInvalid?: boolean | undefined;
|
||||
|
||||
/**
|
||||
* if present and the cookie was not received from the client or explicitly set by the route handler, the
|
||||
* cookie is automatically added to the response with the provided value. The value can be
|
||||
* a function with signature async function(request) where:
|
||||
*/
|
||||
autoValue?(request: HapiRequest): any;
|
||||
|
||||
/**
|
||||
* Used by proxy plugins (e.g. h2o2).
|
||||
*/
|
||||
passThrough?: any | undefined;
|
||||
}
|
||||
|
||||
export interface FormatCookie<HapiRequest> {
|
||||
name: string;
|
||||
value: any;
|
||||
options: StateOptions<HapiRequest>;
|
||||
}
|
||||
|
||||
export class Definitions<HapiRequest> {
|
||||
constructor(options: StateOptions<HapiRequest>);
|
||||
|
||||
add(name: string, options: StateOptions<HapiRequest>): void;
|
||||
|
||||
parse(cookies: string): Promise<{
|
||||
states: Record<string, string>;
|
||||
failed: {
|
||||
name?: string;
|
||||
value?: string;
|
||||
settings: StateOptions<HapiRequest>;
|
||||
reason: string;
|
||||
}[];
|
||||
}>;
|
||||
|
||||
format(
|
||||
cookies: FormatCookie<HapiRequest> | FormatCookie<HapiRequest>[],
|
||||
context: HapiRequest
|
||||
): Promise<string[]>;
|
||||
|
||||
passThrough(header: string, fallback: boolean): string | Boom;
|
||||
}
|
||||
|
||||
export function prepareValue(
|
||||
name: string,
|
||||
value: any,
|
||||
options: StateOptions<any>
|
||||
): Promise<string>;
|
||||
|
||||
export function exclude(cookies: string, excludes: string[]): string | Boom;
|
||||
555
node_modules/@hapi/statehood/lib/index.js
generated
vendored
Executable file
555
node_modules/@hapi/statehood/lib/index.js
generated
vendored
Executable file
@@ -0,0 +1,555 @@
|
||||
'use strict';
|
||||
|
||||
const Querystring = require('querystring');
|
||||
|
||||
const Boom = require('@hapi/boom');
|
||||
const Bounce = require('@hapi/bounce');
|
||||
const Bourne = require('@hapi/bourne');
|
||||
const Cryptiles = require('@hapi/cryptiles');
|
||||
const Hoek = require('@hapi/hoek');
|
||||
const Iron = require('@hapi/iron');
|
||||
const Validate = require('@hapi/validate');
|
||||
|
||||
|
||||
const internals = {
|
||||
macPrefix: 'hapi.signed.cookie.1'
|
||||
};
|
||||
|
||||
|
||||
internals.schema = Validate.object({
|
||||
strictHeader: Validate.boolean(),
|
||||
ignoreErrors: Validate.boolean(),
|
||||
isSecure: Validate.boolean(),
|
||||
isHttpOnly: Validate.boolean(),
|
||||
isPartitioned: Validate.boolean(),
|
||||
isSameSite: Validate.valid('Strict', 'Lax', 'None', false),
|
||||
path: Validate.string().allow(null),
|
||||
domain: Validate.string().allow(null),
|
||||
ttl: Validate.number().allow(null),
|
||||
encoding: Validate.string().valid('base64json', 'base64', 'form', 'iron', 'none'),
|
||||
sign: Validate.object({
|
||||
password: [Validate.string(), Validate.binary(), Validate.object()],
|
||||
integrity: Validate.object()
|
||||
}),
|
||||
iron: Validate.object(),
|
||||
password: [Validate.string(), Validate.binary(), Validate.object()],
|
||||
contextualize: Validate.function(),
|
||||
|
||||
// Used by hapi
|
||||
|
||||
clearInvalid: Validate.boolean(),
|
||||
autoValue: Validate.any(),
|
||||
passThrough: Validate.boolean()
|
||||
});
|
||||
|
||||
|
||||
internals.defaults = {
|
||||
strictHeader: true, // Require an RFC 6265 compliant header format
|
||||
ignoreErrors: false,
|
||||
isSecure: true,
|
||||
isHttpOnly: true,
|
||||
isPartitioned: false,
|
||||
isSameSite: 'Strict',
|
||||
path: null,
|
||||
domain: null,
|
||||
ttl: null, // MSecs, 0 means remove
|
||||
encoding: 'none' // options: 'base64json', 'base64', 'form', 'iron', 'none'
|
||||
};
|
||||
|
||||
|
||||
// Header format
|
||||
|
||||
internals.validateRx = {
|
||||
nameRx: {
|
||||
strict: /^[^\x00-\x20()<>@,;:\\"\/\[\]?={}\x7F]+$/,
|
||||
loose: /^[^=\s]*$/
|
||||
},
|
||||
valueRx: {
|
||||
strict: /^[^\x00-\x20",;\\\x7F]*$/,
|
||||
loose: /^("[^"]*"|[^;]*)$/
|
||||
},
|
||||
domainRx: /^\.?[a-z\d]+(?:-[a-z\d]+)*(?:\.[a-z\d]+(?:-[a-z\d]+)*)*$/,
|
||||
domainLabelLenRx: /^\.?[a-z\d\-]{1,63}(?:\.[a-z\d\-]{1,63})*$/,
|
||||
pathRx: /^\/[^\x00-\x1F;]*$/
|
||||
};
|
||||
|
||||
// 1: name 2: value
|
||||
internals.pairRx = /^([^=\s]*)\s*=\s*(.*)$/;
|
||||
|
||||
|
||||
exports.Definitions = class {
|
||||
|
||||
constructor(options) {
|
||||
|
||||
this.settings = Hoek.applyToDefaults(internals.defaults, options ?? {});
|
||||
Validate.assert(this.settings, internals.schema, 'Invalid state definition defaults');
|
||||
|
||||
this.cookies = {};
|
||||
this.names = [];
|
||||
}
|
||||
|
||||
add(name, options) {
|
||||
|
||||
Hoek.assert(name && typeof name === 'string', 'Invalid name');
|
||||
Hoek.assert(!this.cookies[name], 'State already defined:', name);
|
||||
|
||||
const settings = Hoek.applyToDefaults(this.settings, options ?? {}, { nullOverride: true });
|
||||
Validate.assert(settings, internals.schema, 'Invalid state definition: ' + name);
|
||||
|
||||
this.cookies[name] = settings;
|
||||
this.names.push(name);
|
||||
}
|
||||
|
||||
async parse(cookies) {
|
||||
|
||||
const state = {};
|
||||
const names = [];
|
||||
const verify = internals.parsePairs(cookies, (name, value) => {
|
||||
|
||||
if (name === '__proto__') {
|
||||
throw Boom.badRequest('Invalid cookie header');
|
||||
}
|
||||
|
||||
if (state[name]) {
|
||||
if (!Array.isArray(state[name])) {
|
||||
state[name] = [state[name]];
|
||||
}
|
||||
|
||||
state[name].push(value);
|
||||
}
|
||||
else {
|
||||
state[name] = value;
|
||||
names.push(name);
|
||||
}
|
||||
});
|
||||
|
||||
// Validate cookie header syntax
|
||||
|
||||
const failed = []; // All errors
|
||||
|
||||
if (verify !== null) {
|
||||
if (!this.settings.ignoreErrors) {
|
||||
throw Boom.badRequest('Invalid cookie header');
|
||||
}
|
||||
|
||||
failed.push({ settings: this.settings, reason: `Header contains unexpected syntax: ${verify}` });
|
||||
}
|
||||
|
||||
// Collect errors
|
||||
|
||||
const errored = []; // Unignored errors
|
||||
const record = (reason, name, value, definition) => {
|
||||
|
||||
const details = {
|
||||
name,
|
||||
value,
|
||||
settings: definition,
|
||||
reason: typeof reason === 'string' ? reason : reason.message
|
||||
};
|
||||
|
||||
failed.push(details);
|
||||
if (!definition.ignoreErrors) {
|
||||
errored.push(details);
|
||||
}
|
||||
};
|
||||
|
||||
// Parse cookies
|
||||
|
||||
const parsed = {};
|
||||
for (const name of names) {
|
||||
const value = state[name];
|
||||
const definition = this.cookies[name] ?? this.settings;
|
||||
|
||||
// Validate cookie
|
||||
|
||||
if (definition.strictHeader) {
|
||||
const reason = internals.validate(name, state);
|
||||
if (reason) {
|
||||
record(reason, name, value, definition);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check cookie format
|
||||
|
||||
if (definition.encoding === 'none') {
|
||||
parsed[name] = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Single value
|
||||
|
||||
if (!Array.isArray(value)) {
|
||||
try {
|
||||
const unsigned = await internals.unsign(name, value, definition);
|
||||
const result = await internals.decode(unsigned, definition);
|
||||
parsed[name] = result;
|
||||
}
|
||||
catch (err) {
|
||||
Bounce.rethrow(err, 'system');
|
||||
record(err, name, value, definition);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Array
|
||||
|
||||
const arrayResult = [];
|
||||
for (const arrayValue of value) {
|
||||
try {
|
||||
const unsigned = await internals.unsign(name, arrayValue, definition);
|
||||
const result = await internals.decode(unsigned, definition);
|
||||
arrayResult.push(result);
|
||||
}
|
||||
catch (err) {
|
||||
Bounce.rethrow(err, 'system');
|
||||
record(err, name, value, definition);
|
||||
}
|
||||
}
|
||||
|
||||
parsed[name] = arrayResult;
|
||||
}
|
||||
|
||||
if (errored.length) {
|
||||
const error = Boom.badRequest('Invalid cookie value', errored);
|
||||
error.states = parsed;
|
||||
error.failed = failed;
|
||||
throw error;
|
||||
}
|
||||
|
||||
return { states: parsed, failed };
|
||||
}
|
||||
|
||||
async format(cookies, context) {
|
||||
|
||||
if (!cookies ||
|
||||
Array.isArray(cookies) && !cookies.length) {
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!Array.isArray(cookies)) {
|
||||
cookies = [cookies];
|
||||
}
|
||||
|
||||
const header = [];
|
||||
for (let i = 0; i < cookies.length; ++i) {
|
||||
const cookie = cookies[i];
|
||||
|
||||
// Apply definition to local configuration
|
||||
|
||||
const base = this.cookies[cookie.name] ?? this.settings;
|
||||
let definition = cookie.options ? Hoek.applyToDefaults(base, cookie.options, { nullOverride: true }) : base;
|
||||
|
||||
// Contextualize definition
|
||||
|
||||
if (definition.contextualize) {
|
||||
if (definition === base) {
|
||||
definition = Hoek.clone(definition);
|
||||
}
|
||||
|
||||
await definition.contextualize(definition, context);
|
||||
}
|
||||
|
||||
// Validate name
|
||||
|
||||
const nameRx = definition.strictHeader ? internals.validateRx.nameRx.strict : internals.validateRx.nameRx.loose;
|
||||
if (!nameRx.test(cookie.name)) {
|
||||
throw Boom.badImplementation('Invalid cookie name: ' + cookie.name);
|
||||
}
|
||||
|
||||
// Prepare value (encode, sign)
|
||||
|
||||
const value = await exports.prepareValue(cookie.name, cookie.value, definition);
|
||||
|
||||
// Validate prepared value
|
||||
|
||||
const valueRx = definition.strictHeader ? internals.validateRx.valueRx.strict : internals.validateRx.valueRx.loose;
|
||||
if (value &&
|
||||
(typeof value !== 'string' || !value.match(valueRx))) {
|
||||
|
||||
throw Boom.badImplementation('Invalid cookie value: ' + cookie.value);
|
||||
}
|
||||
|
||||
// Construct cookie
|
||||
|
||||
let segment = cookie.name + '=' + (value || '');
|
||||
|
||||
if (definition.ttl !== null &&
|
||||
definition.ttl !== undefined) { // Can be zero
|
||||
|
||||
const expires = new Date(definition.ttl ? Date.now() + definition.ttl : 0);
|
||||
segment = segment + '; Max-Age=' + Math.floor(definition.ttl / 1000) + '; Expires=' + expires.toUTCString();
|
||||
}
|
||||
|
||||
if (definition.isSecure) {
|
||||
segment = segment + '; Secure';
|
||||
}
|
||||
|
||||
if (definition.isHttpOnly) {
|
||||
segment = segment + '; HttpOnly';
|
||||
}
|
||||
|
||||
if (definition.isSameSite) {
|
||||
segment = `${segment}; SameSite=${definition.isSameSite}`;
|
||||
}
|
||||
|
||||
if (definition.isPartitioned) {
|
||||
if (!definition.isSecure) {
|
||||
throw Boom.badImplementation('Partitioned cookies must be secure');
|
||||
}
|
||||
|
||||
if (definition.isSameSite !== 'None') {
|
||||
throw Boom.badImplementation('Partitioned cookies must have SameSite=None');
|
||||
}
|
||||
|
||||
segment = `${segment}; Partitioned`;
|
||||
}
|
||||
|
||||
if (definition.domain) {
|
||||
const domain = definition.domain.toLowerCase();
|
||||
if (!domain.match(internals.validateRx.domainLabelLenRx)) {
|
||||
throw Boom.badImplementation('Cookie domain too long: ' + definition.domain);
|
||||
}
|
||||
|
||||
if (!domain.match(internals.validateRx.domainRx)) {
|
||||
throw Boom.badImplementation('Invalid cookie domain: ' + definition.domain);
|
||||
}
|
||||
|
||||
segment = segment + '; Domain=' + domain;
|
||||
}
|
||||
|
||||
if (definition.path) {
|
||||
if (!definition.path.match(internals.validateRx.pathRx)) {
|
||||
throw Boom.badImplementation('Invalid cookie path: ' + definition.path);
|
||||
}
|
||||
|
||||
segment = segment + '; Path=' + definition.path;
|
||||
}
|
||||
|
||||
header.push(segment);
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
passThrough(header, fallback) {
|
||||
|
||||
if (!this.names.length) {
|
||||
return header;
|
||||
}
|
||||
|
||||
const exclude = [];
|
||||
for (let i = 0; i < this.names.length; ++i) {
|
||||
const name = this.names[i];
|
||||
const definition = this.cookies[name];
|
||||
const passCookie = definition.passThrough !== undefined ? definition.passThrough : fallback;
|
||||
if (!passCookie) {
|
||||
exclude.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
return exports.exclude(header, exclude);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.parsePairs = function (cookies, eachPairFn) {
|
||||
|
||||
let index = 0;
|
||||
|
||||
while (index < cookies.length) {
|
||||
|
||||
const eqIndex = cookies.indexOf('=', index);
|
||||
|
||||
if (eqIndex === -1) {
|
||||
return cookies.slice(index); // E.g. 'a=1;xyz' -> 'xyz'
|
||||
}
|
||||
|
||||
const semiIndex = cookies.indexOf(';', eqIndex);
|
||||
const endOfValueIndex = semiIndex !== -1 ? semiIndex : cookies.length;
|
||||
|
||||
const name = cookies.slice(index, eqIndex).trim();
|
||||
const value = cookies.slice(eqIndex + 1, endOfValueIndex).trim();
|
||||
const unquotedValue = (value.startsWith('"') && value.endsWith('"') && value !== '"') ?
|
||||
value.slice(1, -1) : // E.g. '"abc"' -> 'abc'
|
||||
value;
|
||||
|
||||
eachPairFn(name, unquotedValue);
|
||||
index = endOfValueIndex + 1;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
internals.validate = function (name, state) {
|
||||
|
||||
if (!name.match(internals.validateRx.nameRx.strict)) {
|
||||
return 'Invalid cookie name';
|
||||
}
|
||||
|
||||
const values = [].concat(state[name]);
|
||||
for (let i = 0; i < values.length; ++i) {
|
||||
if (!values[i].match(internals.validateRx.valueRx.strict)) {
|
||||
return 'Invalid cookie value';
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
internals.unsign = async function (name, value, definition) {
|
||||
|
||||
if (!definition.sign) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const pos = value.lastIndexOf('.');
|
||||
if (pos === -1) {
|
||||
throw Boom.badRequest('Missing signature separator');
|
||||
}
|
||||
|
||||
const unsigned = value.slice(0, pos);
|
||||
const sig = value.slice(pos + 1);
|
||||
|
||||
if (!sig) {
|
||||
throw Boom.badRequest('Missing signature');
|
||||
}
|
||||
|
||||
const sigParts = sig.split('*');
|
||||
if (sigParts.length !== 2) {
|
||||
throw Boom.badRequest('Invalid signature format');
|
||||
}
|
||||
|
||||
const hmacSalt = sigParts[0];
|
||||
const hmac = sigParts[1];
|
||||
|
||||
const macOptions = Hoek.clone(definition.sign.integrity ?? Iron.defaults.integrity);
|
||||
macOptions.salt = hmacSalt;
|
||||
const mac = await Iron.hmacWithPassword(definition.sign.password, macOptions, [internals.macPrefix, name, unsigned].join('\n'));
|
||||
if (!Cryptiles.fixedTimeComparison(mac.digest, hmac)) {
|
||||
throw Boom.badRequest('Invalid hmac value');
|
||||
}
|
||||
|
||||
return unsigned;
|
||||
};
|
||||
|
||||
|
||||
internals.decode = async function (value, definition) {
|
||||
|
||||
if (!value &&
|
||||
definition.encoding === 'form') {
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Hoek.assert(typeof value === 'string', 'Invalid string');
|
||||
|
||||
// Encodings: 'base64json', 'base64', 'form', 'iron', 'none'
|
||||
|
||||
if (definition.encoding === 'iron') {
|
||||
return await Iron.unseal(value, definition.password, definition.iron ?? Iron.defaults);
|
||||
}
|
||||
|
||||
if (definition.encoding === 'base64json') {
|
||||
const decoded = Buffer.from(value, 'base64').toString('binary');
|
||||
try {
|
||||
return Bourne.parse(decoded);
|
||||
}
|
||||
catch {
|
||||
throw Boom.badRequest('Invalid JSON payload');
|
||||
}
|
||||
}
|
||||
|
||||
if (definition.encoding === 'base64') {
|
||||
return Buffer.from(value, 'base64').toString('binary');
|
||||
}
|
||||
|
||||
// encoding: 'form'
|
||||
|
||||
return Querystring.parse(value);
|
||||
};
|
||||
|
||||
|
||||
exports.prepareValue = async function (name, value, options) {
|
||||
|
||||
Hoek.assert(options && typeof options === 'object', 'Missing or invalid options');
|
||||
|
||||
try {
|
||||
const encoded = await internals.encode(value, options);
|
||||
const signed = await internals.sign(name, encoded, options.sign);
|
||||
return signed;
|
||||
}
|
||||
catch (err) {
|
||||
throw Boom.badImplementation('Failed to encode cookie (' + name + ') value: ' + err.message);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.encode = function (value, options) {
|
||||
|
||||
// Encodings: 'base64json', 'base64', 'form', 'iron', 'none'
|
||||
|
||||
if (value === undefined ||
|
||||
options.encoding === 'none') {
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
if (options.encoding === 'iron') {
|
||||
return Iron.seal(value, options.password, options.iron ?? Iron.defaults);
|
||||
}
|
||||
|
||||
if (options.encoding === 'base64') {
|
||||
return Buffer.from(value, 'binary').toString('base64');
|
||||
}
|
||||
|
||||
if (options.encoding === 'base64json') {
|
||||
const stringified = JSON.stringify(value);
|
||||
return Buffer.from(stringified, 'binary').toString('base64');
|
||||
}
|
||||
|
||||
// encoding: 'form'
|
||||
|
||||
return Querystring.stringify(value);
|
||||
};
|
||||
|
||||
|
||||
internals.sign = async function (name, value, options) {
|
||||
|
||||
if (value === undefined ||
|
||||
!options) {
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
const mac = await Iron.hmacWithPassword(options.password, options.integrity ?? Iron.defaults.integrity, [internals.macPrefix, name, value].join('\n'));
|
||||
const signed = value + '.' + mac.salt + '*' + mac.digest;
|
||||
return signed;
|
||||
};
|
||||
|
||||
|
||||
exports.exclude = function (cookies, excludes) {
|
||||
|
||||
const result = [];
|
||||
|
||||
const chunks = cookies.split(';');
|
||||
|
||||
for (const chunk of chunks) {
|
||||
const match = internals.pairRx.exec(chunk.trim());
|
||||
|
||||
if (!match) {
|
||||
return Boom.badRequest('Invalid cookie header');
|
||||
}
|
||||
|
||||
const [, name, value] = match;
|
||||
|
||||
if (!excludes.includes(name)) {
|
||||
result.push(`${name}=${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
return result.join(';');
|
||||
};
|
||||
Reference in New Issue
Block a user