mirror of
https://github.com/immich-app/immich.git
synced 2025-12-25 01:11:43 +03:00
80 lines
3.0 KiB
TypeScript
80 lines
3.0 KiB
TypeScript
import { SystemConfig, UserEntity } from '@app/infra/db/entities';
|
|
import { IncomingHttpHeaders } from 'http';
|
|
import { ISystemConfigRepository } from '../system-config';
|
|
import { SystemConfigCore } from '../system-config/system-config.core';
|
|
import { AuthType, IMMICH_ACCESS_COOKIE, IMMICH_AUTH_TYPE_COOKIE } from './auth.constant';
|
|
import { ICryptoRepository } from './crypto.repository';
|
|
import { LoginResponseDto, mapLoginResponse } from './response-dto';
|
|
import { IUserTokenRepository, UserTokenCore } from '@app/domain';
|
|
import cookieParser from 'cookie';
|
|
|
|
export type JwtValidationResult = {
|
|
status: boolean;
|
|
userId: string | null;
|
|
};
|
|
|
|
export class AuthCore {
|
|
private userTokenCore: UserTokenCore;
|
|
constructor(
|
|
private cryptoRepository: ICryptoRepository,
|
|
configRepository: ISystemConfigRepository,
|
|
userTokenRepository: IUserTokenRepository,
|
|
private config: SystemConfig,
|
|
) {
|
|
this.userTokenCore = new UserTokenCore(cryptoRepository, userTokenRepository);
|
|
const configCore = new SystemConfigCore(configRepository);
|
|
configCore.config$.subscribe((config) => (this.config = config));
|
|
}
|
|
|
|
isPasswordLoginEnabled() {
|
|
return this.config.passwordLogin.enabled;
|
|
}
|
|
|
|
public getCookies(loginResponse: LoginResponseDto, authType: AuthType, isSecure: boolean) {
|
|
const maxAge = 7 * 24 * 3600; // 7 days
|
|
|
|
let authTypeCookie = '';
|
|
let accessTokenCookie = '';
|
|
|
|
if (isSecure) {
|
|
accessTokenCookie = `${IMMICH_ACCESS_COOKIE}=${loginResponse.accessToken}; HttpOnly; Secure; Path=/; Max-Age=${maxAge}; SameSite=Lax;`;
|
|
authTypeCookie = `${IMMICH_AUTH_TYPE_COOKIE}=${authType}; HttpOnly; Secure; Path=/; Max-Age=${maxAge}; SameSite=Lax;`;
|
|
} else {
|
|
accessTokenCookie = `${IMMICH_ACCESS_COOKIE}=${loginResponse.accessToken}; HttpOnly; Path=/; Max-Age=${maxAge}; SameSite=Lax;`;
|
|
authTypeCookie = `${IMMICH_AUTH_TYPE_COOKIE}=${authType}; HttpOnly; Path=/; Max-Age=${maxAge}; SameSite=Lax;`;
|
|
}
|
|
return [accessTokenCookie, authTypeCookie];
|
|
}
|
|
|
|
public async createLoginResponse(user: UserEntity, authType: AuthType, isSecure: boolean) {
|
|
const accessToken = await this.userTokenCore.createToken(user);
|
|
const response = mapLoginResponse(user, accessToken);
|
|
const cookie = this.getCookies(response, authType, isSecure);
|
|
return { response, cookie };
|
|
}
|
|
|
|
validatePassword(inputPassword: string, user: UserEntity): boolean {
|
|
if (!user || !user.password) {
|
|
return false;
|
|
}
|
|
return this.cryptoRepository.compareBcrypt(inputPassword, user.password);
|
|
}
|
|
|
|
extractTokenFromHeader(headers: IncomingHttpHeaders) {
|
|
if (!headers.authorization) {
|
|
return this.extractTokenFromCookie(cookieParser.parse(headers.cookie || ''));
|
|
}
|
|
|
|
const [type, accessToken] = headers.authorization.split(' ');
|
|
if (type.toLowerCase() !== 'bearer') {
|
|
return null;
|
|
}
|
|
|
|
return accessToken;
|
|
}
|
|
|
|
extractTokenFromCookie(cookies: Record<string, string>) {
|
|
return cookies?.[IMMICH_ACCESS_COOKIE] || null;
|
|
}
|
|
}
|