ngx-cookie-service-ssr
Version:
Angular SSR cookie service
228 lines (223 loc) • 8.51 kB
JavaScript
import { isPlatformBrowser } from '@angular/common';
import * as i0 from '@angular/core';
import { inject, DOCUMENT, PLATFORM_ID, REQUEST, Injectable } from '@angular/core';
class SsrCookieService {
constructor() {
this.document = inject(DOCUMENT);
this.platformId = inject(PLATFORM_ID);
this.request = inject(REQUEST, { optional: true });
this.documentIsAccessible = isPlatformBrowser(this.platformId);
}
/**
* Get cookie Regular Expression
*
* @param name Cookie name
* @returns property RegExp
*
* @author: Stepan Suvorov
* @since: 1.0.0
*/
static getCookieRegExp(name) {
const escapedName = name.replace(/([[\]{}()|=;+?,.*^$\\])/gi, '\\$1');
return new RegExp('(?:^' + escapedName + '|;\\s*' + escapedName + ')=(.*?)(?:;|$)', 'g');
}
/**
* Gets the unencoded version of an encoded component of a Uniform Resource Identifier (URI).
*
* @param encodedURIComponent A value representing an encoded URI component.
*
* @returns The unencoded version of an encoded component of a Uniform Resource Identifier (URI).
*
* @author: Stepan Suvorov
* @since: 1.0.0
*/
static safeDecodeURIComponent(encodedURIComponent) {
try {
return decodeURIComponent(encodedURIComponent);
}
catch {
// probably it is not uri encoded. return as is
return encodedURIComponent;
}
}
/**
* Return `true` if {@link Document} is accessible, otherwise return `false`
*
* @param name Cookie name
* @returns boolean - whether cookie with specified name exists
*
* @author: Stepan Suvorov
* @since: 1.0.0
*/
check(name) {
name = encodeURIComponent(name);
const regExp = SsrCookieService.getCookieRegExp(name);
return regExp.test(this.documentIsAccessible ? this.document.cookie : this.getRequestCookies());
}
/**
* Get cookies by name
*
* @param name Cookie name
* @returns property value
*
* @author: Stepan Suvorov
* @since: 1.0.0
*/
get(name) {
if (this.check(name)) {
name = encodeURIComponent(name);
const regExp = SsrCookieService.getCookieRegExp(name);
const result = regExp.exec(this.documentIsAccessible ? this.document.cookie : this.getRequestCookies());
return result?.[1] ? SsrCookieService.safeDecodeURIComponent(result[1]) : '';
}
return '';
}
/**
* Get all cookies in JSON format
*
* @returns all the cookies in json
*
* @author: Stepan Suvorov
* @since: 1.0.0
*/
getAll() {
const cookies = {};
const cookieString = this.documentIsAccessible ? this.document?.cookie : this.getRequestCookies();
if (cookieString && cookieString !== '') {
cookieString.split(';').forEach((currentCookie) => {
const [cookieName, cookieValue] = currentCookie.split('=');
cookies[SsrCookieService.safeDecodeURIComponent(cookieName.replace(/^ /, ''))] = SsrCookieService.safeDecodeURIComponent(cookieValue);
});
}
return cookies;
}
set(name, value, expiresOrOptions, path, domain, secure, sameSite, partitioned) {
if (!this.documentIsAccessible) {
return;
}
if (typeof expiresOrOptions === 'number' || expiresOrOptions instanceof Date || path || domain || secure || sameSite) {
const optionsBody = {
expires: expiresOrOptions,
path,
domain,
secure,
sameSite: sameSite ?? 'Lax',
partitioned,
};
this.set(name, value, optionsBody);
return;
}
let cookieString = encodeURIComponent(name) + '=' + encodeURIComponent(value) + ';';
const options = expiresOrOptions ?? {};
if (options.expires) {
if (typeof options.expires === 'number') {
const dateExpires = new Date(new Date().getTime() + options.expires * 1000 * 60 * 60 * 24);
cookieString += 'expires=' + dateExpires.toUTCString() + ';';
}
else {
cookieString += 'expires=' + options.expires.toUTCString() + ';';
}
}
if (options.path) {
cookieString += 'path=' + options.path + ';';
}
if (options.domain) {
cookieString += 'domain=' + options.domain + ';';
}
if (options.secure === false && options.sameSite === 'None') {
options.secure = true;
console.warn(`[ngx-cookie-service] Cookie ${name} was forced with secure flag because sameSite=None.` +
`More details : https://github.com/stevermeister/ngx-cookie-service/issues/86#issuecomment-597720130`);
}
if (options.secure) {
cookieString += 'secure;';
}
options.sameSite ??= 'Lax';
cookieString += 'sameSite=' + options.sameSite + ';';
if (options.partitioned) {
cookieString += 'Partitioned;';
}
this.document.cookie = cookieString;
}
/**
* Delete cookie by name at given path and domain. If not path is not specified, cookie at '/' path will be deleted.
*
* @param name Cookie name
* @param path Cookie path
* @param domain Cookie domain
* @param secure Cookie secure flag
* @param sameSite Cookie sameSite flag - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
*
* @author: Stepan Suvorov
* @since: 1.0.0
*/
delete(name, path, domain, secure, sameSite = 'Lax') {
if (!this.documentIsAccessible) {
return;
}
const expiresDate = new Date('Thu, 01 Jan 1970 00:00:01 GMT');
this.set(name, '', { expires: expiresDate, path, domain, secure, sameSite });
}
/**
* Delete all cookies at given path and domain. If not path is not specified, all cookies at '/' path will be deleted.
*
* @param path Cookie path
* @param domain Cookie domain
* @param secure Is the Cookie secure
* @param sameSite Is the cookie same site
*
* @author: Stepan Suvorov
* @since: 1.0.0
*/
deleteAll(path, domain, secure, sameSite = 'Lax') {
if (!this.documentIsAccessible) {
return;
}
const cookies = this.getAll();
for (const cookieName in cookies) {
if (cookies.hasOwnProperty(cookieName)) {
this.delete(cookieName, path, domain, secure, sameSite);
}
}
}
/**
* Helper method to safely get cookies from request object
* Handles both Angular's REQUEST interface and Express's req interface
*/
getRequestCookies() {
if (!this.request) {
return null;
}
// Handle Angular REQUEST object (has headers.get method)
if (this.request.headers && typeof this.request.headers.get === 'function') {
return this.request.headers.get('cookie');
}
// Handle Express request object (has headers object and get method)
const reqAny = this.request;
if (typeof reqAny.get === 'function') {
return reqAny.get('cookie') || reqAny.get('Cookie');
}
// Handle direct headers object access
const headers = this.request.headers;
if (headers && typeof headers === 'object') {
return headers['cookie'] || headers['Cookie'];
}
return null;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: SsrCookieService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: SsrCookieService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: SsrCookieService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}] });
/*
* Public API Surface of ngx-cookie-service-ssr
*/
/**
* Generated bundle index. Do not edit.
*/
export { SsrCookieService };
//# sourceMappingURL=ngx-cookie-service-ssr.mjs.map