diff --git a/server/src/domain/auth/auth.service.ts b/server/src/domain/auth/auth.service.ts index a7e467c5a3..e3b51f360f 100644 --- a/server/src/domain/auth/auth.service.ts +++ b/server/src/domain/auth/auth.service.ts @@ -147,7 +147,7 @@ export class AuthService { return mapAdminSignupResponse(admin); } - async validate(headers: IncomingHttpHeaders, params: Record): Promise { + async validate(headers: IncomingHttpHeaders, params: Record): Promise { const shareKey = (headers['x-immich-share-key'] || params.key) as string; const userToken = (headers['x-immich-user-token'] || params.userToken || diff --git a/server/src/immich/app.guard.ts b/server/src/immich/app.guard.ts index 66e0d0dd10..bf4538ad05 100644 --- a/server/src/immich/app.guard.ts +++ b/server/src/immich/app.guard.ts @@ -99,11 +99,6 @@ export class AppGuard implements CanActivate { const req = context.switchToHttp().getRequest(); const authDto = await this.authService.validate(req.headers, req.query as Record); - if (!authDto) { - this.logger.warn(`Denied access to authenticated route: ${req.path}`); - return false; - } - if (authDto.isPublicUser && !isSharedRoute) { this.logger.warn(`Denied access to non-shared route: ${req.path}`); return false; diff --git a/server/src/infra/repositories/communication.repository.ts b/server/src/infra/repositories/communication.repository.ts index 8cc5ce0e07..908044f40e 100644 --- a/server/src/infra/repositories/communication.repository.ts +++ b/server/src/infra/repositories/communication.repository.ts @@ -18,26 +18,22 @@ export class CommunicationRepository implements OnGatewayConnection, OnGatewayDi async handleConnection(client: Socket) { try { - this.logger.log(`New websocket connection: ${client.id}`); + this.logger.log(`Websocket Connect: ${client.id}`); const user = await this.authService.validate(client.request.headers, {}); - if (user) { - await client.join(user.id); - for (const callback of this.onConnectCallbacks) { - await callback(user.id); - } - } else { - client.emit('error', 'unauthorized'); - client.disconnect(); + await client.join(user.id); + for (const callback of this.onConnectCallbacks) { + await callback(user.id); } - } catch (e) { + } catch (error: Error | any) { + this.logger.error(`Websocket connection error: ${error}`, error?.stack); client.emit('error', 'unauthorized'); client.disconnect(); } } async handleDisconnect(client: Socket) { + this.logger.log(`Websocket Disconnect: ${client.id}`); await client.leave(client.nsp.name); - this.logger.log(`Client ${client.id} disconnected from Websocket`); } send(event: CommunicationEvent, userId: string, data: any) { diff --git a/web/src/lib/stores/websocket.ts b/web/src/lib/stores/websocket.ts index 213dadfda7..3371359177 100644 --- a/web/src/lib/stores/websocket.ts +++ b/web/src/lib/stores/websocket.ts @@ -1,5 +1,5 @@ import type { AssetResponseDto, ServerVersionResponseDto } from '@api'; -import { io } from 'socket.io-client'; +import { Socket, io } from 'socket.io-client'; import { writable } from 'svelte/store'; import { loadConfig } from './server-config.store'; @@ -20,9 +20,15 @@ export const websocketStore = { onRelease: writable(), }; +let websocket: Socket | null = null; + export const openWebsocketConnection = () => { try { - const websocket = io('', { + if (websocket) { + return; + } + + websocket = io('', { path: '/api/socket.io', reconnection: true, forceNew: true, @@ -40,9 +46,14 @@ export const openWebsocketConnection = () => { .on('on_config_update', () => loadConfig()) .on('on_new_release', (data) => websocketStore.onRelease.set(data)) .on('error', (e) => console.log('Websocket Error', e)); - - return () => websocket?.close(); } catch (e) { console.log('Cannot connect to websocket ', e); } }; + +export const closeWebsocketConnection = () => { + if (websocket) { + websocket.close(); + } + websocket = null; +}; diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index b658f26e27..8f8a61dbde 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -18,7 +18,7 @@ import { handleError } from '$lib/utils/handle-error'; import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store'; import { api } from '@api'; - import { openWebsocketConnection } from '$lib/stores/websocket'; + import { closeWebsocketConnection, openWebsocketConnection } from '$lib/stores/websocket'; let showNavigationLoadingBar = false; export let data: LayoutData; @@ -28,7 +28,18 @@ api.setKey($page.params.key); } - beforeNavigate(() => { + beforeNavigate(({ from, to }) => { + const fromRoute = from?.route?.id || ''; + const toRoute = to?.route?.id || ''; + + if (fromRoute.startsWith('/auth') && !toRoute.startsWith('/auth')) { + openWebsocketConnection(); + } + + if (!fromRoute.startsWith('/auth') && toRoute.startsWith('/auth')) { + closeWebsocketConnection(); + } + showNavigationLoadingBar = true; }); @@ -37,7 +48,9 @@ }); onMount(async () => { - openWebsocketConnection(); + if ($page.route.id?.startsWith('/auth') === false) { + openWebsocketConnection(); + } try { await loadConfig();