From 482ec9981707ec0e320e1a4237b3529c86e35d32 Mon Sep 17 00:00:00 2001 From: Ada Date: Fri, 13 Mar 2026 21:52:22 +0000 Subject: [PATCH] fix: get all Set-Cookie headers and strip attributes ClassCharts returns two cookies on login: - cc-session - parent_session_credentials Two bugs were fixed: 1. response.headers.get('set-cookie') only returns the first cookie Fix: use getSetCookie() to get ALL Set-Cookie headers 2. authCookies was storing full Set-Cookie header values (with path, HttpOnly, Secure attributes) which breaks the Cookie header Fix: extract only name=value portion: h.split(';')[0].trim() 3. Cookie header join used ';' instead of '; ' (missing space) Fix: use '; ' as per RFC 7230 --- src/core/baseClient.ts | 2 +- src/core/parentClient.ts | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/core/baseClient.ts b/src/core/baseClient.ts index 0904128..3dbe8e6 100644 --- a/src/core/baseClient.ts +++ b/src/core/baseClient.ts @@ -96,7 +96,7 @@ export abstract class BaseClient { const requestOptions = { ...fetchOptions, headers: { - Cookie: this?.authCookies?.join(";") ?? [], + Cookie: this?.authCookies?.join("; ") ?? [], Authorization: `Basic ${this.sessionId}`, "User-Agent": "classcharts-api https://github.com/classchartsapi/classcharts-api-js", diff --git a/src/core/parentClient.ts b/src/core/parentClient.ts index 7cc30a3..2fa7658 100644 --- a/src/core/parentClient.ts +++ b/src/core/parentClient.ts @@ -61,11 +61,23 @@ export class ParentClient extends BaseClient { ); } - const cookies = String(response.headers.get("set-cookie")); - // this.authCookies = cookies.split(";"); - const sessionCookies = parseCookies(cookies); + // Get ALL Set-Cookie headers (get() only returns the first one!) + const setCookieHeaders = response.headers.getSetCookie(); + if (!setCookieHeaders || setCookieHeaders.length < 2) { + await response.body?.cancel(); + throw new Error("Unauthenticated: Missing Set-Cookie headers"); + } + + // Parse both cookies + const cookie1 = parseCookies(setCookieHeaders[0]); + const cookie2 = parseCookies(setCookieHeaders[1]); + + // Store only the name=value portion of each Set-Cookie header + this.authCookies = setCookieHeaders.map((h) => h.split(";")[0].trim()); + + // Get session ID from parent_session_credentials cookie const sessionID = JSON.parse( - String(sessionCookies.parent_session_credentials), + String(cookie1.parent_session_credentials || cookie2.parent_session_credentials), ); this.sessionId = sessionID.session_id; this.pupils = await this.getPupils();