refactor(server): upload config (#3148)

This commit is contained in:
Jason Rasmussen
2023-07-09 00:37:40 -04:00
committed by GitHub
parent 8349a28ed8
commit 398bd04ffd
23 changed files with 473 additions and 624 deletions

View File

@@ -1,4 +1,4 @@
import { BadRequestException } from '@nestjs/common';
import { BadRequestException, UnauthorizedException } from '@nestjs/common';
import { AuthUserDto } from '../auth';
import { IAccessRepository } from './access.repository';
@@ -25,6 +25,13 @@ export enum Permission {
export class AccessCore {
constructor(private repository: IAccessRepository) {}
requireUploadAccess(authUser: AuthUserDto | null): AuthUserDto {
if (!authUser || (authUser.isPublicUser && !authUser.isAllowUpload)) {
throw new UnauthorizedException();
}
return authUser;
}
async requirePermission(authUser: AuthUserDto, permission: Permission, ids: string[] | string) {
const hasAccess = await this.hasPermission(authUser, permission, ids);
if (!hasAccess) {

View File

@@ -1,10 +1,10 @@
import { AssetEntity } from '@app/infra/entities';
import { BadRequestException, Inject } from '@nestjs/common';
import { DateTime } from 'luxon';
import { extname } from 'path';
import { AssetEntity } from '../../infra/entities/asset.entity';
import { AccessCore, IAccessRepository, Permission } from '../access';
import { AuthUserDto } from '../auth';
import { HumanReadableSize, usePagination } from '../domain.util';
import { AccessCore, IAccessRepository, Permission } from '../index';
import { ImmichReadStream, IStorageRepository } from '../storage';
import { IAssetRepository } from './asset.repository';
import { AssetIdsDto, DownloadArchiveInfo, DownloadDto, DownloadResponseDto, MemoryLaneDto } from './dto';
@@ -12,6 +12,20 @@ import { MapMarkerDto } from './dto/map-marker.dto';
import { mapAsset, MapMarkerResponseDto } from './response-dto';
import { MemoryLaneResponseDto } from './response-dto/memory-lane-response.dto';
export enum UploadFieldName {
ASSET_DATA = 'assetData',
LIVE_PHOTO_DATA = 'livePhotoData',
SIDECAR_DATA = 'sidecarData',
PROFILE_DATA = 'file',
}
export interface UploadFile {
mimeType: string;
checksum: Buffer;
originalPath: string;
originalName: string;
}
export class AssetService {
private access: AccessCore;

View File

@@ -2,6 +2,7 @@ export const ICryptoRepository = 'ICryptoRepository';
export interface ICryptoRepository {
randomBytes(size: number): Buffer;
randomUUID(): string;
hashFile(filePath: string): Promise<Buffer>;
hashSha256(data: string): string;
hashBcrypt(data: string | Buffer, saltOrRounds: string | number): Promise<string>;

View File

@@ -1,21 +0,0 @@
import { validMimeTypes } from './domain.constant';
describe('valid mime types', () => {
it('should be a sorted list', () => {
expect(validMimeTypes).toEqual(validMimeTypes.sort());
});
it('should contain only unique values', () => {
expect(validMimeTypes).toEqual([...new Set(validMimeTypes)]);
});
it('should contain only image or video mime types', () => {
expect(validMimeTypes).toEqual(
validMimeTypes.filter((mimeType) => mimeType.startsWith('image/') || mimeType.startsWith('video/')),
);
});
it('should contain only lowercase mime types', () => {
expect(validMimeTypes).toEqual(validMimeTypes.map((mimeType) => mimeType.toLowerCase()));
});
});

View File

@@ -28,7 +28,7 @@ export function assertMachineLearningEnabled() {
}
}
export const validMimeTypes = [
export const ASSET_MIME_TYPES = [
'image/3fr',
'image/ari',
'image/arw',
@@ -106,11 +106,14 @@ export const validMimeTypes = [
'video/x-ms-wmv',
'video/x-msvideo',
];
export function isSupportedFileType(mimetype: string): boolean {
return validMimeTypes.includes(mimetype);
}
export function isSidecarFileType(mimeType: string): boolean {
return ['application/xml', 'text/xml'].includes(mimeType);
}
export const LIVE_PHOTO_MIME_TYPES = ASSET_MIME_TYPES;
export const SIDECAR_MIME_TYPES = ['application/xml', 'text/xml'];
export const PROFILE_MIME_TYPES = [
'image/jpeg',
'image/png',
'image/heic',
'image/heif',
'image/dng',
'image/webp',
'image/avif',
];

View File

@@ -1,7 +1,7 @@
import { ApiProperty } from '@nestjs/swagger';
import { Express } from 'express';
import { UploadFieldName } from '../../asset/asset.service';
export class CreateProfileImageDto {
@ApiProperty({ type: 'string', format: 'binary' })
file!: Express.Multer.File;
[UploadFieldName.PROFILE_DATA]!: Express.Multer.File;
}