1
0
mirror of https://github.com/immich-app/immich.git synced 2024-12-26 10:50:29 +02:00

feat(server): improve validation in controllers (#2149)

* feat(server): improve validation in controllers

* set ValidationPipe config with decorator
This commit is contained in:
Michel Heusschen 2023-04-03 06:24:18 +02:00 committed by GitHub
parent ed551500e7
commit c584791b65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 54 additions and 24 deletions

View File

@ -1,14 +1,15 @@
import { AlbumService, AuthUserDto } from '@app/domain'; import { AlbumService, AuthUserDto } from '@app/domain';
import { GetAlbumsDto } from '@app/domain/album/dto/get-albums.dto'; import { GetAlbumsDto } from '@app/domain/album/dto/get-albums.dto';
import { Controller, Get, Query, UsePipes, ValidationPipe } from '@nestjs/common'; import { Controller, Get, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { GetAuthUser } from '../decorators/auth-user.decorator'; import { GetAuthUser } from '../decorators/auth-user.decorator';
import { Authenticated } from '../decorators/authenticated.decorator'; import { Authenticated } from '../decorators/authenticated.decorator';
import { UseValidation } from '../decorators/use-validation.decorator';
@ApiTags('Album') @ApiTags('Album')
@Controller('album') @Controller('album')
@Authenticated() @Authenticated()
@UsePipes(new ValidationPipe({ transform: true })) @UseValidation()
export class AlbumController { export class AlbumController {
constructor(private service: AlbumService) {} constructor(private service: AlbumService) {}

View File

@ -6,15 +6,16 @@ import {
APIKeyUpdateDto, APIKeyUpdateDto,
AuthUserDto, AuthUserDto,
} from '@app/domain'; } from '@app/domain';
import { Body, Controller, Delete, Get, Param, Post, Put, UsePipes, ValidationPipe } from '@nestjs/common'; import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { GetAuthUser } from '../decorators/auth-user.decorator'; import { GetAuthUser } from '../decorators/auth-user.decorator';
import { Authenticated } from '../decorators/authenticated.decorator'; import { Authenticated } from '../decorators/authenticated.decorator';
import { UseValidation } from '../decorators/use-validation.decorator';
@ApiTags('API Key') @ApiTags('API Key')
@Controller('api-key') @Controller('api-key')
@Authenticated() @Authenticated()
@UsePipes(new ValidationPipe({ transform: true })) @UseValidation()
export class APIKeyController { export class APIKeyController {
constructor(private service: APIKeyService) {} constructor(private service: APIKeyService) {}

View File

@ -13,15 +13,16 @@ import {
UserResponseDto, UserResponseDto,
ValidateAccessTokenResponseDto, ValidateAccessTokenResponseDto,
} from '@app/domain'; } from '@app/domain';
import { Body, Controller, Ip, Post, Req, Res, UsePipes, ValidationPipe } from '@nestjs/common'; import { Body, Controller, Ip, Post, Req, Res } from '@nestjs/common';
import { ApiBadRequestResponse, ApiTags } from '@nestjs/swagger'; import { ApiBadRequestResponse, ApiTags } from '@nestjs/swagger';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { GetAuthUser } from '../decorators/auth-user.decorator'; import { GetAuthUser } from '../decorators/auth-user.decorator';
import { Authenticated } from '../decorators/authenticated.decorator'; import { Authenticated } from '../decorators/authenticated.decorator';
import { UseValidation } from '../decorators/use-validation.decorator';
@ApiTags('Authentication') @ApiTags('Authentication')
@Controller('auth') @Controller('auth')
@UsePipes(new ValidationPipe({ transform: true })) @UseValidation()
export class AuthController { export class AuthController {
constructor(private readonly service: AuthService) {} constructor(private readonly service: AuthService) {}

View File

@ -4,15 +4,16 @@ import {
DeviceInfoService, DeviceInfoService,
UpsertDeviceInfoDto as UpsertDto, UpsertDeviceInfoDto as UpsertDto,
} from '@app/domain'; } from '@app/domain';
import { Body, Controller, Put, UsePipes, ValidationPipe } from '@nestjs/common'; import { Body, Controller, Put } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { GetAuthUser } from '../decorators/auth-user.decorator'; import { GetAuthUser } from '../decorators/auth-user.decorator';
import { Authenticated } from '../decorators/authenticated.decorator'; import { Authenticated } from '../decorators/authenticated.decorator';
import { UseValidation } from '../decorators/use-validation.decorator';
@ApiTags('Device Info') @ApiTags('Device Info')
@Controller('device-info') @Controller('device-info')
@Authenticated() @Authenticated()
@UsePipes(new ValidationPipe({ transform: true })) @UseValidation()
export class DeviceInfoController { export class DeviceInfoController {
constructor(private readonly service: DeviceInfoService) {} constructor(private readonly service: DeviceInfoService) {}

View File

@ -1,12 +1,13 @@
import { AllJobStatusResponseDto, JobCommandDto, JobStatusDto, JobIdDto, JobService } from '@app/domain'; import { AllJobStatusResponseDto, JobCommandDto, JobStatusDto, JobIdDto, JobService } from '@app/domain';
import { Body, Controller, Get, Param, Put, UsePipes, ValidationPipe } from '@nestjs/common'; import { Body, Controller, Get, Param, Put } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { Authenticated } from '../decorators/authenticated.decorator'; import { Authenticated } from '../decorators/authenticated.decorator';
import { UseValidation } from '../decorators/use-validation.decorator';
@ApiTags('Job') @ApiTags('Job')
@Controller('jobs') @Controller('jobs')
@Authenticated({ admin: true }) @Authenticated({ admin: true })
@UsePipes(new ValidationPipe({ transform: true })) @UseValidation()
export class JobController { export class JobController {
constructor(private service: JobService) {} constructor(private service: JobService) {}

View File

@ -7,15 +7,16 @@ import {
OAuthService, OAuthService,
UserResponseDto, UserResponseDto,
} from '@app/domain'; } from '@app/domain';
import { Body, Controller, Get, HttpStatus, Post, Redirect, Req, Res, UsePipes, ValidationPipe } from '@nestjs/common'; import { Body, Controller, Get, HttpStatus, Post, Redirect, Req, Res } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { GetAuthUser } from '../decorators/auth-user.decorator'; import { GetAuthUser } from '../decorators/auth-user.decorator';
import { Authenticated } from '../decorators/authenticated.decorator'; import { Authenticated } from '../decorators/authenticated.decorator';
import { UseValidation } from '../decorators/use-validation.decorator';
@ApiTags('OAuth') @ApiTags('OAuth')
@Controller('oauth') @Controller('oauth')
@UsePipes(new ValidationPipe({ transform: true })) @UseValidation()
export class OAuthController { export class OAuthController {
constructor(private service: OAuthService) {} constructor(private service: OAuthService) {}

View File

@ -6,15 +6,16 @@ import {
SearchResponseDto, SearchResponseDto,
SearchService, SearchService,
} from '@app/domain'; } from '@app/domain';
import { Controller, Get, Query, UsePipes, ValidationPipe } from '@nestjs/common'; import { Controller, Get, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { GetAuthUser } from '../decorators/auth-user.decorator'; import { GetAuthUser } from '../decorators/auth-user.decorator';
import { Authenticated } from '../decorators/authenticated.decorator'; import { Authenticated } from '../decorators/authenticated.decorator';
import { UseValidation } from '../decorators/use-validation.decorator';
@ApiTags('Search') @ApiTags('Search')
@Controller('search') @Controller('search')
@Authenticated() @Authenticated()
@UsePipes(new ValidationPipe({ transform: true })) @UseValidation()
export class SearchController { export class SearchController {
constructor(private service: SearchService) {} constructor(private service: SearchService) {}

View File

@ -5,13 +5,14 @@ import {
ServerStatsResponseDto, ServerStatsResponseDto,
ServerVersionReponseDto, ServerVersionReponseDto,
} from '@app/domain'; } from '@app/domain';
import { Controller, Get, UsePipes, ValidationPipe } from '@nestjs/common'; import { Controller, Get } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { Authenticated } from '../decorators/authenticated.decorator'; import { Authenticated } from '../decorators/authenticated.decorator';
import { UseValidation } from '../decorators/use-validation.decorator';
@ApiTags('Server Info') @ApiTags('Server Info')
@Controller('server-info') @Controller('server-info')
@UsePipes(new ValidationPipe({ transform: true })) @UseValidation()
export class ServerInfoController { export class ServerInfoController {
constructor(private service: ServerInfoService) {} constructor(private service: ServerInfoService) {}

View File

@ -1,12 +1,13 @@
import { AuthUserDto, EditSharedLinkDto, SharedLinkResponseDto, ShareService } from '@app/domain'; import { AuthUserDto, EditSharedLinkDto, SharedLinkResponseDto, ShareService } from '@app/domain';
import { Body, Controller, Delete, Get, Param, Patch, UsePipes, ValidationPipe } from '@nestjs/common'; import { Body, Controller, Delete, Get, Param, Patch } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { GetAuthUser } from '../decorators/auth-user.decorator'; import { GetAuthUser } from '../decorators/auth-user.decorator';
import { Authenticated } from '../decorators/authenticated.decorator'; import { Authenticated } from '../decorators/authenticated.decorator';
import { UseValidation } from '../decorators/use-validation.decorator';
@ApiTags('share') @ApiTags('share')
@Controller('share') @Controller('share')
@UsePipes(new ValidationPipe({ transform: true })) @UseValidation()
export class ShareController { export class ShareController {
constructor(private readonly service: ShareService) {} constructor(private readonly service: ShareService) {}

View File

@ -1,12 +1,13 @@
import { SystemConfigDto, SystemConfigService, SystemConfigTemplateStorageOptionDto } from '@app/domain'; import { SystemConfigDto, SystemConfigService, SystemConfigTemplateStorageOptionDto } from '@app/domain';
import { Body, Controller, Get, Put, UsePipes, ValidationPipe } from '@nestjs/common'; import { Body, Controller, Get, Put } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { Authenticated } from '../decorators/authenticated.decorator'; import { Authenticated } from '../decorators/authenticated.decorator';
import { UseValidation } from '../decorators/use-validation.decorator';
@ApiTags('System Config') @ApiTags('System Config')
@Controller('system-config') @Controller('system-config')
@Authenticated({ admin: true }) @Authenticated({ admin: true })
@UsePipes(new ValidationPipe({ transform: true })) @UseValidation()
export class SystemConfigController { export class SystemConfigController {
constructor(private readonly service: SystemConfigService) {} constructor(private readonly service: SystemConfigService) {}

View File

@ -5,7 +5,6 @@ import {
Delete, Delete,
Body, Body,
Param, Param,
ValidationPipe,
Put, Put,
Query, Query,
UseInterceptors, UseInterceptors,
@ -13,7 +12,6 @@ import {
Response, Response,
StreamableFile, StreamableFile,
Header, Header,
UsePipes,
} from '@nestjs/common'; } from '@nestjs/common';
import { UserService } from '@app/domain'; import { UserService } from '@app/domain';
import { Authenticated } from '../decorators/authenticated.decorator'; import { Authenticated } from '../decorators/authenticated.decorator';
@ -29,10 +27,11 @@ import { UserCountResponseDto } from '@app/domain';
import { CreateProfileImageDto } from '@app/domain'; import { CreateProfileImageDto } from '@app/domain';
import { CreateProfileImageResponseDto } from '@app/domain'; import { CreateProfileImageResponseDto } from '@app/domain';
import { UserCountDto } from '@app/domain'; import { UserCountDto } from '@app/domain';
import { UseValidation } from '../decorators/use-validation.decorator';
@ApiTags('User') @ApiTags('User')
@Controller('user') @Controller('user')
@UsePipes(new ValidationPipe({ transform: true, whitelist: true })) @UseValidation()
export class UserController { export class UserController {
constructor(private service: UserService) {} constructor(private service: UserService) {}

View File

@ -0,0 +1,12 @@
import { applyDecorators, UsePipes, ValidationPipe } from '@nestjs/common';
export function UseValidation() {
return applyDecorators(
UsePipes(
new ValidationPipe({
transform: true,
whitelist: true,
}),
),
);
}

View File

@ -1,21 +1,30 @@
import { SystemConfig } from '@app/infra/entities'; import { SystemConfig } from '@app/infra/entities';
import { ValidateNested } from 'class-validator'; import { Type } from 'class-transformer';
import { IsObject, ValidateNested } from 'class-validator';
import { SystemConfigFFmpegDto } from './system-config-ffmpeg.dto'; import { SystemConfigFFmpegDto } from './system-config-ffmpeg.dto';
import { SystemConfigOAuthDto } from './system-config-oauth.dto'; import { SystemConfigOAuthDto } from './system-config-oauth.dto';
import { SystemConfigPasswordLoginDto } from './system-config-password-login.dto'; import { SystemConfigPasswordLoginDto } from './system-config-password-login.dto';
import { SystemConfigStorageTemplateDto } from './system-config-storage-template.dto'; import { SystemConfigStorageTemplateDto } from './system-config-storage-template.dto';
export class SystemConfigDto { export class SystemConfigDto {
@Type(() => SystemConfigFFmpegDto)
@ValidateNested() @ValidateNested()
@IsObject()
ffmpeg!: SystemConfigFFmpegDto; ffmpeg!: SystemConfigFFmpegDto;
@Type(() => SystemConfigOAuthDto)
@ValidateNested() @ValidateNested()
@IsObject()
oauth!: SystemConfigOAuthDto; oauth!: SystemConfigOAuthDto;
@Type(() => SystemConfigPasswordLoginDto)
@ValidateNested() @ValidateNested()
@IsObject()
passwordLogin!: SystemConfigPasswordLoginDto; passwordLogin!: SystemConfigPasswordLoginDto;
@Type(() => SystemConfigStorageTemplateDto)
@ValidateNested() @ValidateNested()
@IsObject()
storageTemplate!: SystemConfigStorageTemplateDto; storageTemplate!: SystemConfigStorageTemplateDto;
} }