Compare commits

...

2 Commits

Author SHA1 Message Date
fallenbagel
6caa0456bf feat: use gravatar for jellyfin users' with missing jellyfin avatars 2024-02-23 09:26:45 +05:00
fallenbagel
d9da3a2e3f refactor: jellyfin authentication
This refactor standardizes the authentication approach in Jellyfin to mirror the method employed in
Plex authentication for consistency
2024-02-23 09:18:13 +05:00
3 changed files with 101 additions and 64 deletions

View File

@@ -11,6 +11,7 @@ import logger from '@server/logger';
import { isAuthenticated } from '@server/middleware/auth';
import * as EmailValidator from 'email-validator';
import { Router } from 'express';
import gravatarUrl from 'gravatar-url';
const authRoutes = Router();
@@ -274,24 +275,82 @@ authRoutes.post('/jellyfin', async (req, res, next) => {
where: { jellyfinUserId: account.User.Id },
});
if (user) {
if (!user && !(await userRepository.count())) {
logger.info(
'Sign-in attempt from Jellyfin user with access to the media server; creating initial admin user for Overseerr',
{
label: 'API',
ip: req.ip,
jellyfinUsername: account.User.Name,
}
);
// User doesn't exist, and there are no users in the database, we'll create the user
// with admin permission
settings.main.mediaServerType = MediaServerType.JELLYFIN;
user = new User({
email: body.email,
jellyfinUsername: account.User.Name,
jellyfinUserId: account.User.Id,
jellyfinDeviceId: deviceId,
jellyfinAuthToken: account.AccessToken,
permissions: Permission.ADMIN,
avatar: account.User.PrimaryImageTag
? `${jellyfinHost}/Users/${account.User.Id}/Images/Primary/?tag=${account.User.PrimaryImageTag}&quality=90`
: gravatarUrl(body.email ?? '', { default: 'mm', size: 200 }),
userType: UserType.JELLYFIN,
});
settings.jellyfin.hostname = body.hostname ?? '';
settings.jellyfin.serverId = account.User.ServerId;
settings.save();
startJobs();
await userRepository.save(user);
}
// User already exists, let's update their information
else if (body.username === user?.jellyfinUsername) {
logger.info(
`Found matching ${
settings.main.mediaServerType === MediaServerType.JELLYFIN
? 'Jellyfin'
: 'Emby'
} user; updating user with ${
settings.main.mediaServerType === MediaServerType.JELLYFIN
? 'Jellyfin'
: 'Emby'
}`,
{
label: 'API',
ip: req.ip,
jellyfinUsername: account.User.Name,
}
);
// Let's check if their authtoken is up to date
if (user.jellyfinAuthToken !== account.AccessToken) {
user.jellyfinAuthToken = account.AccessToken;
}
// Update the users avatar with their jellyfin profile pic (incase it changed)
if (account.User.PrimaryImageTag) {
user.avatar = `${jellyfinHost}/Users/${account.User.Id}/Images/Primary/?tag=${account.User.PrimaryImageTag}&quality=90`;
} else {
user.avatar = '/os_logo_square.png';
user.avatar = gravatarUrl(user.email, {
default: 'mm',
size: 200,
});
}
user.jellyfinUsername = account.User.Name;
if (user.username === account.User.Name) {
user.username = '';
}
// If JELLYFIN_TYPE is set to 'emby' then set mediaServerType to EMBY
if (process.env.JELLYFIN_TYPE === 'emby') {
settings.main.mediaServerType = MediaServerType.EMBY;
settings.save();
}
await userRepository.save(user);
} else if (!settings.main.newPlexLogin) {
logger.warn(
@@ -307,69 +366,38 @@ authRoutes.post('/jellyfin', async (req, res, next) => {
status: 403,
message: 'Access denied.',
});
} else {
// Here we check if it's the first user. If it is, we create the user with no check
// and give them admin permissions
const totalUsers = await userRepository.count();
if (totalUsers === 0) {
logger.info(
'Sign-in attempt from Jellyfin user with access to the media server; creating initial admin user for Overseerr',
{
label: 'API',
ip: req.ip,
jellyfinUsername: account.User.Name,
}
);
user = new User({
email: body.email,
} else if (!user) {
logger.info(
'Sign-in attempt from Jellyfin user with access to the media server; creating new Overseerr user',
{
label: 'API',
ip: req.ip,
jellyfinUsername: account.User.Name,
jellyfinUserId: account.User.Id,
jellyfinDeviceId: deviceId,
jellyfinAuthToken: account.AccessToken,
permissions: Permission.ADMIN,
avatar: account.User.PrimaryImageTag
? `${jellyfinHost}/Users/${account.User.Id}/Images/Primary/?tag=${account.User.PrimaryImageTag}&quality=90`
: '/os_logo_square.png',
userType: UserType.JELLYFIN,
});
await userRepository.save(user);
//Update hostname in settings if it doesn't exist (initial configuration)
//Also set mediaservertype to JELLYFIN
if (settings.jellyfin.hostname === '') {
settings.main.mediaServerType = MediaServerType.JELLYFIN;
settings.jellyfin.hostname = body.hostname ?? '';
settings.jellyfin.serverId = account.User.ServerId;
settings.save();
startJobs();
}
);
if (!body.email) {
throw new Error('add_email');
}
if (!user) {
if (!body.email) {
throw new Error('add_email');
}
user = new User({
email: body.email,
jellyfinUsername: account.User.Name,
jellyfinUserId: account.User.Id,
jellyfinDeviceId: deviceId,
jellyfinAuthToken: account.AccessToken,
permissions: settings.main.defaultPermissions,
avatar: account.User.PrimaryImageTag
? `${jellyfinHost}/Users/${account.User.Id}/Images/Primary/?tag=${account.User.PrimaryImageTag}&quality=90`
: '/os_logo_square.png',
userType: UserType.JELLYFIN,
});
//initialize Jellyfin/Emby users with local login
const passedExplicitPassword =
body.password && body.password.length > 0;
if (passedExplicitPassword) {
await user.setPassword(body.password ?? '');
}
await userRepository.save(user);
user = new User({
email: body.email,
jellyfinUsername: account.User.Name,
jellyfinUserId: account.User.Id,
jellyfinDeviceId: deviceId,
jellyfinAuthToken: account.AccessToken,
permissions: settings.main.defaultPermissions,
avatar: account.User.PrimaryImageTag
? `${jellyfinHost}/Users/${account.User.Id}/Images/Primary/?tag=${account.User.PrimaryImageTag}&quality=90`
: gravatarUrl(body.email, { default: 'mm', size: 200 }),
userType: UserType.JELLYFIN,
});
//initialize Jellyfin/Emby users with local login
const passedExplicitPassword = body.password && body.password.length > 0;
if (passedExplicitPassword) {
await user.setPassword(body.password ?? '');
}
await userRepository.save(user);
}
// Set logged in session
@@ -400,6 +428,11 @@ authRoutes.post('/jellyfin', async (req, res, next) => {
status: 406,
message: 'CREDENTIAL_ERROR_ADD_EMAIL',
});
} else if (e.message === 'select_server_type') {
return next({
status: 406,
message: 'CREDENTIAL_ERROR_NO_SERVER_TYPE',
});
} else {
logger.error(e.message, { label: 'Auth' });
return next({

View File

@@ -29,6 +29,7 @@ import { getAppVersion } from '@server/utils/appVersion';
import { Router } from 'express';
import rateLimit from 'express-rate-limit';
import fs from 'fs';
import gravatarUrl from 'gravatar-url';
import { escapeRegExp, merge, omit, set, sortBy } from 'lodash';
import { rescheduleJob } from 'node-schedule';
import path from 'path';
@@ -337,7 +338,7 @@ settingsRoutes.get('/jellyfin/users', async (req, res) => {
id: user.Id,
thumb: user.PrimaryImageTag
? `${jellyfinHost}/Users/${user.Id}/Images/Primary/?tag=${user.PrimaryImageTag}&quality=90`
: '/os_logo_square.png',
: gravatarUrl(user.Name, { default: 'mm', size: 200 }),
email: user.Name,
}));

View File

@@ -537,7 +537,10 @@ router.post(
permissions: settings.main.defaultPermissions,
avatar: jellyfinUser?.PrimaryImageTag
? `${jellyfinHost}/Users/${jellyfinUser.Id}/Images/Primary/?tag=${jellyfinUser.PrimaryImageTag}&quality=90`
: '/os_logo_square.png',
: gravatarUrl(jellyfinUser?.Name ?? '', {
default: 'mm',
size: 200,
}),
userType: UserType.JELLYFIN,
});