mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-04 03:39:37 -05:00 
			
		
		
		
	test(server): change password (#1177)
This commit is contained in:
		
							parent
							
								
									4f8bc641bd
								
							
						
					
					
						commit
						0c896d9e59
					
				@ -1,11 +1,10 @@
 | 
			
		||||
import { UserEntity } from '@app/database/entities/user.entity';
 | 
			
		||||
import { BadRequestException } from '@nestjs/common';
 | 
			
		||||
import { Test } from '@nestjs/testing';
 | 
			
		||||
import { BadRequestException, UnauthorizedException } from '@nestjs/common';
 | 
			
		||||
import * as bcrypt from 'bcrypt';
 | 
			
		||||
import { AuthType } from '../../constants/jwt.constant';
 | 
			
		||||
import { ImmichJwtService } from '../../modules/immich-jwt/immich-jwt.service';
 | 
			
		||||
import { OAuthService } from '../oauth/oauth.service';
 | 
			
		||||
import { IUserRepository, USER_REPOSITORY } from '../user/user-repository';
 | 
			
		||||
import { IUserRepository } from '../user/user-repository';
 | 
			
		||||
import { AuthService } from './auth.service';
 | 
			
		||||
import { SignUpDto } from './dto/sign-up.dto';
 | 
			
		||||
import { LoginResponseDto } from './response-dto/login-response.dto';
 | 
			
		||||
@ -20,6 +19,17 @@ const fixtures = {
 | 
			
		||||
const CLIENT_IP = '127.0.0.1';
 | 
			
		||||
 | 
			
		||||
jest.mock('bcrypt');
 | 
			
		||||
jest.mock('@nestjs/common', () => ({
 | 
			
		||||
  ...jest.requireActual('@nestjs/common'),
 | 
			
		||||
  Logger: jest.fn().mockReturnValue({
 | 
			
		||||
    verbose: jest.fn(),
 | 
			
		||||
    debug: jest.fn(),
 | 
			
		||||
    log: jest.fn(),
 | 
			
		||||
    info: jest.fn(),
 | 
			
		||||
    warn: jest.fn(),
 | 
			
		||||
    error: jest.fn(),
 | 
			
		||||
  }),
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
describe('AuthService', () => {
 | 
			
		||||
  let sut: AuthService;
 | 
			
		||||
@ -61,19 +71,7 @@ describe('AuthService', () => {
 | 
			
		||||
      getLogoutEndpoint: jest.fn(),
 | 
			
		||||
    } as unknown as jest.Mocked<OAuthService>;
 | 
			
		||||
 | 
			
		||||
    const moduleRef = await Test.createTestingModule({
 | 
			
		||||
      providers: [
 | 
			
		||||
        AuthService,
 | 
			
		||||
        { provide: ImmichJwtService, useValue: immichJwtServiceMock },
 | 
			
		||||
        { provide: OAuthService, useValue: oauthServiceMock },
 | 
			
		||||
        {
 | 
			
		||||
          provide: USER_REPOSITORY,
 | 
			
		||||
          useValue: userRepositoryMock,
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    }).compile();
 | 
			
		||||
 | 
			
		||||
    sut = moduleRef.get(AuthService);
 | 
			
		||||
    sut = new AuthService(oauthServiceMock, immichJwtServiceMock, userRepositoryMock);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should be defined', () => {
 | 
			
		||||
@ -104,6 +102,62 @@ describe('AuthService', () => {
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('changePassword', () => {
 | 
			
		||||
    it('should change the password', async () => {
 | 
			
		||||
      const authUser = { email: 'test@imimch.com' } as UserEntity;
 | 
			
		||||
      const dto = { password: 'old-password', newPassword: 'new-password' };
 | 
			
		||||
 | 
			
		||||
      compare.mockResolvedValue(true);
 | 
			
		||||
 | 
			
		||||
      userRepositoryMock.getByEmail.mockResolvedValue({
 | 
			
		||||
        email: 'test@immich.com',
 | 
			
		||||
        password: 'hash-password',
 | 
			
		||||
      } as UserEntity);
 | 
			
		||||
 | 
			
		||||
      await sut.changePassword(authUser, dto);
 | 
			
		||||
 | 
			
		||||
      expect(userRepositoryMock.getByEmail).toHaveBeenCalledWith(authUser.email, true);
 | 
			
		||||
      expect(compare).toHaveBeenCalledWith('old-password', 'hash-password');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should throw when auth user email is not found', async () => {
 | 
			
		||||
      const authUser = { email: 'test@imimch.com' } as UserEntity;
 | 
			
		||||
      const dto = { password: 'old-password', newPassword: 'new-password' };
 | 
			
		||||
 | 
			
		||||
      userRepositoryMock.getByEmail.mockResolvedValue(null);
 | 
			
		||||
 | 
			
		||||
      await expect(sut.changePassword(authUser, dto)).rejects.toBeInstanceOf(UnauthorizedException);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should throw when password does not match existing password', async () => {
 | 
			
		||||
      const authUser = { email: 'test@imimch.com' } as UserEntity;
 | 
			
		||||
      const dto = { password: 'old-password', newPassword: 'new-password' };
 | 
			
		||||
 | 
			
		||||
      compare.mockResolvedValue(false);
 | 
			
		||||
 | 
			
		||||
      userRepositoryMock.getByEmail.mockResolvedValue({
 | 
			
		||||
        email: 'test@immich.com',
 | 
			
		||||
        password: 'hash-password',
 | 
			
		||||
      } as UserEntity);
 | 
			
		||||
 | 
			
		||||
      await expect(sut.changePassword(authUser, dto)).rejects.toBeInstanceOf(BadRequestException);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should throw when user does not have a password', async () => {
 | 
			
		||||
      const authUser = { email: 'test@imimch.com' } as UserEntity;
 | 
			
		||||
      const dto = { password: 'old-password', newPassword: 'new-password' };
 | 
			
		||||
 | 
			
		||||
      compare.mockResolvedValue(false);
 | 
			
		||||
 | 
			
		||||
      userRepositoryMock.getByEmail.mockResolvedValue({
 | 
			
		||||
        email: 'test@immich.com',
 | 
			
		||||
        password: '',
 | 
			
		||||
      } as UserEntity);
 | 
			
		||||
 | 
			
		||||
      await expect(sut.changePassword(authUser, dto)).rejects.toBeInstanceOf(BadRequestException);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('logout', () => {
 | 
			
		||||
    it('should return the end session endpoint', async () => {
 | 
			
		||||
      oauthServiceMock.getLogoutEndpoint.mockResolvedValue('end-session-endpoint');
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,7 @@ import { UserCore } from '../user/user.core';
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AuthService {
 | 
			
		||||
  private userCore: UserCore;
 | 
			
		||||
  private logger = new Logger(AuthService.name);
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private oauthService: OAuthService,
 | 
			
		||||
@ -44,7 +45,7 @@ export class AuthService {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!user) {
 | 
			
		||||
      Logger.warn(`Failed login attempt for user ${loginCredential.email} from ip address ${clientIp}`);
 | 
			
		||||
      this.logger.warn(`Failed login attempt for user ${loginCredential.email} from ip address ${clientIp}`);
 | 
			
		||||
      throw new BadRequestException('Incorrect email or password');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -94,8 +95,8 @@ export class AuthService {
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return mapAdminSignupResponse(admin);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      Logger.error('e', 'signUp');
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      this.logger.error(`Unable to register admin user: ${error}`, (error as Error).stack);
 | 
			
		||||
      throw new InternalServerErrorException('Failed to register new admin user');
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { SystemConfig } from '@app/database/entities/system-config.entity';
 | 
			
		||||
import { UserEntity } from '@app/database/entities/user.entity';
 | 
			
		||||
import { ImmichConfigService } from '@app/immich-config';
 | 
			
		||||
import { BadRequestException, Logger } from '@nestjs/common';
 | 
			
		||||
import { BadRequestException } from '@nestjs/common';
 | 
			
		||||
import { generators, Issuer } from 'openid-client';
 | 
			
		||||
import { AuthUserDto } from '../../decorators/auth-user.decorator';
 | 
			
		||||
import { ImmichJwtService } from '../../modules/immich-jwt/immich-jwt.service';
 | 
			
		||||
@ -32,20 +32,17 @@ const loginResponse = {
 | 
			
		||||
  userEmail: 'user@immich.com,',
 | 
			
		||||
} as LoginResponseDto;
 | 
			
		||||
 | 
			
		||||
jest.mock('@nestjs/common', () => {
 | 
			
		||||
  return {
 | 
			
		||||
jest.mock('@nestjs/common', () => ({
 | 
			
		||||
  ...jest.requireActual('@nestjs/common'),
 | 
			
		||||
    Logger: function MockLogger() {
 | 
			
		||||
      Object.assign(this as Logger, {
 | 
			
		||||
  Logger: jest.fn().mockReturnValue({
 | 
			
		||||
    verbose: jest.fn(),
 | 
			
		||||
    debug: jest.fn(),
 | 
			
		||||
    log: jest.fn(),
 | 
			
		||||
    info: jest.fn(),
 | 
			
		||||
    warn: jest.fn(),
 | 
			
		||||
    error: jest.fn(),
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
  }),
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
describe('OAuthService', () => {
 | 
			
		||||
  let sut: OAuthService;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user