1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-07-25 08:35:02 +02:00

feat: 条件に一致したURLプレビューのサムネイルを隠すことができるように (#17635)

* URLプレビューのサムネイルを隠す機能を追加 (MisskeyIO#214)

* Update Changelog

* fix

* Update Changelog

* fix

* fix: もうセンシティブと判定されている場合はそれをそのまま通すように

* fix: unnecessary import

* fix lint

---------

Co-authored-by: CyberRex <hspwinx86@gmail.com>
This commit is contained in:
かっこかり
2026-07-04 16:26:22 +09:00
committed by GitHub
parent 0f056c4955
commit f59bf35615
10 changed files with 69 additions and 0 deletions

View File

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

View File

@@ -672,6 +672,11 @@ export class MiMeta {
})
public urlPreviewUserAgent: string | null;
@Column('varchar', {
length: 3072, array: true, default: '{}',
})
public urlPreviewSensitiveList: string[];
@Column('varchar', {
length: 128,
default: 'none',

View File

@@ -544,6 +544,14 @@ export const meta = {
type: 'string',
optional: false, nullable: true,
},
urlPreviewSensitiveList: {
type: 'array',
optional: false, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
},
},
federation: {
type: 'string',
enum: ['all', 'specified', 'none'],
@@ -760,6 +768,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength,
urlPreviewUserAgent: instance.urlPreviewUserAgent,
urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl,
urlPreviewSensitiveList: instance.urlPreviewSensitiveList,
federation: instance.federation,
federationHosts: instance.federationHosts,
deliverSuspendedSoftware: instance.deliverSuspendedSoftware,

View File

@@ -189,6 +189,12 @@ export const paramDef = {
urlPreviewRequireContentLength: { type: 'boolean' },
urlPreviewUserAgent: { type: 'string', nullable: true },
urlPreviewSummaryProxyUrl: { type: 'string', nullable: true },
urlPreviewSensitiveList: {
type: 'array', nullable: true,
items: {
type: 'string',
}
},
federation: {
type: 'string',
enum: ['all', 'none', 'specified'],
@@ -734,6 +740,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
set.urlPreviewSummaryProxyUrl = value === '' ? null : value;
}
if (Array.isArray(ps.urlPreviewSensitiveList)) {
set.urlPreviewSensitiveList = ps.urlPreviewSensitiveList.filter(Boolean);
}
if (ps.federation !== undefined) {
set.federation = ps.federation;
}

View File

@@ -11,6 +11,7 @@ import { HttpRequestService } from '@/core/HttpRequestService.js';
import type Logger from '@/logger.js';
import { query } from '@/misc/prelude/url.js';
import { LoggerService } from '@/core/LoggerService.js';
import { UtilityService } from '@/core/UtilityService.js';
import { bindThis } from '@/decorators.js';
import { ApiError } from '@/server/api/error.js';
import { MiMeta } from '@/models/Meta.js';
@@ -29,6 +30,7 @@ export class UrlPreviewService {
private meta: MiMeta,
private httpRequestService: HttpRequestService,
private utilityService: UtilityService,
private loggerService: LoggerService,
) {
this.logger = this.loggerService.getLogger('url-preview');
@@ -95,6 +97,10 @@ export class UrlPreviewService {
summary.icon = this.wrap(summary.icon);
summary.thumbnail = this.wrap(summary.thumbnail);
if (summary.sensitive !== true) {
summary.sensitive = this.utilityService.isKeyWordIncluded(summary.url, this.meta.urlPreviewSensitiveList);
}
// Cache 1day
reply.header('Cache-Control', 'max-age=86400, immutable');

View File

@@ -240,6 +240,13 @@ SPDX-License-Identifier: AGPL-3.0-only
</ul>
</div>
</div>
<SearchMarker :keywords="['deny', 'list']">
<MkTextarea v-model="urlPreviewForm.state.urlPreviewSensitiveList" tall>
<template #label><SearchLabel>{{ i18n.ts.urlPreviewSensitiveList }}</SearchLabel><span v-if="urlPreviewForm.modifiedStates.urlPreviewSensitiveList" class="_modified">{{ i18n.ts.modified }}</span></template>
<template #caption>{{ i18n.ts.urlPreviewSensitiveListDescription }}</template>
</MkTextarea>
</SearchMarker>
</template>
</div>
</MkFolder>
@@ -465,6 +472,7 @@ const urlPreviewForm = useForm({
urlPreviewRequireContentLength: meta.urlPreviewRequireContentLength,
urlPreviewUserAgent: meta.urlPreviewUserAgent ?? '',
urlPreviewSummaryProxyUrl: meta.urlPreviewSummaryProxyUrl ?? '',
urlPreviewSensitiveList: meta.urlPreviewSensitiveList.join('\n'),
}, async (state) => {
await os.apiWithDialog('admin/update-meta', {
urlPreviewEnabled: state.urlPreviewEnabled,
@@ -474,6 +482,7 @@ const urlPreviewForm = useForm({
urlPreviewRequireContentLength: state.urlPreviewRequireContentLength,
urlPreviewUserAgent: state.urlPreviewUserAgent,
urlPreviewSummaryProxyUrl: state.urlPreviewSummaryProxyUrl,
urlPreviewSensitiveList: state.urlPreviewSensitiveList.split('\n'),
});
fetchInstance(true);
});

View File

@@ -5691,6 +5691,14 @@ export interface Locale extends ILocale {
* 先頭に追加
*/
"prepend": string;
/**
* サムネイルの表示を制限するURL
*/
"urlPreviewSensitiveList": string;
/**
* スペースで区切るとAND指定になり、改行で区切るとOR指定になります。スラッシュで囲むと正規表現になります。一致した場合、サムネイルが表示されなくなります。
*/
"urlPreviewSensitiveListDescription": string;
"_imageEditing": {
"_vars": {
/**

View File

@@ -9557,6 +9557,7 @@ export interface operations {
urlPreviewRequireContentLength: boolean;
urlPreviewUserAgent: string | null;
urlPreviewSummaryProxyUrl: string | null;
urlPreviewSensitiveList: string[];
/** @enum {string} */
federation: 'all' | 'specified' | 'none';
federationHosts: string[];
@@ -13076,6 +13077,7 @@ export interface operations {
urlPreviewRequireContentLength?: boolean;
urlPreviewUserAgent?: string | null;
urlPreviewSummaryProxyUrl?: string | null;
urlPreviewSensitiveList?: string[] | null;
/** @enum {string} */
federation?: 'all' | 'none' | 'specified';
federationHosts?: string[];