diff --git a/apps/calendar-web/src/auth/providers/authorization/useStartProviderAuthorization.impl.ts b/apps/calendar-web/src/auth/providers/authorization/useStartProviderAuthorization.impl.ts index 864b8f2fa..13e6cf790 100644 --- a/apps/calendar-web/src/auth/providers/authorization/useStartProviderAuthorization.impl.ts +++ b/apps/calendar-web/src/auth/providers/authorization/useStartProviderAuthorization.impl.ts @@ -3,7 +3,7 @@ import { useGoogleLogin as useGoogleLoginBase, } from "@react-oauth/google"; import { useCallback, useMemo, useState } from "react"; -import { buildOAuthStateForClient } from "@core/desktop/desktop-oauth-state.util"; +import { buildSignInOAuthState } from "@core/auth/signin-oauth-state.util"; import { GOOGLE_SCOPES } from "@core/providers/google.scopes"; import { MICROSOFT_SCOPES } from "@core/providers/microsoft.scopes"; import { type ProviderKind } from "@core/types/sync/identity.contracts"; @@ -191,7 +191,7 @@ const useGoogleProviderAuthorizationStrategy: ProviderAuthorizationStrategy = ({ const { state, redirectUri } = useAuthorizationSession( "google", (_redirectUri, posthogDistinctId) => - buildOAuthStateForClient(false, posthogDistinctId), + buildSignInOAuthState({ isDesktopClient: false, posthogDistinctId }), ); const loginOptions = useMemo< @@ -235,7 +235,7 @@ const useMicrosoftProviderAuthorizationStrategy = getClientId: () => getMicrosoftSignInClientId(), notConfiguredMessage: "Microsoft sign-in is not configured", createState: (_redirectUri, posthogDistinctId) => - buildOAuthStateForClient(false, posthogDistinctId), + buildSignInOAuthState({ isDesktopClient: false, posthogDistinctId }), buildAuthorizationUrl: ({ clientId, redirectUri, state, prompt }) => buildMicrosoftAuthorizationUrl({ clientId, diff --git a/apps/calendar-web/src/views/Forms/EventForm/DateControlsSection/DateTimeSection/DatePickers/DatePickers.tsx b/apps/calendar-web/src/views/Forms/EventForm/DateControlsSection/DateTimeSection/DatePickers/DatePickers.tsx index 4d50cb4e3..003847420 100644 --- a/apps/calendar-web/src/views/Forms/EventForm/DateControlsSection/DateTimeSection/DatePickers/DatePickers.tsx +++ b/apps/calendar-web/src/views/Forms/EventForm/DateControlsSection/DateTimeSection/DatePickers/DatePickers.tsx @@ -49,19 +49,13 @@ export const DatePickers: FC = ({ end: selectedEndDate, }); - if (shouldAdjustEnd) { - onScheduleChange({ - kind: "allDay", - start: toAllDayDate(start), - end: toAllDayDate(compliment), - }); - } else { - onScheduleChange({ - kind: "allDay", - start: toAllDayDate(start), - end: currentAllDayBounds().end, - }); - } + onScheduleChange({ + kind: "allDay", + start: toAllDayDate(start), + end: shouldAdjustEnd + ? toAllDayDate(compliment) + : currentAllDayBounds().end, + }); }; const onSelectEndDate = (end: Date) => { diff --git a/packages/core/src/auth/signin-oauth-state.util.ts b/packages/core/src/auth/signin-oauth-state.util.ts index 8f73d476a..6502b4981 100644 --- a/packages/core/src/auth/signin-oauth-state.util.ts +++ b/packages/core/src/auth/signin-oauth-state.util.ts @@ -109,25 +109,21 @@ export function parseSignInOAuthState( }; } +/** + * Apple relays `state` back as its own base64 JSON blob rather than the + * version-prefixed payload above. base64UrlDecode reads both alphabets (it + * only rewrites `-`/`_` and re-pads), so one pass covers plain base64 too. + */ function posthogDistinctIdFromAppleOAuthState( state: string, ): string | undefined { try { - const decoded = base64UrlDecode(state); - const parsed = JSON.parse(decoded) as { ph?: unknown }; + const parsed = JSON.parse(base64UrlDecode(state)) as { ph?: unknown }; return typeof parsed.ph === "string" && parsed.ph.length > 0 ? parsed.ph : undefined; } catch { - try { - const decoded = atob(state); - const parsed = JSON.parse(decoded) as { ph?: unknown }; - return typeof parsed.ph === "string" && parsed.ph.length > 0 - ? parsed.ph - : undefined; - } catch { - return undefined; - } + return undefined; } } diff --git a/packages/core/src/desktop/desktop-oauth-state.util.test.ts b/packages/core/src/desktop/desktop-oauth-state.util.test.ts index 44912d138..4a7fed373 100644 --- a/packages/core/src/desktop/desktop-oauth-state.util.test.ts +++ b/packages/core/src/desktop/desktop-oauth-state.util.test.ts @@ -1,7 +1,6 @@ import { buildDesktopConnectRelayUrl, buildDesktopOAuthRelayUrl, - buildOAuthStateForClient, DESKTOP_OAUTH_STATE_PREFIX, hasDesktopOAuthStateMarker, parseDesktopAuthDeepLink, @@ -12,16 +11,16 @@ import { import { describe, expect, it } from "bun:test"; describe("desktop oauth state", () => { - it("prefixes state when the client is desktop", () => { - const state = buildOAuthStateForClient(true); - expect(state.startsWith(DESKTOP_OAUTH_STATE_PREFIX)).toBe(true); - expect(hasDesktopOAuthStateMarker(state)).toBe(true); + // buildSignInOAuthState owns which states carry the marker, and its own + // test covers that; this is the marker reader on its own. + it("recognizes the desktop marker", () => { + expect( + hasDesktopOAuthStateMarker(`${DESKTOP_OAUTH_STATE_PREFIX}v1.payload`), + ).toBe(true); }); - it("leaves browser state unprefixed", () => { - const state = buildOAuthStateForClient(false); - expect(state.startsWith(DESKTOP_OAUTH_STATE_PREFIX)).toBe(false); - expect(hasDesktopOAuthStateMarker(state)).toBe(false); + it("leaves browser state unmarked", () => { + expect(hasDesktopOAuthStateMarker("v1.payload")).toBe(false); }); }); diff --git a/packages/core/src/desktop/desktop-oauth-state.util.ts b/packages/core/src/desktop/desktop-oauth-state.util.ts index dd094f581..948ffd0bf 100644 --- a/packages/core/src/desktop/desktop-oauth-state.util.ts +++ b/packages/core/src/desktop/desktop-oauth-state.util.ts @@ -1,4 +1,3 @@ -import { buildSignInOAuthState } from "@core/auth/signin-oauth-state.util"; import { type ProviderKind, ProviderKindSchema, @@ -30,13 +29,6 @@ const DESKTOP_EVENT_LINK_PREFIX = `${DESKTOP_DEEP_LINK_SCHEME}event/`; const DESKTOP_DAY_LINK_PATTERN = /^compass:\/\/day\/(?\d{4}-\d{2}-\d{2})\/?$/; -export function buildOAuthStateForClient( - isDesktopClient: boolean, - posthogDistinctId?: string, -): string { - return buildSignInOAuthState({ isDesktopClient, posthogDistinctId }); -} - export function hasDesktopOAuthStateMarker(state: string): boolean { return state.startsWith(DESKTOP_OAUTH_STATE_PREFIX); }