summaryrefslogtreecommitdiff
path: root/packages/backend/src/server
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2023-02-04 14:23:38 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2023-02-04 14:23:38 +0900
commit9bde9edcf68430cb98bc08ff74f6804bd56ecf47 (patch)
treee09781a1f26bae331968902a79253820e3a80e4e /packages/backend/src/server
parentMerge branch 'develop' (diff)
parent13.3.2 (diff)
downloadmisskey-9bde9edcf68430cb98bc08ff74f6804bd56ecf47.tar.gz
misskey-9bde9edcf68430cb98bc08ff74f6804bd56ecf47.tar.bz2
misskey-9bde9edcf68430cb98bc08ff74f6804bd56ecf47.zip
Merge branch 'develop'
Diffstat (limited to 'packages/backend/src/server')
-rw-r--r--packages/backend/src/server/FileServerService.ts73
-rw-r--r--packages/backend/src/server/ServerService.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/meta.ts6
-rw-r--r--packages/backend/src/server/api/endpoints/notes/polls/vote.ts14
-rw-r--r--packages/backend/src/server/api/stream/types.ts2
-rw-r--r--packages/backend/src/server/web/UrlPreviewService.ts10
6 files changed, 68 insertions, 39 deletions
diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts
index 40024270ae..39bc4c1d96 100644
--- a/packages/backend/src/server/FileServerService.ts
+++ b/packages/backend/src/server/FileServerService.ts
@@ -137,38 +137,38 @@ export class FileServerService {
try {
if (file.state === 'remote') {
- const convertFile = async () => {
- if (file.fileRole === 'thumbnail') {
- if (['image/jpeg', 'image/webp', 'image/avif', 'image/png', 'image/svg+xml'].includes(file.mime)) {
- return this.imageProcessingService.convertToWebpStream(
- file.path,
- 498,
- 280
- );
- } else if (file.mime.startsWith('video/')) {
- return await this.videoProcessingService.generateVideoThumbnail(file.path);
- }
+ let image: IImageStreamable | null = null;
+
+ if (file.fileRole === 'thumbnail') {
+ if (isMimeImage(file.mime, 'sharp-convertible-image')) {
+ reply.header('Cache-Control', 'max-age=31536000, immutable');
+
+ const url = new URL(`${this.config.mediaProxy}/static.webp`);
+ url.searchParams.set('url', file.url);
+ url.searchParams.set('static', '1');
+ return await reply.redirect(301, url.toString());
+ } else if (file.mime.startsWith('video/')) {
+ image = await this.videoProcessingService.generateVideoThumbnail(file.path);
}
+ }
- if (file.fileRole === 'webpublic') {
- if (['image/svg+xml'].includes(file.mime)) {
- return this.imageProcessingService.convertToWebpStream(
- file.path,
- 2048,
- 2048,
- { ...webpDefault, lossless: true }
- )
- }
+ if (file.fileRole === 'webpublic') {
+ if (['image/svg+xml'].includes(file.mime)) {
+ reply.header('Cache-Control', 'max-age=31536000, immutable');
+
+ const url = new URL(`${this.config.mediaProxy}/svg.webp`);
+ url.searchParams.set('url', file.url);
+ return await reply.redirect(301, url.toString());
}
+ }
- return {
+ if (!image) {
+ image = {
data: fs.createReadStream(file.path),
ext: file.ext,
type: file.mime,
};
- };
-
- const image = await convertFile();
+ }
if ('pipe' in image.data && typeof image.data.pipe === 'function') {
// image.dataがstreamなら、stream終了後にcleanup
@@ -180,7 +180,6 @@ export class FileServerService {
}
reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(image.type) ? image.type : 'application/octet-stream');
- reply.header('Cache-Control', 'max-age=31536000, immutable');
return image.data;
}
@@ -217,6 +216,23 @@ export class FileServerService {
return;
}
+ if (this.config.externalMediaProxyEnabled) {
+ // 外部のメディアプロキシが有効なら、そちらにリダイレクト
+
+ reply.header('Cache-Control', 'public, max-age=259200'); // 3 days
+
+ const url = new URL(`${this.config.mediaProxy}/${request.params.url || ''}`);
+
+ for (const [key, value] of Object.entries(request.query)) {
+ url.searchParams.append(key, value);
+ }
+
+ return await reply.redirect(
+ 301,
+ url.toString(),
+ );
+ }
+
// Create temp file
const file = await this.getStreamAndTypeFromUrl(url);
if (file === '404') {
@@ -236,7 +252,7 @@ export class FileServerService {
const isAnimationConvertibleImage = isMimeImage(file.mime, 'sharp-animation-convertible-image');
let image: IImageStreamable | null = null;
- if ('emoji' in request.query && isConvertibleImage) {
+ if (('emoji' in request.query || 'avatar' in request.query) && isConvertibleImage) {
if (!isAnimationConvertibleImage && !('static' in request.query)) {
image = {
data: fs.createReadStream(file.path),
@@ -246,7 +262,7 @@ export class FileServerService {
} else {
const data = sharp(file.path, { animated: !('static' in request.query) })
.resize({
- height: 128,
+ height: 'emoji' in request.query ? 128 : 320,
withoutEnlargement: true,
})
.webp(webpDefault);
@@ -370,7 +386,7 @@ export class FileServerService {
@bindThis
private async getFileFromKey(key: string): Promise<
- { state: 'remote'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; mime: string; ext: string | null; path: string; cleanup: () => void; }
+ { state: 'remote'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; url: string; mime: string; ext: string | null; path: string; cleanup: () => void; }
| { state: 'stored_internal'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; mime: string; ext: string | null; path: string; }
| '404'
| '204'
@@ -392,6 +408,7 @@ export class FileServerService {
const result = await this.downloadAndDetectTypeFromUrl(file.uri);
return {
...result,
+ url: file.uri,
fileRole: isThumbnail ? 'thumbnail' : isWebpublic ? 'webpublic' : 'original',
file,
}
diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts
index beb3a34ecd..c7a2c99f94 100644
--- a/packages/backend/src/server/ServerService.ts
+++ b/packages/backend/src/server/ServerService.ts
@@ -106,7 +106,7 @@ export class ServerService {
}
}
- const url = new URL('/proxy/emoji.webp', this.config.url);
+ const url = new URL(`${this.config.mediaProxy}/emoji.webp`);
// || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
url.searchParams.set('url', emoji.publicUrl || emoji.originalUrl);
url.searchParams.set('emoji', '1');
diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts
index 3baf945323..2fa7a09d49 100644
--- a/packages/backend/src/server/api/endpoints/meta.ts
+++ b/packages/backend/src/server/api/endpoints/meta.ts
@@ -181,6 +181,10 @@ export const meta = {
type: 'string',
optional: false, nullable: true,
},
+ mediaProxy: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
features: {
type: 'object',
optional: true, nullable: false,
@@ -307,6 +311,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
policies: { ...DEFAULT_POLICIES, ...instance.policies },
+ mediaProxy: this.config.mediaProxy,
+
...(ps.detail ? {
pinnedPages: instance.pinnedPages,
pinnedClipId: instance.pinnedClipId,
diff --git a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts
index d583dfb936..befaea4664 100644
--- a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts
+++ b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts
@@ -1,6 +1,6 @@
import { Not } from 'typeorm';
import { Inject, Injectable } from '@nestjs/common';
-import type { UsersRepository, BlockingsRepository, PollsRepository, PollVotesRepository } from '@/models/index.js';
+import type { UsersRepository, PollsRepository, PollVotesRepository } from '@/models/index.js';
import type { IRemoteUser } from '@/models/entities/User.js';
import { IdService } from '@/core/IdService.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
@@ -11,6 +11,7 @@ import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { CreateNotificationService } from '@/core/CreateNotificationService.js';
import { DI } from '@/di-symbols.js';
+import { UserBlockingService } from '@/core/UserBlockingService.js';
import { ApiError } from '../../../error.js';
export const meta = {
@@ -77,9 +78,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
- @Inject(DI.blockingsRepository)
- private blockingsRepository: BlockingsRepository,
-
@Inject(DI.pollsRepository)
private pollsRepository: PollsRepository,
@@ -93,6 +91,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private apRendererService: ApRendererService,
private globalEventService: GlobalEventService,
private createNotificationService: CreateNotificationService,
+ private userBlockingService: UserBlockingService,
) {
super(meta, paramDef, async (ps, me) => {
const createdAt = new Date();
@@ -109,11 +108,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
// Check blocking
if (note.userId !== me.id) {
- const block = await this.blockingsRepository.findOneBy({
- blockerId: note.userId,
- blockeeId: me.id,
- });
- if (block) {
+ const blocked = await this.userBlockingService.checkBlocked(note.userId, me.id);
+ if (blocked) {
throw new ApiError(meta.errors.youHaveBeenBlocked);
}
}
diff --git a/packages/backend/src/server/api/stream/types.ts b/packages/backend/src/server/api/stream/types.ts
index 36bfa78363..8bb4147b43 100644
--- a/packages/backend/src/server/api/stream/types.ts
+++ b/packages/backend/src/server/api/stream/types.ts
@@ -25,6 +25,8 @@ export interface InternalStreamTypes {
remoteUserUpdated: { id: User['id']; };
follow: { followerId: User['id']; followeeId: User['id']; };
unfollow: { followerId: User['id']; followeeId: User['id']; };
+ blockingCreated: { blockerId: User['id']; blockeeId: User['id']; };
+ blockingDeleted: { blockerId: User['id']; blockeeId: User['id']; };
policiesUpdated: Role['policies'];
roleCreated: Role;
roleDeleted: Role;
diff --git a/packages/backend/src/server/web/UrlPreviewService.ts b/packages/backend/src/server/web/UrlPreviewService.ts
index 802b404ce6..57461b7a33 100644
--- a/packages/backend/src/server/web/UrlPreviewService.ts
+++ b/packages/backend/src/server/web/UrlPreviewService.ts
@@ -33,7 +33,7 @@ export class UrlPreviewService {
private wrap(url?: string): string | null {
return url != null
? url.match(/^https?:\/\//)
- ? `${this.config.url}/proxy/preview.webp?${query({
+ ? `${this.config.mediaProxy}/preview.webp?${query({
url,
preview: '1',
})}`
@@ -73,6 +73,14 @@ export class UrlPreviewService {
});
this.logger.succ(`Got preview of ${url}: ${summary.title}`);
+
+ if (summary.url && !(summary.url.startsWith('http://') || summary.url.startsWith('https://'))) {
+ throw new Error('unsupported schema included');
+ }
+
+ if (summary.player?.url && !(summary.player.url.startsWith('http://') || summary.player.url.startsWith('https://'))) {
+ throw new Error('unsupported schema included');
+ }
summary.icon = this.wrap(summary.icon);
summary.thumbnail = this.wrap(summary.thumbnail);