Skip to content

Commit 2ea8e23

Browse files
authored
fix(revert): "feat: improve cookie chunk handling via base64url+length encoding (#90)" (#100)
* This reverts commit 6deb687 introduced in #90
1 parent 66710e8 commit 2ea8e23

9 files changed

+348
-1007
lines changed

src/__snapshots__/createServerClient.spec.ts.snap

Lines changed: 12 additions & 480 deletions
Large diffs are not rendered by default.

src/cookies.spec.ts

Lines changed: 1 addition & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@ import { describe, expect, it, beforeEach, afterEach } from "vitest";
33
import { isBrowser, DEFAULT_COOKIE_OPTIONS, MAX_CHUNK_SIZE } from "./utils";
44
import { CookieOptions } from "./types";
55

6-
import {
7-
createStorageFromOptions,
8-
applyServerStorage,
9-
decodeCookie,
10-
} from "./cookies";
6+
import { createStorageFromOptions, applyServerStorage } from "./cookies";
117

128
describe("createStorageFromOptions in browser without cookie methods", () => {
139
beforeEach(() => {
@@ -1074,81 +1070,3 @@ describe("applyServerStorage", () => {
10741070
]);
10751071
});
10761072
});
1077-
1078-
describe("decodeCookie", () => {
1079-
let warnings: any[][] = [];
1080-
let originalWarn: any;
1081-
1082-
beforeEach(() => {
1083-
warnings = [];
1084-
1085-
originalWarn = console.warn;
1086-
console.warn = (...args: any[]) => {
1087-
warnings.push(structuredClone(args));
1088-
};
1089-
});
1090-
1091-
afterEach(() => {
1092-
console.warn = originalWarn;
1093-
});
1094-
1095-
it("should decode base64url+length encoded value", () => {
1096-
const value = JSON.stringify({ a: "b" });
1097-
const valueB64 = Buffer.from(value).toString("base64url");
1098-
1099-
expect(
1100-
decodeCookie(`base64l-${valueB64.length.toString(36)}-${valueB64}`),
1101-
).toEqual(value);
1102-
expect(
1103-
decodeCookie(
1104-
`base64l-${valueB64.length.toString(36)}-${valueB64}padding_that_is_ignored`,
1105-
),
1106-
).toEqual(value);
1107-
expect(
1108-
decodeCookie(
1109-
`base64l-${valueB64.length.toString(36)}-${valueB64.substring(0, valueB64.length - 1)}`,
1110-
),
1111-
).toBeNull();
1112-
expect(decodeCookie(`base64l-0-${valueB64}`)).toBeNull();
1113-
expect(decodeCookie(`base64l-${valueB64}`)).toBeNull();
1114-
expect(warnings).toMatchInlineSnapshot(`
1115-
[
1116-
[
1117-
"@supabase/ssr: Detected stale cookie data. Please check your integration with Supabase for bugs. This can cause your users to loose the session.",
1118-
],
1119-
[
1120-
"@supabase/ssr: Detected stale cookie data. Please check your integration with Supabase for bugs. This can cause your users to loose the session.",
1121-
],
1122-
]
1123-
`);
1124-
});
1125-
1126-
it("should decode base64url encoded value", () => {
1127-
const value = JSON.stringify({ a: "b" });
1128-
const valueB64 = Buffer.from(value).toString("base64url");
1129-
1130-
expect(decodeCookie(`base64-${valueB64}`)).toEqual(value);
1131-
expect(warnings).toMatchInlineSnapshot(`[]`);
1132-
});
1133-
1134-
it("should not decode base64url encoded value with invalid UTF-8", () => {
1135-
const valueB64 = Buffer.from([0xff, 0xff, 0xff, 0xff]).toString(
1136-
"base64url",
1137-
);
1138-
1139-
expect(decodeCookie(`base64-${valueB64}`)).toBeNull();
1140-
expect(
1141-
decodeCookie(`base64l-${valueB64.length.toString(36)}-${valueB64}`),
1142-
).toBeNull();
1143-
expect(warnings).toMatchInlineSnapshot(`
1144-
[
1145-
[
1146-
"@supabase/ssr: Detected stale cookie data that does not decode to a UTF-8 string. Please check your integration with Supabase for bugs. This can cause your users to loose session access.",
1147-
],
1148-
[
1149-
"@supabase/ssr: Detected stale cookie data that does not decode to a UTF-8 string. Please check your integration with Supabase for bugs. This can cause your users to loose session access.",
1150-
],
1151-
]
1152-
`);
1153-
});
1154-
});

src/cookies.ts

Lines changed: 23 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -22,55 +22,6 @@ import type {
2222
} from "./types";
2323

2424
const BASE64_PREFIX = "base64-";
25-
const BASE64_LENGTH_PREFIX = "base64l-";
26-
const BASE64_LENGTH_PATTERN = /^base64l-([0-9a-z]+)-(.+)$/;
27-
28-
export function decodeBase64Cookie(value: string) {
29-
try {
30-
return stringFromBase64URL(value);
31-
} catch (e: any) {
32-
// if an invalid UTF-8 sequence is encountered, it means that reconstructing the chunkedCookie failed and the cookies don't contain useful information
33-
console.warn(
34-
"@supabase/ssr: Detected stale cookie data that does not decode to a UTF-8 string. Please check your integration with Supabase for bugs. This can cause your users to loose session access.",
35-
);
36-
return null;
37-
}
38-
}
39-
40-
export function decodeCookie(chunkedCookie: string) {
41-
let decoded = chunkedCookie;
42-
43-
if (chunkedCookie.startsWith(BASE64_PREFIX)) {
44-
return decodeBase64Cookie(decoded.substring(BASE64_PREFIX.length));
45-
} else if (chunkedCookie.startsWith(BASE64_LENGTH_PREFIX)) {
46-
const match = chunkedCookie.match(BASE64_LENGTH_PATTERN);
47-
48-
if (!match) {
49-
return null;
50-
}
51-
52-
const expectedLength = parseInt(match[1], 36);
53-
54-
if (expectedLength === 0) {
55-
return null;
56-
}
57-
58-
if (match[2].length !== expectedLength) {
59-
console.warn(
60-
"@supabase/ssr: Detected stale cookie data. Please check your integration with Supabase for bugs. This can cause your users to loose the session.",
61-
);
62-
}
63-
64-
if (expectedLength <= match[2].length) {
65-
return decodeBase64Cookie(match[2].substring(0, expectedLength));
66-
} else {
67-
// data is missing, cannot decode cookie
68-
return null;
69-
}
70-
}
71-
72-
return decoded;
73-
}
7425

7526
/**
7627
* Creates a storage client that handles cookies correctly for browser and
@@ -82,7 +33,7 @@ export function decodeCookie(chunkedCookie: string) {
8233
*/
8334
export function createStorageFromOptions(
8435
options: {
85-
cookieEncoding: "raw" | "base64url" | "base64url+length";
36+
cookieEncoding: "raw" | "base64url";
8637
cookies?:
8738
| CookieMethodsBrowser
8839
| CookieMethodsBrowserDeprecated
@@ -252,7 +203,15 @@ export function createStorageFromOptions(
252203
return null;
253204
}
254205

255-
return decodeCookie(chunkedCookie);
206+
let decoded = chunkedCookie;
207+
208+
if (chunkedCookie.startsWith(BASE64_PREFIX)) {
209+
decoded = stringFromBase64URL(
210+
chunkedCookie.substring(BASE64_PREFIX.length),
211+
);
212+
}
213+
214+
return decoded;
256215
},
257216
setItem: async (key: string, value: string) => {
258217
const allCookies = await getAll([key]);
@@ -266,13 +225,6 @@ export function createStorageFromOptions(
266225

267226
if (cookieEncoding === "base64url") {
268227
encoded = BASE64_PREFIX + stringToBase64URL(value);
269-
} else if (cookieEncoding === "base64url+length") {
270-
encoded = [
271-
BASE64_LENGTH_PREFIX,
272-
value.length.toString(36),
273-
"-",
274-
value,
275-
].join("");
276228
}
277229

278230
const setCookies = createChunks(key, encoded);
@@ -390,7 +342,18 @@ export function createStorageFromOptions(
390342
return null;
391343
}
392344

393-
return decodeCookie(chunkedCookie);
345+
let decoded = chunkedCookie;
346+
347+
if (
348+
typeof chunkedCookie === "string" &&
349+
chunkedCookie.startsWith(BASE64_PREFIX)
350+
) {
351+
decoded = stringFromBase64URL(
352+
chunkedCookie.substring(BASE64_PREFIX.length),
353+
);
354+
}
355+
356+
return decoded;
394357
},
395358
setItem: async (key: string, value: string) => {
396359
// We don't have an `onAuthStateChange` event that can let us know that
@@ -448,7 +411,7 @@ export async function applyServerStorage(
448411
removedItems: { [name: string]: boolean };
449412
},
450413
options: {
451-
cookieEncoding: "raw" | "base64url" | "base64url+length";
414+
cookieEncoding: "raw" | "base64url";
452415
cookieOptions?: CookieOptions | null;
453416
},
454417
) {
@@ -476,13 +439,6 @@ export async function applyServerStorage(
476439

477440
if (cookieEncoding === "base64url") {
478441
encoded = BASE64_PREFIX + stringToBase64URL(encoded);
479-
} else if (cookieEncoding === "base64url+length") {
480-
encoded = [
481-
BASE64_LENGTH_PREFIX,
482-
encoded.length.toString(36),
483-
"-",
484-
stringToBase64URL(encoded),
485-
].join("");
486442
}
487443

488444
const chunks = createChunks(itemName, encoded);

src/createBrowserClient.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { MAX_CHUNK_SIZE, stringToBase64URL } from "./utils";
44
import { CookieOptions } from "./types";
55
import { createBrowserClient } from "./createBrowserClient";
66

7-
describe("createBrowserClient", () => {
7+
describe("createServerClient", () => {
88
describe("validation", () => {
99
it("should throw an error on empty URL and anon key", async () => {
1010
expect(() => {

src/createBrowserClient.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export function createBrowserClient<
4848
options?: SupabaseClientOptions<SchemaName> & {
4949
cookies?: CookieMethodsBrowser;
5050
cookieOptions?: CookieOptionsWithName;
51-
cookieEncoding?: "raw" | "base64url" | "base64url+length";
51+
cookieEncoding?: "raw" | "base64url";
5252
isSingleton?: boolean;
5353
},
5454
): SupabaseClient<Database, SchemaName, Schema>;
@@ -72,7 +72,7 @@ export function createBrowserClient<
7272
options?: SupabaseClientOptions<SchemaName> & {
7373
cookies: CookieMethodsBrowserDeprecated;
7474
cookieOptions?: CookieOptionsWithName;
75-
cookieEncoding?: "raw" | "base64url" | "base64url+length";
75+
cookieEncoding?: "raw" | "base64url";
7676
isSingleton?: boolean;
7777
},
7878
): SupabaseClient<Database, SchemaName, Schema>;
@@ -91,7 +91,7 @@ export function createBrowserClient<
9191
options?: SupabaseClientOptions<SchemaName> & {
9292
cookies?: CookieMethodsBrowser | CookieMethodsBrowserDeprecated;
9393
cookieOptions?: CookieOptionsWithName;
94-
cookieEncoding?: "raw" | "base64url" | "base64url+length";
94+
cookieEncoding?: "raw" | "base64url";
9595
isSingleton?: boolean;
9696
},
9797
): SupabaseClient<Database, SchemaName, Schema> {
@@ -113,7 +113,7 @@ export function createBrowserClient<
113113
const { storage } = createStorageFromOptions(
114114
{
115115
...options,
116-
cookieEncoding: options?.cookieEncoding ?? "base64url+length",
116+
cookieEncoding: options?.cookieEncoding ?? "base64url",
117117
},
118118
false,
119119
);

0 commit comments

Comments
 (0)