feat: URLプレビューのリダイレクトを受け入れるかどうかを設定できるようにする (#16112)
* feat: URLプレビューのリダイレクトを受け入れるかどうかを設定できるようにする * fix CHANGELOG.md * fix lang
This commit is contained in:
parent
97e916c912
commit
9bbc2028ad
|
@ -16,6 +16,7 @@
|
||||||
- デフォルトは**テキスト、JSON、画像、動画、音声ファイル**になっています。zipなど、その他の種別のファイルは含まれていないため、必要に応じて設定を変更してください。
|
- デフォルトは**テキスト、JSON、画像、動画、音声ファイル**になっています。zipなど、その他の種別のファイルは含まれていないため、必要に応じて設定を変更してください。
|
||||||
- 場合によってはファイル種別を正しく検出できないことがあります(特にテキストフォーマット)。その場合、ファイル種別は application/octet-stream と見做されます。
|
- 場合によってはファイル種別を正しく検出できないことがあります(特にテキストフォーマット)。その場合、ファイル種別は application/octet-stream と見做されます。
|
||||||
- したがって、それらの種別不明ファイルを許可したい場合は application/octet-stream を指定に追加してください。
|
- したがって、それらの種別不明ファイルを許可したい場合は application/octet-stream を指定に追加してください。
|
||||||
|
- Feat: プレビュー先がリダイレクトを伴う場合、リダイレクト先のコンテンツを取得しに行くか否かを設定できるように(#16043)
|
||||||
- Enhance: UIのアイコンデータの読み込みを軽量化
|
- Enhance: UIのアイコンデータの読み込みを軽量化
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
|
|
|
@ -11232,6 +11232,14 @@ export interface Locale extends ILocale {
|
||||||
* URLプレビューを有効にする
|
* URLプレビューを有効にする
|
||||||
*/
|
*/
|
||||||
"enable": string;
|
"enable": string;
|
||||||
|
/**
|
||||||
|
* プレビュー先のリダイレクトを許可
|
||||||
|
*/
|
||||||
|
"allowRedirect": string;
|
||||||
|
/**
|
||||||
|
* 入力されたURLがリダイレクトされる場合に、そのリダイレクト先をたどってプレビューを表示するかどうかを設定します。無効にするとサーバーリソースの節約になりますが、リダイレクト先の内容は表示されなくなります。
|
||||||
|
*/
|
||||||
|
"allowRedirectDescription": string;
|
||||||
/**
|
/**
|
||||||
* プレビュー取得時のタイムアウト(ms)
|
* プレビュー取得時のタイムアウト(ms)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2987,6 +2987,8 @@ _offlineScreen:
|
||||||
_urlPreviewSetting:
|
_urlPreviewSetting:
|
||||||
title: "URLプレビューの設定"
|
title: "URLプレビューの設定"
|
||||||
enable: "URLプレビューを有効にする"
|
enable: "URLプレビューを有効にする"
|
||||||
|
allowRedirect: "プレビュー先のリダイレクトを許可"
|
||||||
|
allowRedirectDescription: "入力されたURLがリダイレクトされる場合に、そのリダイレクト先をたどってプレビューを表示するかどうかを設定します。無効にするとサーバーリソースの節約になりますが、リダイレクト先の内容は表示されなくなります。"
|
||||||
timeout: "プレビュー取得時のタイムアウト(ms)"
|
timeout: "プレビュー取得時のタイムアウト(ms)"
|
||||||
timeoutDescription: "プレビュー取得の所要時間がこの値を超えた場合、プレビューは生成されません。"
|
timeoutDescription: "プレビュー取得の所要時間がこの値を超えた場合、プレビューは生成されません。"
|
||||||
maximumContentLength: "Content-Lengthの最大値(byte)"
|
maximumContentLength: "Content-Lengthの最大値(byte)"
|
||||||
|
|
|
@ -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"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -619,6 +619,11 @@ export class MiMeta {
|
||||||
})
|
})
|
||||||
public urlPreviewEnabled: boolean;
|
public urlPreviewEnabled: boolean;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: true,
|
||||||
|
})
|
||||||
|
public urlPreviewAllowRedirect: boolean;
|
||||||
|
|
||||||
@Column('integer', {
|
@Column('integer', {
|
||||||
default: 10000,
|
default: 10000,
|
||||||
})
|
})
|
||||||
|
|
|
@ -495,6 +495,10 @@ export const meta = {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
|
urlPreviewAllowRedirect: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
urlPreviewTimeout: {
|
urlPreviewTimeout: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
@ -704,6 +708,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
notesPerOneAd: instance.notesPerOneAd,
|
notesPerOneAd: instance.notesPerOneAd,
|
||||||
summalyProxy: instance.urlPreviewSummaryProxyUrl,
|
summalyProxy: instance.urlPreviewSummaryProxyUrl,
|
||||||
urlPreviewEnabled: instance.urlPreviewEnabled,
|
urlPreviewEnabled: instance.urlPreviewEnabled,
|
||||||
|
urlPreviewAllowRedirect: instance.urlPreviewAllowRedirect,
|
||||||
urlPreviewTimeout: instance.urlPreviewTimeout,
|
urlPreviewTimeout: instance.urlPreviewTimeout,
|
||||||
urlPreviewMaximumContentLength: instance.urlPreviewMaximumContentLength,
|
urlPreviewMaximumContentLength: instance.urlPreviewMaximumContentLength,
|
||||||
urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength,
|
urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength,
|
||||||
|
|
|
@ -170,6 +170,7 @@ export const paramDef = {
|
||||||
description: '[Deprecated] Use "urlPreviewSummaryProxyUrl" instead.',
|
description: '[Deprecated] Use "urlPreviewSummaryProxyUrl" instead.',
|
||||||
},
|
},
|
||||||
urlPreviewEnabled: { type: 'boolean' },
|
urlPreviewEnabled: { type: 'boolean' },
|
||||||
|
urlPreviewAllowRedirect: { type: 'boolean' },
|
||||||
urlPreviewTimeout: { type: 'integer' },
|
urlPreviewTimeout: { type: 'integer' },
|
||||||
urlPreviewMaximumContentLength: { type: 'integer' },
|
urlPreviewMaximumContentLength: { type: 'integer' },
|
||||||
urlPreviewRequireContentLength: { type: 'boolean' },
|
urlPreviewRequireContentLength: { type: 'boolean' },
|
||||||
|
@ -664,6 +665,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
set.urlPreviewEnabled = ps.urlPreviewEnabled;
|
set.urlPreviewEnabled = ps.urlPreviewEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ps.urlPreviewAllowRedirect !== undefined) {
|
||||||
|
set.urlPreviewAllowRedirect = ps.urlPreviewAllowRedirect;
|
||||||
|
}
|
||||||
|
|
||||||
if (ps.urlPreviewTimeout !== undefined) {
|
if (ps.urlPreviewTimeout !== undefined) {
|
||||||
set.urlPreviewTimeout = ps.urlPreviewTimeout;
|
set.urlPreviewTimeout = ps.urlPreviewTimeout;
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,7 +122,7 @@ export class UrlPreviewService {
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
return summaly(url, {
|
return summaly(url, {
|
||||||
followRedirects: false,
|
followRedirects: this.meta.urlPreviewAllowRedirect,
|
||||||
lang: lang ?? 'ja-JP',
|
lang: lang ?? 'ja-JP',
|
||||||
agent: agent,
|
agent: agent,
|
||||||
userAgent: meta.urlPreviewUserAgent ?? undefined,
|
userAgent: meta.urlPreviewUserAgent ?? undefined,
|
||||||
|
@ -137,6 +137,7 @@ export class UrlPreviewService {
|
||||||
const queryStr = query({
|
const queryStr = query({
|
||||||
url: url,
|
url: url,
|
||||||
lang: lang ?? 'ja-JP',
|
lang: lang ?? 'ja-JP',
|
||||||
|
followRedirects: this.meta.urlPreviewAllowRedirect,
|
||||||
userAgent: meta.urlPreviewUserAgent ?? undefined,
|
userAgent: meta.urlPreviewUserAgent ?? undefined,
|
||||||
operationTimeout: meta.urlPreviewTimeout,
|
operationTimeout: meta.urlPreviewTimeout,
|
||||||
contentLengthLimit: meta.urlPreviewMaximumContentLength,
|
contentLengthLimit: meta.urlPreviewMaximumContentLength,
|
||||||
|
|
|
@ -146,6 +146,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
|
|
||||||
<template v-if="urlPreviewForm.state.urlPreviewEnabled">
|
<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">
|
<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 #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>
|
<template #caption>{{ i18n.ts._urlPreviewSetting.requireContentLengthDescription }}</template>
|
||||||
|
@ -288,7 +293,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, reactive } from 'vue';
|
import { computed } from 'vue';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkTextarea from '@/components/MkTextarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
|
@ -301,7 +306,6 @@ import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
|
||||||
import { useForm } from '@/composables/use-form.js';
|
import { useForm } from '@/composables/use-form.js';
|
||||||
import MkFormFooter from '@/components/MkFormFooter.vue';
|
import MkFormFooter from '@/components/MkFormFooter.vue';
|
||||||
import MkRadios from '@/components/MkRadios.vue';
|
import MkRadios from '@/components/MkRadios.vue';
|
||||||
|
@ -370,6 +374,7 @@ const adForm = useForm({
|
||||||
|
|
||||||
const urlPreviewForm = useForm({
|
const urlPreviewForm = useForm({
|
||||||
urlPreviewEnabled: meta.urlPreviewEnabled,
|
urlPreviewEnabled: meta.urlPreviewEnabled,
|
||||||
|
urlPreviewAllowRedirect: meta.urlPreviewAllowRedirect,
|
||||||
urlPreviewTimeout: meta.urlPreviewTimeout,
|
urlPreviewTimeout: meta.urlPreviewTimeout,
|
||||||
urlPreviewMaximumContentLength: meta.urlPreviewMaximumContentLength,
|
urlPreviewMaximumContentLength: meta.urlPreviewMaximumContentLength,
|
||||||
urlPreviewRequireContentLength: meta.urlPreviewRequireContentLength,
|
urlPreviewRequireContentLength: meta.urlPreviewRequireContentLength,
|
||||||
|
@ -378,6 +383,7 @@ const urlPreviewForm = useForm({
|
||||||
}, async (state) => {
|
}, async (state) => {
|
||||||
await os.apiWithDialog('admin/update-meta', {
|
await os.apiWithDialog('admin/update-meta', {
|
||||||
urlPreviewEnabled: state.urlPreviewEnabled,
|
urlPreviewEnabled: state.urlPreviewEnabled,
|
||||||
|
urlPreviewAllowRedirect: state.urlPreviewAllowRedirect,
|
||||||
urlPreviewTimeout: state.urlPreviewTimeout,
|
urlPreviewTimeout: state.urlPreviewTimeout,
|
||||||
urlPreviewMaximumContentLength: state.urlPreviewMaximumContentLength,
|
urlPreviewMaximumContentLength: state.urlPreviewMaximumContentLength,
|
||||||
urlPreviewRequireContentLength: state.urlPreviewRequireContentLength,
|
urlPreviewRequireContentLength: state.urlPreviewRequireContentLength,
|
||||||
|
|
|
@ -8809,6 +8809,7 @@ export type operations = {
|
||||||
uri: string;
|
uri: string;
|
||||||
version: string;
|
version: string;
|
||||||
urlPreviewEnabled: boolean;
|
urlPreviewEnabled: boolean;
|
||||||
|
urlPreviewAllowRedirect: boolean;
|
||||||
urlPreviewTimeout: number;
|
urlPreviewTimeout: number;
|
||||||
urlPreviewMaximumContentLength: number;
|
urlPreviewMaximumContentLength: number;
|
||||||
urlPreviewRequireContentLength: boolean;
|
urlPreviewRequireContentLength: boolean;
|
||||||
|
@ -11536,6 +11537,7 @@ export type operations = {
|
||||||
/** @description [Deprecated] Use "urlPreviewSummaryProxyUrl" instead. */
|
/** @description [Deprecated] Use "urlPreviewSummaryProxyUrl" instead. */
|
||||||
summalyProxy?: string | null;
|
summalyProxy?: string | null;
|
||||||
urlPreviewEnabled?: boolean;
|
urlPreviewEnabled?: boolean;
|
||||||
|
urlPreviewAllowRedirect?: boolean;
|
||||||
urlPreviewTimeout?: number;
|
urlPreviewTimeout?: number;
|
||||||
urlPreviewMaximumContentLength?: number;
|
urlPreviewMaximumContentLength?: number;
|
||||||
urlPreviewRequireContentLength?: boolean;
|
urlPreviewRequireContentLength?: boolean;
|
||||||
|
|
Loading…
Reference in New Issue