Merge branch 'develop' of https://activitypub.software/TransFem-org/Sharkey into feat/instance-admin-ui
This commit is contained in:
commit
fadae347ff
37 changed files with 541 additions and 65 deletions
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class ExternalWebsiteWarn1711008460816 {
|
||||
name = 'ExternalWebsiteWarn1711008460816'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "trustedLinkUrlPatterns" character varying(3072) array NOT NULL DEFAULT '{}'`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "trustedLinkUrlPatterns"`);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class AddRejectReports1728177700920 {
|
||||
name = 'AddRejectReports1728177700920'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "instance" ADD "rejectReports" boolean NOT NULL DEFAULT false`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "rejectReports"`);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { In } from 'typeorm';
|
||||
import * as Bull from 'bullmq';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import { UserFollowingService } from '@/core/UserFollowingService.js';
|
||||
|
|
@ -29,6 +30,7 @@ import { bindThis } from '@/decorators.js';
|
|||
import type { MiRemoteUser } from '@/models/User.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import { AbuseReportService } from '@/core/AbuseReportService.js';
|
||||
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
|
||||
import { ApNoteService } from './models/ApNoteService.js';
|
||||
import { ApLoggerService } from './ApLoggerService.js';
|
||||
|
|
@ -83,6 +85,7 @@ export class ApInboxService {
|
|||
private apQuestionService: ApQuestionService,
|
||||
private queueService: QueueService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private federatedInstanceService: FederatedInstanceService,
|
||||
) {
|
||||
this.logger = this.apLoggerService.logger;
|
||||
}
|
||||
|
|
@ -530,6 +533,12 @@ export class ApInboxService {
|
|||
|
||||
@bindThis
|
||||
private async flag(actor: MiRemoteUser, activity: IFlag): Promise<string> {
|
||||
// Make sure the source instance is allowed to send reports.
|
||||
const instance = await this.federatedInstanceService.fetch(actor.host);
|
||||
if (instance.rejectReports) {
|
||||
throw new Bull.UnrecoverableError(`Rejecting report from instance: ${actor.host}`);
|
||||
}
|
||||
|
||||
// objectは `(User|Note) | (User|Note)[]` だけど、全パターンDBスキーマと対応させられないので
|
||||
// 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する
|
||||
const uris = getApIds(activity.object);
|
||||
|
|
|
|||
|
|
@ -526,6 +526,7 @@ export class ApRendererService {
|
|||
publicKey: this.renderKey(user, keypair, '#main-key'),
|
||||
isCat: user.isCat,
|
||||
noindex: user.noindex,
|
||||
indexable: !user.noindex,
|
||||
speakAsCat: user.speakAsCat,
|
||||
attachment: attachment.length ? attachment : undefined,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -545,6 +545,7 @@ const extension_context_definition = {
|
|||
Emoji: 'toot:Emoji',
|
||||
featured: 'toot:featured',
|
||||
discoverable: 'toot:discoverable',
|
||||
indexable: 'toot:indexable',
|
||||
// schema
|
||||
schema: 'http://schema.org#',
|
||||
PropertyValue: 'schema:PropertyValue',
|
||||
|
|
|
|||
|
|
@ -587,7 +587,7 @@ export class ApNoteService {
|
|||
// ここでuriの代わりに添付されてきたNote Objectが指定されていると、サーバーフェッチを経ずにノートが生成されるが
|
||||
// 添付されてきたNote Objectは偽装されている可能性があるため、常にuriを指定してサーバーフェッチを行う。
|
||||
const createFrom = options.sentFrom?.origin === new URL(uri).origin ? value : uri;
|
||||
return await this.createNote(createFrom, options.resolver, true);
|
||||
return await this.createNote(createFrom, options.resolver, false);
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ export class MetaEntityService {
|
|||
imageUrl: ad.imageUrl,
|
||||
dayOfWeek: ad.dayOfWeek,
|
||||
})),
|
||||
trustedLinkUrlPatterns: instance.trustedLinkUrlPatterns,
|
||||
notesPerOneAd: instance.notesPerOneAd,
|
||||
enableEmail: instance.enableEmail,
|
||||
enableServiceWorker: instance.enableServiceWorker,
|
||||
|
|
|
|||
|
|
@ -158,7 +158,12 @@ export class MiInstance {
|
|||
default: false,
|
||||
})
|
||||
public isNSFW: boolean;
|
||||
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public rejectReports: boolean;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 16384, default: '',
|
||||
})
|
||||
|
|
|
|||
|
|
@ -674,4 +674,12 @@ export class MiMeta {
|
|||
nullable: true,
|
||||
})
|
||||
public urlPreviewUserAgent: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 3072,
|
||||
array: true,
|
||||
default: '{}',
|
||||
comment: 'An array of URL strings or regex that can be used to omit warnings about redirects to external sites. Separate them with spaces to specify AND, and enclose them with slashes to specify regular expressions. Each item is regarded as an OR.',
|
||||
})
|
||||
public trustedLinkUrlPatterns: string[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -273,6 +273,14 @@ export const packedMetaLiteSchema = {
|
|||
optional: false, nullable: false,
|
||||
default: 'local',
|
||||
},
|
||||
trustedLinkUrlPatterns: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export const paramDef = {
|
|||
host: { type: 'string' },
|
||||
isSuspended: { type: 'boolean' },
|
||||
isNSFW: { type: 'boolean' },
|
||||
rejectReports: { type: 'boolean' },
|
||||
moderationNote: { type: 'string' },
|
||||
},
|
||||
required: ['host'],
|
||||
|
|
@ -57,6 +58,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
await this.federatedInstanceService.update(instance.id, {
|
||||
suspensionState,
|
||||
isNSFW: ps.isNSFW,
|
||||
rejectReports: ps.rejectReports,
|
||||
moderationNote: ps.moderationNote,
|
||||
});
|
||||
|
||||
|
|
@ -74,6 +76,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
}
|
||||
}
|
||||
|
||||
if (ps.isNSFW != null && instance.isNSFW !== ps.isNSFW) {
|
||||
const message = ps.rejectReports ? 'setRemoteInstanceNSFW' : 'unsetRemoteInstanceNSFW';
|
||||
this.moderationLogService.log(me, message, {
|
||||
id: instance.id,
|
||||
host: instance.host,
|
||||
});
|
||||
}
|
||||
|
||||
if (ps.rejectReports != null && instance.rejectReports !== ps.rejectReports) {
|
||||
const message = ps.rejectReports ? 'rejectRemoteInstanceReports' : 'acceptRemoteInstanceReports';
|
||||
this.moderationLogService.log(me, message, {
|
||||
id: instance.id,
|
||||
host: instance.host,
|
||||
});
|
||||
}
|
||||
|
||||
if (ps.moderationNote != null && instance.moderationNote !== ps.moderationNote) {
|
||||
this.moderationLogService.log(me, 'updateRemoteInstanceNote', {
|
||||
id: instance.id,
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ export const meta = {
|
|||
},
|
||||
silencedHosts: {
|
||||
type: 'array',
|
||||
optional: true,
|
||||
optional: false,
|
||||
nullable: false,
|
||||
items: {
|
||||
type: 'string',
|
||||
|
|
@ -526,6 +526,14 @@ export const meta = {
|
|||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
trustedLinkUrlPatterns: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
|
@ -669,6 +677,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength,
|
||||
urlPreviewUserAgent: instance.urlPreviewUserAgent,
|
||||
urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl,
|
||||
trustedLinkUrlPatterns: instance.trustedLinkUrlPatterns,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,6 +176,11 @@ export const paramDef = {
|
|||
urlPreviewRequireContentLength: { type: 'boolean' },
|
||||
urlPreviewUserAgent: { type: 'string', nullable: true },
|
||||
urlPreviewSummaryProxyUrl: { type: 'string', nullable: true },
|
||||
trustedLinkUrlPatterns: {
|
||||
type: 'array', nullable: true, items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
|
@ -665,6 +670,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
set.urlPreviewSummaryProxyUrl = value === '' ? null : value;
|
||||
}
|
||||
|
||||
if (Array.isArray(ps.trustedLinkUrlPatterns)) {
|
||||
set.trustedLinkUrlPatterns = ps.trustedLinkUrlPatterns.filter(Boolean);
|
||||
}
|
||||
|
||||
const before = await this.metaService.fetch(true);
|
||||
|
||||
await this.metaService.update(set);
|
||||
|
|
|
|||
|
|
@ -193,9 +193,9 @@ export class ClientServerService {
|
|||
icon: meta.iconUrl,
|
||||
appleTouchIcon: meta.app512IconUrl,
|
||||
themeColor: meta.themeColor,
|
||||
serverErrorImageUrl: meta.serverErrorImageUrl ?? 'https://launcher.moe/error.png',
|
||||
infoImageUrl: meta.infoImageUrl ?? 'https://launcher.moe/nothinghere.png',
|
||||
notFoundImageUrl: meta.notFoundImageUrl ?? 'https://launcher.moe/missingpage.webp',
|
||||
serverErrorImageUrl: meta.serverErrorImageUrl ?? '/status/error.png',
|
||||
infoImageUrl: meta.infoImageUrl ?? '/status/nothinghere.png',
|
||||
notFoundImageUrl: meta.notFoundImageUrl ?? '/status/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)),
|
||||
|
|
|
|||
|
|
@ -77,8 +77,12 @@ export const moderationLogTypes = [
|
|||
'deleteGlobalAnnouncement',
|
||||
'deleteUserAnnouncement',
|
||||
'resetPassword',
|
||||
'setRemoteInstanceNSFW',
|
||||
'unsetRemoteInstanceNSFW',
|
||||
'suspendRemoteInstance',
|
||||
'unsuspendRemoteInstance',
|
||||
'rejectRemoteInstanceReports',
|
||||
'acceptRemoteInstanceReports',
|
||||
'updateRemoteInstanceNote',
|
||||
'markSensitiveDriveFile',
|
||||
'unmarkSensitiveDriveFile',
|
||||
|
|
@ -227,6 +231,14 @@ export type ModerationLogPayloads = {
|
|||
userUsername: string;
|
||||
userHost: string | null;
|
||||
};
|
||||
setRemoteInstanceNSFW: {
|
||||
id: string;
|
||||
host: string;
|
||||
};
|
||||
unsetRemoteInstanceNSFW: {
|
||||
id: string;
|
||||
host: string;
|
||||
};
|
||||
suspendRemoteInstance: {
|
||||
id: string;
|
||||
host: string;
|
||||
|
|
@ -235,6 +247,14 @@ export type ModerationLogPayloads = {
|
|||
id: string;
|
||||
host: string;
|
||||
};
|
||||
rejectRemoteInstanceReports: {
|
||||
id: string;
|
||||
host: string;
|
||||
};
|
||||
acceptRemoteInstanceReports: {
|
||||
id: string;
|
||||
host: string;
|
||||
};
|
||||
updateRemoteInstanceNote: {
|
||||
id: string;
|
||||
host: string;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue