1
0
mirror of https://github.com/immich-app/immich.git synced 2025-01-12 15:32:36 +02:00

fix(web,server): web socket auth (for web) (#4632)

This commit is contained in:
Jason Rasmussen 2023-10-24 18:07:24 -04:00 committed by GitHub
parent 3021eca8e5
commit 0fb1d33f17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 39 additions and 24 deletions

View File

@ -147,7 +147,7 @@ export class AuthService {
return mapAdminSignupResponse(admin); return mapAdminSignupResponse(admin);
} }
async validate(headers: IncomingHttpHeaders, params: Record<string, string>): Promise<AuthUserDto | null> { async validate(headers: IncomingHttpHeaders, params: Record<string, string>): Promise<AuthUserDto> {
const shareKey = (headers['x-immich-share-key'] || params.key) as string; const shareKey = (headers['x-immich-share-key'] || params.key) as string;
const userToken = (headers['x-immich-user-token'] || const userToken = (headers['x-immich-user-token'] ||
params.userToken || params.userToken ||

View File

@ -99,11 +99,6 @@ export class AppGuard implements CanActivate {
const req = context.switchToHttp().getRequest<AuthRequest>(); const req = context.switchToHttp().getRequest<AuthRequest>();
const authDto = await this.authService.validate(req.headers, req.query as Record<string, string>); const authDto = await this.authService.validate(req.headers, req.query as Record<string, string>);
if (!authDto) {
this.logger.warn(`Denied access to authenticated route: ${req.path}`);
return false;
}
if (authDto.isPublicUser && !isSharedRoute) { if (authDto.isPublicUser && !isSharedRoute) {
this.logger.warn(`Denied access to non-shared route: ${req.path}`); this.logger.warn(`Denied access to non-shared route: ${req.path}`);
return false; return false;

View File

@ -18,26 +18,22 @@ export class CommunicationRepository implements OnGatewayConnection, OnGatewayDi
async handleConnection(client: Socket) { async handleConnection(client: Socket) {
try { 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, {}); const user = await this.authService.validate(client.request.headers, {});
if (user) { await client.join(user.id);
await client.join(user.id); for (const callback of this.onConnectCallbacks) {
for (const callback of this.onConnectCallbacks) { await callback(user.id);
await callback(user.id);
}
} else {
client.emit('error', 'unauthorized');
client.disconnect();
} }
} catch (e) { } catch (error: Error | any) {
this.logger.error(`Websocket connection error: ${error}`, error?.stack);
client.emit('error', 'unauthorized'); client.emit('error', 'unauthorized');
client.disconnect(); client.disconnect();
} }
} }
async handleDisconnect(client: Socket) { async handleDisconnect(client: Socket) {
this.logger.log(`Websocket Disconnect: ${client.id}`);
await client.leave(client.nsp.name); await client.leave(client.nsp.name);
this.logger.log(`Client ${client.id} disconnected from Websocket`);
} }
send(event: CommunicationEvent, userId: string, data: any) { send(event: CommunicationEvent, userId: string, data: any) {

View File

@ -1,5 +1,5 @@
import type { AssetResponseDto, ServerVersionResponseDto } from '@api'; 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 { writable } from 'svelte/store';
import { loadConfig } from './server-config.store'; import { loadConfig } from './server-config.store';
@ -20,9 +20,15 @@ export const websocketStore = {
onRelease: writable<ReleaseEvent>(), onRelease: writable<ReleaseEvent>(),
}; };
let websocket: Socket | null = null;
export const openWebsocketConnection = () => { export const openWebsocketConnection = () => {
try { try {
const websocket = io('', { if (websocket) {
return;
}
websocket = io('', {
path: '/api/socket.io', path: '/api/socket.io',
reconnection: true, reconnection: true,
forceNew: true, forceNew: true,
@ -40,9 +46,14 @@ export const openWebsocketConnection = () => {
.on('on_config_update', () => loadConfig()) .on('on_config_update', () => loadConfig())
.on('on_new_release', (data) => websocketStore.onRelease.set(data)) .on('on_new_release', (data) => websocketStore.onRelease.set(data))
.on('error', (e) => console.log('Websocket Error', e)); .on('error', (e) => console.log('Websocket Error', e));
return () => websocket?.close();
} catch (e) { } catch (e) {
console.log('Cannot connect to websocket ', e); console.log('Cannot connect to websocket ', e);
} }
}; };
export const closeWebsocketConnection = () => {
if (websocket) {
websocket.close();
}
websocket = null;
};

View File

@ -18,7 +18,7 @@
import { handleError } from '$lib/utils/handle-error'; import { handleError } from '$lib/utils/handle-error';
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store'; import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
import { api } from '@api'; import { api } from '@api';
import { openWebsocketConnection } from '$lib/stores/websocket'; import { closeWebsocketConnection, openWebsocketConnection } from '$lib/stores/websocket';
let showNavigationLoadingBar = false; let showNavigationLoadingBar = false;
export let data: LayoutData; export let data: LayoutData;
@ -28,7 +28,18 @@
api.setKey($page.params.key); 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; showNavigationLoadingBar = true;
}); });
@ -37,7 +48,9 @@
}); });
onMount(async () => { onMount(async () => {
openWebsocketConnection(); if ($page.route.id?.startsWith('/auth') === false) {
openWebsocketConnection();
}
try { try {
await loadConfig(); await loadConfig();