test(server): auth e2e (#3492)

* test(server): auth controller e2e test

* test(server): user e2e test

* refactor(server): album e2e

* fix: linting
This commit is contained in:
Jason Rasmussen 2023-08-01 11:49:50 -04:00 committed by GitHub
parent 9e085c1071
commit e53625b067
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 927 additions and 496 deletions

View file

@ -101,13 +101,13 @@ describe('AuthService', () => {
it('should check the user exists', async () => {
userMock.getByEmail.mockResolvedValue(null);
await expect(sut.login(fixtures.login, loginDetails)).rejects.toBeInstanceOf(BadRequestException);
await expect(sut.login(fixtures.login, loginDetails)).rejects.toBeInstanceOf(UnauthorizedException);
expect(userMock.getByEmail).toHaveBeenCalledTimes(1);
});
it('should check the user has a password', async () => {
userMock.getByEmail.mockResolvedValue({} as UserEntity);
await expect(sut.login(fixtures.login, loginDetails)).rejects.toBeInstanceOf(BadRequestException);
await expect(sut.login(fixtures.login, loginDetails)).rejects.toBeInstanceOf(UnauthorizedException);
expect(userMock.getByEmail).toHaveBeenCalledTimes(1);
});

View file

@ -1,12 +1,5 @@
import { SystemConfig, UserEntity } from '@app/infra/entities';
import {
BadRequestException,
Inject,
Injectable,
InternalServerErrorException,
Logger,
UnauthorizedException,
} from '@nestjs/common';
import { BadRequestException, Inject, Injectable, Logger, UnauthorizedException } from '@nestjs/common';
import cookieParser from 'cookie';
import { IncomingHttpHeaders } from 'http';
import { DateTime } from 'luxon';
@ -90,7 +83,7 @@ export class AuthService {
if (!user) {
this.logger.warn(`Failed login attempt for user ${dto.email} from ip address ${details.clientIp}`);
throw new BadRequestException('Incorrect email or password');
throw new UnauthorizedException('Incorrect email or password');
}
return this.createLoginResponse(user, AuthType.PASSWORD, details);
@ -129,21 +122,16 @@ export class AuthService {
throw new BadRequestException('The server already has an admin');
}
try {
const admin = await this.userCore.createUser({
isAdmin: true,
email: dto.email,
firstName: dto.firstName,
lastName: dto.lastName,
password: dto.password,
storageLabel: 'admin',
});
const admin = await this.userCore.createUser({
isAdmin: true,
email: dto.email,
firstName: dto.firstName,
lastName: dto.lastName,
password: dto.password,
storageLabel: 'admin',
});
return mapAdminSignupResponse(admin);
} catch (error) {
this.logger.error(`Unable to register admin user: ${error}`, (error as Error).stack);
throw new InternalServerErrorException('Failed to register new admin user');
}
return mapAdminSignupResponse(admin);
}
async validate(headers: IncomingHttpHeaders, params: Record<string, string>): Promise<AuthUserDto | null> {

View file

@ -2,7 +2,6 @@ import {
AdminSignupResponseDto,
AuthDeviceResponseDto,
AuthService,
AuthType,
AuthUserDto,
ChangePasswordDto,
IMMICH_ACCESS_COOKIE,
@ -15,7 +14,7 @@ import {
UserResponseDto,
ValidateAccessTokenResponseDto,
} from '@app/domain';
import { Body, Controller, Delete, Get, Param, Post, Req, Res } from '@nestjs/common';
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Req, Res } from '@nestjs/common';
import { ApiBadRequestResponse, ApiTags } from '@nestjs/swagger';
import { Request, Response } from 'express';
import { Authenticated, AuthUser, GetLoginDetails, PublicRoute } from '../app.guard';
@ -54,36 +53,39 @@ export class AuthController {
}
@Delete('devices')
@HttpCode(HttpStatus.NO_CONTENT)
logoutAuthDevices(@AuthUser() authUser: AuthUserDto): Promise<void> {
return this.service.logoutDevices(authUser);
}
@Delete('devices/:id')
@HttpCode(HttpStatus.NO_CONTENT)
logoutAuthDevice(@AuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise<void> {
return this.service.logoutDevice(authUser, id);
}
@Post('validateToken')
@HttpCode(HttpStatus.OK)
validateAccessToken(): ValidateAccessTokenResponseDto {
return { authStatus: true };
}
@Post('change-password')
@HttpCode(HttpStatus.OK)
changePassword(@AuthUser() authUser: AuthUserDto, @Body() dto: ChangePasswordDto): Promise<UserResponseDto> {
return this.service.changePassword(authUser, dto);
}
@Post('logout')
@HttpCode(HttpStatus.OK)
logout(
@Req() req: Request,
@Res({ passthrough: true }) res: Response,
@AuthUser() authUser: AuthUserDto,
): Promise<LogoutResponseDto> {
const authType: AuthType = req.cookies[IMMICH_AUTH_TYPE_COOKIE];
res.clearCookie(IMMICH_ACCESS_COOKIE);
res.clearCookie(IMMICH_AUTH_TYPE_COOKIE);
return this.service.logout(authUser, authType);
return this.service.logout(authUser, (req.cookies || {})[IMMICH_AUTH_TYPE_COOKIE]);
}
}

View file

@ -77,6 +77,7 @@ export class UserController {
return this.service.restoreUser(authUser, userId);
}
// TODO: replace with @Put(':id')
@Put()
updateUser(@AuthUser() authUser: AuthUserDto, @Body() updateUserDto: UpdateUserDto): Promise<UserResponseDto> {
return this.service.updateUser(authUser, updateUserDto);

View file

@ -0,0 +1,2 @@
export * from './app.module';
export * from './controllers';