diff --git a/apps/dotcom/client/src/components/LoginRedirectPage/LoginRedirectPage.tsx b/apps/dotcom/client/src/components/LoginRedirectPage/LoginRedirectPage.tsx new file mode 100644 index 000000000000..4e73ce71c04b --- /dev/null +++ b/apps/dotcom/client/src/components/LoginRedirectPage/LoginRedirectPage.tsx @@ -0,0 +1,25 @@ +import { ClerkProvider, useClerk } from '@clerk/clerk-react' + +export default function LoginRedirectPage() { + // @ts-ignore this is fine + const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY + + if (!PUBLISHABLE_KEY) { + throw new Error('Missing VITE_CLERK_PUBLISHABLE_KEY in .env.local') + } + + return ( + + + + ) +} + +function LoginRedirectPageInner() { + const clerk = useClerk() + + const signInUrl = clerk.buildSignInUrl({ signInForceRedirectUrl: window.location.href }) + window.location.href = signInUrl + + return null +} diff --git a/apps/dotcom/client/src/components/StoreErrorScreen.tsx b/apps/dotcom/client/src/components/StoreErrorScreen.tsx index 42c3f5fec15e..9a9d33307b19 100644 --- a/apps/dotcom/client/src/components/StoreErrorScreen.tsx +++ b/apps/dotcom/client/src/components/StoreErrorScreen.tsx @@ -1,9 +1,11 @@ import { TLRemoteSyncError, TLSyncErrorCloseEventReason } from '@tldraw/sync-core' import { ErrorPage } from './ErrorPage/ErrorPage' +import LoginRedirectPage from './LoginRedirectPage/LoginRedirectPage' export function StoreErrorScreen({ error }: { error: Error }) { let header = 'Could not connect to server.' let message = '' + if (error instanceof TLRemoteSyncError) { switch (error.reason) { case TLSyncErrorCloseEventReason.CLIENT_TOO_OLD: { @@ -41,10 +43,12 @@ export function StoreErrorScreen({ error }: { error: Error }) { message = 'The room you are trying to connect to does not exist.' break } - case TLSyncErrorCloseEventReason.NOT_AUTHENTICATED: + case TLSyncErrorCloseEventReason.NOT_AUTHENTICATED: { + return + } case TLSyncErrorCloseEventReason.FORBIDDEN: { - header = 'Unauthorized' - message = 'You need to be authorized to view this room.' + header = 'Forbidden' + message = 'You are forbidden to view this room.' break } default: { diff --git a/apps/dotcom/client/src/routes.tsx b/apps/dotcom/client/src/routes.tsx index 289c9b565573..e0adeecac54e 100644 --- a/apps/dotcom/client/src/routes.tsx +++ b/apps/dotcom/client/src/routes.tsx @@ -6,11 +6,13 @@ import { SNAPSHOT_PREFIX, } from '@tldraw/dotcom-shared' import { TLRemoteSyncError, TLSyncErrorCloseEventReason } from '@tldraw/sync-core' -import { useEffect } from 'react' -import { Link, Route, createRoutesFromElements, useRouteError } from 'react-router-dom' +import { Suspense, lazy, useEffect } from 'react' +import { Route, createRoutesFromElements, useRouteError } from 'react-router-dom' import { DefaultErrorFallback } from './components/DefaultErrorFallback/DefaultErrorFallback' import { ErrorPage } from './components/ErrorPage/ErrorPage' +const LoginRedirectPage = lazy(() => import('./components/LoginRedirectPage/LoginRedirectPage')) + export const router = createRoutesFromElements( { @@ -19,42 +21,27 @@ export const router = createRoutesFromElements( captureException(error) }, [error]) + let header = 'Something went wrong' + let para1 = + 'Please try refreshing the page. Still having trouble? Let us know at hello@tldraw.com.' if (error instanceof TLRemoteSyncError) { switch (error.reason) { case TLSyncErrorCloseEventReason.NOT_FOUND: { - return ( - - ) + header = 'Not found' + para1 = 'The file you are looking for does not exist.' + break } case TLSyncErrorCloseEventReason.NOT_AUTHENTICATED: { return ( - + + + ) } case TLSyncErrorCloseEventReason.FORBIDDEN: { - return ( - - {'Back to tldraw.'} - - } - /> - ) + header = 'Forbidden' + para1 = 'You are forbidden to view this file.' + break } } } @@ -62,9 +49,8 @@ export const router = createRoutesFromElements( return ( ) diff --git a/apps/dotcom/sync-worker/src/TLDrawDurableObject.ts b/apps/dotcom/sync-worker/src/TLDrawDurableObject.ts index 4b58a8a0c8f4..e9004778ac2e 100644 --- a/apps/dotcom/sync-worker/src/TLDrawDurableObject.ts +++ b/apps/dotcom/sync-worker/src/TLDrawDurableObject.ts @@ -333,6 +333,9 @@ export class TLDrawDurableObject extends DurableObject { const ownerId = await this.getOwnerId() if (ownerId) { + if (!auth) { + return closeSocket(TLSyncErrorCloseEventReason.NOT_AUTHENTICATED) + } if (ownerId !== TldrawAppUserRecordType.createId(auth?.userId)) { const ownerDurableObject = this.env.TLAPP_DO.get(this.env.TLAPP_DO.idFromName(APP_ID)) const shareType = await ownerDurableObject.getFileShareType( diff --git a/packages/sync/src/useSync.ts b/packages/sync/src/useSync.ts index c321c338c964..356314ca9838 100644 --- a/packages/sync/src/useSync.ts +++ b/packages/sync/src/useSync.ts @@ -162,7 +162,7 @@ export function useSync(opts: UseSyncOptions & TLStoreSchemaOptions): RemoteTLSt track?.(MULTIPLAYER_EVENT_NAME, { name: 'room-not-found', roomId }) break case TLSyncErrorCloseEventReason.FORBIDDEN: - track?.(MULTIPLAYER_EVENT_NAME, { name: 'not-authorized', roomId }) + track?.(MULTIPLAYER_EVENT_NAME, { name: 'forbidden', roomId }) break case TLSyncErrorCloseEventReason.NOT_AUTHENTICATED: track?.(MULTIPLAYER_EVENT_NAME, { name: 'not-authenticated', roomId })