From 4735ae64516a82b525a8dfd16a04c4b91d1f23c0 Mon Sep 17 00:00:00 2001 From: tamaina Date: Thu, 26 Jan 2023 16:06:29 +0900 Subject: refactor: /proxyをFileServerServiceに統合し、/proxyのurlで/filesが指定されていた場合は直接ファイルを解決するようにする (#9709) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip? * clean up * Implement? HttpFetchService * :v: * remove node-fetch * fix * refactor * fix * gateway timeout * UndiciFetcherクラスを追加 (仮コミット, ビルドもstartもさせていない) * fix * add logger and fix url preview * fix ip check * enhance logger and error handling * fix * fix * clean up * Use custom fetcher for ApRequest / ApResolver * bypassProxyはproxyBypassHostsに判断を委譲するように * set maxRedirections (default 3, ApRequest/ApResolver: 0) * fix * wip???? * wip * :v: * set .node-version * clean up * refactor * clean up * refactor * refactor detectRequestType * rename detectResponseType * :v: * fix * wip * clean up * no got * remove got * wip * :v: * fix * clean up * remove unnnecessary const * good cleanup * no stream * Revert "no stream" This reverts commit 636f9192fcd2b17e71bbf6b5b106b490e0f66244. * fix * cache-control: max-age=300 to error * refactor cleanup --- .../backend/src/server/MediaProxyServerService.ts | 177 --------------------- 1 file changed, 177 deletions(-) delete mode 100644 packages/backend/src/server/MediaProxyServerService.ts (limited to 'packages/backend/src/server/MediaProxyServerService.ts') diff --git a/packages/backend/src/server/MediaProxyServerService.ts b/packages/backend/src/server/MediaProxyServerService.ts deleted file mode 100644 index 5b76f15020..0000000000 --- a/packages/backend/src/server/MediaProxyServerService.ts +++ /dev/null @@ -1,177 +0,0 @@ -import * as fs from 'node:fs'; -import { fileURLToPath } from 'node:url'; -import { dirname } from 'node:path'; -import { Inject, Injectable } from '@nestjs/common'; -import sharp from 'sharp'; -import fastifyStatic from '@fastify/static'; -import { DI } from '@/di-symbols.js'; -import type { Config } from '@/config.js'; -import { isMimeImage } from '@/misc/is-mime-image.js'; -import { createTemp } from '@/misc/create-temp.js'; -import { DownloadService } from '@/core/DownloadService.js'; -import { ImageProcessingService, webpDefault } from '@/core/ImageProcessingService.js'; -import type { IImage } from '@/core/ImageProcessingService.js'; -import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; -import { StatusError } from '@/misc/status-error.js'; -import type Logger from '@/logger.js'; -import { FileInfoService } from '@/core/FileInfoService.js'; -import { LoggerService } from '@/core/LoggerService.js'; -import { bindThis } from '@/decorators.js'; -import type { FastifyInstance, FastifyPluginOptions, FastifyReply, FastifyRequest } from 'fastify'; - -const _filename = fileURLToPath(import.meta.url); -const _dirname = dirname(_filename); - -const assets = `${_dirname}/../../src/server/assets/`; - -@Injectable() -export class MediaProxyServerService { - private logger: Logger; - - constructor( - @Inject(DI.config) - private config: Config, - - private fileInfoService: FileInfoService, - private downloadService: DownloadService, - private imageProcessingService: ImageProcessingService, - private loggerService: LoggerService, - ) { - this.logger = this.loggerService.getLogger('server', 'gray', false); - - //this.createServer = this.createServer.bind(this); - } - - @bindThis - public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) { - fastify.addHook('onRequest', (request, reply, done) => { - reply.header('Content-Security-Policy', 'default-src \'none\'; img-src \'self\'; media-src \'self\'; style-src \'unsafe-inline\''); - done(); - }); - - fastify.register(fastifyStatic, { - root: _dirname, - serve: false, - }); - - fastify.get<{ - Params: { url: string; }; - Querystring: { url?: string; }; - }>('/:url*', async (request, reply) => await this.handler(request, reply)); - - done(); - } - - @bindThis - private async handler(request: FastifyRequest<{ Params: { url: string; }; Querystring: { url?: string; }; }>, reply: FastifyReply) { - const url = 'url' in request.query ? request.query.url : 'https://' + request.params.url; - - if (typeof url !== 'string') { - reply.code(400); - return; - } - - // Create temp file - const [path, cleanup] = await createTemp(); - - try { - await this.downloadService.downloadUrl(url, path); - - const { mime, ext } = await this.fileInfoService.detectType(path); - const isConvertibleImage = isMimeImage(mime, 'sharp-convertible-image'); - const isAnimationConvertibleImage = isMimeImage(mime, 'sharp-animation-convertible-image'); - - let image: IImage; - if ('emoji' in request.query && isConvertibleImage) { - if (!isAnimationConvertibleImage && !('static' in request.query)) { - image = { - data: fs.readFileSync(path), - ext, - type: mime, - }; - } else { - const data = await sharp(path, { animated: !('static' in request.query) }) - .resize({ - height: 128, - withoutEnlargement: true, - }) - .webp(webpDefault) - .toBuffer(); - - image = { - data, - ext: 'webp', - type: 'image/webp', - }; - } - } else if ('static' in request.query && isConvertibleImage) { - image = await this.imageProcessingService.convertToWebp(path, 498, 280); - } else if ('preview' in request.query && isConvertibleImage) { - image = await this.imageProcessingService.convertToWebp(path, 200, 200); - } else if ('badge' in request.query) { - if (!isConvertibleImage) { - // 画像でないなら404でお茶を濁す - throw new StatusError('Unexpected mime', 404); - } - - const mask = sharp(path) - .resize(96, 96, { - fit: 'inside', - withoutEnlargement: false, - }) - .greyscale() - .normalise() - .linear(1.75, -(128 * 1.75) + 128) // 1.75x contrast - .flatten({ background: '#000' }) - .toColorspace('b-w'); - - const stats = await mask.clone().stats(); - - if (stats.entropy < 0.1) { - // エントロピーがあまりない場合は404にする - throw new StatusError('Skip to provide badge', 404); - } - - const data = sharp({ - create: { width: 96, height: 96, channels: 4, background: { r: 0, g: 0, b: 0, alpha: 0 } }, - }) - .pipelineColorspace('b-w') - .boolean(await mask.png().toBuffer(), 'eor'); - - image = { - data: await data.png().toBuffer(), - ext: 'png', - type: 'image/png', - }; - } else if (mime === 'image/svg+xml') { - image = await this.imageProcessingService.convertToWebp(path, 2048, 2048, webpDefault); - } else if (!mime.startsWith('image/') || !FILE_TYPE_BROWSERSAFE.includes(mime)) { - throw new StatusError('Rejected type', 403, 'Rejected type'); - } else { - image = { - data: fs.readFileSync(path), - ext, - type: mime, - }; - } - - reply.header('Content-Type', image.type); - reply.header('Cache-Control', 'max-age=31536000, immutable'); - return image.data; - } catch (err) { - this.logger.error(`${err}`); - - if ('fallback' in request.query) { - return reply.sendFile('/dummy.png', assets); - } - - if (err instanceof StatusError && (err.statusCode === 302 || err.isClientError)) { - reply.code(err.statusCode); - } else { - reply.code(500); - } - } finally { - cleanup(); - } - } -} -- cgit v1.2.3-freya