From 7696bbbd28cac3c411d217cc02311e60ee9402f4 Mon Sep 17 00:00:00 2001 From: Farzad Shafiee Date: Wed, 3 Apr 2024 18:52:01 -0400 Subject: [PATCH 1/4] Accept common cookie attributes when deleting a cookie --- .changeset/shaggy-cats-film.md | 5 +++ packages/astro/src/core/cookies/cookies.ts | 21 ++++++---- .../astro/test/units/cookies/delete.test.js | 39 +++++++++++++++++-- 3 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 .changeset/shaggy-cats-film.md diff --git a/.changeset/shaggy-cats-film.md b/.changeset/shaggy-cats-film.md new file mode 100644 index 000000000000..23a7020244e7 --- /dev/null +++ b/.changeset/shaggy-cats-film.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Accept standard cookie attributes when deleting a cookie diff --git a/packages/astro/src/core/cookies/cookies.ts b/packages/astro/src/core/cookies/cookies.ts index 862d86ff0364..57575e31d38f 100644 --- a/packages/astro/src/core/cookies/cookies.ts +++ b/packages/astro/src/core/cookies/cookies.ts @@ -17,7 +17,7 @@ export interface AstroCookieGetOptions { decode?: (value: string) => string; } -type AstroCookieDeleteOptions = Pick; +type AstroCookieDeleteOptions = Omit; interface AstroCookieInterface { value: string; @@ -78,17 +78,22 @@ class AstroCookies implements AstroCookiesInterface { * @param options Options related to this deletion, such as the path of the cookie. */ delete(key: string, options?: AstroCookieDeleteOptions): void { + /** + * The `@ts-expect-error` is necessary because `maxAge` and `expires` properties + * must not appear in the AstroCookieDeleteOptions type. + */ + const { + // @ts-expect-error + maxAge: _ignoredMaxAge, + // @ts-expect-error + expires: _ignoredExpires, + ...sanitizedOptions + } = options || {}; const serializeOptions: CookieSerializeOptions = { expires: DELETED_EXPIRATION, + ...sanitizedOptions, }; - if (options?.domain) { - serializeOptions.domain = options.domain; - } - if (options?.path) { - serializeOptions.path = options.path; - } - // Set-Cookie: token=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT this.#ensureOutgoingMap().set(key, [ DELETED_VALUE, diff --git a/packages/astro/test/units/cookies/delete.test.js b/packages/astro/test/units/cookies/delete.test.js index 4b5f188e1a17..39a5d7daed56 100644 --- a/packages/astro/test/units/cookies/delete.test.js +++ b/packages/astro/test/units/cookies/delete.test.js @@ -47,26 +47,57 @@ describe('astro/src/core/cookies', () => { assert.equal(cookies.has('foo'), false); }); - it('can provide a path', () => { + it('deletes a cookie with attributes', () => { let req = new Request('http://example.com/'); let cookies = new AstroCookies(req); + cookies.delete('foo', { + domain: 'example.com', path: '/subpath/', + priority: 'high', + secure: true, + httpOnly: true, + sameSite: 'strict', }); + let headers = Array.from(cookies.headers()); assert.equal(headers.length, 1); + assert.equal(/foo=deleted/.test(headers[0]), true); + assert.equal(/Expires=Thu, 01 Jan 1970 00:00:00 GMT/.test(headers[0]), true); + assert.equal(/Domain=example.com/.test(headers[0]), true); assert.equal(/Path=\/subpath\//.test(headers[0]), true); + assert.equal(/Priority=High/.test(headers[0]), true); + assert.equal(/Secure/.test(headers[0]), true); + assert.equal(/HttpOnly/.test(headers[0]), true); + assert.equal(/SameSite=Strict/.test(headers[0]), true); + }); + + it('ignores expires option', () => { + let req = new Request('http://example.com/'); + let cookies = new AstroCookies(req); + + cookies.delete('foo', { + expires: new Date(), + }); + + let headers = Array.from(cookies.headers()); + assert.equal(headers.length, 1); + assert.equal(/foo=deleted/.test(headers[0]), true); + assert.equal(/Expires=Thu, 01 Jan 1970 00:00:00 GMT/.test(headers[0]), true); }); - it('can provide a domain', () => { + it('ignores maxAge option', () => { let req = new Request('http://example.com/'); let cookies = new AstroCookies(req); + cookies.delete('foo', { - domain: '.example.com', + maxAge: 60, }); + let headers = Array.from(cookies.headers()); assert.equal(headers.length, 1); - assert.equal(/Domain=\.example\.com/.test(headers[0]), true); + assert.equal(/foo=deleted/.test(headers[0]), true); + assert.equal(/Expires=Thu, 01 Jan 1970 00:00:00 GMT/.test(headers[0]), true); }); }); }); From 6035992d040b145390898464dae21c0e1ecb5a95 Mon Sep 17 00:00:00 2001 From: Farzad Shafiee Date: Sun, 7 Apr 2024 23:06:30 -0400 Subject: [PATCH 2/4] Fix AstroCookieSetOptions IDE annotations --- packages/astro/src/core/cookies/cookies.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/packages/astro/src/core/cookies/cookies.ts b/packages/astro/src/core/cookies/cookies.ts index 57575e31d38f..2657683f2101 100644 --- a/packages/astro/src/core/cookies/cookies.ts +++ b/packages/astro/src/core/cookies/cookies.ts @@ -2,16 +2,10 @@ import type { CookieSerializeOptions } from 'cookie'; import { parse, serialize } from 'cookie'; import { AstroError, AstroErrorData } from '../errors/index.js'; -export interface AstroCookieSetOptions { - domain?: string; - expires?: Date; - httpOnly?: boolean; - maxAge?: number; - path?: string; - sameSite?: boolean | 'lax' | 'none' | 'strict'; - secure?: boolean; - encode?: (value: string) => string; -} +export type AstroCookieSetOptions = Pick< + CookieSerializeOptions, + 'domain' | 'path' | 'expires' | 'maxAge' | 'httpOnly' | 'sameSite' | 'secure' | 'encode' +>; export interface AstroCookieGetOptions { decode?: (value: string) => string; From 58e6feddad8d549dfb4f10fb69c83323f68622ab Mon Sep 17 00:00:00 2001 From: Farzad Shafiee Date: Sun, 7 Apr 2024 23:08:00 -0400 Subject: [PATCH 3/4] Use AstroCookieSetOptions to construct AstroCookieDeleteOptions --- .changeset/shaggy-cats-film.md | 10 ++++++++-- packages/astro/src/core/cookies/cookies.ts | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.changeset/shaggy-cats-film.md b/.changeset/shaggy-cats-film.md index 23a7020244e7..35c9f9710008 100644 --- a/.changeset/shaggy-cats-film.md +++ b/.changeset/shaggy-cats-film.md @@ -1,5 +1,11 @@ --- -"astro": patch +"astro": minor --- -Accept standard cookie attributes when deleting a cookie +Extends the acceptable cookie options when deleting a cookie, to the following attribute: + +- `domain` +- `path` +- `httpOnly` *(Added)* +- `sameSite` *(Added)* +- `secure` *(Added)* diff --git a/packages/astro/src/core/cookies/cookies.ts b/packages/astro/src/core/cookies/cookies.ts index 2657683f2101..069afc796e9c 100644 --- a/packages/astro/src/core/cookies/cookies.ts +++ b/packages/astro/src/core/cookies/cookies.ts @@ -11,7 +11,7 @@ export interface AstroCookieGetOptions { decode?: (value: string) => string; } -type AstroCookieDeleteOptions = Omit; +type AstroCookieDeleteOptions = Omit; interface AstroCookieInterface { value: string; From 28b353b5133e11da677cbdec9b2ce8c4c4b7a618 Mon Sep 17 00:00:00 2001 From: Farzad Date: Mon, 8 Apr 2024 16:42:55 -0400 Subject: [PATCH 4/4] Update .changeset/shaggy-cats-film.md Co-authored-by: Florian Lefebvre --- .changeset/shaggy-cats-film.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.changeset/shaggy-cats-film.md b/.changeset/shaggy-cats-film.md index 35c9f9710008..4aaecea6c026 100644 --- a/.changeset/shaggy-cats-film.md +++ b/.changeset/shaggy-cats-film.md @@ -2,10 +2,4 @@ "astro": minor --- -Extends the acceptable cookie options when deleting a cookie, to the following attribute: - -- `domain` -- `path` -- `httpOnly` *(Added)* -- `sameSite` *(Added)* -- `secure` *(Added)* +Adds the `httpOnly`, `sameSite`, and `secure` options when deleting a cookie