UNPKG

@sapphire/plugin-api

Version:

Plugin for @sapphire/framework to expose a REST API

1 lines 7.78 kB
{"version":3,"sources":["../../../../../src/lib/structures/api/CookieStore.ts"],"names":["getDomain"],"mappings":"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","file":"CookieStore.cjs","sourcesContent":["// Copyright (c) 2018 Stanislav Woodger. All rights reserved. MIT license.\n// Source: https://github.com/woodger/cookie-httponly\n\nimport { getDomain } from 'tldts';\nimport type { ApiRequest } from './ApiRequest';\nimport type { ApiResponse } from './ApiResponse';\n\nexport class CookieStore extends Map<string, string> {\n\tprotected request: ApiRequest;\n\tprotected response: ApiResponse;\n\tprivate domain: string;\n\tprivate secure: boolean;\n\n\tpublic constructor(request: ApiRequest, response: ApiResponse, secure: boolean, domainOverwrite?: string | null) {\n\t\tsuper();\n\n\t\tthis.request = request;\n\t\tthis.response = response;\n\n\t\t// Read cookies\n\t\tconst { cookie = '' } = request.headers;\n\t\tconst pairs = cookie.split(';');\n\n\t\tfor (const pair of pairs) {\n\t\t\tconst index = pair.indexOf('=');\n\t\t\tif (index === -1) continue;\n\n\t\t\tconst key = decodeURIComponent(pair.slice(0, index).trim());\n\t\t\tconst value = decodeURIComponent(pair.slice(index + 1).trim());\n\t\t\tthis.set(key, value);\n\t\t}\n\n\t\tconst [splitHost] = this.request.headers.host?.split(':') ?? [''];\n\n\t\tthis.domain = domainOverwrite ?? this.getHostDomain(splitHost);\n\n\t\tif (this.request.socket.remoteAddress === this.domain) {\n\t\t\tthrow new Error('The connection must be established from the domain name (i.e., not an IP address)');\n\t\t}\n\n\t\t// RFC 6265 4.1.2.5. The Secure Attribute\n\t\tthis.secure = secure;\n\t}\n\n\tpublic add(name: string, value: string, options?: SecureCookieStoreSetOptions) {\n\t\tthis.insert(name, this.prepare(name, value, options));\n\t}\n\n\tpublic remove(name: string) {\n\t\tthis.add(name, '', { expires: new Date(0) });\n\t}\n\n\tprotected insert(name: string, entry: string) {\n\t\tlet set = this.response.getHeader('Set-Cookie');\n\n\t\tif (set === undefined) {\n\t\t\tset = [];\n\t\t} else if (!Array.isArray(set)) {\n\t\t\tset = [set.toString()];\n\t\t}\n\n\t\tset = set.filter((i) => i.slice(0, i.indexOf('=')) !== name);\n\t\tset.push(entry);\n\n\t\tthis.response.setHeader('Set-Cookie', set);\n\t}\n\n\tprotected prepare(name: string, value: string, { expires, maxAge, domain, path, httpOnly }: SecureCookieStoreSetOptions = {}) {\n\t\tconst now = new Date();\n\n\t\tif (expires === undefined) {\n\t\t\texpires = now;\n\t\t}\n\n\t\t// RFC 6265 4.1.1. Syntax\n\t\tname = CookieStore.encodeCookieOctet(name);\n\t\tvalue = CookieStore.encodeCookieOctet(value);\n\n\t\tlet entry = `${name}=${value}`;\n\n\t\tif (expires !== now) {\n\t\t\tentry += `; Expires=${expires.toUTCString()}`;\n\t\t} else if (maxAge) {\n\t\t\tentry += `; Max-Age=${maxAge}`;\n\t\t}\n\n\t\t// RFC 6265 5.1.3 Domain Matching\n\t\tdomain = (domain ?? this.domain).toLowerCase();\n\n\t\tentry += `; Domain=${domain}`;\n\t\tentry += `; Path=${path ?? '/'}`;\n\n\t\tif (this.secure) {\n\t\t\tentry += `; Secure`;\n\t\t}\n\n\t\tif (httpOnly ?? true) {\n\t\t\tentry += `; HttpOnly`;\n\t\t}\n\n\t\treturn entry;\n\t}\n\n\t/**\n\t * Parses a host using the {@linkplain https://github.com/remusao/tldts tldts} library to extract the domain.\n\t * This is used for the domain of the cookie\n\t * @param host The hot to parse\n\t * @returns Either the host in all lower case or the parsed domain, ready for use on cookies\n\t */\n\tprivate getHostDomain(host: string): string {\n\t\t// Transform the host to lower case\n\t\tconst lowercaseHost = host.toLowerCase();\n\n\t\t// Try parsing the host with tldts\n\t\tconst tldParsedInfo = getDomain(lowercaseHost);\n\n\t\t// If the domain is not defined then return the host in lowercase\n\t\tif (!tldParsedInfo) return lowercaseHost;\n\n\t\t// If the domain was found from parsing then prefix it with a . for a cookie that works with subdomains and return it\n\t\treturn `.${tldParsedInfo}`;\n\t}\n\n\t// RFC 6265 4.1.1. Syntax\n\tprivate static readonly octetRegExp = /[^\\x21\\x23-\\x2B\\x2D-\\x3A\\x3C-\\x5B\\x5D-\\x7E]/g;\n\n\tprivate static encodeCookieOctet(value: string) {\n\t\tif (CookieStore.octetRegExp.test(value)) {\n\t\t\tthrow new Error(`Invalid character in value`);\n\t\t}\n\n\t\treturn encodeURIComponent(value);\n\t}\n}\n\nexport interface SecureCookieStoreSetOptions {\n\texpires?: Date;\n\tmaxAge?: number;\n\tdomain?: string;\n\tpath?: string;\n\thttpOnly?: boolean;\n}\n"]}