mirror of
https://github.com/immich-app/immich.git
synced 2024-12-25 10:43:13 +02:00
fix(server): read file permission checks (#3046)
This commit is contained in:
parent
ad343b7b32
commit
455a36b0fc
@ -82,7 +82,7 @@ describe(MetadataService.name, () => {
|
|||||||
assetMock.save.mockResolvedValue(assetEntityStub.image);
|
assetMock.save.mockResolvedValue(assetEntityStub.image);
|
||||||
storageMock.checkFileExists.mockResolvedValue(true);
|
storageMock.checkFileExists.mockResolvedValue(true);
|
||||||
await sut.handleSidecarDiscovery({ id: assetEntityStub.image.id });
|
await sut.handleSidecarDiscovery({ id: assetEntityStub.image.id });
|
||||||
expect(storageMock.checkFileExists).toHaveBeenCalledWith('/original/path.ext.xmp', constants.W_OK);
|
expect(storageMock.checkFileExists).toHaveBeenCalledWith('/original/path.ext.xmp', constants.R_OK);
|
||||||
expect(assetMock.save).toHaveBeenCalledWith({
|
expect(assetMock.save).toHaveBeenCalledWith({
|
||||||
id: assetEntityStub.image.id,
|
id: assetEntityStub.image.id,
|
||||||
sidecarPath: '/original/path.ext.xmp',
|
sidecarPath: '/original/path.ext.xmp',
|
||||||
@ -94,7 +94,7 @@ describe(MetadataService.name, () => {
|
|||||||
assetMock.save.mockResolvedValue(assetEntityStub.video);
|
assetMock.save.mockResolvedValue(assetEntityStub.video);
|
||||||
storageMock.checkFileExists.mockResolvedValue(true);
|
storageMock.checkFileExists.mockResolvedValue(true);
|
||||||
await sut.handleSidecarDiscovery({ id: assetEntityStub.video.id });
|
await sut.handleSidecarDiscovery({ id: assetEntityStub.video.id });
|
||||||
expect(storageMock.checkFileExists).toHaveBeenCalledWith('/original/path.ext.xmp', constants.W_OK);
|
expect(storageMock.checkFileExists).toHaveBeenCalledWith('/original/path.ext.xmp', constants.R_OK);
|
||||||
expect(assetMock.save).toHaveBeenCalledWith({
|
expect(assetMock.save).toHaveBeenCalledWith({
|
||||||
id: assetEntityStub.image.id,
|
id: assetEntityStub.image.id,
|
||||||
sidecarPath: '/original/path.ext.xmp',
|
sidecarPath: '/original/path.ext.xmp',
|
||||||
|
@ -42,7 +42,7 @@ export class MetadataService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sidecarPath = `${asset.originalPath}.xmp`;
|
const sidecarPath = `${asset.originalPath}.xmp`;
|
||||||
const exists = await this.storageRepository.checkFileExists(sidecarPath, constants.W_OK);
|
const exists = await this.storageRepository.checkFileExists(sidecarPath, constants.R_OK);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ export class UserCore {
|
|||||||
if (!user.profileImagePath) {
|
if (!user.profileImagePath) {
|
||||||
throw new NotFoundException('User does not have a profile image');
|
throw new NotFoundException('User does not have a profile image');
|
||||||
}
|
}
|
||||||
await fs.access(user.profileImagePath, constants.R_OK | constants.W_OK);
|
await fs.access(user.profileImagePath, constants.R_OK);
|
||||||
return createReadStream(user.profileImagePath);
|
return createReadStream(user.profileImagePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,9 +24,8 @@ import {
|
|||||||
StreamableFile,
|
StreamableFile,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { R_OK, W_OK } from 'constants';
|
|
||||||
import { Response as Res } from 'express';
|
import { Response as Res } from 'express';
|
||||||
import { createReadStream, stat } from 'fs';
|
import { constants, createReadStream, stat } from 'fs';
|
||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
import mime from 'mime-types';
|
import mime from 'mime-types';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
@ -156,7 +155,7 @@ export class AssetService {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const exists = await this.storageRepository.checkFileExists(filepath, R_OK);
|
const exists = await this.storageRepository.checkFileExists(filepath, constants.R_OK);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
throw new BadRequestException('File does not exist');
|
throw new BadRequestException('File does not exist');
|
||||||
}
|
}
|
||||||
@ -307,7 +306,7 @@ export class AssetService {
|
|||||||
let videoPath = asset.originalPath;
|
let videoPath = asset.originalPath;
|
||||||
let mimeType = asset.mimeType;
|
let mimeType = asset.mimeType;
|
||||||
|
|
||||||
await fs.access(videoPath, R_OK | W_OK);
|
await fs.access(videoPath, constants.R_OK);
|
||||||
|
|
||||||
if (asset.encodedVideoPath) {
|
if (asset.encodedVideoPath) {
|
||||||
videoPath = asset.encodedVideoPath == '' ? String(asset.originalPath) : String(asset.encodedVideoPath);
|
videoPath = asset.encodedVideoPath == '' ? String(asset.originalPath) : String(asset.encodedVideoPath);
|
||||||
@ -355,8 +354,8 @@ export class AssetService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.streamFile(videoPath, res, headers, mimeType);
|
return this.streamFile(videoPath, res, headers, mimeType);
|
||||||
} catch (e) {
|
} catch (e: Error | any) {
|
||||||
this.logger.error(`Error serving VIDEO asset=${asset.id}`);
|
this.logger.error(`Error serving VIDEO asset=${asset.id}`, e?.stack);
|
||||||
throw new InternalServerErrorException(`Failed to serve video asset ${e}`, 'ServeFile');
|
throw new InternalServerErrorException(`Failed to serve video asset ${e}`, 'ServeFile');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -632,7 +631,7 @@ export class AssetService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await fs.access(filepath, R_OK);
|
await fs.access(filepath, constants.R_OK);
|
||||||
|
|
||||||
return new StreamableFile(createReadStream(filepath));
|
return new StreamableFile(createReadStream(filepath));
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ export class FilesystemProvider implements IStorageRepository {
|
|||||||
|
|
||||||
async createReadStream(filepath: string, mimeType?: string | null): Promise<ImmichReadStream> {
|
async createReadStream(filepath: string, mimeType?: string | null): Promise<ImmichReadStream> {
|
||||||
const { size } = await fs.stat(filepath);
|
const { size } = await fs.stat(filepath);
|
||||||
await fs.access(filepath, constants.R_OK | constants.W_OK);
|
await fs.access(filepath, constants.R_OK);
|
||||||
return {
|
return {
|
||||||
stream: createReadStream(filepath),
|
stream: createReadStream(filepath),
|
||||||
length: size,
|
length: size,
|
||||||
|
Loading…
Reference in New Issue
Block a user