feat: URLプレビューのリダイレクトを受け入れるかどうかを設定できるようにする (#16112)

* feat: URLプレビューのリダイレクトを受け入れるかどうかを設定できるようにする

* fix CHANGELOG.md

* fix lang
This commit is contained in:
おさむのひと 2025-05-27 20:46:22 +09:00 committed by GitHub
parent 97e916c912
commit 9bbc2028ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 54 additions and 3 deletions

View File

@ -16,6 +16,7 @@
- デフォルトは**テキスト、JSON、画像、動画、音声ファイル**になっています。zipなど、その他の種別のファイルは含まれていないため、必要に応じて設定を変更してください。
- 場合によってはファイル種別を正しく検出できないことがあります(特にテキストフォーマット)。その場合、ファイル種別は application/octet-stream と見做されます。
- したがって、それらの種別不明ファイルを許可したい場合は application/octet-stream を指定に追加してください。
- Feat: プレビュー先がリダイレクトを伴う場合、リダイレクト先のコンテンツを取得しに行くか否かを設定できるように(#16043)
- Enhance: UIのアイコンデータの読み込みを軽量化
### Client

8
locales/index.d.ts vendored
View File

@ -11232,6 +11232,14 @@ export interface Locale extends ILocale {
* URLプレビューを有効にする
*/
"enable": string;
/**
*
*/
"allowRedirect": string;
/**
* URLがリダイレクトされる場合に
*/
"allowRedirectDescription": string;
/**
* (ms)
*/

View File

@ -2987,6 +2987,8 @@ _offlineScreen:
_urlPreviewSetting:
title: "URLプレビューの設定"
enable: "URLプレビューを有効にする"
allowRedirect: "プレビュー先のリダイレクトを許可"
allowRedirectDescription: "入力されたURLがリダイレクトされる場合に、そのリダイレクト先をたどってプレビューを表示するかどうかを設定します。無効にするとサーバーリソースの節約になりますが、リダイレクト先の内容は表示されなくなります。"
timeout: "プレビュー取得時のタイムアウト(ms)"
timeoutDescription: "プレビュー取得の所要時間がこの値を超えた場合、プレビューは生成されません。"
maximumContentLength: "Content-Lengthの最大値(byte)"

View File

@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class AddUrlPreviewAllowRedirect1748310233000 {
name = 'AddUrlPreviewAllowRedirect1748310233000'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "urlPreviewAllowRedirect" boolean NOT NULL DEFAULT true`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "urlPreviewAllowRedirect"`);
}
}

View File

@ -619,6 +619,11 @@ export class MiMeta {
})
public urlPreviewEnabled: boolean;
@Column('boolean', {
default: true,
})
public urlPreviewAllowRedirect: boolean;
@Column('integer', {
default: 10000,
})

View File

@ -495,6 +495,10 @@ export const meta = {
type: 'boolean',
optional: false, nullable: false,
},
urlPreviewAllowRedirect: {
type: 'boolean',
optional: false, nullable: false,
},
urlPreviewTimeout: {
type: 'number',
optional: false, nullable: false,
@ -704,6 +708,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
notesPerOneAd: instance.notesPerOneAd,
summalyProxy: instance.urlPreviewSummaryProxyUrl,
urlPreviewEnabled: instance.urlPreviewEnabled,
urlPreviewAllowRedirect: instance.urlPreviewAllowRedirect,
urlPreviewTimeout: instance.urlPreviewTimeout,
urlPreviewMaximumContentLength: instance.urlPreviewMaximumContentLength,
urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength,

View File

@ -170,6 +170,7 @@ export const paramDef = {
description: '[Deprecated] Use "urlPreviewSummaryProxyUrl" instead.',
},
urlPreviewEnabled: { type: 'boolean' },
urlPreviewAllowRedirect: { type: 'boolean' },
urlPreviewTimeout: { type: 'integer' },
urlPreviewMaximumContentLength: { type: 'integer' },
urlPreviewRequireContentLength: { type: 'boolean' },
@ -664,6 +665,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
set.urlPreviewEnabled = ps.urlPreviewEnabled;
}
if (ps.urlPreviewAllowRedirect !== undefined) {
set.urlPreviewAllowRedirect = ps.urlPreviewAllowRedirect;
}
if (ps.urlPreviewTimeout !== undefined) {
set.urlPreviewTimeout = ps.urlPreviewTimeout;
}

View File

@ -122,7 +122,7 @@ export class UrlPreviewService {
: undefined;
return summaly(url, {
followRedirects: false,
followRedirects: this.meta.urlPreviewAllowRedirect,
lang: lang ?? 'ja-JP',
agent: agent,
userAgent: meta.urlPreviewUserAgent ?? undefined,
@ -137,6 +137,7 @@ export class UrlPreviewService {
const queryStr = query({
url: url,
lang: lang ?? 'ja-JP',
followRedirects: this.meta.urlPreviewAllowRedirect,
userAgent: meta.urlPreviewUserAgent ?? undefined,
operationTimeout: meta.urlPreviewTimeout,
contentLengthLimit: meta.urlPreviewMaximumContentLength,

View File

@ -146,6 +146,11 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkSwitch>
<template v-if="urlPreviewForm.state.urlPreviewEnabled">
<MkSwitch v-model="urlPreviewForm.state.urlPreviewAllowRedirect">
<template #label>{{ i18n.ts._urlPreviewSetting.allowRedirect }}<span v-if="urlPreviewForm.modifiedStates.urlPreviewAllowRedirect" class="_modified">{{ i18n.ts.modified }}</span></template>
<template #caption>{{ i18n.ts._urlPreviewSetting.allowRedirectDescription }}</template>
</MkSwitch>
<MkSwitch v-model="urlPreviewForm.state.urlPreviewRequireContentLength">
<template #label>{{ i18n.ts._urlPreviewSetting.requireContentLength }}<span v-if="urlPreviewForm.modifiedStates.urlPreviewRequireContentLength" class="_modified">{{ i18n.ts.modified }}</span></template>
<template #caption>{{ i18n.ts._urlPreviewSetting.requireContentLengthDescription }}</template>
@ -288,7 +293,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import { ref, computed, reactive } from 'vue';
import { computed } from 'vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkInput from '@/components/MkInput.vue';
import MkTextarea from '@/components/MkTextarea.vue';
@ -301,7 +306,6 @@ import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import MkButton from '@/components/MkButton.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkKeyValue from '@/components/MkKeyValue.vue';
import { useForm } from '@/composables/use-form.js';
import MkFormFooter from '@/components/MkFormFooter.vue';
import MkRadios from '@/components/MkRadios.vue';
@ -370,6 +374,7 @@ const adForm = useForm({
const urlPreviewForm = useForm({
urlPreviewEnabled: meta.urlPreviewEnabled,
urlPreviewAllowRedirect: meta.urlPreviewAllowRedirect,
urlPreviewTimeout: meta.urlPreviewTimeout,
urlPreviewMaximumContentLength: meta.urlPreviewMaximumContentLength,
urlPreviewRequireContentLength: meta.urlPreviewRequireContentLength,
@ -378,6 +383,7 @@ const urlPreviewForm = useForm({
}, async (state) => {
await os.apiWithDialog('admin/update-meta', {
urlPreviewEnabled: state.urlPreviewEnabled,
urlPreviewAllowRedirect: state.urlPreviewAllowRedirect,
urlPreviewTimeout: state.urlPreviewTimeout,
urlPreviewMaximumContentLength: state.urlPreviewMaximumContentLength,
urlPreviewRequireContentLength: state.urlPreviewRequireContentLength,

View File

@ -8809,6 +8809,7 @@ export type operations = {
uri: string;
version: string;
urlPreviewEnabled: boolean;
urlPreviewAllowRedirect: boolean;
urlPreviewTimeout: number;
urlPreviewMaximumContentLength: number;
urlPreviewRequireContentLength: boolean;
@ -11536,6 +11537,7 @@ export type operations = {
/** @description [Deprecated] Use "urlPreviewSummaryProxyUrl" instead. */
summalyProxy?: string | null;
urlPreviewEnabled?: boolean;
urlPreviewAllowRedirect?: boolean;
urlPreviewTimeout?: number;
urlPreviewMaximumContentLength?: number;
urlPreviewRequireContentLength?: boolean;