fix(jellyfin): clean up Jellyfin sessions on Jellyseerr logout (#1651)
* fix(jellyfin): clean up Jellyfin sessions on Jellyseerr logout * refactor(auth): remove deleteUserDevice method and handle device deletion directly in logout process * refactor(auth): optimize logout route for Jellyfin/Emby Only query database for Jellyfin/Emby users during logout to avoid unnecessary database queries for Plex/local users. This improves performance by skipping the device deletion process when it's not needed.
This commit is contained in:
@@ -22,6 +22,23 @@ export interface JellyfinUserResponse {
|
||||
PrimaryImageTag?: string;
|
||||
}
|
||||
|
||||
export interface JellyfinDevice {
|
||||
Id: string;
|
||||
Name: string;
|
||||
LastUserName: string;
|
||||
AppName: string;
|
||||
AppVersion: string;
|
||||
LastUserId: string;
|
||||
DateLastActivity: string;
|
||||
Capabilities: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface JellyfinDevicesResponse {
|
||||
Items: JellyfinDevice[];
|
||||
TotalRecordCount: number;
|
||||
StartIndex: number;
|
||||
}
|
||||
|
||||
export interface JellyfinLoginResponse {
|
||||
User: JellyfinUserResponse;
|
||||
AccessToken: string;
|
||||
|
||||
@@ -12,7 +12,9 @@ import logger from '@server/logger';
|
||||
import { isAuthenticated } from '@server/middleware/auth';
|
||||
import { checkAvatarChanged } from '@server/routes/avatarproxy';
|
||||
import { ApiError } from '@server/types/error';
|
||||
import { getAppVersion } from '@server/utils/appVersion';
|
||||
import { getHostname } from '@server/utils/getHostname';
|
||||
import axios from 'axios';
|
||||
import * as EmailValidator from 'email-validator';
|
||||
import { Router } from 'express';
|
||||
import net from 'net';
|
||||
@@ -716,17 +718,79 @@ authRoutes.post('/local', async (req, res, next) => {
|
||||
}
|
||||
});
|
||||
|
||||
authRoutes.post('/logout', (req, res, next) => {
|
||||
req.session?.destroy((err) => {
|
||||
if (err) {
|
||||
return next({
|
||||
status: 500,
|
||||
message: 'Something went wrong.',
|
||||
});
|
||||
authRoutes.post('/logout', async (req, res, next) => {
|
||||
try {
|
||||
const userId = req.session?.userId;
|
||||
if (!userId) {
|
||||
return res.status(200).json({ status: 'ok' });
|
||||
}
|
||||
|
||||
return res.status(200).json({ status: 'ok' });
|
||||
});
|
||||
const settings = getSettings();
|
||||
const isJellyfinOrEmby =
|
||||
settings.main.mediaServerType === MediaServerType.JELLYFIN ||
|
||||
settings.main.mediaServerType === MediaServerType.EMBY;
|
||||
|
||||
if (isJellyfinOrEmby) {
|
||||
const user = await getRepository(User)
|
||||
.createQueryBuilder('user')
|
||||
.addSelect(['user.jellyfinUserId', 'user.jellyfinDeviceId'])
|
||||
.where('user.id = :id', { id: userId })
|
||||
.getOne();
|
||||
|
||||
if (user?.jellyfinUserId && user.jellyfinDeviceId) {
|
||||
try {
|
||||
const baseUrl = getHostname();
|
||||
try {
|
||||
await axios.delete(`${baseUrl}/Devices`, {
|
||||
params: { Id: user.jellyfinDeviceId },
|
||||
headers: {
|
||||
'X-Emby-Authorization': `MediaBrowser Client="Jellyseerr", Device="Jellyseerr", DeviceId="jellyseerr", Version="${getAppVersion()}", Token="${
|
||||
settings.jellyfin.apiKey
|
||||
}"`,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to delete Jellyfin device', {
|
||||
label: 'Auth',
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
userId: user.id,
|
||||
jellyfinUserId: user.jellyfinUserId,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to delete Jellyfin device', {
|
||||
label: 'Auth',
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
userId: user.id,
|
||||
jellyfinUserId: user.jellyfinUserId,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
req.session?.destroy((err: Error | null) => {
|
||||
if (err) {
|
||||
logger.error('Failed to destroy session', {
|
||||
label: 'Auth',
|
||||
error: err.message,
|
||||
userId,
|
||||
});
|
||||
return next({ status: 500, message: 'Failed to destroy session.' });
|
||||
}
|
||||
logger.info('Successfully logged out user', {
|
||||
label: 'Auth',
|
||||
userId,
|
||||
});
|
||||
res.status(200).json({ status: 'ok' });
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error during logout process', {
|
||||
label: 'Auth',
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
userId: req.session?.userId,
|
||||
});
|
||||
next({ status: 500, message: 'Error during logout process.' });
|
||||
}
|
||||
});
|
||||
|
||||
authRoutes.post('/reset-password', async (req, res, next) => {
|
||||
|
||||
Reference in New Issue
Block a user