Merge remote-tracking branch 'origin/main' into dev/asset-access-control

This commit is contained in:
Matthias Rupp
2022-12-01 17:12:12 +01:00
122 changed files with 2012 additions and 940 deletions
@@ -306,7 +306,12 @@ export class AssetService {
}
}
public async getAssetThumbnail(assetId: string, query: GetAssetThumbnailDto, res: Res) {
public async getAssetThumbnail(
assetId: string,
query: GetAssetThumbnailDto,
res: Res,
headers: Record<string, string>,
) {
let fileReadStream: ReadStream;
const asset = await this.assetRepository.findOne({ where: { id: assetId } });
@@ -316,28 +321,22 @@ export class AssetService {
}
try {
if (query.format == GetAssetThumbnailFormatEnum.JPEG) {
if (query.format == GetAssetThumbnailFormatEnum.WEBP && asset.webpPath && asset.webpPath.length > 0) {
if (await processETag(asset.webpPath, res, headers)) {
return;
}
await fs.access(asset.webpPath, constants.R_OK);
fileReadStream = createReadStream(asset.webpPath);
} else {
if (!asset.resizePath) {
throw new NotFoundException('resizePath not set');
}
await fs.access(asset.resizePath, constants.R_OK | constants.W_OK);
fileReadStream = createReadStream(asset.resizePath);
} else {
if (asset.webpPath && asset.webpPath.length > 0) {
await fs.access(asset.webpPath, constants.R_OK | constants.W_OK);
fileReadStream = createReadStream(asset.webpPath);
} else {
if (!asset.resizePath) {
throw new NotFoundException('resizePath not set');
}
await fs.access(asset.resizePath, constants.R_OK | constants.W_OK);
fileReadStream = createReadStream(asset.resizePath);
if (await processETag(asset.resizePath, res, headers)) {
return;
}
await fs.access(asset.resizePath, constants.R_OK);
fileReadStream = createReadStream(asset.resizePath);
}
res.header('Cache-Control', 'max-age=300');
return new StreamableFile(fileReadStream);
} catch (e) {
res.header('Cache-Control', 'none');
@@ -349,7 +348,7 @@ export class AssetService {
}
}
public async serveFile(assetId: string, query: ServeFileDto, res: Res, headers: any) {
public async serveFile(assetId: string, query: ServeFileDto, res: Res, headers: Record<string, string>) {
let fileReadStream: ReadStream;
const asset = await this._assetRepository.getById(assetId);
@@ -371,6 +370,9 @@ export class AssetService {
Logger.error('Error serving IMAGE asset for web', 'ServeFile');
throw new InternalServerErrorException(`Failed to serve image asset for web`, 'ServeFile');
}
if (await processETag(asset.resizePath, res, headers)) {
return;
}
await fs.access(asset.resizePath, constants.R_OK | constants.W_OK);
fileReadStream = createReadStream(asset.resizePath);
@@ -384,7 +386,9 @@ export class AssetService {
res.set({
'Content-Type': asset.mimeType,
});
if (await processETag(asset.originalPath, res, headers)) {
return;
}
await fs.access(asset.originalPath, constants.R_OK | constants.W_OK);
fileReadStream = createReadStream(asset.originalPath);
} else {
@@ -392,7 +396,9 @@ export class AssetService {
res.set({
'Content-Type': 'image/webp',
});
if (await processETag(asset.webpPath, res, headers)) {
return;
}
await fs.access(asset.webpPath, constants.R_OK | constants.W_OK);
fileReadStream = createReadStream(asset.webpPath);
} else {
@@ -403,6 +409,9 @@ export class AssetService {
if (!asset.resizePath) {
throw new Error('resizePath not set');
}
if (await processETag(asset.resizePath, res, headers)) {
return;
}
await fs.access(asset.resizePath, constants.R_OK | constants.W_OK);
fileReadStream = createReadStream(asset.resizePath);
@@ -436,9 +445,9 @@ export class AssetService {
if (range) {
/** Extracting Start and End value from Range Header */
let [start, end] = range.replace(/bytes=/, '').split('-');
start = parseInt(start, 10);
end = end ? parseInt(end, 10) : size - 1;
const [startStr, endStr] = range.replace(/bytes=/, '').split('-');
let start = parseInt(startStr, 10);
let end = endStr ? parseInt(endStr, 10) : size - 1;
if (!isNaN(start) && isNaN(end)) {
start = start;
@@ -475,7 +484,9 @@ export class AssetService {
res.set({
'Content-Type': mimeType,
});
if (await processETag(asset.originalPath, res, headers)) {
return;
}
return new StreamableFile(createReadStream(videoPath));
}
} catch (e) {
@@ -651,3 +662,14 @@ export class AssetService {
}
}
}
async function processETag(path: string, res: Res, headers: Record<string, string>): Promise<boolean> {
const { size, mtimeNs } = await fs.stat(path, { bigint: true });
const etag = `W/"${size}-${mtimeNs}"`;
res.setHeader('ETag', etag);
if (etag === headers['if-none-match']) {
res.status(304);
return true;
}
return false;
}