diff options
Diffstat (limited to 'packages/backend/src/server/web/ClientServerService.ts')
| -rw-r--r-- | packages/backend/src/server/web/ClientServerService.ts | 100 |
1 files changed, 83 insertions, 17 deletions
diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts index aa696046ea..cb41c4f338 100644 --- a/packages/backend/src/server/web/ClientServerService.ts +++ b/packages/backend/src/server/web/ClientServerService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -19,6 +19,7 @@ import fastifyView from '@fastify/view'; import fastifyCookie from '@fastify/cookie'; import fastifyProxy from '@fastify/http-proxy'; import vary from 'vary'; +import htmlSafeJsonStringify from 'htmlescape'; import type { Config } from '@/config.js'; import { getNoteSummary } from '@/misc/get-note-summary.js'; import { DI } from '@/di-symbols.js'; @@ -28,15 +29,17 @@ import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, Obj import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { PageEntityService } from '@/core/entities/PageEntityService.js'; +import { MetaEntityService } from '@/core/entities/MetaEntityService.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { ClipEntityService } from '@/core/entities/ClipEntityService.js'; import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js'; -import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, MiMeta, NotesRepository, PagesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; +import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, MiMeta, NotesRepository, PagesRepository, ReversiGamesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; import type Logger from '@/logger.js'; -import { deepClone } from '@/misc/clone.js'; +import { handleRequestRedirectToOmitSearch } from '@/misc/fastify-hook-handlers.js'; import { bindThis } from '@/decorators.js'; import { FlashEntityService } from '@/core/entities/FlashEntityService.js'; import { RoleService } from '@/core/RoleService.js'; +import { ReversiGameEntityService } from '@/core/entities/ReversiGameEntityService.js'; import { FeedService } from './FeedService.js'; import { UrlPreviewService } from './UrlPreviewService.js'; import { ClientLoggerService } from './ClientLoggerService.js'; @@ -50,6 +53,7 @@ const clientAssets = `${_dirname}/../../../../frontend/assets/`; const assets = `${_dirname}/../../../../../built/_frontend_dist_/`; const swAssets = `${_dirname}/../../../../../built/_sw_dist_/`; const viteOut = `${_dirname}/../../../../../built/_vite_/`; +const tarball = `${_dirname}/../../../../../built/tarball/`; @Injectable() export class ClientServerService { @@ -83,13 +87,18 @@ export class ClientServerService { @Inject(DI.flashsRepository) private flashsRepository: FlashsRepository, + @Inject(DI.reversiGamesRepository) + private reversiGamesRepository: ReversiGamesRepository, + private flashEntityService: FlashEntityService, private userEntityService: UserEntityService, private noteEntityService: NoteEntityService, private pageEntityService: PageEntityService, + private metaEntityService: MetaEntityService, private galleryPostEntityService: GalleryPostEntityService, private clipEntityService: ClipEntityService, private channelEntityService: ChannelEntityService, + private reversiGameEntityService: ReversiGameEntityService, private metaService: MetaService, private urlPreviewService: UrlPreviewService, private feedService: FeedService, @@ -168,7 +177,7 @@ export class ClientServerService { } @bindThis - private generateCommonPugData(meta: MiMeta) { + private async generateCommonPugData(meta: MiMeta) { return { instanceName: meta.name ?? 'Sharkey', icon: meta.iconUrl, @@ -179,6 +188,8 @@ export class ClientServerService { notFoundImageUrl: meta.notFoundImageUrl ?? 'https://launcher.moe/missingpage.webp', instanceUrl: this.config.url, randomMOTD: this.config.customMOTD ? this.config.customMOTD[Math.floor(Math.random() * this.config.customMOTD.length)] : undefined, + metaJson: htmlSafeJsonStringify(await this.metaEntityService.packDetailed(meta)), + now: Date.now(), }; } @@ -250,11 +261,16 @@ export class ClientServerService { //#region vite assets if (this.config.clientManifestExists) { - fastify.register(fastifyStatic, { - root: viteOut, - prefix: '/vite/', - maxAge: ms('30 days'), - decorateReply: false, + fastify.register((fastify, options, done) => { + fastify.register(fastifyStatic, { + root: viteOut, + prefix: '/vite/', + maxAge: ms('30 days'), + immutable: true, + decorateReply: false, + }); + fastify.addHook('onRequest', handleRequestRedirectToOmitSearch); + done(); }); } else { const port = (process.env.VITE_PORT ?? '5173'); @@ -289,6 +305,18 @@ export class ClientServerService { decorateReply: false, }); + fastify.register((fastify, options, done) => { + fastify.register(fastifyStatic, { + root: tarball, + prefix: '/tarball/', + maxAge: ms('30 days'), + immutable: true, + decorateReply: false, + }); + fastify.addHook('onRequest', handleRequestRedirectToOmitSearch); + done(); + }); + fastify.get('/favicon.ico', async (request, reply) => { return reply.sendFile('/favicon.ico', staticAssets); }); @@ -327,6 +355,21 @@ export class ClientServerService { }); }); + fastify.get<{ Params: { path: string } }>('/tossface/:path(.*)', async (request, reply) => { + const path = request.params.path; + + if (!path.match(/^[0-9a-f-]+\.svg$/)) { + reply.code(404); + return; + } + + reply.header('Content-Security-Policy', 'default-src \'none\'; style-src \'unsafe-inline\''); + + return await reply.sendFile(path, `${_dirname}/../../../../../tossface-emojis/dist`, { + maxAge: ms('30 days'), + }); + }); + fastify.get<{ Params: { path: string } }>('/twemoji-badge/:path(.*)', async (request, reply) => { const path = request.params.path; @@ -412,7 +455,7 @@ export class ClientServerService { url: this.config.url, title: meta.name ?? 'Misskey', desc: meta.description, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); }; @@ -479,6 +522,8 @@ export class ClientServerService { isSuspended: false, }); + vary(reply.raw, 'Accept'); + if (user != null) { const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); const meta = await this.metaService.fetch(); @@ -497,7 +542,7 @@ export class ClientServerService { user, profile, me, avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user), sub: request.params.sub, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { // リモートユーザーなので @@ -518,6 +563,8 @@ export class ClientServerService { return; } + vary(reply.raw, 'Accept'); + reply.redirect(`/@${user.username}${ user.host == null ? '' : '@' + user.host}`); }); @@ -545,7 +592,7 @@ export class ClientServerService { avatarUrl: _note.user.avatarUrl, // TODO: Let locale changeable by instance setting summary: getNoteSummary(_note), - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -584,7 +631,7 @@ export class ClientServerService { page: _page, profile, avatarUrl: _page.user.avatarUrl, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -610,7 +657,7 @@ export class ClientServerService { flash: _flash, profile, avatarUrl: _flash.user.avatarUrl, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -636,7 +683,7 @@ export class ClientServerService { clip: _clip, profile, avatarUrl: _clip.user.avatarUrl, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -660,7 +707,7 @@ export class ClientServerService { post: _post, profile, avatarUrl: _post.user.avatarUrl, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -679,7 +726,26 @@ export class ClientServerService { reply.header('Cache-Control', 'public, max-age=15'); return await reply.view('channel', { channel: _channel, - ...this.generateCommonPugData(meta), + ...await this.generateCommonPugData(meta), + }); + } else { + return await renderBase(reply); + } + }); + + // Reversi game + fastify.get<{ Params: { game: string; } }>('/reversi/g/:game', async (request, reply) => { + const game = await this.reversiGamesRepository.findOneBy({ + id: request.params.game, + }); + + if (game) { + const _game = await this.reversiGameEntityService.packDetail(game); + const meta = await this.metaService.fetch(); + reply.header('Cache-Control', 'public, max-age=3600'); + return await reply.view('reversi-game', { + game: _game, + ...await this.generateCommonPugData(meta), }); } else { return await renderBase(reply); |