From 247b64a252634159a6c158371328f7bc4f941b2a Mon Sep 17 00:00:00 2001 From: jebibot <83044352+jebibot@users.noreply.github.com> Date: Fri, 8 Dec 2023 23:27:09 +0900 Subject: [PATCH 1/2] feat: base64-encode cookie value --- packages/ssr/src/createBrowserClient.ts | 6 ++++-- packages/ssr/src/createServerClient.ts | 6 ++++-- packages/ssr/src/utils/base64.ts | 21 +++++++++++++++++++++ packages/ssr/src/utils/index.ts | 1 + 4 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 packages/ssr/src/utils/base64.ts diff --git a/packages/ssr/src/createBrowserClient.ts b/packages/ssr/src/createBrowserClient.ts index 81fadb42..0b6a7943 100644 --- a/packages/ssr/src/createBrowserClient.ts +++ b/packages/ssr/src/createBrowserClient.ts @@ -4,7 +4,9 @@ import { DEFAULT_COOKIE_OPTIONS, combineChunks, createChunks, + decodeBase64Url, deleteChunks, + encodeBase64Url, isBrowser } from './utils'; import { parse, serialize } from 'cookie'; @@ -72,10 +74,10 @@ export function createBrowserClient< return cookie[chunkName]; } }); - return chunkedCookie; + return decodeBase64Url(chunkedCookie); }, setItem: async (key: string, value: string) => { - const chunks = await createChunks(key, value); + const chunks = await createChunks(key, encodeBase64Url(value)); await Promise.all( chunks.map(async (chunk) => { if (typeof cookies.set === 'function') { diff --git a/packages/ssr/src/createServerClient.ts b/packages/ssr/src/createServerClient.ts index 2d77b9f0..e2c5a1e2 100644 --- a/packages/ssr/src/createServerClient.ts +++ b/packages/ssr/src/createServerClient.ts @@ -4,7 +4,9 @@ import { DEFAULT_COOKIE_OPTIONS, combineChunks, createChunks, + decodeBase64Url, deleteChunks, + encodeBase64Url, isBrowser } from './utils'; @@ -56,10 +58,10 @@ export function createServerClient< return await cookies.get(chunkName); } }); - return chunkedCookie; + return decodeBase64Url(chunkedCookie); }, setItem: async (key: string, value: string) => { - const chunks = createChunks(key, value); + const chunks = createChunks(key, encodeBase64Url(value)); await Promise.all( chunks.map(async (chunk) => { if (typeof cookies.set === 'function') { diff --git a/packages/ssr/src/utils/base64.ts b/packages/ssr/src/utils/base64.ts new file mode 100644 index 00000000..6921ca97 --- /dev/null +++ b/packages/ssr/src/utils/base64.ts @@ -0,0 +1,21 @@ +const encoder = new TextEncoder(); +const decoder = new TextDecoder(); + +export function encodeBase64Url(str: string): string { + if (typeof Buffer !== 'undefined') { + return Buffer.from(str).toString('base64url'); + } + const bytes = Array.from(encoder.encode(str), (x) => String.fromCodePoint(x)).join(''); + return btoa(bytes).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); +} + +export function decodeBase64Url(str: string | undefined): string | undefined { + if (str == null) { + return str; + } + if (typeof Buffer !== 'undefined') { + return Buffer.from(str, 'base64url').toString(); + } + const bytes = Uint8Array.from(atob(str), (x) => x.codePointAt(0)!); + return decoder.decode(bytes); +} diff --git a/packages/ssr/src/utils/index.ts b/packages/ssr/src/utils/index.ts index 47eb760b..42bd0d6f 100644 --- a/packages/ssr/src/utils/index.ts +++ b/packages/ssr/src/utils/index.ts @@ -1,3 +1,4 @@ export * from './helpers'; export * from './constants'; export * from './chunker'; +export * from './base64'; From 281cb5d9b7950b4744abb7d8a1ae1b1d960c342b Mon Sep 17 00:00:00 2001 From: jebibot <83044352+jebibot@users.noreply.github.com> Date: Fri, 8 Dec 2023 23:35:47 +0900 Subject: [PATCH 2/2] fix: increase max chunk size to 3800 --- packages/ssr/src/utils/chunker.ts | 2 +- packages/ssr/tests/chunker.spec.ts | 14 +++++++------- packages/ssr/tests/helper.ts | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/ssr/src/utils/chunker.ts b/packages/ssr/src/utils/chunker.ts index 2e63d49a..dd9eba13 100644 --- a/packages/ssr/src/utils/chunker.ts +++ b/packages/ssr/src/utils/chunker.ts @@ -7,7 +7,7 @@ function createChunkRegExp(chunkSize: number) { return new RegExp('.{1,' + chunkSize + '}', 'g'); } -const MAX_CHUNK_SIZE = 3180; +const MAX_CHUNK_SIZE = 3800; const MAX_CHUNK_REGEXP = createChunkRegExp(MAX_CHUNK_SIZE); /** diff --git a/packages/ssr/tests/chunker.spec.ts b/packages/ssr/tests/chunker.spec.ts index a9038fd0..d97b0074 100644 --- a/packages/ssr/tests/chunker.spec.ts +++ b/packages/ssr/tests/chunker.spec.ts @@ -16,12 +16,12 @@ describe('chunker', () => { }); return chunk?.value; }); - expect(len(`my-chunks=${CHUNK_STRING}`)).toBe(3621); + expect(len(`my-chunks=${CHUNK_STRING}`)).toBe(3921); expect(chunked.length).toBe(2); expect(combined).toBe(CHUNK_STRING); }); - it('should chunk and return twelve chunks', async () => { + it('should chunk and return thirteen chunks', async () => { const chunked = createChunks('my-chunks', CHUNK_STRING, 320); const combined = await combineChunks('my-chunks', (name) => { let chunk = chunked.find((chunk) => { @@ -29,11 +29,11 @@ describe('chunker', () => { }); return chunk?.value; }); - expect(chunked.length).toBe(12); + expect(chunked.length).toBe(13); expect(combined).toBe(CHUNK_STRING); }); - it('should chunk and return one hundred and one chunks', async () => { + it('should chunk and return one hundred and nine chunks', async () => { const chunked = createChunks('my-chunks', CHUNK_STRING, 36); const combined = await combineChunks('my-chunks', (name) => { let chunk = chunked.find((chunk) => { @@ -41,7 +41,7 @@ describe('chunker', () => { }); return chunk?.value; }); - expect(chunked.length).toBe(101); + expect(chunked.length).toBe(109); expect(combined).toBe(CHUNK_STRING); }); @@ -57,11 +57,11 @@ describe('chunker', () => { chunked.forEach((chunk, i) => { expect(chunk.name).toBe(`${key}.${i}`); - expect([3217, 3217, 899]).toContain(len(`${chunk.name}=${chunk.value}`)); + expect([3837, 3837, 259]).toContain(len(`${chunk.name}=${chunk.value}`)); }); expect(chunked.length).toBe(3); - expect(len(`${key}=${DOUBLE_CHUNK_STRING}`)).toBe(7257); + expect(len(`${key}=${DOUBLE_CHUNK_STRING}`)).toBe(7857); expect(combined).toBe(DOUBLE_CHUNK_STRING); }); }); diff --git a/packages/ssr/tests/helper.ts b/packages/ssr/tests/helper.ts index dede7d6e..fdcee321 100644 --- a/packages/ssr/tests/helper.ts +++ b/packages/ssr/tests/helper.ts @@ -4,6 +4,6 @@ export const len = (str) => { }; export const CHUNK_STRING = - 'zDq8KDAdv4PwF3UOp3mnEyx1xY71CaY4ZJdPTG8HpLHy3bCYs1x3vwPXdUqY75d0LYHL8KhxgrKqBEK531igiQNk1KqUKmMsabNlwcaF5E2gXA79vpwlxvi1wecwmKGVig4mJ0dzEEXKNsLgyQCsjKOpI7Nw2gnGAKKFdHle1SJeuFj9PyAHx9stMvQFpRQhoLRt3iI0uFA.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.lww9VHv5CCETYEFj9Q1emgiZI2nXZuvHbyJmIbYgMF9w533oG8ZEsdiKo81LAflQeUHYbbxOXTtroR2bdax0VYgjZ2qg5YeOnekqbgyDXwvmsOMktvg4x7JBJiHjzKK2kSPX0cCAhcU17ydRx19xq1gOUBup1j4kqEBbvKFKt67cfqZhT4kiERgbOt6mIyurSzUPgAhBNiqUJPM3872jVtweoum6mAfSgnG4H1qs2oNZjrbGi6Xv1H5WPALAdNzDwca0evrbbufUCKDX0XO27UTAFh9k4UFf0Dk1pPgKhomuWsfsJAJDvo2ZimmkXrlUo8OfihbpGCLMbEDRpxyIcIGTUQ30WeCyaHo2ds2hs2sh'; + 'zDq8KDAdv4PwF3UOp3mnEyx1xY71CaY4ZJdPTG8HpLHy3bCYs1x3vwPXdUqY75d0LYHL8KhxgrKqBEK531igiQNk1KqUKmMsabNlwcaF5E2gXA79vpwlxvi1wecwmKGVig4mJ0dzEEXKNsLgyQCsjKOpI7Nw2gnGAKKFdHle1SJeuFj9PyAHx9stMvQFpRQhoLRt3iI0uFA.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.lww9VHv5CCETYEFj9Q1emgiZI2nXZuvHbyJmIbYgMF9w533oG8ZEsdiKo81LAflQeUHYbbxOXTtroR2bdax0VYgjZ2qg5YeOnekqbgyDXwvmsOMktvg4x7JBJiHjzKK2kSPX0cCAhcU17ydRx19xq1gOUBup1j4kqEBbvKFKt67cfqZhT4kiERgbOt6mIyurSzUPgAhBNiqUJPM3872jVtweoum6mAfSgnG4H1qs2oNZjrbGi6Xv1H5WPALAdNzDwca0evrbbufUCKDX0XO27UTAFh9k4UFf0Dk1pPgKhomuWsfsJAJDvo2ZimmkXrlUo8OfihbpGCLMbEDRpxyIcIGTUQ30WeCyaHo2ds2hs2shzDq8KDAdv4PwF3UOp3mnEyx1xY71CaY4ZJdPTG8HpLHy3bCYs1x3vwPXdUqY75d0LYHL8KhxgrKqBEK531igiQNk1KqUKmMsabNlwcaF5E2gXA79vpwlxvi1wecwmKGVig4mJ0dzEEXKNsLgyQCsjKOpI7Nw2gnGAKKFdHle1SJeuFj9PyAHx9stMvQFpRQhoLRt3iI0uFA.axN9TdbRmcyIVYroYWoIVHJCvQceRtCjF8dDpmEqD4PRhvuGPue3fLQITp90RXJ3Fchvz7uhJcyjPWchXFNSKQsxVd02bt1R'; export const DOUBLE_CHUNK_STRING = `${CHUNK_STRING}${CHUNK_STRING}`;