diff --git a/backend/src/modules/upload/dto/CreateHotlinkUploadDto.ts b/backend/src/modules/upload/dto/CreateHotlinkUploadDto.ts new file mode 100644 index 0000000..9d851bd --- /dev/null +++ b/backend/src/modules/upload/dto/CreateHotlinkUploadDto.ts @@ -0,0 +1,19 @@ +import { Type } from 'class-transformer'; +import { ArrayMaxSize, ArrayMinSize, IsArray, IsNotEmpty, ValidateNested } from 'class-validator'; +import { getAppConfig } from '../../../config'; +import { CreateHotlinkUploadItemDto } from './CreateHotlinkUploadItemDto'; +import { UploadBatchOptionsDto } from './UploadBatchOptionsDto'; + +const { + validation: { maxImagesPerUpload } +} = getAppConfig(); + +export class CreateHotlinkUploadDto extends UploadBatchOptionsDto { + @IsNotEmpty() + @IsArray() + @ArrayMinSize(1) + @ArrayMaxSize(maxImagesPerUpload) + @ValidateNested({ each: true }) + @Type(() => CreateHotlinkUploadItemDto) + items: CreateHotlinkUploadItemDto[]; +} diff --git a/backend/src/modules/upload/dto/CreateHotlinkUploadItemDto.ts b/backend/src/modules/upload/dto/CreateHotlinkUploadItemDto.ts new file mode 100644 index 0000000..b14b8cf --- /dev/null +++ b/backend/src/modules/upload/dto/CreateHotlinkUploadItemDto.ts @@ -0,0 +1,9 @@ +import { IsMimeType, IsNotEmpty, IsString } from 'class-validator'; +import { CreateUploadCiphertextItemDto } from './CreateUploadCiphertextItemDto'; + +export class CreateHotlinkUploadItemDto extends CreateUploadCiphertextItemDto { + @IsNotEmpty() + @IsString() + @IsMimeType() + mimeType: string; +} diff --git a/backend/src/modules/upload/dto/CreateUploadCiphertextItemDto.ts b/backend/src/modules/upload/dto/CreateUploadCiphertextItemDto.ts new file mode 100644 index 0000000..cba342c --- /dev/null +++ b/backend/src/modules/upload/dto/CreateUploadCiphertextItemDto.ts @@ -0,0 +1,12 @@ +import { IsNotEmpty } from 'class-validator'; +import { IsBase64 } from '../../../validation/decorators/isBase64'; + +export class CreateUploadCiphertextItemDto { + @IsNotEmpty() + @IsBase64({ byteLength: 12 }) + iv: string; + + @IsNotEmpty() + @IsBase64() + ciphertext: string; +} diff --git a/backend/src/modules/upload/dto/CreateZkPasswordUploadItemDto.ts b/backend/src/modules/upload/dto/CreateZkPasswordUploadItemDto.ts new file mode 100644 index 0000000..fc3a5b1 --- /dev/null +++ b/backend/src/modules/upload/dto/CreateZkPasswordUploadItemDto.ts @@ -0,0 +1,17 @@ +import { IsNotEmpty } from 'class-validator'; +import { IsBase64 } from '../../../validation/decorators/isBase64'; +import { CreateUploadCiphertextItemDto } from './CreateUploadCiphertextItemDto'; + +export class CreateZkPasswordUploadItemDto extends CreateUploadCiphertextItemDto { + @IsNotEmpty() + @IsBase64() + wrappedDek: string; + + @IsNotEmpty() + @IsBase64({ byteLength: 12 }) + wrapIv: string; + + @IsNotEmpty() + @IsBase64() + salt: string; +} diff --git a/backend/src/modules/upload/dto/CreateZkUploadDto.ts b/backend/src/modules/upload/dto/CreateZkUploadDto.ts new file mode 100644 index 0000000..ccab0b6 --- /dev/null +++ b/backend/src/modules/upload/dto/CreateZkUploadDto.ts @@ -0,0 +1,40 @@ +import { plainToInstance, Transform } from 'class-transformer'; +import { + ArrayMaxSize, + ArrayMinSize, + IsArray, + IsBoolean, + IsNotEmpty, + ValidateNested +} from 'class-validator'; +import { getAppConfig } from '../../../config'; +import { CreateUploadCiphertextItemDto } from './CreateUploadCiphertextItemDto'; +import { CreateZkPasswordUploadItemDto } from './CreateZkPasswordUploadItemDto'; +import { UploadBatchOptionsDto } from './UploadBatchOptionsDto'; + +const { + validation: { maxImagesPerUpload } +} = getAppConfig(); + +export class CreateZkUploadDto extends UploadBatchOptionsDto { + @IsNotEmpty() + @IsBoolean() + passwordProtected: boolean; + + @IsNotEmpty() + @IsArray() + @ArrayMinSize(1) + @ArrayMaxSize(maxImagesPerUpload) + @ValidateNested({ each: true }) + @Transform(({ value, obj }: { value: unknown; obj: CreateZkUploadDto }) => { + if (!Array.isArray(value)) { + return value; + } + + const ItemClass = + obj.passwordProtected === true ? CreateZkPasswordUploadItemDto : CreateUploadCiphertextItemDto; + + return value.map(item => plainToInstance(ItemClass, item)); + }) + items: Array; +} diff --git a/backend/src/modules/upload/dto/UploadBatchOptionsDto.ts b/backend/src/modules/upload/dto/UploadBatchOptionsDto.ts new file mode 100644 index 0000000..4070d34 --- /dev/null +++ b/backend/src/modules/upload/dto/UploadBatchOptionsDto.ts @@ -0,0 +1,14 @@ +import { getAppConfig } from '../../../config'; +import { NullOrDate, NullOrInt } from '../../../validation/decorators/nullOr'; + +const { + validation: { uploadMaxViewsMax } +} = getAppConfig(); + +export class UploadBatchOptionsDto { + @NullOrDate() + expiresAt: Date | null; + + @NullOrInt({ min: 1, max: uploadMaxViewsMax }) + maxViews: number | null; +}