diff --git a/projects/ngx-cookie-service-ssr/src/lib/ssr-cookie.service.ts b/projects/ngx-cookie-service-ssr/src/lib/ssr-cookie.service.ts index e3be187..b95cd19 100644 --- a/projects/ngx-cookie-service-ssr/src/lib/ssr-cookie.service.ts +++ b/projects/ngx-cookie-service-ssr/src/lib/ssr-cookie.service.ts @@ -122,12 +122,22 @@ export class SsrCookieService { * @param path Cookie path * @param domain Cookie domain * @param secure Secure flag - * @param sameSite OWASP samesite token `Lax`, `None`, or `Strict`. Defaults to `Lax` + * @param sameSite OWASP same site token `Lax`, `None`, or `Strict`. Defaults to `Lax` + * @param partitioned Partitioned flag * * @author: Stepan Suvorov * @since: 1.0.0 */ - set(name: string, value: string, expires?: number | Date, path?: string, domain?: string, secure?: boolean, sameSite?: 'Lax' | 'None' | 'Strict'): void; + set( + name: string, + value: string, + expires?: number | Date, + path?: string, + domain?: string, + secure?: boolean, + sameSite?: 'Lax' | 'None' | 'Strict', + partitioned?: boolean + ): void; /** * Set cookie based on provided information @@ -137,8 +147,8 @@ export class SsrCookieService { * expires Number of days until the cookies expires or an actual `Date` * path Cookie path * domain Cookie domain - * secure Secure flag - * sameSite OWASP samesite token `Lax`, `None`, or `Strict`. Defaults to `Lax` + * secure Cookie secure flag + * sameSite OWASP same site token `Lax`, `None`, or `Strict`. Defaults to `Lax` * * * @param name Cookie name @@ -157,6 +167,7 @@ export class SsrCookieService { domain?: string; secure?: boolean; sameSite?: 'Lax' | 'None' | 'Strict'; + partitioned?: boolean; } ): void; @@ -167,7 +178,8 @@ export class SsrCookieService { path?: string, domain?: string, secure?: boolean, - sameSite?: 'Lax' | 'None' | 'Strict' + sameSite?: 'Lax' | 'None' | 'Strict', + partitioned?: boolean ): void { if (!this.documentIsAccessible) { return; @@ -180,6 +192,7 @@ export class SsrCookieService { domain, secure, sameSite: sameSite ? sameSite : 'Lax', + partitioned, }; this.set(name, value, optionsBody); @@ -225,6 +238,10 @@ export class SsrCookieService { cookieString += 'sameSite=' + options.sameSite + ';'; + if (options.partitioned) { + cookieString += 'Partitioned;'; + } + this.document.cookie = cookieString; } diff --git a/projects/ngx-cookie-service/src/lib/cookie.service.spec.ts b/projects/ngx-cookie-service/src/lib/cookie.service.spec.ts index cd72ff6..58c10f9 100644 --- a/projects/ngx-cookie-service/src/lib/cookie.service.spec.ts +++ b/projects/ngx-cookie-service/src/lib/cookie.service.spec.ts @@ -205,7 +205,7 @@ describe('NgxCookieServiceService', () => { expect(documentCookieSetterSpy).toHaveBeenCalledWith('foo=bar;domain=example.com;sameSite=Lax;'); }); it('should set cookie with secure option', () => { - cookieService.set('foo', 'bar', undefined, undefined, undefined, true, 'Lax'); + cookieService.set('foo', 'bar', undefined, undefined, undefined, true, 'Lax', false); expect(documentCookieSetterSpy).toHaveBeenCalledWith('foo=bar;secure;sameSite=Lax;'); }); @@ -215,7 +215,7 @@ describe('NgxCookieServiceService', () => { expect(documentCookieSetterSpy).toHaveBeenCalledWith('foo=bar;secure;sameSite=Lax;'); }); it('should set cookie with forced secure flag when SameSite option is "None"', () => { - cookieService.set('foo', 'bar', undefined, undefined, undefined, false, 'None'); + cookieService.set('foo', 'bar', undefined, undefined, undefined, false, 'None', false); expect(documentCookieSetterSpy).toHaveBeenCalledWith('foo=bar;secure;sameSite=None;'); }); @@ -225,7 +225,7 @@ describe('NgxCookieServiceService', () => { expect(documentCookieSetterSpy).toHaveBeenCalledWith('foo=bar;secure;sameSite=None;'); }); it('should set cookie with SameSite option', () => { - cookieService.set('foo', 'bar', undefined, undefined, undefined, false, 'Strict'); + cookieService.set('foo', 'bar', undefined, undefined, undefined, false, 'Strict', false); expect(documentCookieSetterSpy).toHaveBeenCalledWith('foo=bar;sameSite=Strict;'); }); @@ -236,12 +236,21 @@ describe('NgxCookieServiceService', () => { }); it('should set cookie with all options', () => { const expiresDate = new Date('Mon, 15 Mar 2021 10:00:00 GMT'); - cookieService.set('foo', 'bar', expiresDate, '/test', 'example.com', true, 'Strict'); + cookieService.set('foo', 'bar', expiresDate, '/test', 'example.com', true, 'Strict', false); expect(documentCookieSetterSpy).toHaveBeenCalledWith( 'foo=bar;expires=Mon, 15 Mar 2021 10:00:00 GMT;path=/test;domain=example.com;secure;sameSite=Strict;' ); }); + it('should set cookie with partitioned', () => { + const expiresDate = new Date('Mon, 15 Mar 2021 10:00:00 GMT'); + cookieService.set('foo', 'bar', expiresDate, '/test', 'example.com', true, 'Strict', true); + + expect(documentCookieSetterSpy).toHaveBeenCalledWith( + 'foo=bar;expires=Mon, 15 Mar 2021 10:00:00 GMT;path=/test;domain=example.com;secure;sameSite=Strict;Partitioned;' + ); + }); + it('should set cookie with all options in options body', () => { const expiresDate = new Date('Mon, 15 Mar 2021 10:00:00 GMT'); diff --git a/projects/ngx-cookie-service/src/lib/cookie.service.ts b/projects/ngx-cookie-service/src/lib/cookie.service.ts index 7cd5157..20e0463 100644 --- a/projects/ngx-cookie-service/src/lib/cookie.service.ts +++ b/projects/ngx-cookie-service/src/lib/cookie.service.ts @@ -13,6 +13,7 @@ export interface CookieOptions { domain?: string; secure?: boolean; sameSite?: SameSite; + partitioned?: boolean; } @Injectable({ @@ -138,7 +139,8 @@ export class CookieService { * @param path Cookie path * @param domain Cookie domain * @param secure Secure flag - * @param sameSite OWASP samesite token `Lax`, `None`, or `Strict`. Defaults to `Lax` + * @param partitioned Partitioned flag + * @param sameSite OWASP same site token `Lax`, `None`, or `Strict`. Defaults to `Lax` * * @author: Stepan Suvorov * @since: 1.0.0 @@ -150,7 +152,8 @@ export class CookieService { path?: CookieOptions['path'], domain?: CookieOptions['domain'], secure?: CookieOptions['secure'], - sameSite?: SameSite + sameSite?: SameSite, + partitioned?: CookieOptions['partitioned'] ): void; /** @@ -161,8 +164,8 @@ export class CookieService { * expires Number of days until the cookies expires or an actual `Date` * path Cookie path * domain Cookie domain - * secure Secure flag - * sameSite OWASP samesite token `Lax`, `None`, or `Strict`. Defaults to `Lax` + * secure flag + * sameSite OWASP same site token `Lax`, `None`, or `Strict`. Defaults to `Lax` * * * @param name Cookie name @@ -181,7 +184,8 @@ export class CookieService { path?: CookieOptions['path'], domain?: CookieOptions['domain'], secure?: CookieOptions['secure'], - sameSite?: SameSite + sameSite?: SameSite, + partitioned?: CookieOptions['partitioned'] ): void { if (!this.documentIsAccessible) { return; @@ -194,6 +198,7 @@ export class CookieService { domain, secure, sameSite: sameSite ? sameSite : 'Lax', + partitioned, }; this.set(name, value, optionsBody); @@ -239,6 +244,10 @@ export class CookieService { cookieString += 'sameSite=' + options.sameSite + ';'; + if (options.partitioned) { + cookieString += 'Partitioned;'; + } + this.document.cookie = cookieString; }