iceshrimp/src/server/file/send-drive-file.ts

102 lines
3.0 KiB
TypeScript
Raw Normal View History

2018-04-13 06:06:18 +09:00
import * as Koa from 'koa';
import * as send from 'koa-send';
import * as mongodb from 'mongodb';
import * as rename from 'rename';
import DriveFile, { getDriveFileBucket } from '../../models/drive-file';
import DriveFileThumbnail, { getDriveFileThumbnailBucket } from '../../models/drive-file-thumbnail';
import DriveFileWebpublic, { getDriveFileWebpublicBucket } from '../../models/drive-file-webpublic';
import { serverLogger } from '..';
import { contentDisposition } from '../../misc/content-disposition';
2018-05-04 17:59:51 +09:00
const assets = `${__dirname}/../../server/file/assets/`;
2019-01-22 21:42:05 +09:00
const commonReadableHandlerGenerator = (ctx: Koa.BaseContext) => (e: Error): void => {
serverLogger.error(e);
ctx.status = 500;
};
2018-04-13 06:06:18 +09:00
2019-01-22 21:42:05 +09:00
export default async function(ctx: Koa.BaseContext) {
2018-04-13 06:06:18 +09:00
// Validate id
if (!mongodb.ObjectID.isValid(ctx.params.id)) {
ctx.throw(400, 'incorrect id');
return;
}
const fileId = new mongodb.ObjectID(ctx.params.id);
// Fetch drive file
const file = await DriveFile.findOne({ _id: fileId });
if (file == null) {
ctx.status = 404;
2019-01-22 21:42:05 +09:00
await send(ctx as any, '/dummy.png', { root: assets });
2018-04-13 06:06:18 +09:00
return;
}
2018-04-17 20:04:19 +09:00
if (file.metadata.deletedAt) {
ctx.status = 410;
2019-01-22 21:42:05 +09:00
await send(ctx as any, '/tombstone.png', { root: assets });
return;
}
2018-07-24 05:04:43 +09:00
if (file.metadata.withoutChunks) {
ctx.status = 204;
2018-04-17 20:04:19 +09:00
return;
}
2018-05-03 20:12:08 +09:00
const sendRaw = async () => {
if (file.metadata && file.metadata.accessKey && file.metadata.accessKey != ctx.query['original']) {
ctx.status = 403;
return;
}
2018-05-03 20:12:08 +09:00
const bucket = await getDriveFileBucket();
const readable = bucket.openDownloadStream(fileId);
readable.on('error', commonReadableHandlerGenerator(ctx));
ctx.set('Content-Type', file.contentType);
ctx.body = readable;
};
if ('thumbnail' in ctx.query) {
2018-08-16 07:17:04 +09:00
const thumb = await DriveFileThumbnail.findOne({
'metadata.originalId': fileId
});
if (thumb != null) {
ctx.set('Content-Type', 'image/jpeg');
2019-03-25 03:12:08 +09:00
ctx.set('Content-Disposition', contentDisposition('inline', `${rename(file.filename, { suffix: '-thumb', extname: '.jpeg' })}`));
2018-08-16 07:17:04 +09:00
const bucket = await getDriveFileThumbnailBucket();
ctx.body = bucket.openDownloadStream(thumb._id);
} else {
if (file.contentType.startsWith('image/')) {
2019-03-25 03:12:08 +09:00
ctx.set('Content-Disposition', contentDisposition('inline', `${file.filename}`));
await sendRaw();
} else {
ctx.status = 404;
await send(ctx as any, '/dummy.png', { root: assets });
}
}
} else if ('web' in ctx.query) {
const web = await DriveFileWebpublic.findOne({
'metadata.originalId': fileId
});
if (web != null) {
ctx.set('Content-Type', file.contentType);
2019-03-25 03:12:08 +09:00
ctx.set('Content-Disposition', contentDisposition('inline', `${rename(file.filename, { suffix: '-web' })}`));
const bucket = await getDriveFileWebpublicBucket();
ctx.body = bucket.openDownloadStream(web._id);
} else {
2019-03-25 03:12:08 +09:00
ctx.set('Content-Disposition', contentDisposition('inline', `${file.filename}`));
await sendRaw();
}
} else {
if ('download' in ctx.query) {
ctx.set('Content-Disposition', contentDisposition('attachment', `${file.filename}`));
}
2018-04-13 06:06:18 +09:00
2018-05-03 20:12:08 +09:00
await sendRaw();
}
2018-04-13 06:06:18 +09:00
}