};
type ObjectSchemaTypeDef =
p['ref'] extends keyof typeof refs ? Packed
:
@@ -235,12 +232,6 @@ export type SchemaTypeDef
=
p['items']['allOf'] extends ReadonlyArray ? UnionToIntersection>>[] :
never
) :
- p['prefixItems'] extends ReadonlyArray ? (
- p['items'] extends NonNullable ? [...ArrayToTuple, ...SchemaType
[]] :
- p['items'] extends false ? ArrayToTuple
:
- p['unevaluatedItems'] extends false ? ArrayToTuple
:
- [...ArrayToTuple
, ...unknown[]]
- ) :
p['items'] extends NonNullable ? SchemaType[] :
any[]
) :
diff --git a/packages/backend/src/misc/sql-like-escape.ts b/packages/backend/src/misc/sql-like-escape.ts
index 6b4f51b00e..0c05255674 100644
--- a/packages/backend/src/misc/sql-like-escape.ts
+++ b/packages/backend/src/misc/sql-like-escape.ts
@@ -4,5 +4,5 @@
*/
export function sqlLikeEscape(s: string) {
- return s.replace(/([\\%_])/g, '\\$1');
+ return s.replace(/([%_])/g, '\\$1');
}
diff --git a/packages/backend/src/models/AbuseUserReport.ts b/packages/backend/src/models/AbuseUserReport.ts
index cb5672e4ac..0615fd7eb5 100644
--- a/packages/backend/src/models/AbuseUserReport.ts
+++ b/packages/backend/src/models/AbuseUserReport.ts
@@ -50,9 +50,6 @@ export class MiAbuseUserReport {
})
public resolved: boolean;
- /**
- * リモートサーバーに転送したかどうか
- */
@Column('boolean', {
default: false,
})
@@ -63,21 +60,6 @@ export class MiAbuseUserReport {
})
public comment: string;
- @Column('varchar', {
- length: 8192, default: '',
- })
- public moderationNote: string;
-
- /**
- * accept 是認 ... 通報内容が正当であり、肯定的に対応された
- * reject 否認 ... 通報内容が正当でなく、否定的に対応された
- * null ... その他
- */
- @Column('varchar', {
- length: 128, nullable: true,
- })
- public resolvedAs: 'accept' | 'reject' | null;
-
//#region Denormalized fields
@Index()
@Column('varchar', {
diff --git a/packages/backend/src/models/Flash.ts b/packages/backend/src/models/Flash.ts
index 5db7dca992..a1469a0d94 100644
--- a/packages/backend/src/models/Flash.ts
+++ b/packages/backend/src/models/Flash.ts
@@ -7,9 +7,6 @@ import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typ
import { id } from './util/id.js';
import { MiUser } from './User.js';
-export const flashVisibility = ['public', 'private'] as const;
-export type FlashVisibility = typeof flashVisibility[number];
-
@Entity('flash')
export class MiFlash {
@PrimaryColumn(id())
@@ -66,5 +63,5 @@ export class MiFlash {
@Column('varchar', {
length: 512, default: 'public',
})
- public visibility: FlashVisibility;
+ public visibility: 'public' | 'private';
}
diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts
index ad5e31ad6f..70d41801b5 100644
--- a/packages/backend/src/models/Meta.ts
+++ b/packages/backend/src/models/Meta.ts
@@ -81,11 +81,6 @@ export class MiMeta {
})
public prohibitedWords: string[];
- @Column('varchar', {
- length: 1024, array: true, default: '{}',
- })
- public prohibitedWordsForNameOfUser: string[];
-
@Column('varchar', {
length: 1024, array: true, default: '{}',
})
@@ -263,11 +258,6 @@ export class MiMeta {
})
public turnstileSecretKey: string | null;
- @Column('boolean', {
- default: false,
- })
- public enableTestcaptcha: boolean;
-
// chaptcha系を追加した際にはnodeinfoのレスポンスに追加するのを忘れないようにすること
@Column('enum', {
@@ -529,11 +519,6 @@ export class MiMeta {
})
public enableChartsForFederatedInstances: boolean;
- @Column('boolean', {
- default: true,
- })
- public enableStatsForFederatedInstances: boolean;
-
@Column('boolean', {
default: false,
})
@@ -604,11 +589,6 @@ export class MiMeta {
})
public perUserListTimelineCacheMax: number;
- @Column('boolean', {
- default: false,
- })
- public enableReactionsBuffering: boolean;
-
@Column('integer', {
default: 0,
})
@@ -645,17 +625,4 @@ export class MiMeta {
nullable: true,
})
public urlPreviewUserAgent: string | null;
-
- @Column('varchar', {
- length: 128,
- default: 'all',
- })
- public federation: 'all' | 'specified' | 'none';
-
- @Column('varchar', {
- length: 1024,
- array: true,
- default: '{}',
- })
- public federationHosts: string[];
}
diff --git a/packages/backend/src/models/NoteReaction.ts b/packages/backend/src/models/NoteReaction.ts
index 42dfcaa9ad..366a4423f7 100644
--- a/packages/backend/src/models/NoteReaction.ts
+++ b/packages/backend/src/models/NoteReaction.ts
@@ -9,7 +9,8 @@ import { MiUser } from './User.js';
import { MiNote } from './Note.js';
@Entity('note_reaction')
-@Index(['userId', 'noteId'], { unique: true })
+@Index(['userId', 'noteId'])
+@Index(['userId', 'noteId', 'reaction'], { unique: true })
export class MiNoteReaction {
@PrimaryColumn(id())
public id: string;
diff --git a/packages/backend/src/models/Notification.ts b/packages/backend/src/models/Notification.ts
index b7f8e94d69..df88b99636 100644
--- a/packages/backend/src/models/Notification.ts
+++ b/packages/backend/src/models/Notification.ts
@@ -3,12 +3,10 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { userExportableEntities } from '@/types.js';
import { MiUser } from './User.js';
import { MiNote } from './Note.js';
import { MiAccessToken } from './AccessToken.js';
import { MiRole } from './Role.js';
-import { MiDriveFile } from './DriveFile.js';
export type MiNotification = {
type: 'note';
@@ -69,7 +67,6 @@ export type MiNotification = {
id: string;
createdAt: string;
notifierId: MiUser['id'];
- message: string | null;
} | {
type: 'roleAssigned';
id: string;
@@ -80,16 +77,6 @@ export type MiNotification = {
id: string;
createdAt: string;
achievement: string;
-} | {
- type: 'exportCompleted';
- id: string;
- createdAt: string;
- exportedEntity: typeof userExportableEntities[number];
- fileId: MiDriveFile['id'];
-} | {
- type: 'login';
- id: string;
- createdAt: string;
} | {
type: 'app';
id: string;
@@ -98,7 +85,7 @@ export type MiNotification = {
/**
* アプリ通知のbody
*/
- customBody: string;
+ customBody: string | null;
/**
* アプリ通知のheader
diff --git a/packages/backend/src/models/SystemWebhook.ts b/packages/backend/src/models/SystemWebhook.ts
index 1a7ce4962b..d6c27eae51 100644
--- a/packages/backend/src/models/SystemWebhook.ts
+++ b/packages/backend/src/models/SystemWebhook.ts
@@ -14,10 +14,6 @@ export const systemWebhookEventTypes = [
'abuseReportResolved',
// ユーザが作成された時
'userCreated',
- // モデレータが一定期間不在である警告
- 'inactiveModeratorsWarning',
- // モデレータが一定期間不在のためシステムにより招待制へと変更された
- 'inactiveModeratorsInvitationOnlyChanged',
] as const;
export type SystemWebhookEventType = typeof systemWebhookEventTypes[number];
diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts
index 96de30c4c2..9e2d7a3444 100644
--- a/packages/backend/src/models/User.ts
+++ b/packages/backend/src/models/User.ts
@@ -155,11 +155,6 @@ export class MiUser {
})
public tags: string[];
- @Column('integer', {
- default: 0,
- })
- public score: number;
-
@Column('boolean', {
default: false,
comment: 'Whether the User is suspended.',
@@ -202,23 +197,6 @@ export class MiUser {
})
public isHibernated: boolean;
- @Column('boolean', {
- default: false,
- })
- public requireSigninToViewContents: boolean;
-
- // in sec, マイナスで相対時間
- @Column('integer', {
- nullable: true,
- })
- public makeNotesFollowersOnlyBefore: number | null;
-
- // in sec, マイナスで相対時間
- @Column('integer', {
- nullable: true,
- })
- public makeNotesHiddenBefore: number | null;
-
// アカウントが削除されたかどうかのフラグだが、完全に削除される際は物理削除なので実質削除されるまでの「削除が進行しているかどうか」のフラグ
@Column('boolean', {
default: false,
@@ -311,6 +289,5 @@ export const localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toStr
export const passwordSchema = { type: 'string', minLength: 1 } as const;
export const nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const;
export const descriptionSchema = { type: 'string', minLength: 1, maxLength: 1500 } as const;
-export const followedMessageSchema = { type: 'string', minLength: 1, maxLength: 256 } as const;
export const locationSchema = { type: 'string', minLength: 1, maxLength: 50 } as const;
export const birthdaySchema = { type: 'string', pattern: /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.toString().slice(1, -1) } as const;
diff --git a/packages/backend/src/models/UserProfile.ts b/packages/backend/src/models/UserProfile.ts
index 5544555296..7dbe0b3717 100644
--- a/packages/backend/src/models/UserProfile.ts
+++ b/packages/backend/src/models/UserProfile.ts
@@ -42,14 +42,6 @@ export class MiUserProfile {
})
public description: string | null;
- // フォローされた際のメッセージ
- @Column('varchar', {
- length: 256, nullable: true,
- })
- public followedMessage: string | null;
-
- // TODO: 鍵アカウントの場合の、フォローリクエスト受信時のメッセージも設定できるようにする
-
@Column('jsonb', {
default: [],
})
diff --git a/packages/backend/src/models/Webhook.ts b/packages/backend/src/models/Webhook.ts
index b4cab4edc8..db24c03b3d 100644
--- a/packages/backend/src/models/Webhook.ts
+++ b/packages/backend/src/models/Webhook.ts
@@ -8,7 +8,6 @@ import { id } from './util/id.js';
import { MiUser } from './User.js';
export const webhookEventTypes = ['mention', 'unfollow', 'follow', 'followed', 'note', 'reply', 'renote', 'reaction'] as const;
-export type WebhookEventTypes = typeof webhookEventTypes[number];
@Entity('webhook')
export class MiWebhook {
diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts
index e3fd63464a..3bcf9cac92 100644
--- a/packages/backend/src/models/json-schema/meta.ts
+++ b/packages/backend/src/models/json-schema/meta.ts
@@ -115,10 +115,6 @@ export const packedMetaLiteSchema = {
type: 'string',
optional: false, nullable: true,
},
- enableTestcaptcha: {
- type: 'boolean',
- optional: false, nullable: false,
- },
swPublickey: {
type: 'string',
optional: false, nullable: true,
@@ -257,10 +253,6 @@ export const packedMetaLiteSchema = {
optional: false, nullable: false,
default: 'local',
},
- maxFileSize: {
- type: 'number',
- optional: false, nullable: false,
- },
},
} as const;
diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts
index cddaf4bc83..b4c4442758 100644
--- a/packages/backend/src/models/json-schema/notification.ts
+++ b/packages/backend/src/models/json-schema/notification.ts
@@ -3,8 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { ACHIEVEMENT_TYPES } from '@/core/AchievementService.js';
-import { notificationTypes, userExportableEntities } from '@/types.js';
+import { notificationTypes } from '@/types.js';
const baseSchema = {
type: 'object',
@@ -267,10 +266,6 @@ export const packedNotificationSchema = {
optional: false, nullable: false,
format: 'id',
},
- message: {
- type: 'string',
- optional: false, nullable: true,
- },
},
}, {
type: 'object',
@@ -299,37 +294,6 @@ export const packedNotificationSchema = {
achievement: {
type: 'string',
optional: false, nullable: false,
- enum: ACHIEVEMENT_TYPES,
- },
- },
- }, {
- type: 'object',
- properties: {
- ...baseSchema.properties,
- type: {
- type: 'string',
- optional: false, nullable: false,
- enum: ['exportCompleted'],
- },
- exportedEntity: {
- type: 'string',
- optional: false, nullable: false,
- enum: userExportableEntities,
- },
- fileId: {
- type: 'string',
- optional: false, nullable: false,
- format: 'id',
- },
- },
- }, {
- type: 'object',
- properties: {
- ...baseSchema.properties,
- type: {
- type: 'string',
- optional: false, nullable: false,
- enum: ['login'],
},
},
}, {
@@ -347,11 +311,11 @@ export const packedNotificationSchema = {
},
header: {
type: 'string',
- optional: false, nullable: true,
+ optional: false, nullable: false,
},
icon: {
type: 'string',
- optional: false, nullable: true,
+ optional: false, nullable: false,
},
},
}, {
diff --git a/packages/backend/src/models/json-schema/role.ts b/packages/backend/src/models/json-schema/role.ts
index 3537de94c8..5820aa32e3 100644
--- a/packages/backend/src/models/json-schema/role.ts
+++ b/packages/backend/src/models/json-schema/role.ts
@@ -236,6 +236,10 @@ export const packedRolePoliciesSchema = {
type: 'integer',
optional: false, nullable: false,
},
+ reactionsPerNoteLimit: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
antennaLimit: {
type: 'integer',
optional: false, nullable: false,
@@ -272,26 +276,6 @@ export const packedRolePoliciesSchema = {
type: 'integer',
optional: false, nullable: false,
},
- canImportAntennas: {
- type: 'boolean',
- optional: false, nullable: false,
- },
- canImportBlocking: {
- type: 'boolean',
- optional: false, nullable: false,
- },
- canImportFollowing: {
- type: 'boolean',
- optional: false, nullable: false,
- },
- canImportMuting: {
- type: 'boolean',
- optional: false, nullable: false,
- },
- canImportUserLists: {
- type: 'boolean',
- optional: false, nullable: false,
- },
},
} as const;
diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts
index 38631f907d..947a9317d7 100644
--- a/packages/backend/src/models/json-schema/user.ts
+++ b/packages/backend/src/models/json-schema/user.ts
@@ -115,18 +115,6 @@ export const packedUserLiteSchema = {
type: 'boolean',
nullable: false, optional: true,
},
- requireSigninToViewContents: {
- type: 'boolean',
- nullable: false, optional: true,
- },
- makeNotesFollowersOnlyBefore: {
- type: 'number',
- nullable: true, optional: true,
- },
- makeNotesHiddenBefore: {
- type: 'number',
- nullable: true, optional: true,
- },
instance: {
type: 'object',
nullable: false, optional: true,
@@ -358,6 +346,21 @@ export const packedUserDetailedNotMeOnlySchema = {
nullable: false, optional: false,
enum: ['public', 'followers', 'private'],
},
+ twoFactorEnabled: {
+ type: 'boolean',
+ nullable: false, optional: false,
+ default: false,
+ },
+ usePasswordLessLogin: {
+ type: 'boolean',
+ nullable: false, optional: false,
+ default: false,
+ },
+ securityKeys: {
+ type: 'boolean',
+ nullable: false, optional: false,
+ default: false,
+ },
roles: {
type: 'array',
nullable: false, optional: false,
@@ -367,10 +370,6 @@ export const packedUserDetailedNotMeOnlySchema = {
ref: 'RoleLite',
},
},
- followedMessage: {
- type: 'string',
- nullable: true, optional: true,
- },
memo: {
type: 'string',
nullable: true, optional: false,
@@ -379,18 +378,6 @@ export const packedUserDetailedNotMeOnlySchema = {
type: 'string',
nullable: false, optional: true,
},
- twoFactorEnabled: {
- type: 'boolean',
- nullable: false, optional: true,
- },
- usePasswordLessLogin: {
- type: 'boolean',
- nullable: false, optional: true,
- },
- securityKeys: {
- type: 'boolean',
- nullable: false, optional: true,
- },
//#region relations
isFollowing: {
type: 'boolean',
@@ -450,10 +437,6 @@ export const packedMeDetailedOnlySchema = {
nullable: true, optional: false,
format: 'id',
},
- followedMessage: {
- type: 'string',
- nullable: true, optional: false,
- },
isModerator: {
type: 'boolean',
nullable: true, optional: false,
@@ -639,21 +622,6 @@ export const packedMeDetailedOnlySchema = {
nullable: false, optional: false,
ref: 'RolePolicies',
},
- twoFactorEnabled: {
- type: 'boolean',
- nullable: false, optional: false,
- default: false,
- },
- usePasswordLessLogin: {
- type: 'boolean',
- nullable: false, optional: false,
- default: false,
- },
- securityKeys: {
- type: 'boolean',
- nullable: false, optional: false,
- default: false,
- },
//#region secrets
email: {
type: 'string',
diff --git a/packages/backend/src/queue/QueueProcessorModule.ts b/packages/backend/src/queue/QueueProcessorModule.ts
index 9044285bf6..a1fd38fcc5 100644
--- a/packages/backend/src/queue/QueueProcessorModule.ts
+++ b/packages/backend/src/queue/QueueProcessorModule.ts
@@ -6,7 +6,6 @@
import { Module } from '@nestjs/common';
import { CoreModule } from '@/core/CoreModule.js';
import { GlobalModule } from '@/GlobalModule.js';
-import { CheckModeratorsActivityProcessorService } from '@/queue/processors/CheckModeratorsActivityProcessorService.js';
import { QueueLoggerService } from './QueueLoggerService.js';
import { QueueProcessorService } from './QueueProcessorService.js';
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
@@ -15,7 +14,6 @@ import { InboxProcessorService } from './processors/InboxProcessorService.js';
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
import { CheckExpiredMutingsProcessorService } from './processors/CheckExpiredMutingsProcessorService.js';
-import { BakeBufferedReactionsProcessorService } from './processors/BakeBufferedReactionsProcessorService.js';
import { CleanChartsProcessorService } from './processors/CleanChartsProcessorService.js';
import { CleanProcessorService } from './processors/CleanProcessorService.js';
import { CleanRemoteFilesProcessorService } from './processors/CleanRemoteFilesProcessorService.js';
@@ -53,7 +51,6 @@ import { RelationshipProcessorService } from './processors/RelationshipProcessor
ResyncChartsProcessorService,
CleanChartsProcessorService,
CheckExpiredMutingsProcessorService,
- BakeBufferedReactionsProcessorService,
CleanProcessorService,
DeleteDriveFilesProcessorService,
ExportCustomEmojisProcessorService,
@@ -81,8 +78,6 @@ import { RelationshipProcessorService } from './processors/RelationshipProcessor
DeliverProcessorService,
InboxProcessorService,
AggregateRetentionProcessorService,
- CheckExpiredMutingsProcessorService,
- CheckModeratorsActivityProcessorService,
QueueProcessorService,
],
exports: [
diff --git a/packages/backend/src/queue/QueueProcessorService.ts b/packages/backend/src/queue/QueueProcessorService.ts
index 6940e1c188..7bd74f3210 100644
--- a/packages/backend/src/queue/QueueProcessorService.ts
+++ b/packages/backend/src/queue/QueueProcessorService.ts
@@ -10,7 +10,6 @@ import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js';
import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
-import { CheckModeratorsActivityProcessorService } from '@/queue/processors/CheckModeratorsActivityProcessorService.js';
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
@@ -40,7 +39,6 @@ import { TickChartsProcessorService } from './processors/TickChartsProcessorServ
import { ResyncChartsProcessorService } from './processors/ResyncChartsProcessorService.js';
import { CleanChartsProcessorService } from './processors/CleanChartsProcessorService.js';
import { CheckExpiredMutingsProcessorService } from './processors/CheckExpiredMutingsProcessorService.js';
-import { BakeBufferedReactionsProcessorService } from './processors/BakeBufferedReactionsProcessorService.js';
import { CleanProcessorService } from './processors/CleanProcessorService.js';
import { AggregateRetentionProcessorService } from './processors/AggregateRetentionProcessorService.js';
import { QueueLoggerService } from './QueueLoggerService.js';
@@ -67,7 +65,7 @@ function getJobInfo(job: Bull.Job | undefined, increment = false): string {
// onActiveとかonCompletedのattemptsMadeがなぜか0始まりなのでインクリメントする
const currentAttempts = job.attemptsMade + (increment ? 1 : 0);
- const maxAttempts = job.opts.attempts ?? 0;
+ const maxAttempts = job.opts ? job.opts.attempts : 0;
return `id=${job.id} attempts=${currentAttempts}/${maxAttempts} age=${formated}`;
}
@@ -120,36 +118,24 @@ export class QueueProcessorService implements OnApplicationShutdown {
private cleanChartsProcessorService: CleanChartsProcessorService,
private aggregateRetentionProcessorService: AggregateRetentionProcessorService,
private checkExpiredMutingsProcessorService: CheckExpiredMutingsProcessorService,
- private bakeBufferedReactionsProcessorService: BakeBufferedReactionsProcessorService,
- private checkModeratorsActivityProcessorService: CheckModeratorsActivityProcessorService,
private cleanProcessorService: CleanProcessorService,
) {
this.logger = this.queueLoggerService.logger;
- function renderError(e?: Error) {
- // 何故かeがundefinedで来ることがある
- if (!e) return '?';
-
- if (e instanceof Bull.UnrecoverableError || e.name === 'AbortError') {
- return `${e.name}: ${e.message}`;
+ function renderError(e: Error): any {
+ if (e) { // 何故かeがundefinedで来ることがある
+ return {
+ stack: e.stack,
+ message: e.message,
+ name: e.name,
+ };
+ } else {
+ return {
+ stack: '?',
+ message: '?',
+ name: '?',
+ };
}
-
- return {
- stack: e.stack,
- message: e.message,
- name: e.name,
- };
- }
-
- function renderJob(job?: Bull.Job) {
- if (!job) return '?';
-
- return {
- name: job.name || undefined,
- info: getJobInfo(job),
- failedReason: job.failedReason || undefined,
- data: job.data,
- };
}
//#region system
@@ -161,8 +147,6 @@ export class QueueProcessorService implements OnApplicationShutdown {
case 'cleanCharts': return this.cleanChartsProcessorService.process();
case 'aggregateRetention': return this.aggregateRetentionProcessorService.process();
case 'checkExpiredMutings': return this.checkExpiredMutingsProcessorService.process();
- case 'bakeBufferedReactions': return this.bakeBufferedReactionsProcessorService.process();
- case 'checkModeratorsActivity': return this.checkModeratorsActivityProcessorService.process();
case 'clean': return this.cleanProcessorService.process();
default: throw new Error(`unrecognized job type ${job.name} for system`);
}
@@ -185,15 +169,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
.on('active', (job) => logger.debug(`active id=${job.id}`))
.on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`))
.on('failed', (job, err: Error) => {
- logger.error(`failed(${err.name}: ${err.message}) id=${job?.id ?? '?'}`, { job: renderJob(job), e: renderError(err) });
+ logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) });
if (config.sentryForBackend) {
- Sentry.captureMessage(`Queue: System: ${job?.name ?? '?'}: ${err.name}: ${err.message}`, {
+ Sentry.captureMessage(`Queue: System: ${job?.name ?? '?'}: ${err.message}`, {
level: 'error',
extra: { job, err },
});
}
})
- .on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
}
//#endregion
@@ -242,15 +226,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
.on('active', (job) => logger.debug(`active id=${job.id}`))
.on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`))
.on('failed', (job, err) => {
- logger.error(`failed(${err.name}: ${err.message}) id=${job?.id ?? '?'}`, { job: renderJob(job), e: renderError(err) });
+ logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) });
if (config.sentryForBackend) {
- Sentry.captureMessage(`Queue: DB: ${job?.name ?? '?'}: ${err.name}: ${err.message}`, {
+ Sentry.captureMessage(`Queue: DB: ${job?.name ?? '?'}: ${err.message}`, {
level: 'error',
extra: { job, err },
});
}
})
- .on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
}
//#endregion
@@ -282,15 +266,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
.on('active', (job) => logger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`))
.on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`))
.on('failed', (job, err) => {
- logger.error(`failed(${err.name}: ${err.message}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
+ logger.error(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
if (config.sentryForBackend) {
- Sentry.captureMessage(`Queue: Deliver: ${err.name}: ${err.message}`, {
+ Sentry.captureMessage(`Queue: Deliver: ${err.message}`, {
level: 'error',
extra: { job, err },
});
}
})
- .on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
}
//#endregion
@@ -322,15 +306,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
.on('active', (job) => logger.debug(`active ${getJobInfo(job, true)}`))
.on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)}`))
.on('failed', (job, err) => {
- logger.error(`failed(${err.name}: ${err.message}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job: renderJob(job), e: renderError(err) });
+ logger.error(`failed(${err.stack}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job, e: renderError(err) });
if (config.sentryForBackend) {
- Sentry.captureMessage(`Queue: Inbox: ${err.name}: ${err.message}`, {
+ Sentry.captureMessage(`Queue: Inbox: ${err.message}`, {
level: 'error',
extra: { job, err },
});
}
})
- .on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
}
//#endregion
@@ -362,15 +346,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
.on('active', (job) => logger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`))
.on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`))
.on('failed', (job, err) => {
- logger.error(`failed(${err.name}: ${err.message}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
+ logger.error(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
if (config.sentryForBackend) {
- Sentry.captureMessage(`Queue: UserWebhookDeliver: ${err.name}: ${err.message}`, {
+ Sentry.captureMessage(`Queue: UserWebhookDeliver: ${err.message}`, {
level: 'error',
extra: { job, err },
});
}
})
- .on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
}
//#endregion
@@ -402,15 +386,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
.on('active', (job) => logger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`))
.on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`))
.on('failed', (job, err) => {
- logger.error(`failed(${err.name}: ${err.message}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
+ logger.error(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`);
if (config.sentryForBackend) {
- Sentry.captureMessage(`Queue: SystemWebhookDeliver: ${err.name}: ${err.message}`, {
+ Sentry.captureMessage(`Queue: SystemWebhookDeliver: ${err.message}`, {
level: 'error',
extra: { job, err },
});
}
})
- .on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
}
//#endregion
@@ -449,15 +433,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
.on('active', (job) => logger.debug(`active id=${job.id}`))
.on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`))
.on('failed', (job, err) => {
- logger.error(`failed(${err.name}: ${err.message}) id=${job?.id ?? '?'}`, { job: renderJob(job), e: renderError(err) });
+ logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) });
if (config.sentryForBackend) {
- Sentry.captureMessage(`Queue: Relationship: ${job?.name ?? '?'}: ${err.name}: ${err.message}`, {
+ Sentry.captureMessage(`Queue: Relationship: ${job?.name ?? '?'}: ${err.message}`, {
level: 'error',
extra: { job, err },
});
}
})
- .on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
}
//#endregion
@@ -490,15 +474,15 @@ export class QueueProcessorService implements OnApplicationShutdown {
.on('active', (job) => logger.debug(`active id=${job.id}`))
.on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`))
.on('failed', (job, err) => {
- logger.error(`failed(${err.name}: ${err.message}) id=${job?.id ?? '?'}`, { job: renderJob(job), e: renderError(err) });
+ logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) });
if (config.sentryForBackend) {
- Sentry.captureMessage(`Queue: ObjectStorage: ${job?.name ?? '?'}: ${err.name}: ${err.message}`, {
+ Sentry.captureMessage(`Queue: ObjectStorage: ${job?.name ?? '?'}: ${err.message}`, {
level: 'error',
extra: { job, err },
});
}
})
- .on('error', (err: Error) => logger.error(`error ${err.name}: ${err.message}`, { e: renderError(err) }))
+ .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) }))
.on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`));
}
//#endregion
diff --git a/packages/backend/src/queue/processors/BakeBufferedReactionsProcessorService.ts b/packages/backend/src/queue/processors/BakeBufferedReactionsProcessorService.ts
deleted file mode 100644
index d49c99f694..0000000000
--- a/packages/backend/src/queue/processors/BakeBufferedReactionsProcessorService.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Inject, Injectable } from '@nestjs/common';
-import type Logger from '@/logger.js';
-import { bindThis } from '@/decorators.js';
-import { ReactionsBufferingService } from '@/core/ReactionsBufferingService.js';
-import { QueueLoggerService } from '../QueueLoggerService.js';
-import type * as Bull from 'bullmq';
-import { MiMeta } from '@/models/_.js';
-import { DI } from '@/di-symbols.js';
-
-@Injectable()
-export class BakeBufferedReactionsProcessorService {
- private logger: Logger;
-
- constructor(
- @Inject(DI.meta)
- private meta: MiMeta,
-
- private reactionsBufferingService: ReactionsBufferingService,
- private queueLoggerService: QueueLoggerService,
- ) {
- this.logger = this.queueLoggerService.logger.createSubLogger('bake-buffered-reactions');
- }
-
- @bindThis
- public async process(): Promise {
- if (!this.meta.enableReactionsBuffering) {
- this.logger.info('Reactions buffering is disabled. Skipping...');
- return;
- }
-
- this.logger.info('Baking buffered reactions...');
-
- await this.reactionsBufferingService.bake();
-
- this.logger.succ('All buffered reactions baked.');
- }
-}
diff --git a/packages/backend/src/queue/processors/CheckModeratorsActivityProcessorService.ts b/packages/backend/src/queue/processors/CheckModeratorsActivityProcessorService.ts
deleted file mode 100644
index 87183cb342..0000000000
--- a/packages/backend/src/queue/processors/CheckModeratorsActivityProcessorService.ts
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Inject, Injectable } from '@nestjs/common';
-import { In } from 'typeorm';
-import type Logger from '@/logger.js';
-import { bindThis } from '@/decorators.js';
-import { MetaService } from '@/core/MetaService.js';
-import { RoleService } from '@/core/RoleService.js';
-import { EmailService } from '@/core/EmailService.js';
-import { MiUser, type UserProfilesRepository } from '@/models/_.js';
-import { DI } from '@/di-symbols.js';
-import { SystemWebhookService } from '@/core/SystemWebhookService.js';
-import { AnnouncementService } from '@/core/AnnouncementService.js';
-import { QueueLoggerService } from '../QueueLoggerService.js';
-
-// モデレーターが不在と判断する日付の閾値
-const MODERATOR_INACTIVITY_LIMIT_DAYS = 7;
-// 警告通知やログ出力を行う残日数の閾値
-const MODERATOR_INACTIVITY_WARNING_REMAINING_DAYS = 2;
-// 期限から6時間ごとに通知を行う
-const MODERATOR_INACTIVITY_WARNING_NOTIFY_INTERVAL_HOURS = 6;
-const ONE_HOUR_MILLI_SEC = 1000 * 60 * 60;
-const ONE_DAY_MILLI_SEC = ONE_HOUR_MILLI_SEC * 24;
-
-export type ModeratorInactivityEvaluationResult = {
- isModeratorsInactive: boolean;
- inactiveModerators: MiUser[];
- remainingTime: ModeratorInactivityRemainingTime;
-}
-
-export type ModeratorInactivityRemainingTime = {
- time: number;
- asHours: number;
- asDays: number;
-};
-
-function generateModeratorInactivityMail(remainingTime: ModeratorInactivityRemainingTime) {
- const subject = 'Moderator Inactivity Warning / モデレーター不在の通知';
-
- const timeVariant = remainingTime.asDays === 0 ? `${remainingTime.asHours} hours` : `${remainingTime.asDays} days`;
- const timeVariantJa = remainingTime.asDays === 0 ? `${remainingTime.asHours} 時間` : `${remainingTime.asDays} 日間`;
- const message = [
- 'To Moderators,',
- '',
- `A moderator has been inactive for a period of time. If there are ${timeVariant} of inactivity left, it will switch to invitation only.`,
- 'If you do not wish to move to invitation only, you must log into Misskey and update your last active date and time.',
- '',
- '---------------',
- '',
- 'To モデレーター各位',
- '',
- `モデレーターが一定期間活動していないようです。あと${timeVariantJa}活動していない状態が続くと招待制に切り替わります。`,
- '招待制に切り替わることを望まない場合は、Misskeyにログインして最終アクティブ日時を更新してください。',
- '',
- ];
-
- const html = message.join('
');
- const text = message.join('\n');
-
- return {
- subject,
- html,
- text,
- };
-}
-
-function generateInvitationOnlyChangedMail() {
- const subject = 'Change to Invitation-Only / 招待制に変更されました';
-
- const message = [
- 'To Moderators,',
- '',
- `Changed to invitation only because no moderator activity was detected for ${MODERATOR_INACTIVITY_LIMIT_DAYS} days.`,
- 'To cancel the invitation only, you need to access the control panel.',
- '',
- '---------------',
- '',
- 'To モデレーター各位',
- '',
- `モデレーターの活動が${MODERATOR_INACTIVITY_LIMIT_DAYS}日間検出されなかったため、招待制に変更されました。`,
- '招待制を解除するには、コントロールパネルにアクセスする必要があります。',
- '',
- ];
-
- const html = message.join('
');
- const text = message.join('\n');
-
- return {
- subject,
- html,
- text,
- };
-}
-
-@Injectable()
-export class CheckModeratorsActivityProcessorService {
- private logger: Logger;
-
- constructor(
- @Inject(DI.userProfilesRepository)
- private userProfilesRepository: UserProfilesRepository,
- private metaService: MetaService,
- private roleService: RoleService,
- private emailService: EmailService,
- private announcementService: AnnouncementService,
- private systemWebhookService: SystemWebhookService,
- private queueLoggerService: QueueLoggerService,
- ) {
- this.logger = this.queueLoggerService.logger.createSubLogger('check-moderators-activity');
- }
-
- @bindThis
- public async process(): Promise {
- this.logger.info('start.');
-
- const meta = await this.metaService.fetch(false);
- if (!meta.disableRegistration) {
- await this.processImpl();
- } else {
- this.logger.info('is already invitation only.');
- }
-
- this.logger.succ('finish.');
- }
-
- @bindThis
- private async processImpl() {
- const evaluateResult = await this.evaluateModeratorsInactiveDays();
- if (evaluateResult.isModeratorsInactive) {
- this.logger.warn(`The moderator has been inactive for ${MODERATOR_INACTIVITY_LIMIT_DAYS} days. We will move to invitation only.`);
-
- await this.changeToInvitationOnly();
- await this.notifyChangeToInvitationOnly();
- } else {
- const remainingTime = evaluateResult.remainingTime;
- if (remainingTime.asDays <= MODERATOR_INACTIVITY_WARNING_REMAINING_DAYS) {
- const timeVariant = remainingTime.asDays === 0 ? `${remainingTime.asHours} hours` : `${remainingTime.asDays} days`;
- this.logger.warn(`A moderator has been inactive for a period of time. If you are inactive for an additional ${timeVariant}, it will switch to invitation only.`);
-
- if (remainingTime.asHours % MODERATOR_INACTIVITY_WARNING_NOTIFY_INTERVAL_HOURS === 0) {
- // ジョブの実行頻度と同等だと通知が多すぎるため期限から6時間ごとに通知する
- // つまり、のこり2日を切ったら6時間ごとに通知が送られる
- await this.notifyInactiveModeratorsWarning(remainingTime);
- }
- }
- }
- }
-
- /**
- * モデレーターが不在であるかどうかを確認する。trueの場合はモデレーターが不在である。
- * isModerator, isAdministrator, isRootのいずれかがtrueのユーザを対象に、
- * {@link MiUser.lastActiveDate}の値が実行日時の{@link MODERATOR_INACTIVITY_LIMIT_DAYS}日前よりも古いユーザがいるかどうかを確認する。
- * {@link MiUser.lastActiveDate}がnullの場合は、そのユーザは確認の対象外とする。
- *
- * -----
- *
- * ### サンプルパターン
- * - 実行日時: 2022-01-30 12:00:00
- * - 判定基準: 2022-01-23 12:00:00(実行日時の{@link MODERATOR_INACTIVITY_LIMIT_DAYS}日前)
- *
- * #### パターン①
- * - モデレータA: lastActiveDate = 2022-01-20 00:00:00 ※アウト
- * - モデレータB: lastActiveDate = 2022-01-23 12:00:00 ※セーフ(判定基準と同値なのでギリギリ残り0日)
- * - モデレータC: lastActiveDate = 2022-01-23 11:59:59 ※アウト(残り-1日)
- * - モデレータD: lastActiveDate = null
- *
- * この場合、モデレータBのアクティビティのみ判定基準日よりも古くないため、モデレーターが在席と判断される。
- *
- * #### パターン②
- * - モデレータA: lastActiveDate = 2022-01-20 00:00:00 ※アウト
- * - モデレータB: lastActiveDate = 2022-01-22 12:00:00 ※アウト(残り-1日)
- * - モデレータC: lastActiveDate = 2022-01-23 11:59:59 ※アウト(残り-1日)
- * - モデレータD: lastActiveDate = null
- *
- * この場合、モデレータA, B, Cのアクティビティは判定基準日よりも古いため、モデレーターが不在と判断される。
- */
- @bindThis
- public async evaluateModeratorsInactiveDays(): Promise {
- const today = new Date();
- const inactivePeriod = new Date(today);
- inactivePeriod.setDate(today.getDate() - MODERATOR_INACTIVITY_LIMIT_DAYS);
-
- const moderators = await this.fetchModerators()
- .then(it => it.filter(it => it.lastActiveDate != null));
- const inactiveModerators = moderators
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- .filter(it => it.lastActiveDate!.getTime() < inactivePeriod.getTime());
-
- // 残りの猶予を示したいので、最終アクティブ日時が一番若いモデレータの日数を基準に猶予を計算する
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const newestLastActiveDate = new Date(Math.max(...moderators.map(it => it.lastActiveDate!.getTime())));
- const remainingTime = newestLastActiveDate.getTime() - inactivePeriod.getTime();
- const remainingTimeAsDays = Math.floor(remainingTime / ONE_DAY_MILLI_SEC);
- const remainingTimeAsHours = Math.floor((remainingTime / ONE_HOUR_MILLI_SEC));
-
- return {
- isModeratorsInactive: inactiveModerators.length === moderators.length,
- inactiveModerators,
- remainingTime: {
- time: remainingTime,
- asHours: remainingTimeAsHours,
- asDays: remainingTimeAsDays,
- },
- };
- }
-
- @bindThis
- private async changeToInvitationOnly() {
- await this.metaService.update({ disableRegistration: true });
- }
-
- @bindThis
- public async notifyInactiveModeratorsWarning(remainingTime: ModeratorInactivityRemainingTime) {
- // -- モデレータへのメール送信
-
- const moderators = await this.fetchModerators();
- const moderatorProfiles = await this.userProfilesRepository
- .findBy({ userId: In(moderators.map(it => it.id)) })
- .then(it => new Map(it.map(it => [it.userId, it])));
-
- const mail = generateModeratorInactivityMail(remainingTime);
- for (const moderator of moderators) {
- const profile = moderatorProfiles.get(moderator.id);
- if (profile && profile.email && profile.emailVerified) {
- this.emailService.sendEmail(profile.email, mail.subject, mail.html, mail.text);
- }
- }
-
- // -- SystemWebhook
-
- const systemWebhooks = await this.systemWebhookService.fetchActiveSystemWebhooks()
- .then(it => it.filter(it => it.on.includes('inactiveModeratorsWarning')));
- for (const systemWebhook of systemWebhooks) {
- this.systemWebhookService.enqueueSystemWebhook(
- systemWebhook,
- 'inactiveModeratorsWarning',
- { remainingTime: remainingTime },
- );
- }
- }
-
- @bindThis
- public async notifyChangeToInvitationOnly() {
- // -- モデレータへのメールとお知らせ(個人向け)送信
-
- const moderators = await this.fetchModerators();
- const moderatorProfiles = await this.userProfilesRepository
- .findBy({ userId: In(moderators.map(it => it.id)) })
- .then(it => new Map(it.map(it => [it.userId, it])));
-
- const mail = generateInvitationOnlyChangedMail();
- for (const moderator of moderators) {
- this.announcementService.create({
- title: mail.subject,
- text: mail.text,
- forExistingUsers: true,
- needConfirmationToRead: true,
- userId: moderator.id,
- });
-
- const profile = moderatorProfiles.get(moderator.id);
- if (profile && profile.email && profile.emailVerified) {
- this.emailService.sendEmail(profile.email, mail.subject, mail.html, mail.text);
- }
- }
-
- // -- SystemWebhook
-
- const systemWebhooks = await this.systemWebhookService.fetchActiveSystemWebhooks()
- .then(it => it.filter(it => it.on.includes('inactiveModeratorsInvitationOnlyChanged')));
- for (const systemWebhook of systemWebhooks) {
- this.systemWebhookService.enqueueSystemWebhook(
- systemWebhook,
- 'inactiveModeratorsInvitationOnlyChanged',
- {},
- );
- }
- }
-
- @bindThis
- private async fetchModerators() {
- // TODO: モデレーター以外にも特別な権限を持つユーザーがいる場合は考慮する
- return this.roleService.getModerators({
- includeAdmins: true,
- includeRoot: true,
- excludeExpire: true,
- });
- }
-}
diff --git a/packages/backend/src/queue/processors/DeliverProcessorService.ts b/packages/backend/src/queue/processors/DeliverProcessorService.ts
index 5a16496011..d665945861 100644
--- a/packages/backend/src/queue/processors/DeliverProcessorService.ts
+++ b/packages/backend/src/queue/processors/DeliverProcessorService.ts
@@ -7,8 +7,9 @@ import { Inject, Injectable } from '@nestjs/common';
import * as Bull from 'bullmq';
import { Not } from 'typeorm';
import { DI } from '@/di-symbols.js';
-import type { InstancesRepository, MiMeta } from '@/models/_.js';
+import type { InstancesRepository } from '@/models/_.js';
import type Logger from '@/logger.js';
+import { MetaService } from '@/core/MetaService.js';
import { ApRequestService } from '@/core/activitypub/ApRequestService.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
import { FetchInstanceMetadataService } from '@/core/FetchInstanceMetadataService.js';
@@ -30,12 +31,10 @@ export class DeliverProcessorService {
private latest: string | null;
constructor(
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.instancesRepository)
private instancesRepository: InstancesRepository,
+ private metaService: MetaService,
private utilityService: UtilityService,
private federatedInstanceService: FederatedInstanceService,
private fetchInstanceMetadataService: FetchInstanceMetadataService,
@@ -46,14 +45,16 @@ export class DeliverProcessorService {
private queueLoggerService: QueueLoggerService,
) {
this.logger = this.queueLoggerService.logger.createSubLogger('deliver');
- this.suspendedHostsCache = new MemorySingleCache(1000 * 60 * 60); // 1h
+ this.suspendedHostsCache = new MemorySingleCache(1000 * 60 * 60);
}
@bindThis
public async process(job: Bull.Job): Promise {
const { host } = new URL(job.data.to);
- if (!this.utilityService.isFederationAllowedUri(job.data.to)) {
+ // ブロックしてたら中断
+ const meta = await this.metaService.fetch();
+ if (this.utilityService.isBlockedHost(meta.blockedHosts, this.utilityService.toPuny(host))) {
return 'skip (blocked)';
}
@@ -74,17 +75,8 @@ export class DeliverProcessorService {
try {
await this.apRequestService.signedPost(job.data.user, job.data.to, job.data.content, job.data.digest);
- this.apRequestChart.deliverSucc();
- this.federationChart.deliverd(host, true);
-
- // Update instance stats
- process.nextTick(async () => {
- const i = await (this.meta.enableStatsForFederatedInstances
- ? this.federatedInstanceService.fetchOrRegister(host)
- : this.federatedInstanceService.fetch(host));
-
- if (i == null) return;
-
+ // Update stats
+ this.federatedInstanceService.fetch(host).then(i => {
if (i.isNotResponding) {
this.federatedInstanceService.update(i.id, {
isNotResponding: false,
@@ -92,22 +84,19 @@ export class DeliverProcessorService {
});
}
- if (this.meta.enableStatsForFederatedInstances) {
- this.fetchInstanceMetadataService.fetchInstanceMetadata(i);
- }
+ this.fetchInstanceMetadataService.fetchInstanceMetadata(i);
+ this.apRequestChart.deliverSucc();
+ this.federationChart.deliverd(i.host, true);
- if (this.meta.enableChartsForFederatedInstances) {
+ if (meta.enableChartsForFederatedInstances) {
this.instanceChart.requestSent(i.host, true);
}
});
return 'Success';
} catch (res) {
- this.apRequestChart.deliverFail();
- this.federationChart.deliverd(host, false);
-
- // Update instance stats
- this.federatedInstanceService.fetchOrRegister(host).then(i => {
+ // Update stats
+ this.federatedInstanceService.fetch(host).then(i => {
if (!i.isNotResponding) {
this.federatedInstanceService.update(i.id, {
isNotResponding: true,
@@ -128,7 +117,10 @@ export class DeliverProcessorService {
});
}
- if (this.meta.enableChartsForFederatedInstances) {
+ this.apRequestChart.deliverFail();
+ this.federationChart.deliverd(i.host, false);
+
+ if (meta.enableChartsForFederatedInstances) {
this.instanceChart.requestSent(i.host, false);
}
});
@@ -138,7 +130,7 @@ export class DeliverProcessorService {
if (!res.isRetryable) {
// 相手が閉鎖していることを明示しているため、配送停止する
if (job.data.isSharedInbox && res.statusCode === 410) {
- this.federatedInstanceService.fetchOrRegister(host).then(i => {
+ this.federatedInstanceService.fetch(host).then(i => {
this.federatedInstanceService.update(i.id, {
suspensionState: 'goneSuspended',
});
diff --git a/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts b/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts
index b3111865ad..88c4ea29c0 100644
--- a/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts
+++ b/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts
@@ -14,7 +14,6 @@ import { DriveService } from '@/core/DriveService.js';
import { bindThis } from '@/decorators.js';
import { createTemp } from '@/misc/create-temp.js';
import { UtilityService } from '@/core/UtilityService.js';
-import { NotificationService } from '@/core/NotificationService.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type { DBExportAntennasData } from '../types.js';
import type * as Bull from 'bullmq';
@@ -36,7 +35,6 @@ export class ExportAntennasProcessorService {
private driveService: DriveService,
private utilityService: UtilityService,
private queueLoggerService: QueueLoggerService,
- private notificationService: NotificationService,
) {
this.logger = this.queueLoggerService.logger.createSubLogger('export-antennas');
}
@@ -97,11 +95,6 @@ export class ExportAntennasProcessorService {
const fileName = 'antennas-' + DateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.json';
const driveFile = await this.driveService.addFile({ user, path, name: fileName, force: true, ext: 'json' });
this.logger.succ('Exported to: ' + driveFile.id);
-
- this.notificationService.createNotification(user.id, 'exportCompleted', {
- exportedEntity: 'antenna',
- fileId: driveFile.id,
- });
} finally {
cleanup();
}
diff --git a/packages/backend/src/queue/processors/ExportBlockingProcessorService.ts b/packages/backend/src/queue/processors/ExportBlockingProcessorService.ts
index ecc439db69..6ec3c18786 100644
--- a/packages/backend/src/queue/processors/ExportBlockingProcessorService.ts
+++ b/packages/backend/src/queue/processors/ExportBlockingProcessorService.ts
@@ -13,7 +13,6 @@ import type Logger from '@/logger.js';
import { DriveService } from '@/core/DriveService.js';
import { createTemp } from '@/misc/create-temp.js';
import { UtilityService } from '@/core/UtilityService.js';
-import { NotificationService } from '@/core/NotificationService.js';
import { bindThis } from '@/decorators.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type * as Bull from 'bullmq';
@@ -31,7 +30,6 @@ export class ExportBlockingProcessorService {
private blockingsRepository: BlockingsRepository,
private utilityService: UtilityService,
- private notificationService: NotificationService,
private driveService: DriveService,
private queueLoggerService: QueueLoggerService,
) {
@@ -111,11 +109,6 @@ export class ExportBlockingProcessorService {
const driveFile = await this.driveService.addFile({ user, path, name: fileName, force: true, ext: 'csv' });
this.logger.succ(`Exported to: ${driveFile.id}`);
-
- this.notificationService.createNotification(user.id, 'exportCompleted', {
- exportedEntity: 'blocking',
- fileId: driveFile.id,
- });
} finally {
cleanup();
}
diff --git a/packages/backend/src/queue/processors/ExportClipsProcessorService.ts b/packages/backend/src/queue/processors/ExportClipsProcessorService.ts
index 583ddbb745..01eab26e96 100644
--- a/packages/backend/src/queue/processors/ExportClipsProcessorService.ts
+++ b/packages/backend/src/queue/processors/ExportClipsProcessorService.ts
@@ -19,7 +19,6 @@ import { bindThis } from '@/decorators.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
import { Packed } from '@/misc/json-schema.js';
import { IdService } from '@/core/IdService.js';
-import { NotificationService } from '@/core/NotificationService.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type * as Bull from 'bullmq';
import type { DbJobDataWithUser } from '../types.js';
@@ -44,7 +43,6 @@ export class ExportClipsProcessorService {
private driveService: DriveService,
private queueLoggerService: QueueLoggerService,
private idService: IdService,
- private notificationService: NotificationService,
) {
this.logger = this.queueLoggerService.logger.createSubLogger('export-clips');
}
@@ -81,11 +79,6 @@ export class ExportClipsProcessorService {
const driveFile = await this.driveService.addFile({ user, path, name: fileName, force: true, ext: 'json' });
this.logger.succ(`Exported to: ${driveFile.id}`);
-
- this.notificationService.createNotification(user.id, 'exportCompleted', {
- exportedEntity: 'clip',
- fileId: driveFile.id,
- });
} finally {
cleanup();
}
diff --git a/packages/backend/src/queue/processors/ExportCustomEmojisProcessorService.ts b/packages/backend/src/queue/processors/ExportCustomEmojisProcessorService.ts
index e237cd4975..e4eb4791bd 100644
--- a/packages/backend/src/queue/processors/ExportCustomEmojisProcessorService.ts
+++ b/packages/backend/src/queue/processors/ExportCustomEmojisProcessorService.ts
@@ -16,7 +16,6 @@ import type Logger from '@/logger.js';
import { DriveService } from '@/core/DriveService.js';
import { createTemp, createTempDir } from '@/misc/create-temp.js';
import { DownloadService } from '@/core/DownloadService.js';
-import { NotificationService } from '@/core/NotificationService.js';
import { bindThis } from '@/decorators.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type * as Bull from 'bullmq';
@@ -38,7 +37,6 @@ export class ExportCustomEmojisProcessorService {
private driveService: DriveService,
private downloadService: DownloadService,
private queueLoggerService: QueueLoggerService,
- private notificationService: NotificationService,
) {
this.logger = this.queueLoggerService.logger.createSubLogger('export-custom-emojis');
}
@@ -136,12 +134,6 @@ export class ExportCustomEmojisProcessorService {
const driveFile = await this.driveService.addFile({ user, path: archivePath, name: fileName, force: true });
this.logger.succ(`Exported to: ${driveFile.id}`);
-
- this.notificationService.createNotification(user.id, 'exportCompleted', {
- exportedEntity: 'customEmoji',
- fileId: driveFile.id,
- });
-
cleanup();
archiveCleanup();
resolve();
diff --git a/packages/backend/src/queue/processors/ExportFavoritesProcessorService.ts b/packages/backend/src/queue/processors/ExportFavoritesProcessorService.ts
index b81feece01..7bb626dd31 100644
--- a/packages/backend/src/queue/processors/ExportFavoritesProcessorService.ts
+++ b/packages/backend/src/queue/processors/ExportFavoritesProcessorService.ts
@@ -16,7 +16,6 @@ import type { MiPoll } from '@/models/Poll.js';
import type { MiNote } from '@/models/Note.js';
import { bindThis } from '@/decorators.js';
import { IdService } from '@/core/IdService.js';
-import { NotificationService } from '@/core/NotificationService.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type * as Bull from 'bullmq';
import type { DbJobDataWithUser } from '../types.js';
@@ -38,7 +37,6 @@ export class ExportFavoritesProcessorService {
private driveService: DriveService,
private queueLoggerService: QueueLoggerService,
private idService: IdService,
- private notificationService: NotificationService,
) {
this.logger = this.queueLoggerService.logger.createSubLogger('export-favorites');
}
@@ -125,11 +123,6 @@ export class ExportFavoritesProcessorService {
const driveFile = await this.driveService.addFile({ user, path, name: fileName, force: true, ext: 'json' });
this.logger.succ(`Exported to: ${driveFile.id}`);
-
- this.notificationService.createNotification(user.id, 'exportCompleted', {
- exportedEntity: 'favorite',
- fileId: driveFile.id,
- });
} finally {
cleanup();
}
diff --git a/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts b/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts
index 903f962515..1cc80e66d7 100644
--- a/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts
+++ b/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts
@@ -14,7 +14,6 @@ import { DriveService } from '@/core/DriveService.js';
import { createTemp } from '@/misc/create-temp.js';
import type { MiFollowing } from '@/models/Following.js';
import { UtilityService } from '@/core/UtilityService.js';
-import { NotificationService } from '@/core/NotificationService.js';
import { bindThis } from '@/decorators.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type * as Bull from 'bullmq';
@@ -37,7 +36,6 @@ export class ExportFollowingProcessorService {
private utilityService: UtilityService,
private driveService: DriveService,
private queueLoggerService: QueueLoggerService,
- private notificationService: NotificationService,
) {
this.logger = this.queueLoggerService.logger.createSubLogger('export-following');
}
@@ -115,11 +113,6 @@ export class ExportFollowingProcessorService {
const driveFile = await this.driveService.addFile({ user, path, name: fileName, force: true, ext: 'csv' });
this.logger.succ(`Exported to: ${driveFile.id}`);
-
- this.notificationService.createNotification(user.id, 'exportCompleted', {
- exportedEntity: 'following',
- fileId: driveFile.id,
- });
} finally {
cleanup();
}
diff --git a/packages/backend/src/queue/processors/ExportMutingProcessorService.ts b/packages/backend/src/queue/processors/ExportMutingProcessorService.ts
index f9867ade29..243b74f2c2 100644
--- a/packages/backend/src/queue/processors/ExportMutingProcessorService.ts
+++ b/packages/backend/src/queue/processors/ExportMutingProcessorService.ts
@@ -13,7 +13,6 @@ import type Logger from '@/logger.js';
import { DriveService } from '@/core/DriveService.js';
import { createTemp } from '@/misc/create-temp.js';
import { UtilityService } from '@/core/UtilityService.js';
-import { NotificationService } from '@/core/NotificationService.js';
import { bindThis } from '@/decorators.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type * as Bull from 'bullmq';
@@ -33,7 +32,6 @@ export class ExportMutingProcessorService {
private utilityService: UtilityService,
private driveService: DriveService,
private queueLoggerService: QueueLoggerService,
- private notificationService: NotificationService,
) {
this.logger = this.queueLoggerService.logger.createSubLogger('export-muting');
}
@@ -112,11 +110,6 @@ export class ExportMutingProcessorService {
const driveFile = await this.driveService.addFile({ user, path, name: fileName, force: true, ext: 'csv' });
this.logger.succ(`Exported to: ${driveFile.id}`);
-
- this.notificationService.createNotification(user.id, 'exportCompleted', {
- exportedEntity: 'muting',
- fileId: driveFile.id,
- });
} finally {
cleanup();
}
diff --git a/packages/backend/src/queue/processors/ExportNotesProcessorService.ts b/packages/backend/src/queue/processors/ExportNotesProcessorService.ts
index 9e2b678219..c7611012d7 100644
--- a/packages/backend/src/queue/processors/ExportNotesProcessorService.ts
+++ b/packages/backend/src/queue/processors/ExportNotesProcessorService.ts
@@ -18,7 +18,6 @@ import { bindThis } from '@/decorators.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
import { Packed } from '@/misc/json-schema.js';
import { IdService } from '@/core/IdService.js';
-import { NotificationService } from '@/core/NotificationService.js';
import { JsonArrayStream } from '@/misc/JsonArrayStream.js';
import { FileWriterStream } from '@/misc/FileWriterStream.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
@@ -113,7 +112,6 @@ export class ExportNotesProcessorService {
private queueLoggerService: QueueLoggerService,
private driveFileEntityService: DriveFileEntityService,
private idService: IdService,
- private notificationService: NotificationService,
) {
this.logger = this.queueLoggerService.logger.createSubLogger('export-notes');
}
@@ -152,11 +150,6 @@ export class ExportNotesProcessorService {
const driveFile = await this.driveService.addFile({ user, path, name: fileName, force: true, ext: 'json' });
this.logger.succ(`Exported to: ${driveFile.id}`);
-
- this.notificationService.createNotification(user.id, 'exportCompleted', {
- exportedEntity: 'note',
- fileId: driveFile.id,
- });
} finally {
cleanup();
}
diff --git a/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts b/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts
index c483d79854..ee87cff5d3 100644
--- a/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts
+++ b/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts
@@ -13,7 +13,6 @@ import type Logger from '@/logger.js';
import { DriveService } from '@/core/DriveService.js';
import { createTemp } from '@/misc/create-temp.js';
import { UtilityService } from '@/core/UtilityService.js';
-import { NotificationService } from '@/core/NotificationService.js';
import { bindThis } from '@/decorators.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type * as Bull from 'bullmq';
@@ -36,7 +35,6 @@ export class ExportUserListsProcessorService {
private utilityService: UtilityService,
private driveService: DriveService,
private queueLoggerService: QueueLoggerService,
- private notificationService: NotificationService,
) {
this.logger = this.queueLoggerService.logger.createSubLogger('export-user-lists');
}
@@ -91,11 +89,6 @@ export class ExportUserListsProcessorService {
const driveFile = await this.driveService.addFile({ user, path, name: fileName, force: true, ext: 'csv' });
this.logger.succ(`Exported to: ${driveFile.id}`);
-
- this.notificationService.createNotification(user.id, 'exportCompleted', {
- exportedEntity: 'userList',
- fileId: driveFile.id,
- });
} finally {
cleanup();
}
diff --git a/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts b/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts
index 9e1b8fee70..171809d25c 100644
--- a/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts
+++ b/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts
@@ -87,30 +87,23 @@ export class ImportCustomEmojisProcessorService {
await this.emojisRepository.delete({
name: emojiInfo.name,
});
- try {
- const driveFile = await this.driveService.addFile({
- user: null,
- path: emojiPath,
- name: record.fileName,
- force: true,
- });
- await this.customEmojiService.add({
- name: emojiInfo.name,
- category: emojiInfo.category,
- host: null,
- aliases: emojiInfo.aliases,
- driveFile,
- license: emojiInfo.license,
- isSensitive: emojiInfo.isSensitive,
- localOnly: emojiInfo.localOnly,
- roleIdsThatCanBeUsedThisEmojiAsReaction: [],
- });
- } catch (e) {
- if (e instanceof Error || typeof e === 'string') {
- this.logger.error(`couldn't import ${emojiPath} for ${emojiInfo.name}: ${e}`);
- }
- continue;
- }
+ const driveFile = await this.driveService.addFile({
+ user: null,
+ path: emojiPath,
+ name: record.fileName,
+ force: true,
+ });
+ await this.customEmojiService.add({
+ name: emojiInfo.name,
+ category: emojiInfo.category,
+ host: null,
+ aliases: emojiInfo.aliases,
+ driveFile,
+ license: emojiInfo.license,
+ isSensitive: emojiInfo.isSensitive,
+ localOnly: emojiInfo.localOnly,
+ roleIdsThatCanBeUsedThisEmojiAsReaction: [],
+ });
}
cleanup();
diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts
index 95d764e4d8..fa7009f8f5 100644
--- a/packages/backend/src/queue/processors/InboxProcessorService.ts
+++ b/packages/backend/src/queue/processors/InboxProcessorService.ts
@@ -4,10 +4,11 @@
*/
import { URL } from 'node:url';
-import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
+import { Injectable } from '@nestjs/common';
import httpSignature from '@peertube/http-signature';
import * as Bull from 'bullmq';
import type Logger from '@/logger.js';
+import { MetaService } from '@/core/MetaService.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
import { FetchInstanceMetadataService } from '@/core/FetchInstanceMetadataService.js';
import InstanceChart from '@/core/chart/charts/instance.js';
@@ -25,28 +26,16 @@ import { JsonLdService } from '@/core/activitypub/JsonLdService.js';
import { ApInboxService } from '@/core/activitypub/ApInboxService.js';
import { bindThis } from '@/decorators.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
-import { CollapsedQueue } from '@/misc/collapsed-queue.js';
-import { MiNote } from '@/models/Note.js';
-import { MiMeta } from '@/models/Meta.js';
-import { DI } from '@/di-symbols.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type { InboxJobData } from '../types.js';
-type UpdateInstanceJob = {
- latestRequestReceivedAt: Date,
- shouldUnsuspend: boolean,
-};
-
@Injectable()
-export class InboxProcessorService implements OnApplicationShutdown {
+export class InboxProcessorService {
private logger: Logger;
- private updateInstanceQueue: CollapsedQueue;
constructor(
- @Inject(DI.meta)
- private meta: MiMeta,
-
private utilityService: UtilityService,
+ private metaService: MetaService,
private apInboxService: ApInboxService,
private federatedInstanceService: FederatedInstanceService,
private fetchInstanceMetadataService: FetchInstanceMetadataService,
@@ -59,7 +48,6 @@ export class InboxProcessorService implements OnApplicationShutdown {
private queueLoggerService: QueueLoggerService,
) {
this.logger = this.queueLoggerService.logger.createSubLogger('inbox');
- this.updateInstanceQueue = new CollapsedQueue(process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, this.collapseUpdateInstanceJobs, this.performUpdateInstance);
}
@bindThis
@@ -75,7 +63,9 @@ export class InboxProcessorService implements OnApplicationShutdown {
const host = this.utilityService.toPuny(new URL(signature.keyId).hostname);
- if (!this.utilityService.isFederationAllowedHost(host)) {
+ // ブロックしてたら中断
+ const meta = await this.metaService.fetch();
+ if (this.utilityService.isBlockedHost(meta.blockedHosts, host)) {
return `Blocked request: ${host}`;
}
@@ -174,8 +164,9 @@ export class InboxProcessorService implements OnApplicationShutdown {
throw new Bull.UnrecoverableError(`skip: LD-Signature user(${authUser.user.uri}) !== activity.actor(${activity.actor})`);
}
+ // ブロックしてたら中断
const ldHost = this.utilityService.extractDbHost(authUser.user.uri);
- if (!this.utilityService.isFederationAllowedHost(ldHost)) {
+ if (this.utilityService.isBlockedHost(meta.blockedHosts, ldHost)) {
throw new Bull.UnrecoverableError(`Blocked request: ${ldHost}`);
}
} else {
@@ -192,27 +183,23 @@ export class InboxProcessorService implements OnApplicationShutdown {
}
}
- this.apRequestChart.inbox();
- this.federationChart.inbox(authUser.user.host);
-
- // Update instance stats
- process.nextTick(async () => {
- const i = await (this.meta.enableStatsForFederatedInstances
- ? this.federatedInstanceService.fetchOrRegister(authUser.user.host)
- : this.federatedInstanceService.fetch(authUser.user.host));
-
- if (i == null) return;
-
- this.updateInstanceQueue.enqueue(i.id, {
+ // Update stats
+ this.federatedInstanceService.fetch(authUser.user.host).then(i => {
+ this.federatedInstanceService.update(i.id, {
latestRequestReceivedAt: new Date(),
- shouldUnsuspend: i.suspensionState === 'autoSuspendedForNotResponding',
+ isNotResponding: false,
+ // もしサーバーが死んでるために配信が止まっていた場合には自動的に復活させてあげる
+ suspensionState: i.suspensionState === 'autoSuspendedForNotResponding' ? 'none' : undefined,
});
- if (this.meta.enableChartsForFederatedInstances) {
+ this.fetchInstanceMetadataService.fetchInstanceMetadata(i);
+
+ this.apRequestChart.inbox();
+ this.federationChart.inbox(i.host);
+
+ if (meta.enableChartsForFederatedInstances) {
this.instanceChart.requestReceived(i.host);
}
-
- this.fetchInstanceMetadataService.fetchInstanceMetadata(i);
});
// アクティビティを処理
@@ -238,36 +225,4 @@ export class InboxProcessorService implements OnApplicationShutdown {
}
return 'ok';
}
-
- @bindThis
- public collapseUpdateInstanceJobs(oldJob: UpdateInstanceJob, newJob: UpdateInstanceJob) {
- const latestRequestReceivedAt = oldJob.latestRequestReceivedAt < newJob.latestRequestReceivedAt
- ? newJob.latestRequestReceivedAt
- : oldJob.latestRequestReceivedAt;
- const shouldUnsuspend = oldJob.shouldUnsuspend || newJob.shouldUnsuspend;
- return {
- latestRequestReceivedAt,
- shouldUnsuspend,
- };
- }
-
- @bindThis
- public async performUpdateInstance(id: string, job: UpdateInstanceJob) {
- await this.federatedInstanceService.update(id, {
- latestRequestReceivedAt: new Date(),
- isNotResponding: false,
- // もしサーバーが死んでるために配信が止まっていた場合には自動的に復活させてあげる
- suspensionState: job.shouldUnsuspend ? 'none' : undefined,
- });
- }
-
- @bindThis
- public async dispose(): Promise {
- await this.updateInstanceQueue.performAllNow();
- }
-
- @bindThis
- async onApplicationShutdown(signal?: string) {
- await this.dispose();
- }
}
diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts
index ba2342b630..3255d64621 100644
--- a/packages/backend/src/server/ActivityPubServerService.ts
+++ b/packages/backend/src/server/ActivityPubServerService.ts
@@ -29,7 +29,6 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js';
import { IActivity } from '@/core/activitypub/type.js';
import { isQuote, isRenote } from '@/misc/is-renote.js';
-import * as Acct from '@/misc/acct.js';
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions, FastifyBodyParser } from 'fastify';
import type { FindOptionsWhere } from 'typeorm';
@@ -487,16 +486,6 @@ export class ActivityPubServerService {
return;
}
- // リモートだったらリダイレクト
- if (user.host != null) {
- if (user.uri == null || this.utilityService.isSelfHost(user.host)) {
- reply.code(500);
- return;
- }
- reply.redirect(user.uri, 301);
- return;
- }
-
reply.header('Cache-Control', 'public, max-age=180');
this.setResponseType(request, reply);
return (this.apRendererService.addContext(await this.apRendererService.renderPerson(user as MiLocalUser)));
@@ -665,20 +654,19 @@ export class ActivityPubServerService {
const user = await this.usersRepository.findOneBy({
id: userId,
+ host: IsNull(),
isSuspended: false,
});
return await this.userInfo(request, reply, user);
});
- fastify.get<{ Params: { acct: string; } }>('/@:acct', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
+ fastify.get<{ Params: { user: string; } }>('/@:user', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
vary(reply.raw, 'Accept');
- const acct = Acct.parse(request.params.acct);
-
const user = await this.usersRepository.findOneBy({
- usernameLower: acct.username,
- host: acct.host ?? IsNull(),
+ usernameLower: request.params.user.toLowerCase(),
+ host: IsNull(),
isSuspended: false,
});
diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts
index bf0a011699..77a637d895 100644
--- a/packages/backend/src/server/FileServerService.ts
+++ b/packages/backend/src/server/FileServerService.ts
@@ -82,7 +82,7 @@ export class FileServerService {
.catch(err => this.errorHandler(request, reply, err));
});
fastify.get<{ Params: { key: string; } }>('/files/:key/*', async (request, reply) => {
- return await reply.redirect(`${this.config.url}/files/${request.params.key}`, 301);
+ return await reply.redirect(301, `${this.config.url}/files/${request.params.key}`);
});
done();
});
@@ -147,12 +147,12 @@ export class FileServerService {
url.searchParams.set('static', '1');
file.cleanup();
- return await reply.redirect(url.toString(), 301);
+ return await reply.redirect(301, url.toString());
} else if (file.mime.startsWith('video/')) {
const externalThumbnail = this.videoProcessingService.getExternalVideoThumbnailUrl(file.url);
if (externalThumbnail) {
file.cleanup();
- return await reply.redirect(externalThumbnail, 301);
+ return await reply.redirect(301, externalThumbnail);
}
image = await this.videoProcessingService.generateVideoThumbnail(file.path);
@@ -167,7 +167,7 @@ export class FileServerService {
url.searchParams.set('url', file.url);
file.cleanup();
- return await reply.redirect(url.toString(), 301);
+ return await reply.redirect(301, url.toString());
}
}
@@ -314,17 +314,11 @@ export class FileServerService {
}
return await reply.redirect(
- url.toString(),
301,
+ url.toString(),
);
}
- if (!request.headers['user-agent']) {
- throw new StatusError('User-Agent is required', 400, 'User-Agent is required');
- } else if (request.headers['user-agent'].toLowerCase().indexOf('misskey/') !== -1) {
- throw new StatusError('Refusing to proxy a request from another proxy', 403, 'Proxy is recursive');
- }
-
// Create temp file
const file = await this.getStreamAndTypeFromUrl(url);
if (file === '404') {
diff --git a/packages/backend/src/server/HealthServerService.ts b/packages/backend/src/server/HealthServerService.ts
index 5980609f02..2c3ed85925 100644
--- a/packages/backend/src/server/HealthServerService.ts
+++ b/packages/backend/src/server/HealthServerService.ts
@@ -27,9 +27,6 @@ export class HealthServerService {
@Inject(DI.redisForTimelines)
private redisForTimelines: Redis.Redis,
- @Inject(DI.redisForReactions)
- private redisForReactions: Redis.Redis,
-
@Inject(DI.db)
private db: DataSource,
@@ -46,7 +43,6 @@ export class HealthServerService {
this.redisForPub.ping(),
this.redisForSub.ping(),
this.redisForTimelines.ping(),
- this.redisForReactions.ping(),
this.db.query('SELECT 1'),
...(this.meilisearch ? [this.meilisearch.health()] : []),
]).then(() => 200, () => 503));
diff --git a/packages/backend/src/server/NodeinfoServerService.ts b/packages/backend/src/server/NodeinfoServerService.ts
index 9a641007ee..cc18997fdc 100644
--- a/packages/backend/src/server/NodeinfoServerService.ts
+++ b/packages/backend/src/server/NodeinfoServerService.ts
@@ -134,7 +134,7 @@ export class NodeinfoServerService {
return document;
};
- const cache = new MemorySingleCache>>(1000 * 60 * 10); // 10m
+ const cache = new MemorySingleCache>>(1000 * 60 * 10);
fastify.get(nodeinfo2_1path, async (request, reply) => {
const base = await cache.fetch(() => nodeinfo2(21));
diff --git a/packages/backend/src/server/ServerModule.ts b/packages/backend/src/server/ServerModule.ts
index 3ab0b815f2..12d5061985 100644
--- a/packages/backend/src/server/ServerModule.ts
+++ b/packages/backend/src/server/ServerModule.ts
@@ -46,7 +46,6 @@ import { UserListChannelService } from './api/stream/channels/user-list.js';
import { RoleTimelineChannelService } from './api/stream/channels/role-timeline.js';
import { ReversiChannelService } from './api/stream/channels/reversi.js';
import { ReversiGameChannelService } from './api/stream/channels/reversi-game.js';
-import { SigninWithPasskeyApiService } from './api/SigninWithPasskeyApiService.js';
@Module({
imports: [
@@ -72,7 +71,6 @@ import { SigninWithPasskeyApiService } from './api/SigninWithPasskeyApiService.j
AuthenticateService,
RateLimiterService,
SigninApiService,
- SigninWithPasskeyApiService,
SigninService,
SignupApiService,
StreamingApiServerService,
diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts
index fd2bd3267d..9c849480f2 100644
--- a/packages/backend/src/server/ServerService.ts
+++ b/packages/backend/src/server/ServerService.ts
@@ -13,7 +13,7 @@ import fastifyRawBody from 'fastify-raw-body';
import { IsNull } from 'typeorm';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import type { Config } from '@/config.js';
-import type { EmojisRepository, MiMeta, UserProfilesRepository, UsersRepository } from '@/models/_.js';
+import type { EmojisRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import type Logger from '@/logger.js';
import * as Acct from '@/misc/acct.js';
@@ -21,6 +21,7 @@ import { genIdenticon } from '@/misc/gen-identicon.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { LoggerService } from '@/core/LoggerService.js';
import { bindThis } from '@/decorators.js';
+import { MetaService } from '@/core/MetaService.js';
import { ActivityPubServerService } from './ActivityPubServerService.js';
import { NodeinfoServerService } from './NodeinfoServerService.js';
import { ApiServerService } from './api/ApiServerService.js';
@@ -43,9 +44,6 @@ export class ServerService implements OnApplicationShutdown {
@Inject(DI.config)
private config: Config,
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -55,6 +53,7 @@ export class ServerService implements OnApplicationShutdown {
@Inject(DI.emojisRepository)
private emojisRepository: EmojisRepository,
+ private metaService: MetaService,
private userEntityService: UserEntityService,
private apiServerService: ApiServerService,
private openApiServerService: OpenApiServerService,
@@ -166,8 +165,8 @@ export class ServerService implements OnApplicationShutdown {
}
return await reply.redirect(
- url.toString(),
301,
+ url.toString(),
);
});
@@ -194,7 +193,7 @@ export class ServerService implements OnApplicationShutdown {
reply.header('Content-Type', 'image/png');
reply.header('Cache-Control', 'public, max-age=86400');
- if (this.meta.enableIdenticonGeneration) {
+ if ((await this.metaService.fetch()).enableIdenticonGeneration) {
return await genIdenticon(request.params.x);
} else {
return reply.redirect('/static-assets/avatar.png');
diff --git a/packages/backend/src/server/api/ApiCallService.ts b/packages/backend/src/server/api/ApiCallService.ts
index aad833f126..47f64f6609 100644
--- a/packages/backend/src/server/api/ApiCallService.ts
+++ b/packages/backend/src/server/api/ApiCallService.ts
@@ -13,7 +13,8 @@ import { getIpHash } from '@/misc/get-ip-hash.js';
import type { MiLocalUser, MiUser } from '@/models/User.js';
import type { MiAccessToken } from '@/models/AccessToken.js';
import type Logger from '@/logger.js';
-import type { MiMeta, UserIpsRepository } from '@/models/_.js';
+import type { UserIpsRepository } from '@/models/_.js';
+import { MetaService } from '@/core/MetaService.js';
import { createTemp } from '@/misc/create-temp.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
@@ -39,15 +40,13 @@ export class ApiCallService implements OnApplicationShutdown {
private userIpHistoriesClearIntervalId: NodeJS.Timeout;
constructor(
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.config)
private config: Config,
@Inject(DI.userIpsRepository)
private userIpsRepository: UserIpsRepository,
+ private metaService: MetaService,
private authenticateService: AuthenticateService,
private rateLimiterService: RateLimiterService,
private roleService: RoleService,
@@ -65,6 +64,15 @@ export class ApiCallService implements OnApplicationShutdown {
let statusCode = err.httpStatusCode;
if (err.httpStatusCode === 401) {
reply.header('WWW-Authenticate', 'Bearer realm="Misskey"');
+ } else if (err.kind === 'client') {
+ reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="invalid_request", error_description="${err.message}"`);
+ statusCode = statusCode ?? 400;
+ } else if (err.kind === 'permission') {
+ // (ROLE_PERMISSION_DENIEDは関係ない)
+ if (err.code === 'PERMISSION_DENIED') {
+ reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="insufficient_scope", error_description="${err.message}"`);
+ }
+ statusCode = statusCode ?? 403;
} else if (err.code === 'RATE_LIMIT_EXCEEDED') {
const info: unknown = err.info;
const unixEpochInSeconds = Date.now();
@@ -75,15 +83,6 @@ export class ApiCallService implements OnApplicationShutdown {
} else {
this.logger.warn(`rate limit information has unexpected type ${typeof(err.info?.reset)}`);
}
- } else if (err.kind === 'client') {
- reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="invalid_request", error_description="${err.message}"`);
- statusCode = statusCode ?? 400;
- } else if (err.kind === 'permission') {
- // (ROLE_PERMISSION_DENIEDは関係ない)
- if (err.code === 'PERMISSION_DENIED') {
- reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="insufficient_scope", error_description="${err.message}"`);
- }
- statusCode = statusCode ?? 403;
} else if (!statusCode) {
statusCode = 500;
}
@@ -200,18 +199,9 @@ export class ApiCallService implements OnApplicationShutdown {
return;
}
- const [path, cleanup] = await createTemp();
+ const [path] = await createTemp();
await stream.pipeline(multipartData.file, fs.createWriteStream(path));
- // ファイルサイズが制限を超えていた場合
- // なお truncated はストリームを読み切ってからでないと機能しないため、stream.pipeline より後にある必要がある
- if (multipartData.file.truncated) {
- cleanup();
- reply.code(413);
- reply.send();
- return;
- }
-
const fields = {} as Record;
for (const [k, v] of Object.entries(multipartData.fields)) {
fields[k] = typeof v === 'object' && 'value' in v ? v.value : undefined;
@@ -266,8 +256,9 @@ export class ApiCallService implements OnApplicationShutdown {
}
@bindThis
- private logIp(request: FastifyRequest, user: MiLocalUser) {
- if (!this.meta.enableIpLogging) return;
+ private async logIp(request: FastifyRequest, user: MiLocalUser) {
+ const meta = await this.metaService.fetch();
+ if (!meta.enableIpLogging) return;
const ip = request.ip;
const ips = this.userIpHistories.get(user.id);
if (ips == null || !ips.has(ip)) {
diff --git a/packages/backend/src/server/api/ApiServerService.ts b/packages/backend/src/server/api/ApiServerService.ts
index 3a8cb19f01..4a5935f930 100644
--- a/packages/backend/src/server/api/ApiServerService.ts
+++ b/packages/backend/src/server/api/ApiServerService.ts
@@ -8,7 +8,6 @@ import cors from '@fastify/cors';
import multipart from '@fastify/multipart';
import fastifyCookie from '@fastify/cookie';
import { ModuleRef } from '@nestjs/core';
-import { AuthenticationResponseJSON } from '@simplewebauthn/types';
import type { Config } from '@/config.js';
import type { InstancesRepository, AccessTokensRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
@@ -18,7 +17,6 @@ import endpoints from './endpoints.js';
import { ApiCallService } from './ApiCallService.js';
import { SignupApiService } from './SignupApiService.js';
import { SigninApiService } from './SigninApiService.js';
-import { SigninWithPasskeyApiService } from './SigninWithPasskeyApiService.js';
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
@Injectable()
@@ -39,7 +37,6 @@ export class ApiServerService {
private apiCallService: ApiCallService,
private signupApiService: SignupApiService,
private signinApiService: SigninApiService,
- private signinWithPasskeyApiService: SigninWithPasskeyApiService,
) {
//this.createServer = this.createServer.bind(this);
}
@@ -52,7 +49,7 @@ export class ApiServerService {
fastify.register(multipart, {
limits: {
- fileSize: this.config.maxFileSize,
+ fileSize: this.config.maxFileSize ?? 262144000,
files: 1,
},
});
@@ -118,31 +115,21 @@ export class ApiServerService {
'hcaptcha-response'?: string;
'g-recaptcha-response'?: string;
'turnstile-response'?: string;
- 'm-captcha-response'?: string;
- 'testcaptcha-response'?: string;
}
}>('/signup', (request, reply) => this.signupApiService.signup(request, reply));
fastify.post<{
Body: {
username: string;
- password?: string;
+ password: string;
token?: string;
- credential?: AuthenticationResponseJSON;
- 'hcaptcha-response'?: string;
- 'g-recaptcha-response'?: string;
- 'turnstile-response'?: string;
- 'm-captcha-response'?: string;
- 'testcaptcha-response'?: string;
+ signature?: string;
+ authenticatorData?: string;
+ clientDataJSON?: string;
+ credentialId?: string;
+ challengeId?: string;
};
- }>('/signin-flow', (request, reply) => this.signinApiService.signin(request, reply));
-
- fastify.post<{
- Body: {
- credential?: AuthenticationResponseJSON;
- context?: string;
- };
- }>('/signin-with-passkey', (request, reply) => this.signinWithPasskeyApiService.signin(request, reply));
+ }>('/signin', (request, reply) => this.signinApiService.signin(request, reply));
fastify.post<{ Body: { code: string; } }>('/signup-pending', (request, reply) => this.signupApiService.signupPending(request, reply));
diff --git a/packages/backend/src/server/api/AuthenticateService.ts b/packages/backend/src/server/api/AuthenticateService.ts
index 690ff2e022..ddef8db987 100644
--- a/packages/backend/src/server/api/AuthenticateService.ts
+++ b/packages/backend/src/server/api/AuthenticateService.ts
@@ -37,7 +37,7 @@ export class AuthenticateService implements OnApplicationShutdown {
private cacheService: CacheService,
) {
- this.appCache = new MemoryKVCache(1000 * 60 * 60 * 24 * 7); // 1w
+ this.appCache = new MemoryKVCache(Infinity);
}
@bindThis
diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts
index 3557fa40a5..41576bedaa 100644
--- a/packages/backend/src/server/api/EndpointsModule.ts
+++ b/packages/backend/src/server/api/EndpointsModule.ts
@@ -68,8 +68,6 @@ import * as ep___admin_relays_list from './endpoints/admin/relays/list.js';
import * as ep___admin_relays_remove from './endpoints/admin/relays/remove.js';
import * as ep___admin_resetPassword from './endpoints/admin/reset-password.js';
import * as ep___admin_resolveAbuseUserReport from './endpoints/admin/resolve-abuse-user-report.js';
-import * as ep___admin_forwardAbuseUserReport from './endpoints/admin/forward-abuse-user-report.js';
-import * as ep___admin_updateAbuseUserReport from './endpoints/admin/update-abuse-user-report.js';
import * as ep___admin_sendEmail from './endpoints/admin/send-email.js';
import * as ep___admin_serverInfo from './endpoints/admin/server-info.js';
import * as ep___admin_showModerationLogs from './endpoints/admin/show-moderation-logs.js';
@@ -94,7 +92,6 @@ import * as ep___admin_systemWebhook_delete from './endpoints/admin/system-webho
import * as ep___admin_systemWebhook_list from './endpoints/admin/system-webhook/list.js';
import * as ep___admin_systemWebhook_show from './endpoints/admin/system-webhook/show.js';
import * as ep___admin_systemWebhook_update from './endpoints/admin/system-webhook/update.js';
-import * as ep___admin_systemWebhook_test from './endpoints/admin/system-webhook/test.js';
import * as ep___announcements from './endpoints/announcements.js';
import * as ep___announcements_show from './endpoints/announcements/show.js';
import * as ep___antennas_create from './endpoints/antennas/create.js';
@@ -261,7 +258,6 @@ import * as ep___i_webhooks_show from './endpoints/i/webhooks/show.js';
import * as ep___i_webhooks_list from './endpoints/i/webhooks/list.js';
import * as ep___i_webhooks_update from './endpoints/i/webhooks/update.js';
import * as ep___i_webhooks_delete from './endpoints/i/webhooks/delete.js';
-import * as ep___i_webhooks_test from './endpoints/i/webhooks/test.js';
import * as ep___invite_create from './endpoints/invite/create.js';
import * as ep___invite_delete from './endpoints/invite/delete.js';
import * as ep___invite_list from './endpoints/invite/list.js';
@@ -455,8 +451,6 @@ const $admin_relays_list: Provider = { provide: 'ep:admin/relays/list', useClass
const $admin_relays_remove: Provider = { provide: 'ep:admin/relays/remove', useClass: ep___admin_relays_remove.default };
const $admin_resetPassword: Provider = { provide: 'ep:admin/reset-password', useClass: ep___admin_resetPassword.default };
const $admin_resolveAbuseUserReport: Provider = { provide: 'ep:admin/resolve-abuse-user-report', useClass: ep___admin_resolveAbuseUserReport.default };
-const $admin_forwardAbuseUserReport: Provider = { provide: 'ep:admin/forward-abuse-user-report', useClass: ep___admin_forwardAbuseUserReport.default };
-const $admin_updateAbuseUserReport: Provider = { provide: 'ep:admin/update-abuse-user-report', useClass: ep___admin_updateAbuseUserReport.default };
const $admin_sendEmail: Provider = { provide: 'ep:admin/send-email', useClass: ep___admin_sendEmail.default };
const $admin_serverInfo: Provider = { provide: 'ep:admin/server-info', useClass: ep___admin_serverInfo.default };
const $admin_showModerationLogs: Provider = { provide: 'ep:admin/show-moderation-logs', useClass: ep___admin_showModerationLogs.default };
@@ -481,7 +475,6 @@ const $admin_systemWebhook_delete: Provider = { provide: 'ep:admin/system-webhoo
const $admin_systemWebhook_list: Provider = { provide: 'ep:admin/system-webhook/list', useClass: ep___admin_systemWebhook_list.default };
const $admin_systemWebhook_show: Provider = { provide: 'ep:admin/system-webhook/show', useClass: ep___admin_systemWebhook_show.default };
const $admin_systemWebhook_update: Provider = { provide: 'ep:admin/system-webhook/update', useClass: ep___admin_systemWebhook_update.default };
-const $admin_systemWebhook_test: Provider = { provide: 'ep:admin/system-webhook/test', useClass: ep___admin_systemWebhook_test.default };
const $announcements: Provider = { provide: 'ep:announcements', useClass: ep___announcements.default };
const $announcements_show: Provider = { provide: 'ep:announcements/show', useClass: ep___announcements_show.default };
const $antennas_create: Provider = { provide: 'ep:antennas/create', useClass: ep___antennas_create.default };
@@ -648,7 +641,6 @@ const $i_webhooks_list: Provider = { provide: 'ep:i/webhooks/list', useClass: ep
const $i_webhooks_show: Provider = { provide: 'ep:i/webhooks/show', useClass: ep___i_webhooks_show.default };
const $i_webhooks_update: Provider = { provide: 'ep:i/webhooks/update', useClass: ep___i_webhooks_update.default };
const $i_webhooks_delete: Provider = { provide: 'ep:i/webhooks/delete', useClass: ep___i_webhooks_delete.default };
-const $i_webhooks_test: Provider = { provide: 'ep:i/webhooks/test', useClass: ep___i_webhooks_test.default };
const $invite_create: Provider = { provide: 'ep:invite/create', useClass: ep___invite_create.default };
const $invite_delete: Provider = { provide: 'ep:invite/delete', useClass: ep___invite_delete.default };
const $invite_list: Provider = { provide: 'ep:invite/list', useClass: ep___invite_list.default };
@@ -846,8 +838,6 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
$admin_relays_remove,
$admin_resetPassword,
$admin_resolveAbuseUserReport,
- $admin_forwardAbuseUserReport,
- $admin_updateAbuseUserReport,
$admin_sendEmail,
$admin_serverInfo,
$admin_showModerationLogs,
@@ -872,7 +862,6 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
$admin_systemWebhook_list,
$admin_systemWebhook_show,
$admin_systemWebhook_update,
- $admin_systemWebhook_test,
$announcements,
$announcements_show,
$antennas_create,
@@ -1039,7 +1028,6 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
$i_webhooks_show,
$i_webhooks_update,
$i_webhooks_delete,
- $i_webhooks_test,
$invite_create,
$invite_delete,
$invite_list,
@@ -1231,8 +1219,6 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
$admin_relays_remove,
$admin_resetPassword,
$admin_resolveAbuseUserReport,
- $admin_forwardAbuseUserReport,
- $admin_updateAbuseUserReport,
$admin_sendEmail,
$admin_serverInfo,
$admin_showModerationLogs,
@@ -1257,7 +1243,6 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
$admin_systemWebhook_list,
$admin_systemWebhook_show,
$admin_systemWebhook_update,
- $admin_systemWebhook_test,
$announcements,
$announcements_show,
$antennas_create,
@@ -1424,7 +1409,6 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
$i_webhooks_show,
$i_webhooks_update,
$i_webhooks_delete,
- $i_webhooks_test,
$invite_create,
$invite_delete,
$invite_list,
diff --git a/packages/backend/src/server/api/GetterService.ts b/packages/backend/src/server/api/GetterService.ts
index 444e6db744..bff3ab96f3 100644
--- a/packages/backend/src/server/api/GetterService.ts
+++ b/packages/backend/src/server/api/GetterService.ts
@@ -39,17 +39,6 @@ export class GetterService {
return note;
}
- @bindThis
- public async getNoteWithUser(noteId: MiNote['id']) {
- const note = await this.notesRepository.findOne({ where: { id: noteId }, relations: ['user'] });
-
- if (note == null) {
- throw new IdentifiableError('9725d0ce-ba28-4dde-95a7-2cbb2c15de24', 'No such note.');
- }
-
- return note;
- }
-
/**
* Get user for API processing
*/
diff --git a/packages/backend/src/server/api/SigninApiService.ts b/packages/backend/src/server/api/SigninApiService.ts
index 1d983ca4bc..edac9b3beb 100644
--- a/packages/backend/src/server/api/SigninApiService.ts
+++ b/packages/backend/src/server/api/SigninApiService.ts
@@ -5,14 +5,12 @@
import { Inject, Injectable } from '@nestjs/common';
import bcrypt from 'bcryptjs';
+import * as OTPAuth from 'otpauth';
import { IsNull } from 'typeorm';
-import * as Misskey from 'misskey-js';
import { DI } from '@/di-symbols.js';
import type {
- MiMeta,
SigninsRepository,
UserProfilesRepository,
- UserSecurityKeysRepository,
UsersRepository,
} from '@/models/_.js';
import type { Config } from '@/config.js';
@@ -22,8 +20,6 @@ import { IdService } from '@/core/IdService.js';
import { bindThis } from '@/decorators.js';
import { WebAuthnService } from '@/core/WebAuthnService.js';
import { UserAuthService } from '@/core/UserAuthService.js';
-import { CaptchaService } from '@/core/CaptchaService.js';
-import { FastifyReplyError } from '@/misc/fastify-reply-error.js';
import { RateLimiterService } from './RateLimiterService.js';
import { SigninService } from './SigninService.js';
import type { AuthenticationResponseJSON } from '@simplewebauthn/types';
@@ -35,18 +31,12 @@ export class SigninApiService {
@Inject(DI.config)
private config: Config,
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@Inject(DI.userProfilesRepository)
private userProfilesRepository: UserProfilesRepository,
- @Inject(DI.userSecurityKeysRepository)
- private userSecurityKeysRepository: UserSecurityKeysRepository,
-
@Inject(DI.signinsRepository)
private signinsRepository: SigninsRepository,
@@ -55,7 +45,6 @@ export class SigninApiService {
private signinService: SigninService,
private userAuthService: UserAuthService,
private webAuthnService: WebAuthnService,
- private captchaService: CaptchaService,
) {
}
@@ -64,14 +53,9 @@ export class SigninApiService {
request: FastifyRequest<{
Body: {
username: string;
- password?: string;
+ password: string;
token?: string;
credential?: AuthenticationResponseJSON;
- 'hcaptcha-response'?: string;
- 'g-recaptcha-response'?: string;
- 'turnstile-response'?: string;
- 'm-captcha-response'?: string;
- 'testcaptcha-response'?: string;
};
}>,
reply: FastifyReply,
@@ -108,6 +92,11 @@ export class SigninApiService {
return;
}
+ if (typeof password !== 'string') {
+ reply.code(400);
+ return;
+ }
+
if (token != null && typeof token !== 'string') {
reply.code(400);
return;
@@ -132,32 +121,11 @@ export class SigninApiService {
}
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
- const securityKeysAvailable = await this.userSecurityKeysRepository.countBy({ userId: user.id }).then(result => result >= 1);
-
- if (password == null) {
- reply.code(200);
- if (profile.twoFactorEnabled) {
- return {
- finished: false,
- next: 'password',
- } satisfies Misskey.entities.SigninFlowResponse;
- } else {
- return {
- finished: false,
- next: 'captcha',
- } satisfies Misskey.entities.SigninFlowResponse;
- }
- }
-
- if (typeof password !== 'string') {
- reply.code(400);
- return;
- }
// Compare password
const same = await bcrypt.compare(password, profile.password!);
- const fail = async (status?: number, failure?: { id: string; }) => {
+ const fail = async (status?: number, failure?: { id: string }) => {
// Append signin history
await this.signinsRepository.insert({
id: this.idService.gen(),
@@ -171,38 +139,6 @@ export class SigninApiService {
};
if (!profile.twoFactorEnabled) {
- if (process.env.NODE_ENV !== 'test') {
- if (this.meta.enableHcaptcha && this.meta.hcaptchaSecretKey) {
- await this.captchaService.verifyHcaptcha(this.meta.hcaptchaSecretKey, body['hcaptcha-response']).catch(err => {
- throw new FastifyReplyError(400, err);
- });
- }
-
- if (this.meta.enableMcaptcha && this.meta.mcaptchaSecretKey && this.meta.mcaptchaSitekey && this.meta.mcaptchaInstanceUrl) {
- await this.captchaService.verifyMcaptcha(this.meta.mcaptchaSecretKey, this.meta.mcaptchaSitekey, this.meta.mcaptchaInstanceUrl, body['m-captcha-response']).catch(err => {
- throw new FastifyReplyError(400, err);
- });
- }
-
- if (this.meta.enableRecaptcha && this.meta.recaptchaSecretKey) {
- await this.captchaService.verifyRecaptcha(this.meta.recaptchaSecretKey, body['g-recaptcha-response']).catch(err => {
- throw new FastifyReplyError(400, err);
- });
- }
-
- if (this.meta.enableTurnstile && this.meta.turnstileSecretKey) {
- await this.captchaService.verifyTurnstile(this.meta.turnstileSecretKey, body['turnstile-response']).catch(err => {
- throw new FastifyReplyError(400, err);
- });
- }
-
- if (this.meta.enableTestcaptcha) {
- await this.captchaService.verifyTestcaptcha(body['testcaptcha-response']).catch(err => {
- throw new FastifyReplyError(400, err);
- });
- }
- }
-
if (same) {
return this.signinService.signin(request, reply, user);
} else {
@@ -244,7 +180,7 @@ export class SigninApiService {
id: '93b86c4b-72f9-40eb-9815-798928603d1e',
});
}
- } else if (securityKeysAvailable) {
+ } else {
if (!same && !profile.usePasswordLessLogin) {
return await fail(403, {
id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c',
@@ -254,23 +190,7 @@ export class SigninApiService {
const authRequest = await this.webAuthnService.initiateAuthentication(user.id);
reply.code(200);
- return {
- finished: false,
- next: 'passkey',
- authRequest,
- } satisfies Misskey.entities.SigninFlowResponse;
- } else {
- if (!same || !profile.twoFactorEnabled) {
- return await fail(403, {
- id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c',
- });
- } else {
- reply.code(200);
- return {
- finished: false,
- next: 'totp',
- } satisfies Misskey.entities.SigninFlowResponse;
- }
+ return authRequest;
}
// never get here
}
diff --git a/packages/backend/src/server/api/SigninService.ts b/packages/backend/src/server/api/SigninService.ts
index 640356b50c..70306c3113 100644
--- a/packages/backend/src/server/api/SigninService.ts
+++ b/packages/backend/src/server/api/SigninService.ts
@@ -4,16 +4,13 @@
*/
import { Inject, Injectable } from '@nestjs/common';
-import * as Misskey from 'misskey-js';
import { DI } from '@/di-symbols.js';
-import type { SigninsRepository, UserProfilesRepository } from '@/models/_.js';
+import type { SigninsRepository } from '@/models/_.js';
import { IdService } from '@/core/IdService.js';
import type { MiLocalUser } from '@/models/User.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { SigninEntityService } from '@/core/entities/SigninEntityService.js';
import { bindThis } from '@/decorators.js';
-import { EmailService } from '@/core/EmailService.js';
-import { NotificationService } from '@/core/NotificationService.js';
import type { FastifyRequest, FastifyReply } from 'fastify';
@Injectable()
@@ -22,12 +19,7 @@ export class SigninService {
@Inject(DI.signinsRepository)
private signinsRepository: SigninsRepository,
- @Inject(DI.userProfilesRepository)
- private userProfilesRepository: UserProfilesRepository,
-
private signinEntityService: SigninEntityService,
- private emailService: EmailService,
- private notificationService: NotificationService,
private idService: IdService,
private globalEventService: GlobalEventService,
) {
@@ -36,8 +28,7 @@ export class SigninService {
@bindThis
public signin(request: FastifyRequest, reply: FastifyReply, user: MiLocalUser) {
setImmediate(async () => {
- this.notificationService.createNotification(user.id, 'login', {});
-
+ // Append signin history
const record = await this.signinsRepository.insertOne({
id: this.idService.gen(),
userId: user.id,
@@ -46,22 +37,15 @@ export class SigninService {
success: true,
});
+ // Publish signin event
this.globalEventService.publishMainStream(user.id, 'signin', await this.signinEntityService.pack(record));
-
- const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
- if (profile.email && profile.emailVerified) {
- this.emailService.sendEmail(profile.email, 'New login / ログインがありました',
- 'There is a new login. If you do not recognize this login, update the security status of your account, including changing your password. / 新しいログインがありました。このログインに心当たりがない場合は、パスワードを変更するなど、アカウントのセキュリティ状態を更新してください。',
- 'There is a new login. If you do not recognize this login, update the security status of your account, including changing your password. / 新しいログインがありました。このログインに心当たりがない場合は、パスワードを変更するなど、アカウントのセキュリティ状態を更新してください。');
- }
});
reply.code(200);
return {
- finished: true,
id: user.id,
- i: user.token!,
- } satisfies Misskey.entities.SigninFlowResponse;
+ i: user.token,
+ };
}
}
diff --git a/packages/backend/src/server/api/SigninWithPasskeyApiService.ts b/packages/backend/src/server/api/SigninWithPasskeyApiService.ts
deleted file mode 100644
index 9ba23c54e2..0000000000
--- a/packages/backend/src/server/api/SigninWithPasskeyApiService.ts
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { randomUUID } from 'crypto';
-import { Inject, Injectable } from '@nestjs/common';
-import { IsNull } from 'typeorm';
-import { DI } from '@/di-symbols.js';
-import type {
- SigninsRepository,
- UserProfilesRepository,
- UsersRepository,
-} from '@/models/_.js';
-import type { Config } from '@/config.js';
-import { getIpHash } from '@/misc/get-ip-hash.js';
-import type { MiLocalUser, MiUser } from '@/models/User.js';
-import { IdService } from '@/core/IdService.js';
-import { bindThis } from '@/decorators.js';
-import { WebAuthnService } from '@/core/WebAuthnService.js';
-import Logger from '@/logger.js';
-import { LoggerService } from '@/core/LoggerService.js';
-import type { IdentifiableError } from '@/misc/identifiable-error.js';
-import { RateLimiterService } from './RateLimiterService.js';
-import { SigninService } from './SigninService.js';
-import type { AuthenticationResponseJSON } from '@simplewebauthn/types';
-import type { FastifyReply, FastifyRequest } from 'fastify';
-
-@Injectable()
-export class SigninWithPasskeyApiService {
- private logger: Logger;
- constructor(
- @Inject(DI.config)
- private config: Config,
-
- @Inject(DI.usersRepository)
- private usersRepository: UsersRepository,
-
- @Inject(DI.userProfilesRepository)
- private userProfilesRepository: UserProfilesRepository,
-
- @Inject(DI.signinsRepository)
- private signinsRepository: SigninsRepository,
-
- private idService: IdService,
- private rateLimiterService: RateLimiterService,
- private signinService: SigninService,
- private webAuthnService: WebAuthnService,
- private loggerService: LoggerService,
- ) {
- this.logger = this.loggerService.getLogger('PasskeyAuth');
- }
-
- @bindThis
- public async signin(
- request: FastifyRequest<{
- Body: {
- credential?: AuthenticationResponseJSON;
- context?: string;
- };
- }>,
- reply: FastifyReply,
- ) {
- reply.header('Access-Control-Allow-Origin', this.config.url);
- reply.header('Access-Control-Allow-Credentials', 'true');
-
- const body = request.body;
- const credential = body['credential'];
-
- function error(status: number, error: { id: string }) {
- reply.code(status);
- return { error };
- }
-
- const fail = async (userId: MiUser['id'], status?: number, failure?: { id: string }) => {
- // Append signin history
- await this.signinsRepository.insert({
- id: this.idService.gen(),
- userId: userId,
- ip: request.ip,
- headers: request.headers as any,
- success: false,
- });
- return error(status ?? 500, failure ?? { id: '4e30e80c-e338-45a0-8c8f-44455efa3b76' });
- };
-
- try {
- // Not more than 1 API call per 250ms and not more than 100 attempts per 30min
- // NOTE: 1 Sign-in require 2 API calls
- await this.rateLimiterService.limit({ key: 'signin-with-passkey', duration: 60 * 30 * 1000, max: 200, minInterval: 250 }, getIpHash(request.ip));
- } catch (err) {
- reply.code(429);
- return {
- error: {
- message: 'Too many failed attempts to sign in. Try again later.',
- code: 'TOO_MANY_AUTHENTICATION_FAILURES',
- id: '22d05606-fbcf-421a-a2db-b32610dcfd1b',
- },
- };
- }
-
- // Initiate Passkey Auth challenge with context
- if (!credential) {
- const context = randomUUID();
- this.logger.info(`Initiate Passkey challenge: context: ${context}`);
- const authChallengeOptions = {
- option: await this.webAuthnService.initiateSignInWithPasskeyAuthentication(context),
- context: context,
- };
- reply.code(200);
- return authChallengeOptions;
- }
-
- const context = body.context;
- if (!context || typeof context !== 'string') {
- // If try Authentication without context
- return error(400, {
- id: '1658cc2e-4495-461f-aee4-d403cdf073c1',
- });
- }
-
- this.logger.debug(`Try Sign-in with Passkey: context: ${context}`);
-
- let authorizedUserId: MiUser['id'] | null;
- try {
- authorizedUserId = await this.webAuthnService.verifySignInWithPasskeyAuthentication(context, credential);
- } catch (err) {
- this.logger.warn(`Passkey challenge Verify error! : ${err}`);
- const errorId = (err as IdentifiableError).id;
- return error(403, {
- id: errorId,
- });
- }
-
- if (!authorizedUserId) {
- return error(403, {
- id: '932c904e-9460-45b7-9ce6-7ed33be7eb2c',
- });
- }
-
- // Fetch user
- const user = await this.usersRepository.findOneBy({
- id: authorizedUserId,
- host: IsNull(),
- }) as MiLocalUser | null;
-
- if (user == null) {
- return error(403, {
- id: '652f899f-66d4-490e-993e-6606c8ec04c3',
- });
- }
-
- if (user.isSuspended) {
- return error(403, {
- id: 'e03a5f46-d309-4865-9b69-56282d94e1eb',
- });
- }
-
- const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
-
- // Authentication was successful, but passwordless login is not enabled
- if (!profile.usePasswordLessLogin) {
- return await fail(user.id, 403, {
- id: '2d84773e-f7b7-4d0b-8f72-bb69b584c912',
- });
- }
-
- const signinResponse = this.signinService.signin(request, reply, user);
- return {
- signinResponse: signinResponse,
- };
- }
-}
diff --git a/packages/backend/src/server/api/SignupApiService.ts b/packages/backend/src/server/api/SignupApiService.ts
index 3ec5e5d3e6..632b0c62bc 100644
--- a/packages/backend/src/server/api/SignupApiService.ts
+++ b/packages/backend/src/server/api/SignupApiService.ts
@@ -7,8 +7,9 @@ import { Inject, Injectable } from '@nestjs/common';
import bcrypt from 'bcryptjs';
import { IsNull } from 'typeorm';
import { DI } from '@/di-symbols.js';
-import type { RegistrationTicketsRepository, UsedUsernamesRepository, UserPendingsRepository, UserProfilesRepository, UsersRepository, MiRegistrationTicket, MiMeta } from '@/models/_.js';
+import type { RegistrationTicketsRepository, UsedUsernamesRepository, UserPendingsRepository, UserProfilesRepository, UsersRepository, MiRegistrationTicket } from '@/models/_.js';
import type { Config } from '@/config.js';
+import { MetaService } from '@/core/MetaService.js';
import { CaptchaService } from '@/core/CaptchaService.js';
import { IdService } from '@/core/IdService.js';
import { SignupService } from '@/core/SignupService.js';
@@ -27,9 +28,6 @@ export class SignupApiService {
@Inject(DI.config)
private config: Config,
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -47,6 +45,7 @@ export class SignupApiService {
private userEntityService: UserEntityService,
private idService: IdService,
+ private metaService: MetaService,
private captchaService: CaptchaService,
private signupService: SignupService,
private signinService: SigninService,
@@ -67,42 +66,37 @@ export class SignupApiService {
'g-recaptcha-response'?: string;
'turnstile-response'?: string;
'm-captcha-response'?: string;
- 'testcaptcha-response'?: string;
}
}>,
reply: FastifyReply,
) {
const body = request.body;
+ const instance = await this.metaService.fetch(true);
+
// Verify *Captcha
// ただしテスト時はこの機構は障害となるため無効にする
if (process.env.NODE_ENV !== 'test') {
- if (this.meta.enableHcaptcha && this.meta.hcaptchaSecretKey) {
- await this.captchaService.verifyHcaptcha(this.meta.hcaptchaSecretKey, body['hcaptcha-response']).catch(err => {
+ if (instance.enableHcaptcha && instance.hcaptchaSecretKey) {
+ await this.captchaService.verifyHcaptcha(instance.hcaptchaSecretKey, body['hcaptcha-response']).catch(err => {
throw new FastifyReplyError(400, err);
});
}
- if (this.meta.enableMcaptcha && this.meta.mcaptchaSecretKey && this.meta.mcaptchaSitekey && this.meta.mcaptchaInstanceUrl) {
- await this.captchaService.verifyMcaptcha(this.meta.mcaptchaSecretKey, this.meta.mcaptchaSitekey, this.meta.mcaptchaInstanceUrl, body['m-captcha-response']).catch(err => {
+ if (instance.enableMcaptcha && instance.mcaptchaSecretKey && instance.mcaptchaSitekey && instance.mcaptchaInstanceUrl) {
+ await this.captchaService.verifyMcaptcha(instance.mcaptchaSecretKey, instance.mcaptchaSitekey, instance.mcaptchaInstanceUrl, body['m-captcha-response']).catch(err => {
throw new FastifyReplyError(400, err);
});
}
- if (this.meta.enableRecaptcha && this.meta.recaptchaSecretKey) {
- await this.captchaService.verifyRecaptcha(this.meta.recaptchaSecretKey, body['g-recaptcha-response']).catch(err => {
+ if (instance.enableRecaptcha && instance.recaptchaSecretKey) {
+ await this.captchaService.verifyRecaptcha(instance.recaptchaSecretKey, body['g-recaptcha-response']).catch(err => {
throw new FastifyReplyError(400, err);
});
}
- if (this.meta.enableTurnstile && this.meta.turnstileSecretKey) {
- await this.captchaService.verifyTurnstile(this.meta.turnstileSecretKey, body['turnstile-response']).catch(err => {
- throw new FastifyReplyError(400, err);
- });
- }
-
- if (this.meta.enableTestcaptcha) {
- await this.captchaService.verifyTestcaptcha(body['testcaptcha-response']).catch(err => {
+ if (instance.enableTurnstile && instance.turnstileSecretKey) {
+ await this.captchaService.verifyTurnstile(instance.turnstileSecretKey, body['turnstile-response']).catch(err => {
throw new FastifyReplyError(400, err);
});
}
@@ -114,7 +108,7 @@ export class SignupApiService {
const invitationCode = body['invitationCode'];
const emailAddress = body['emailAddress'];
- if (this.meta.emailRequiredForSignup) {
+ if (instance.emailRequiredForSignup) {
if (emailAddress == null || typeof emailAddress !== 'string') {
reply.code(400);
return;
@@ -129,7 +123,7 @@ export class SignupApiService {
let ticket: MiRegistrationTicket | null = null;
- if (this.meta.disableRegistration) {
+ if (instance.disableRegistration) {
if (invitationCode == null || typeof invitationCode !== 'string') {
reply.code(400);
return;
@@ -150,7 +144,7 @@ export class SignupApiService {
}
// メアド認証が有効の場合
- if (this.meta.emailRequiredForSignup) {
+ if (instance.emailRequiredForSignup) {
// メアド認証済みならエラー
if (ticket.usedBy) {
reply.code(400);
@@ -168,7 +162,7 @@ export class SignupApiService {
}
}
- if (this.meta.emailRequiredForSignup) {
+ if (instance.emailRequiredForSignup) {
if (await this.usersRepository.exists({ where: { usernameLower: username.toLowerCase(), host: IsNull() } })) {
throw new FastifyReplyError(400, 'DUPLICATED_USERNAME');
}
@@ -178,7 +172,7 @@ export class SignupApiService {
throw new FastifyReplyError(400, 'USED_USERNAME');
}
- const isPreserved = this.meta.preservedUsernames.map(x => x.toLowerCase()).includes(username.toLowerCase());
+ const isPreserved = instance.preservedUsernames.map(x => x.toLowerCase()).includes(username.toLowerCase());
if (isPreserved) {
throw new FastifyReplyError(400, 'DENIED_USERNAME');
}
diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts
index 49b07d6ced..3dfb7fdad4 100644
--- a/packages/backend/src/server/api/endpoints.ts
+++ b/packages/backend/src/server/api/endpoints.ts
@@ -74,8 +74,6 @@ import * as ep___admin_relays_list from './endpoints/admin/relays/list.js';
import * as ep___admin_relays_remove from './endpoints/admin/relays/remove.js';
import * as ep___admin_resetPassword from './endpoints/admin/reset-password.js';
import * as ep___admin_resolveAbuseUserReport from './endpoints/admin/resolve-abuse-user-report.js';
-import * as ep___admin_forwardAbuseUserReport from './endpoints/admin/forward-abuse-user-report.js';
-import * as ep___admin_updateAbuseUserReport from './endpoints/admin/update-abuse-user-report.js';
import * as ep___admin_sendEmail from './endpoints/admin/send-email.js';
import * as ep___admin_serverInfo from './endpoints/admin/server-info.js';
import * as ep___admin_showModerationLogs from './endpoints/admin/show-moderation-logs.js';
@@ -100,7 +98,6 @@ import * as ep___admin_systemWebhook_delete from './endpoints/admin/system-webho
import * as ep___admin_systemWebhook_list from './endpoints/admin/system-webhook/list.js';
import * as ep___admin_systemWebhook_show from './endpoints/admin/system-webhook/show.js';
import * as ep___admin_systemWebhook_update from './endpoints/admin/system-webhook/update.js';
-import * as ep___admin_systemWebhook_test from './endpoints/admin/system-webhook/test.js';
import * as ep___announcements from './endpoints/announcements.js';
import * as ep___announcements_show from './endpoints/announcements/show.js';
import * as ep___antennas_create from './endpoints/antennas/create.js';
@@ -267,7 +264,6 @@ import * as ep___i_webhooks_show from './endpoints/i/webhooks/show.js';
import * as ep___i_webhooks_list from './endpoints/i/webhooks/list.js';
import * as ep___i_webhooks_update from './endpoints/i/webhooks/update.js';
import * as ep___i_webhooks_delete from './endpoints/i/webhooks/delete.js';
-import * as ep___i_webhooks_test from './endpoints/i/webhooks/test.js';
import * as ep___invite_create from './endpoints/invite/create.js';
import * as ep___invite_delete from './endpoints/invite/delete.js';
import * as ep___invite_list from './endpoints/invite/list.js';
@@ -459,8 +455,6 @@ const eps = [
['admin/relays/remove', ep___admin_relays_remove],
['admin/reset-password', ep___admin_resetPassword],
['admin/resolve-abuse-user-report', ep___admin_resolveAbuseUserReport],
- ['admin/forward-abuse-user-report', ep___admin_forwardAbuseUserReport],
- ['admin/update-abuse-user-report', ep___admin_updateAbuseUserReport],
['admin/send-email', ep___admin_sendEmail],
['admin/server-info', ep___admin_serverInfo],
['admin/show-moderation-logs', ep___admin_showModerationLogs],
@@ -485,7 +479,6 @@ const eps = [
['admin/system-webhook/list', ep___admin_systemWebhook_list],
['admin/system-webhook/show', ep___admin_systemWebhook_show],
['admin/system-webhook/update', ep___admin_systemWebhook_update],
- ['admin/system-webhook/test', ep___admin_systemWebhook_test],
['announcements', ep___announcements],
['announcements/show', ep___announcements_show],
['antennas/create', ep___antennas_create],
@@ -652,7 +645,6 @@ const eps = [
['i/webhooks/show', ep___i_webhooks_show],
['i/webhooks/update', ep___i_webhooks_update],
['i/webhooks/delete', ep___i_webhooks_delete],
- ['i/webhooks/test', ep___i_webhooks_test],
['invite/create', ep___invite_create],
['invite/delete', ep___invite_delete],
['invite/list', ep___invite_list],
diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts
index 0dbfaae054..cf3f257ca6 100644
--- a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts
+++ b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts
@@ -71,22 +71,9 @@ export const meta = {
},
assignee: {
type: 'object',
- nullable: true, optional: false,
+ nullable: true, optional: true,
ref: 'UserDetailedNotMe',
},
- forwarded: {
- type: 'boolean',
- nullable: false, optional: false,
- },
- resolvedAs: {
- type: 'string',
- nullable: true, optional: false,
- enum: ['accept', 'reject', null],
- },
- moderationNote: {
- type: 'string',
- nullable: false, optional: false,
- },
},
},
},
@@ -101,6 +88,7 @@ export const paramDef = {
state: { type: 'string', nullable: true, default: null },
reporterOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'combined' },
targetUserOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'combined' },
+ forwarded: { type: 'boolean', default: false },
},
required: [],
} as const;
diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts
index d30131a62f..a7e8a3b018 100644
--- a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts
+++ b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts
@@ -12,27 +12,11 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { InstanceActorService } from '@/core/InstanceActorService.js';
import { localUsernameSchema, passwordSchema } from '@/models/User.js';
import { DI } from '@/di-symbols.js';
-import type { Config } from '@/config.js';
-import { ApiError } from '@/server/api/error.js';
import { Packed } from '@/misc/json-schema.js';
export const meta = {
tags: ['admin'],
- errors: {
- accessDenied: {
- message: 'Access denied.',
- code: 'ACCESS_DENIED',
- id: '1fb7cb09-d46a-4fff-b8df-057708cce513',
- },
-
- wrongInitialPassword: {
- message: 'Initial password is incorrect.',
- code: 'INCORRECT_INITIAL_PASSWORD',
- id: '97147c55-1ae1-4f6f-91d6-e1c3e0e76d62',
- },
- },
-
res: {
type: 'object',
optional: false, nullable: false,
@@ -51,7 +35,6 @@ export const paramDef = {
properties: {
username: localUsernameSchema,
password: passwordSchema,
- setupPassword: { type: 'string', nullable: true },
},
required: ['username', 'password'],
} as const;
@@ -59,9 +42,6 @@ export const paramDef = {
@Injectable()
export default class extends Endpoint { // eslint-disable-line import/no-default-export
constructor(
- @Inject(DI.config)
- private config: Config,
-
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -72,23 +52,7 @@ export default class extends Endpoint { // eslint-
super(meta, paramDef, async (ps, _me, token) => {
const me = _me ? await this.usersRepository.findOneByOrFail({ id: _me.id }) : null;
const realUsers = await this.instanceActorService.realLocalUsersPresent();
-
- if (!realUsers && me == null && token == null) {
- // 初回セットアップの場合
- if (this.config.setupPassword != null) {
- // 初期パスワードが設定されている場合
- if (ps.setupPassword !== this.config.setupPassword) {
- // 初期パスワードが違う場合
- throw new ApiError(meta.errors.wrongInitialPassword);
- }
- } else if (ps.setupPassword != null && ps.setupPassword.trim() !== '') {
- // 初期パスワードが設定されていないのに初期パスワードが入力された場合
- throw new ApiError(meta.errors.wrongInitialPassword);
- }
- } else if ((realUsers && !me?.isRoot) || token !== null) {
- // 初回セットアップではなく、管理者でない場合 or 外部トークンを使用している場合
- throw new ApiError(meta.errors.accessDenied);
- }
+ if ((realUsers && !me?.isRoot) || token !== null) throw new Error('access denied');
const { account, secret } = await this.signupService.signup({
username: ps.username,
diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts
index 87d80cbe80..fd21309818 100644
--- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts
+++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/create.ts
@@ -6,7 +6,6 @@
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
-import { IdService } from '@/core/IdService.js';
export const meta = {
tags: ['admin'],
@@ -14,49 +13,6 @@ export const meta = {
requireCredential: true,
requireRolePolicy: 'canManageAvatarDecorations',
kind: 'write:admin:avatar-decorations',
-
- res: {
- type: 'object',
- optional: false, nullable: false,
- properties: {
- id: {
- type: 'string',
- optional: false, nullable: false,
- format: 'id',
- },
- createdAt: {
- type: 'string',
- optional: false, nullable: false,
- format: 'date-time',
- },
- updatedAt: {
- type: 'string',
- optional: false, nullable: true,
- format: 'date-time',
- },
- name: {
- type: 'string',
- optional: false, nullable: false,
- },
- description: {
- type: 'string',
- optional: false, nullable: false,
- },
- url: {
- type: 'string',
- optional: false, nullable: false,
- },
- roleIdsThatCanBeUsedThisDecoration: {
- type: 'array',
- optional: false, nullable: false,
- items: {
- type: 'string',
- optional: false, nullable: false,
- format: 'id',
- },
- },
- },
- },
} as const;
export const paramDef = {
@@ -76,25 +32,14 @@ export const paramDef = {
export default class extends Endpoint { // eslint-disable-line import/no-default-export
constructor(
private avatarDecorationService: AvatarDecorationService,
- private idService: IdService,
) {
super(meta, paramDef, async (ps, me) => {
- const created = await this.avatarDecorationService.create({
+ await this.avatarDecorationService.create({
name: ps.name,
description: ps.description,
url: ps.url,
roleIdsThatCanBeUsedThisDecoration: ps.roleIdsThatCanBeUsedThisDecoration,
}, me);
-
- return {
- id: created.id,
- createdAt: this.idService.parse(created.id).date.toISOString(),
- updatedAt: null,
- name: created.name,
- description: created.description,
- url: created.url,
- roleIdsThatCanBeUsedThisDecoration: created.roleIdsThatCanBeUsedThisDecoration,
- };
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts
index d785f085ac..aee90023e1 100644
--- a/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts
+++ b/packages/backend/src/server/api/endpoints/admin/avatar-decorations/list.ts
@@ -4,7 +4,10 @@
*/
import { Inject, Injectable } from '@nestjs/common';
+import type { AnnouncementsRepository, AnnouncementReadsRepository } from '@/models/_.js';
+import type { MiAnnouncement } from '@/models/Announcement.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
+import { QueryService } from '@/core/QueryService.js';
import { DI } from '@/di-symbols.js';
import { IdService } from '@/core/IdService.js';
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts
index 212cba5c5d..22609a16a3 100644
--- a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts
+++ b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts
@@ -6,7 +6,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
-import type { DriveFilesRepository, MiEmoji } from '@/models/_.js';
+import type { DriveFilesRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';
@@ -78,14 +78,25 @@ export default class extends Endpoint { // eslint-
if (driveFile == null) throw new ApiError(meta.errors.noSuchFile);
}
- // JSON schemeのanyOfの型変換がうまくいっていないらしい
- const required = { id: ps.id, name: ps.name } as
- | { id: MiEmoji['id']; name?: string }
- | { id?: MiEmoji['id']; name: string };
+ let emojiId;
+ if (ps.id) {
+ emojiId = ps.id;
+ const emoji = await this.customEmojiService.getEmojiById(ps.id);
+ if (!emoji) throw new ApiError(meta.errors.noSuchEmoji);
+ if (ps.name && (ps.name !== emoji.name)) {
+ const isDuplicate = await this.customEmojiService.checkDuplicate(ps.name);
+ if (isDuplicate) throw new ApiError(meta.errors.sameNameEmojiExists);
+ }
+ } else {
+ if (!ps.name) throw new Error('Invalid Params unexpectedly passed. This is a BUG. Please report it to the development team.');
+ const emoji = await this.customEmojiService.getEmojiByName(ps.name);
+ if (!emoji) throw new ApiError(meta.errors.noSuchEmoji);
+ emojiId = emoji.id;
+ }
- const error = await this.customEmojiService.update({
- ...required,
+ await this.customEmojiService.update(emojiId, {
driveFile,
+ name: ps.name,
category: ps.category,
aliases: ps.aliases,
license: ps.license,
@@ -93,14 +104,6 @@ export default class extends Endpoint { // eslint-
localOnly: ps.localOnly,
roleIdsThatCanBeUsedThisEmojiAsReaction: ps.roleIdsThatCanBeUsedThisEmojiAsReaction,
}, me);
-
- switch (error) {
- case null: return;
- case 'NO_SUCH_EMOJI': throw new ApiError(meta.errors.noSuchEmoji);
- case 'SAME_NAME_EMOJI_EXISTS': throw new ApiError(meta.errors.sameNameEmojiExists);
- }
- // 網羅性チェック
- const mustBeNever: never = error;
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/admin/forward-abuse-user-report.ts b/packages/backend/src/server/api/endpoints/admin/forward-abuse-user-report.ts
deleted file mode 100644
index 3e42c91fed..0000000000
--- a/packages/backend/src/server/api/endpoints/admin/forward-abuse-user-report.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Inject, Injectable } from '@nestjs/common';
-import { Endpoint } from '@/server/api/endpoint-base.js';
-import type { AbuseUserReportsRepository } from '@/models/_.js';
-import { DI } from '@/di-symbols.js';
-import { ApiError } from '@/server/api/error.js';
-import { AbuseReportService } from '@/core/AbuseReportService.js';
-
-export const meta = {
- tags: ['admin'],
-
- requireCredential: true,
- requireModerator: true,
- kind: 'write:admin:resolve-abuse-user-report',
-
- errors: {
- noSuchAbuseReport: {
- message: 'No such abuse report.',
- code: 'NO_SUCH_ABUSE_REPORT',
- id: '8763e21b-d9bc-40be-acf6-54c1a6986493',
- kind: 'server',
- httpStatusCode: 404,
- },
- },
-} as const;
-
-export const paramDef = {
- type: 'object',
- properties: {
- reportId: { type: 'string', format: 'misskey:id' },
- },
- required: ['reportId'],
-} as const;
-
-@Injectable()
-export default class extends Endpoint { // eslint-disable-line import/no-default-export
- constructor(
- @Inject(DI.abuseUserReportsRepository)
- private abuseUserReportsRepository: AbuseUserReportsRepository,
- private abuseReportService: AbuseReportService,
- ) {
- super(meta, paramDef, async (ps, me) => {
- const report = await this.abuseUserReportsRepository.findOneBy({ id: ps.reportId });
- if (!report) {
- throw new ApiError(meta.errors.noSuchAbuseReport);
- }
-
- await this.abuseReportService.forward(report.id, me);
- });
- }
-}
diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts
index 64e3cc33bd..2e7f73da73 100644
--- a/packages/backend/src/server/api/endpoints/admin/meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/meta.ts
@@ -69,10 +69,6 @@ export const meta = {
type: 'string',
optional: false, nullable: true,
},
- enableTestcaptcha: {
- type: 'boolean',
- optional: false, nullable: false,
- },
swPublickey: {
type: 'string',
optional: false, nullable: true,
@@ -177,13 +173,6 @@ export const meta = {
type: 'string',
},
},
- prohibitedWordsForNameOfUser: {
- type: 'array',
- optional: false, nullable: false,
- items: {
- type: 'string',
- },
- },
bannedEmailDomains: {
type: 'array',
optional: true, nullable: false,
@@ -348,10 +337,6 @@ export const meta = {
type: 'boolean',
optional: false, nullable: false,
},
- enableStatsForFederatedInstances: {
- type: 'boolean',
- optional: false, nullable: false,
- },
enableServerMachineStats: {
type: 'boolean',
optional: false, nullable: false,
@@ -392,10 +377,6 @@ export const meta = {
type: 'number',
optional: false, nullable: false,
},
- enableReactionsBuffering: {
- type: 'boolean',
- optional: false, nullable: false,
- },
notesPerOneAd: {
type: 'number',
optional: false, nullable: false,
@@ -510,18 +491,6 @@ export const meta = {
type: 'string',
optional: false, nullable: true,
},
- federation: {
- type: 'string',
- optional: false, nullable: false,
- },
- federationHosts: {
- type: 'array',
- optional: false, nullable: false,
- items: {
- type: 'string',
- optional: false, nullable: false,
- },
- },
},
},
} as const;
@@ -570,7 +539,6 @@ export default class extends Endpoint { // eslint-
recaptchaSiteKey: instance.recaptchaSiteKey,
enableTurnstile: instance.enableTurnstile,
turnstileSiteKey: instance.turnstileSiteKey,
- enableTestcaptcha: instance.enableTestcaptcha,
swPublickey: instance.swPublicKey,
themeColor: instance.themeColor,
mascotImageUrl: instance.mascotImageUrl,
@@ -597,7 +565,6 @@ export default class extends Endpoint { // eslint-
mediaSilencedHosts: instance.mediaSilencedHosts,
sensitiveWords: instance.sensitiveWords,
prohibitedWords: instance.prohibitedWords,
- prohibitedWordsForNameOfUser: instance.prohibitedWordsForNameOfUser,
preservedUsernames: instance.preservedUsernames,
hcaptchaSecretKey: instance.hcaptchaSecretKey,
mcaptchaSecretKey: instance.mcaptchaSecretKey,
@@ -639,7 +606,6 @@ export default class extends Endpoint { // eslint-
truemailAuthKey: instance.truemailAuthKey,
enableChartsForRemoteUser: instance.enableChartsForRemoteUser,
enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances,
- enableStatsForFederatedInstances: instance.enableStatsForFederatedInstances,
enableServerMachineStats: instance.enableServerMachineStats,
enableIdenticonGeneration: instance.enableIdenticonGeneration,
bannedEmailDomains: instance.bannedEmailDomains,
@@ -651,7 +617,6 @@ export default class extends Endpoint { // eslint-
perRemoteUserUserTimelineCacheMax: instance.perRemoteUserUserTimelineCacheMax,
perUserHomeTimelineCacheMax: instance.perUserHomeTimelineCacheMax,
perUserListTimelineCacheMax: instance.perUserListTimelineCacheMax,
- enableReactionsBuffering: instance.enableReactionsBuffering,
notesPerOneAd: instance.notesPerOneAd,
summalyProxy: instance.urlPreviewSummaryProxyUrl,
urlPreviewEnabled: instance.urlPreviewEnabled,
@@ -660,8 +625,6 @@ export default class extends Endpoint { // eslint-
urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength,
urlPreviewUserAgent: instance.urlPreviewUserAgent,
urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl,
- federation: instance.federation,
- federationHosts: instance.federationHosts,
};
});
}
diff --git a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts
index f3e440b4cb..7a3410ffa7 100644
--- a/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts
+++ b/packages/backend/src/server/api/endpoints/admin/queue/deliver-delayed.ts
@@ -21,15 +21,16 @@ export const meta = {
items: {
type: 'array',
optional: false, nullable: false,
- prefixItems: [
- {
- type: 'string',
- },
- {
- type: 'number',
- },
- ],
- unevaluatedItems: false,
+ items: {
+ anyOf: [
+ {
+ type: 'string',
+ },
+ {
+ type: 'number',
+ },
+ ],
+ },
},
example: [[
'example.com',
diff --git a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts
index e7589cba81..305ae1af1d 100644
--- a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts
+++ b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts
@@ -21,15 +21,16 @@ export const meta = {
items: {
type: 'array',
optional: false, nullable: false,
- prefixItems: [
- {
- type: 'string',
- },
- {
- type: 'number',
- },
- ],
- unevaluatedItems: false,
+ items: {
+ anyOf: [
+ {
+ type: 'string',
+ },
+ {
+ type: 'number',
+ },
+ ],
+ },
},
example: [[
'example.com',
diff --git a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts
index 554d324ff2..9b79100fcf 100644
--- a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts
+++ b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts
@@ -32,7 +32,7 @@ export const paramDef = {
type: 'object',
properties: {
reportId: { type: 'string', format: 'misskey:id' },
- resolvedAs: { type: 'string', enum: ['accept', 'reject', null], nullable: true },
+ forward: { type: 'boolean', default: false },
},
required: ['reportId'],
} as const;
@@ -50,7 +50,7 @@ export default class extends Endpoint { // eslint-
throw new ApiError(meta.errors.noSuchAbuseReport);
}
- await this.abuseReportService.resolve([{ reportId: report.id, resolvedAs: ps.resolvedAs ?? null }], me);
+ await this.abuseReportService.resolve([{ reportId: report.id, forward: ps.forward }], me);
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts
index 655bd32bce..5a1c05f41a 100644
--- a/packages/backend/src/server/api/endpoints/admin/show-user.ts
+++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts
@@ -31,10 +31,6 @@ export const meta = {
type: 'boolean',
optional: false, nullable: false,
},
- followedMessage: {
- type: 'string',
- optional: false, nullable: true,
- },
autoAcceptFollowed: {
type: 'boolean',
optional: false, nullable: false,
@@ -230,7 +226,6 @@ export default class extends Endpoint { // eslint-
return {
email: profile.email,
emailVerified: profile.emailVerified,
- followedMessage: profile.followedMessage,
autoAcceptFollowed: profile.autoAcceptFollowed,
noCrawle: profile.noCrawle,
preventAiLearning: profile.preventAiLearning,
diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts
index 2b2c8c60ab..2fef9abbf9 100644
--- a/packages/backend/src/server/api/endpoints/admin/show-users.ts
+++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts
@@ -71,13 +71,13 @@ export default class extends Endpoint { // eslint-
break;
}
case 'moderator': {
- const moderatorIds = await this.roleService.getModeratorIds({ includeAdmins: false });
+ const moderatorIds = await this.roleService.getModeratorIds(false);
if (moderatorIds.length === 0) return [];
query.where('user.id IN (:...moderatorIds)', { moderatorIds: moderatorIds });
break;
}
case 'adminOrModerator': {
- const adminOrModeratorIds = await this.roleService.getModeratorIds({ includeAdmins: true });
+ const adminOrModeratorIds = await this.roleService.getModeratorIds();
if (adminOrModeratorIds.length === 0) return [];
query.where('user.id IN (:...adminOrModeratorIds)', { adminOrModeratorIds: adminOrModeratorIds });
break;
diff --git a/packages/backend/src/server/api/endpoints/admin/system-webhook/test.ts b/packages/backend/src/server/api/endpoints/admin/system-webhook/test.ts
deleted file mode 100644
index fb2ddf4b44..0000000000
--- a/packages/backend/src/server/api/endpoints/admin/system-webhook/test.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Injectable } from '@nestjs/common';
-import ms from 'ms';
-import { Endpoint } from '@/server/api/endpoint-base.js';
-import { WebhookTestService } from '@/core/WebhookTestService.js';
-import { ApiError } from '@/server/api/error.js';
-import { systemWebhookEventTypes } from '@/models/SystemWebhook.js';
-
-export const meta = {
- tags: ['webhooks'],
-
- requireCredential: true,
- requireModerator: true,
- secure: true,
- kind: 'read:admin:system-webhook',
-
- limit: {
- duration: ms('15min'),
- max: 60,
- },
-
- errors: {
- noSuchWebhook: {
- message: 'No such webhook.',
- code: 'NO_SUCH_WEBHOOK',
- id: '0c52149c-e913-18f8-5dc7-74870bfe0cf9',
- },
- },
-} as const;
-
-export const paramDef = {
- type: 'object',
- properties: {
- webhookId: {
- type: 'string',
- format: 'misskey:id',
- },
- type: {
- type: 'string',
- enum: systemWebhookEventTypes,
- },
- override: {
- type: 'object',
- properties: {
- url: { type: 'string', nullable: false },
- secret: { type: 'string', nullable: false },
- },
- },
- },
- required: ['webhookId', 'type'],
-} as const;
-
-@Injectable()
-export default class extends Endpoint { // eslint-disable-line import/no-default-export
- constructor(
- private webhookTestService: WebhookTestService,
- ) {
- super(meta, paramDef, async (ps) => {
- try {
- await this.webhookTestService.testSystemWebhook({
- webhookId: ps.webhookId,
- type: ps.type,
- override: ps.override,
- });
- } catch (e) {
- if (e instanceof WebhookTestService.NoSuchWebhookError) {
- throw new ApiError(meta.errors.noSuchWebhook);
- }
- throw e;
- }
- });
- }
-}
diff --git a/packages/backend/src/server/api/endpoints/admin/update-abuse-user-report.ts b/packages/backend/src/server/api/endpoints/admin/update-abuse-user-report.ts
deleted file mode 100644
index 73d4b843f0..0000000000
--- a/packages/backend/src/server/api/endpoints/admin/update-abuse-user-report.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Inject, Injectable } from '@nestjs/common';
-import { Endpoint } from '@/server/api/endpoint-base.js';
-import type { AbuseUserReportsRepository } from '@/models/_.js';
-import { DI } from '@/di-symbols.js';
-import { ApiError } from '@/server/api/error.js';
-import { AbuseReportService } from '@/core/AbuseReportService.js';
-
-export const meta = {
- tags: ['admin'],
-
- requireCredential: true,
- requireModerator: true,
- kind: 'write:admin:resolve-abuse-user-report',
-
- errors: {
- noSuchAbuseReport: {
- message: 'No such abuse report.',
- code: 'NO_SUCH_ABUSE_REPORT',
- id: '15f51cf5-46d1-4b1d-a618-b35bcbed0662',
- kind: 'server',
- httpStatusCode: 404,
- },
- },
-} as const;
-
-export const paramDef = {
- type: 'object',
- properties: {
- reportId: { type: 'string', format: 'misskey:id' },
- moderationNote: { type: 'string' },
- },
- required: ['reportId'],
-} as const;
-
-@Injectable()
-export default class extends Endpoint { // eslint-disable-line import/no-default-export
- constructor(
- @Inject(DI.abuseUserReportsRepository)
- private abuseUserReportsRepository: AbuseUserReportsRepository,
- private abuseReportService: AbuseReportService,
- ) {
- super(meta, paramDef, async (ps, me) => {
- const report = await this.abuseUserReportsRepository.findOneBy({ id: ps.reportId });
- if (!report) {
- throw new ApiError(meta.errors.noSuchAbuseReport);
- }
-
- await this.abuseReportService.update(report.id, {
- moderationNote: ps.moderationNote,
- }, me);
- });
- }
-}
diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
index 38ef0d1de8..5efdc9d8c4 100644
--- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
@@ -46,11 +46,6 @@ export const paramDef = {
type: 'string',
},
},
- prohibitedWordsForNameOfUser: {
- type: 'array', nullable: true, items: {
- type: 'string',
- },
- },
themeColor: { type: 'string', nullable: true, pattern: '^#[0-9a-fA-F]{6}$' },
mascotImageUrl: { type: 'string', nullable: true },
bannerUrl: { type: 'string', nullable: true },
@@ -83,7 +78,6 @@ export const paramDef = {
enableTurnstile: { type: 'boolean' },
turnstileSiteKey: { type: 'string', nullable: true },
turnstileSecretKey: { type: 'string', nullable: true },
- enableTestcaptcha: { type: 'boolean' },
sensitiveMediaDetection: { type: 'string', enum: ['none', 'all', 'local', 'remote'] },
sensitiveMediaDetectionSensitivity: { type: 'string', enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'] },
setSensitiveFlagAutomatically: { type: 'boolean' },
@@ -136,7 +130,6 @@ export const paramDef = {
truemailAuthKey: { type: 'string', nullable: true },
enableChartsForRemoteUser: { type: 'boolean' },
enableChartsForFederatedInstances: { type: 'boolean' },
- enableStatsForFederatedInstances: { type: 'boolean' },
enableServerMachineStats: { type: 'boolean' },
enableIdenticonGeneration: { type: 'boolean' },
serverRules: { type: 'array', items: { type: 'string' } },
@@ -149,7 +142,6 @@ export const paramDef = {
perRemoteUserUserTimelineCacheMax: { type: 'integer' },
perUserHomeTimelineCacheMax: { type: 'integer' },
perUserListTimelineCacheMax: { type: 'integer' },
- enableReactionsBuffering: { type: 'boolean' },
notesPerOneAd: { type: 'integer' },
silencedHosts: {
type: 'array',
@@ -175,16 +167,6 @@ export const paramDef = {
urlPreviewRequireContentLength: { type: 'boolean' },
urlPreviewUserAgent: { type: 'string', nullable: true },
urlPreviewSummaryProxyUrl: { type: 'string', nullable: true },
- federation: {
- type: 'string',
- enum: ['all', 'none', 'specified'],
- },
- federationHosts: {
- type: 'array',
- items: {
- type: 'string',
- },
- },
},
required: [],
} as const;
@@ -220,9 +202,6 @@ export default class extends Endpoint { // eslint-
if (Array.isArray(ps.prohibitedWords)) {
set.prohibitedWords = ps.prohibitedWords.filter(Boolean);
}
- if (Array.isArray(ps.prohibitedWordsForNameOfUser)) {
- set.prohibitedWordsForNameOfUser = ps.prohibitedWordsForNameOfUser.filter(Boolean);
- }
if (Array.isArray(ps.silencedHosts)) {
let lastValue = '';
set.silencedHosts = ps.silencedHosts.sort().filter((h) => {
@@ -367,10 +346,6 @@ export default class extends Endpoint { // eslint-
set.turnstileSecretKey = ps.turnstileSecretKey;
}
- if (ps.enableTestcaptcha !== undefined) {
- set.enableTestcaptcha = ps.enableTestcaptcha;
- }
-
if (ps.sensitiveMediaDetection !== undefined) {
set.sensitiveMediaDetection = ps.sensitiveMediaDetection;
}
@@ -579,10 +554,6 @@ export default class extends Endpoint { // eslint-
set.enableChartsForFederatedInstances = ps.enableChartsForFederatedInstances;
}
- if (ps.enableStatsForFederatedInstances !== undefined) {
- set.enableStatsForFederatedInstances = ps.enableStatsForFederatedInstances;
- }
-
if (ps.enableServerMachineStats !== undefined) {
set.enableServerMachineStats = ps.enableServerMachineStats;
}
@@ -627,10 +598,6 @@ export default class extends Endpoint { // eslint-
set.perUserListTimelineCacheMax = ps.perUserListTimelineCacheMax;
}
- if (ps.enableReactionsBuffering !== undefined) {
- set.enableReactionsBuffering = ps.enableReactionsBuffering;
- }
-
if (ps.notesPerOneAd !== undefined) {
set.notesPerOneAd = ps.notesPerOneAd;
}
@@ -665,14 +632,6 @@ export default class extends Endpoint { // eslint-
set.urlPreviewSummaryProxyUrl = value === '' ? null : value;
}
- if (ps.federation !== undefined) {
- set.federation = ps.federation;
- }
-
- if (Array.isArray(ps.federationHosts)) {
- set.federationHosts = ps.federationHosts.filter(Boolean).map(x => x.toLowerCase());
- }
-
const before = await this.metaService.fetch(true);
await this.metaService.update(set);
diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts
index e0c8ddcc84..577b9e1b1f 100644
--- a/packages/backend/src/server/api/endpoints/antennas/create.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/create.ts
@@ -34,12 +34,6 @@ export const meta = {
code: 'TOO_MANY_ANTENNAS',
id: 'faf47050-e8b5-438c-913c-db2b1576fde4',
},
-
- emptyKeyword: {
- message: 'Either keywords or excludeKeywords is required.',
- code: 'EMPTY_KEYWORD',
- id: '53ee222e-1ddd-4f9a-92e5-9fb82ddb463a',
- },
},
res: {
@@ -93,7 +87,7 @@ export default class extends Endpoint { // eslint-
) {
super(meta, paramDef, async (ps, me) => {
if (ps.keywords.flat().every(x => x === '') && ps.excludeKeywords.flat().every(x => x === '')) {
- throw new ApiError(meta.errors.emptyKeyword);
+ throw new Error('either keywords or excludeKeywords is required.');
}
const currentAntennasCount = await this.antennasRepository.countBy({
diff --git a/packages/backend/src/server/api/endpoints/antennas/update.ts b/packages/backend/src/server/api/endpoints/antennas/update.ts
index 10f26b1912..0c30bca9e0 100644
--- a/packages/backend/src/server/api/endpoints/antennas/update.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/update.ts
@@ -32,12 +32,6 @@ export const meta = {
code: 'NO_SUCH_USER_LIST',
id: '1c6b35c9-943e-48c2-81e4-2844989407f7',
},
-
- emptyKeyword: {
- message: 'Either keywords or excludeKeywords is required.',
- code: 'EMPTY_KEYWORD',
- id: '721aaff6-4e1b-4d88-8de6-877fae9f68c4',
- },
},
res: {
@@ -91,7 +85,7 @@ export default class extends Endpoint { // eslint-
super(meta, paramDef, async (ps, me) => {
if (ps.keywords && ps.excludeKeywords) {
if (ps.keywords.flat().every(x => x === '') && ps.excludeKeywords.flat().every(x => x === '')) {
- throw new ApiError(meta.errors.emptyKeyword);
+ throw new Error('either keywords or excludeKeywords is required.');
}
}
// Fetch the antenna
diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts
index c52608cefb..d3c40dba59 100644
--- a/packages/backend/src/server/api/endpoints/ap/show.ts
+++ b/packages/backend/src/server/api/endpoints/ap/show.ts
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { Inject, Injectable } from '@nestjs/common';
+import { Injectable } from '@nestjs/common';
import ms from 'ms';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { MiNote } from '@/models/Note.js';
@@ -12,6 +12,7 @@ import { isActor, isPost, getApId } from '@/core/activitypub/type.js';
import type { SchemaType } from '@/misc/json-schema.js';
import { ApResolverService } from '@/core/activitypub/ApResolverService.js';
import { ApDbResolverService } from '@/core/activitypub/ApDbResolverService.js';
+import { MetaService } from '@/core/MetaService.js';
import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
import { ApNoteService } from '@/core/activitypub/models/ApNoteService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
@@ -90,6 +91,7 @@ export default class extends Endpoint { // eslint-
private utilityService: UtilityService,
private userEntityService: UserEntityService,
private noteEntityService: NoteEntityService,
+ private metaService: MetaService,
private apResolverService: ApResolverService,
private apDbResolverService: ApDbResolverService,
private apPersonService: ApPersonService,
@@ -110,7 +112,9 @@ export default class extends Endpoint { // eslint-
*/
@bindThis
private async fetchAny(uri: string, me: MiLocalUser | null | undefined): Promise | null> {
- if (!this.utilityService.isFederationAllowedUri(uri)) return null;
+ // ブロックしてたら中断
+ const fetchedMeta = await this.metaService.fetch();
+ if (this.utilityService.isBlockedHost(fetchedMeta.blockedHosts, this.utilityService.extractDbHost(uri))) return null;
let local = await this.mergePack(me, ...await Promise.all([
this.apDbResolverService.getUserFromApId(uri),
diff --git a/packages/backend/src/server/api/endpoints/channels/timeline.ts b/packages/backend/src/server/api/endpoints/channels/timeline.ts
index d4fd75e049..8c55673590 100644
--- a/packages/backend/src/server/api/endpoints/channels/timeline.ts
+++ b/packages/backend/src/server/api/endpoints/channels/timeline.ts
@@ -5,12 +5,14 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
-import type { ChannelsRepository, MiMeta, NotesRepository } from '@/models/_.js';
+import type { ChannelsRepository, NotesRepository } from '@/models/_.js';
import { QueryService } from '@/core/QueryService.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import ActiveUsersChart from '@/core/chart/charts/active-users.js';
import { DI } from '@/di-symbols.js';
import { IdService } from '@/core/IdService.js';
+import { CacheService } from '@/core/CacheService.js';
+import { MetaService } from '@/core/MetaService.js';
import { FanoutTimelineEndpointService } from '@/core/FanoutTimelineEndpointService.js';
import { MiLocalUser } from '@/models/User.js';
import { ApiError } from '../../error.js';
@@ -56,9 +58,6 @@ export const paramDef = {
@Injectable()
export default class extends Endpoint { // eslint-disable-line import/no-default-export
constructor(
- @Inject(DI.meta)
- private serverSettings: MiMeta,
-
@Inject(DI.notesRepository)
private notesRepository: NotesRepository,
@@ -69,12 +68,16 @@ export default class extends Endpoint { // eslint-
private noteEntityService: NoteEntityService,
private queryService: QueryService,
private fanoutTimelineEndpointService: FanoutTimelineEndpointService,
+ private cacheService: CacheService,
private activeUsersChart: ActiveUsersChart,
+ private metaService: MetaService,
) {
super(meta, paramDef, async (ps, me) => {
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : null);
+ const serverSettings = await this.metaService.fetch();
+
const channel = await this.channelsRepository.findOneBy({
id: ps.channelId,
});
@@ -85,7 +88,7 @@ export default class extends Endpoint { // eslint-
if (me) this.activeUsersChart.read(me);
- if (!this.serverSettings.enableFanoutTimeline) {
+ if (!serverSettings.enableFanoutTimeline) {
return await this.noteEntityService.packMany(await this.getFromDb({ untilId, sinceId, limit: ps.limit, channelId: channel.id }, me), me);
}
diff --git a/packages/backend/src/server/api/endpoints/drive.ts b/packages/backend/src/server/api/endpoints/drive.ts
index eb45e29f9e..7e9b0fa0e1 100644
--- a/packages/backend/src/server/api/endpoints/drive.ts
+++ b/packages/backend/src/server/api/endpoints/drive.ts
@@ -5,6 +5,7 @@
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
+import { MetaService } from '@/core/MetaService.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
import { RoleService } from '@/core/RoleService.js';
@@ -40,10 +41,14 @@ export const paramDef = {
@Injectable()
export default class extends Endpoint { // eslint-disable-line import/no-default-export
constructor(
+ private metaService: MetaService,
private driveFileEntityService: DriveFileEntityService,
private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
+ const instance = await this.metaService.fetch(true);
+
+ // Calculate drive usage
const usage = await this.driveFileEntityService.calcDriveUsageOf(me.id);
const policies = await this.roleService.getUserPolicies(me.id);
diff --git a/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts b/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts
index b86059b5e7..4670392025 100644
--- a/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts
+++ b/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts
@@ -10,7 +10,6 @@ import { QueryService } from '@/core/QueryService.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';
-import { RoleService } from '@/core/RoleService.js';
export const meta = {
tags: ['drive', 'notes'],
@@ -62,13 +61,12 @@ export default class extends Endpoint { // eslint-
private noteEntityService: NoteEntityService,
private queryService: QueryService,
- private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
// Fetch file
const file = await this.driveFilesRepository.findOneBy({
id: ps.fileId,
- userId: await this.roleService.isModerator(me) ? undefined : me.id,
+ userId: me.id,
});
if (file == null) {
diff --git a/packages/backend/src/server/api/endpoints/drive/files/create.ts b/packages/backend/src/server/api/endpoints/drive/files/create.ts
index 74eb4dded7..9c17f93ab2 100644
--- a/packages/backend/src/server/api/endpoints/drive/files/create.ts
+++ b/packages/backend/src/server/api/endpoints/drive/files/create.ts
@@ -4,15 +4,14 @@
*/
import ms from 'ms';
-import { Inject, Injectable } from '@nestjs/common';
+import { Injectable } from '@nestjs/common';
import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/const.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
+import { MetaService } from '@/core/MetaService.js';
import { DriveService } from '@/core/DriveService.js';
import { ApiError } from '../../../error.js';
-import { MiMeta } from '@/models/_.js';
-import { DI } from '@/di-symbols.js';
export const meta = {
tags: ['drive'],
@@ -74,10 +73,8 @@ export const paramDef = {
@Injectable()
export default class extends Endpoint { // eslint-disable-line import/no-default-export
constructor(
- @Inject(DI.meta)
- private serverSettings: MiMeta,
-
private driveFileEntityService: DriveFileEntityService,
+ private metaService: MetaService,
private driveService: DriveService,
) {
super(meta, paramDef, async (ps, me, _, file, cleanup, ip, headers) => {
@@ -94,6 +91,8 @@ export default class extends Endpoint { // eslint-
}
}
+ const instance = await this.metaService.fetch();
+
try {
// Create file
const driveFile = await this.driveService.addFile({
@@ -104,8 +103,8 @@ export default class extends Endpoint { // eslint-
folderId: ps.folderId,
force: ps.force,
sensitive: ps.isSensitive,
- requestIp: this.serverSettings.enableIpLogging ? ip : null,
- requestHeaders: this.serverSettings.enableIpLogging ? headers : null,
+ requestIp: instance.enableIpLogging ? ip : null,
+ requestHeaders: instance.enableIpLogging ? headers : null,
});
return await this.driveFileEntityService.pack(driveFile, { self: true });
} catch (err) {
diff --git a/packages/backend/src/server/api/endpoints/flash/featured.ts b/packages/backend/src/server/api/endpoints/flash/featured.ts
index 9a0cb461f2..c2d6ab5085 100644
--- a/packages/backend/src/server/api/endpoints/flash/featured.ts
+++ b/packages/backend/src/server/api/endpoints/flash/featured.ts
@@ -8,7 +8,6 @@ import type { FlashsRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { FlashEntityService } from '@/core/entities/FlashEntityService.js';
import { DI } from '@/di-symbols.js';
-import { FlashService } from '@/core/FlashService.js';
export const meta = {
tags: ['flash'],
@@ -28,25 +27,26 @@ export const meta = {
export const paramDef = {
type: 'object',
- properties: {
- offset: { type: 'integer', minimum: 0, default: 0 },
- limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
- },
+ properties: {},
required: [],
} as const;
@Injectable()
export default class extends Endpoint { // eslint-disable-line import/no-default-export
constructor(
- private flashService: FlashService,
+ @Inject(DI.flashsRepository)
+ private flashsRepository: FlashsRepository,
+
private flashEntityService: FlashEntityService,
) {
super(meta, paramDef, async (ps, me) => {
- const result = await this.flashService.featured({
- offset: ps.offset,
- limit: ps.limit,
- });
- return await this.flashEntityService.packMany(result, me);
+ const query = this.flashsRepository.createQueryBuilder('flash')
+ .andWhere('flash.likedCount > 0')
+ .orderBy('flash.likedCount', 'DESC');
+
+ const flashs = await query.limit(10).getMany();
+
+ return await this.flashEntityService.packMany(flashs, me);
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/i/import-antennas.ts b/packages/backend/src/server/api/endpoints/i/import-antennas.ts
index bdf6c065e8..bc46163e3d 100644
--- a/packages/backend/src/server/api/endpoints/i/import-antennas.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-antennas.ts
@@ -16,7 +16,6 @@ import { ApiError } from '../../error.js';
export const meta = {
secure: true,
requireCredential: true,
- requireRolePolicy: 'canImportAntennas',
prohibitMoved: true,
limit: {
diff --git a/packages/backend/src/server/api/endpoints/i/import-blocking.ts b/packages/backend/src/server/api/endpoints/i/import-blocking.ts
index d7bb6bcd22..2606108539 100644
--- a/packages/backend/src/server/api/endpoints/i/import-blocking.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-blocking.ts
@@ -15,7 +15,6 @@ import { ApiError } from '../../error.js';
export const meta = {
secure: true,
requireCredential: true,
- requireRolePolicy: 'canImportBlocking',
prohibitMoved: true,
limit: {
diff --git a/packages/backend/src/server/api/endpoints/i/import-following.ts b/packages/backend/src/server/api/endpoints/i/import-following.ts
index e03192d8c6..d5e824df27 100644
--- a/packages/backend/src/server/api/endpoints/i/import-following.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-following.ts
@@ -15,7 +15,6 @@ import { ApiError } from '../../error.js';
export const meta = {
secure: true,
requireCredential: true,
- requireRolePolicy: 'canImportFollowing',
prohibitMoved: true,
limit: {
duration: ms('1hour'),
diff --git a/packages/backend/src/server/api/endpoints/i/import-muting.ts b/packages/backend/src/server/api/endpoints/i/import-muting.ts
index 76b285bb7e..0f5800404e 100644
--- a/packages/backend/src/server/api/endpoints/i/import-muting.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-muting.ts
@@ -15,7 +15,6 @@ import { ApiError } from '../../error.js';
export const meta = {
secure: true,
requireCredential: true,
- requireRolePolicy: 'canImportMuting',
prohibitMoved: true,
limit: {
diff --git a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts
index 76ecfd082c..bacdd5c88f 100644
--- a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts
@@ -15,7 +15,6 @@ import { ApiError } from '../../error.js';
export const meta = {
secure: true,
requireCredential: true,
- requireRolePolicy: 'canImportUserLists',
prohibitMoved: true,
limit: {
duration: ms('1hour'),
diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts
index da1faee30d..eea657ebbd 100644
--- a/packages/backend/src/server/api/endpoints/i/update-email.ts
+++ b/packages/backend/src/server/api/endpoints/i/update-email.ts
@@ -7,7 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
import ms from 'ms';
import bcrypt from 'bcryptjs';
import { Endpoint } from '@/server/api/endpoint-base.js';
-import type { MiMeta, UserProfilesRepository } from '@/models/_.js';
+import type { UserProfilesRepository } from '@/models/_.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { EmailService } from '@/core/EmailService.js';
import type { Config } from '@/config.js';
@@ -15,6 +15,7 @@ import { DI } from '@/di-symbols.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { L_CHARS, secureRndstr } from '@/misc/secure-rndstr.js';
import { UserAuthService } from '@/core/UserAuthService.js';
+import { MetaService } from '@/core/MetaService.js';
import { ApiError } from '../../error.js';
export const meta = {
@@ -69,12 +70,10 @@ export default class extends Endpoint { // eslint-
@Inject(DI.config)
private config: Config,
- @Inject(DI.meta)
- private serverSettings: MiMeta,
-
@Inject(DI.userProfilesRepository)
private userProfilesRepository: UserProfilesRepository,
+ private metaService: MetaService,
private userEntityService: UserEntityService,
private emailService: EmailService,
private userAuthService: UserAuthService,
@@ -106,7 +105,7 @@ export default class extends Endpoint { // eslint-
if (!res.available) {
throw new ApiError(meta.errors.unavailable);
}
- } else if (this.serverSettings.emailRequiredForSignup) {
+ } else if ((await this.metaService.fetch()).emailRequiredForSignup) {
throw new ApiError(meta.errors.emailRequired);
}
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index d3eeb75b27..a1e2fa5e4c 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -11,10 +11,11 @@ import { JSDOM } from 'jsdom';
import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js';
import { extractHashtags } from '@/misc/extract-hashtags.js';
import * as Acct from '@/misc/acct.js';
-import type { UsersRepository, DriveFilesRepository, MiMeta, UserProfilesRepository, PagesRepository } from '@/models/_.js';
+import type { UsersRepository, DriveFilesRepository, UserProfilesRepository, PagesRepository } from '@/models/_.js';
import type { MiLocalUser, MiUser } from '@/models/User.js';
-import { birthdaySchema, descriptionSchema, followedMessageSchema, locationSchema, nameSchema } from '@/models/User.js';
+import { birthdaySchema, descriptionSchema, locationSchema, nameSchema } from '@/models/User.js';
import type { MiUserProfile } from '@/models/UserProfile.js';
+import { notificationTypes } from '@/types.js';
import { normalizeForSearch } from '@/misc/normalize-for-search.js';
import { langmap } from '@/misc/langmap.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
@@ -22,7 +23,6 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
import { AccountUpdateService } from '@/core/AccountUpdateService.js';
-import { UtilityService } from '@/core/UtilityService.js';
import { HashtagService } from '@/core/HashtagService.js';
import { DI } from '@/di-symbols.js';
import { RolePolicies, RoleService } from '@/core/RoleService.js';
@@ -115,13 +115,6 @@ export const meta = {
code: 'RESTRICTED_BY_ROLE',
id: '8feff0ba-5ab5-585b-31f4-4df816663fad',
},
-
- nameContainsProhibitedWords: {
- message: 'Your new name contains prohibited words.',
- code: 'YOUR_NAME_CONTAINS_PROHIBITED_WORDS',
- id: '0b3f9f6a-2f4d-4b1f-9fb4-49d3a2fd7191',
- httpStatusCode: 422,
- },
},
res: {
@@ -141,7 +134,6 @@ export const paramDef = {
properties: {
name: { ...nameSchema, nullable: true },
description: { ...descriptionSchema, nullable: true },
- followedMessage: { ...followedMessageSchema, nullable: true },
location: { ...locationSchema, nullable: true },
birthday: { ...birthdaySchema, nullable: true },
lang: { type: 'string', enum: [null, ...Object.keys(langmap)] as string[], nullable: true },
@@ -179,9 +171,6 @@ export const paramDef = {
autoAcceptFollowed: { type: 'boolean' },
noCrawle: { type: 'boolean' },
preventAiLearning: { type: 'boolean' },
- requireSigninToViewContents: { type: 'boolean' },
- makeNotesFollowersOnlyBefore: { type: 'integer', nullable: true },
- makeNotesHiddenBefore: { type: 'integer', nullable: true },
isBot: { type: 'boolean' },
isCat: { type: 'boolean' },
injectFeaturedNote: { type: 'boolean' },
@@ -234,9 +223,6 @@ export default class extends Endpoint { // eslint-
@Inject(DI.config)
private config: Config,
- @Inject(DI.meta)
- private instanceMeta: MiMeta,
-
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -261,7 +247,6 @@ export default class extends Endpoint { // eslint-
private cacheService: CacheService,
private httpRequestService: HttpRequestService,
private avatarDecorationService: AvatarDecorationService,
- private utilityService: UtilityService,
) {
super(meta, paramDef, async (ps, _user, token) => {
const user = await this.usersRepository.findOneByOrFail({ id: _user.id }) as MiLocalUser;
@@ -282,7 +267,6 @@ export default class extends Endpoint { // eslint-
}
}
if (ps.description !== undefined) profileUpdates.description = ps.description;
- if (ps.followedMessage !== undefined) profileUpdates.followedMessage = ps.followedMessage;
if (ps.lang !== undefined) profileUpdates.lang = ps.lang;
if (ps.location !== undefined) profileUpdates.location = ps.location;
if (ps.birthday !== undefined) profileUpdates.birthday = ps.birthday;
@@ -337,9 +321,6 @@ export default class extends Endpoint { // eslint-
if (typeof ps.autoAcceptFollowed === 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed;
if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle;
if (typeof ps.preventAiLearning === 'boolean') profileUpdates.preventAiLearning = ps.preventAiLearning;
- if (typeof ps.requireSigninToViewContents === 'boolean') updates.requireSigninToViewContents = ps.requireSigninToViewContents;
- if ((typeof ps.makeNotesFollowersOnlyBefore === 'number') || (ps.makeNotesFollowersOnlyBefore === null)) updates.makeNotesFollowersOnlyBefore = ps.makeNotesFollowersOnlyBefore;
- if ((typeof ps.makeNotesHiddenBefore === 'number') || (ps.makeNotesHiddenBefore === null)) updates.makeNotesHiddenBefore = ps.makeNotesHiddenBefore;
if (typeof ps.isCat === 'boolean') updates.isCat = ps.isCat;
if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote;
if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail;
@@ -465,17 +446,8 @@ export default class extends Endpoint { // eslint-
const newName = updates.name === undefined ? user.name : updates.name;
const newDescription = profileUpdates.description === undefined ? profile.description : profileUpdates.description;
const newFields = profileUpdates.fields === undefined ? profile.fields : profileUpdates.fields;
- const newFollowedMessage = profileUpdates.followedMessage === undefined ? profile.followedMessage : profileUpdates.followedMessage;
if (newName != null) {
- let hasProhibitedWords = false;
- if (!await this.roleService.isModerator(user)) {
- hasProhibitedWords = this.utilityService.isKeyWordIncluded(newName, this.instanceMeta.prohibitedWordsForNameOfUser);
- }
- if (hasProhibitedWords) {
- throw new ApiError(meta.errors.nameContainsProhibitedWords);
- }
-
const tokens = mfm.parseSimple(newName);
emojis = emojis.concat(extractCustomEmojisFromMfm(tokens));
}
@@ -495,11 +467,6 @@ export default class extends Endpoint { // eslint-
]);
}
- if (newFollowedMessage != null) {
- const tokens = mfm.parse(newFollowedMessage);
- emojis = emojis.concat(extractCustomEmojisFromMfm(tokens));
- }
-
updates.emojis = emojis;
updates.tags = tags;
diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts
index 6e84603f7a..9eb7f5b3a0 100644
--- a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts
+++ b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts
@@ -13,7 +13,6 @@ import { DI } from '@/di-symbols.js';
import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '@/server/api/error.js';
-// TODO: UserWebhook schemaの適用
export const meta = {
tags: ['webhooks'],
diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/list.ts b/packages/backend/src/server/api/endpoints/i/webhooks/list.ts
index 394c178f2a..fe07afb2d0 100644
--- a/packages/backend/src/server/api/endpoints/i/webhooks/list.ts
+++ b/packages/backend/src/server/api/endpoints/i/webhooks/list.ts
@@ -9,7 +9,6 @@ import { webhookEventTypes } from '@/models/Webhook.js';
import type { WebhooksRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
-// TODO: UserWebhook schemaの適用
export const meta = {
tags: ['webhooks', 'account'],
diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/show.ts b/packages/backend/src/server/api/endpoints/i/webhooks/show.ts
index 4a0c09ff0c..5ddb79caf2 100644
--- a/packages/backend/src/server/api/endpoints/i/webhooks/show.ts
+++ b/packages/backend/src/server/api/endpoints/i/webhooks/show.ts
@@ -10,7 +10,6 @@ import type { WebhooksRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../../error.js';
-// TODO: UserWebhook schemaの適用
export const meta = {
tags: ['webhooks'],
diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/test.ts b/packages/backend/src/server/api/endpoints/i/webhooks/test.ts
deleted file mode 100644
index 2bf6df9ce2..0000000000
--- a/packages/backend/src/server/api/endpoints/i/webhooks/test.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Injectable } from '@nestjs/common';
-import ms from 'ms';
-import { Endpoint } from '@/server/api/endpoint-base.js';
-import { webhookEventTypes } from '@/models/Webhook.js';
-import { WebhookTestService } from '@/core/WebhookTestService.js';
-import { ApiError } from '@/server/api/error.js';
-
-export const meta = {
- tags: ['webhooks'],
-
- requireCredential: true,
- secure: true,
- kind: 'read:account',
-
- limit: {
- duration: ms('15min'),
- max: 60,
- },
-
- errors: {
- noSuchWebhook: {
- message: 'No such webhook.',
- code: 'NO_SUCH_WEBHOOK',
- id: '0c52149c-e913-18f8-5dc7-74870bfe0cf9',
- },
- },
-} as const;
-
-export const paramDef = {
- type: 'object',
- properties: {
- webhookId: {
- type: 'string',
- format: 'misskey:id',
- },
- type: {
- type: 'string',
- enum: webhookEventTypes,
- },
- override: {
- type: 'object',
- properties: {
- url: { type: 'string' },
- secret: { type: 'string' },
- },
- },
- },
- required: ['webhookId', 'type'],
-} as const;
-
-@Injectable()
-export default class extends Endpoint { // eslint-disable-line import/no-default-export
- constructor(
- private webhookTestService: WebhookTestService,
- ) {
- super(meta, paramDef, async (ps, me) => {
- try {
- await this.webhookTestService.testUserWebhook({
- webhookId: ps.webhookId,
- type: ps.type,
- override: ps.override,
- }, me);
- } catch (e) {
- if (e instanceof WebhookTestService.NoSuchWebhookError) {
- throw new ApiError(meta.errors.noSuchWebhook);
- }
- throw e;
- }
- });
- }
-}
diff --git a/packages/backend/src/server/api/endpoints/invite/limit.ts b/packages/backend/src/server/api/endpoints/invite/limit.ts
index 2ffd41ae28..2786bd98d5 100644
--- a/packages/backend/src/server/api/endpoints/invite/limit.ts
+++ b/packages/backend/src/server/api/endpoints/invite/limit.ts
@@ -49,7 +49,7 @@ export default class extends Endpoint { // eslint-
const policies = await this.roleService.getUserPolicies(me.id);
const count = policies.inviteLimit ? await this.registrationTicketsRepository.countBy({
- id: MoreThan(this.idService.gen(Date.now() - (policies.inviteLimitCycle * 60 * 1000))),
+ id: MoreThan(this.idService.gen(Date.now() - (policies.inviteExpirationTime * 60 * 1000))),
createdById: me.id,
}) : null;
diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts
index 253a360815..beb77ca7ab 100644
--- a/packages/backend/src/server/api/endpoints/notes/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/create.ts
@@ -17,6 +17,8 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { NoteCreateService } from '@/core/NoteCreateService.js';
import { DI } from '@/di-symbols.js';
import { isQuote, isRenote } from '@/misc/is-renote.js';
+import { MetaService } from '@/core/MetaService.js';
+import { UtilityService } from '@/core/UtilityService.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { ApiError } from '../../error.js';
diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts
index aed9065bf9..2a2c659942 100644
--- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts
@@ -5,7 +5,7 @@
import { Brackets } from 'typeorm';
import { Inject, Injectable } from '@nestjs/common';
-import type { NotesRepository, ChannelFollowingsRepository, MiMeta } from '@/models/_.js';
+import type { NotesRepository, ChannelFollowingsRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import ActiveUsersChart from '@/core/chart/charts/active-users.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
@@ -16,6 +16,7 @@ import { CacheService } from '@/core/CacheService.js';
import { FanoutTimelineName } from '@/core/FanoutTimelineService.js';
import { QueryService } from '@/core/QueryService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
+import { MetaService } from '@/core/MetaService.js';
import { MiLocalUser } from '@/models/User.js';
import { FanoutTimelineEndpointService } from '@/core/FanoutTimelineEndpointService.js';
import { ApiError } from '../../error.js';
@@ -73,9 +74,6 @@ export const paramDef = {
@Injectable()
export default class extends Endpoint { // eslint-disable-line import/no-default-export
constructor(
- @Inject(DI.meta)
- private serverSettings: MiMeta,
-
@Inject(DI.notesRepository)
private notesRepository: NotesRepository,
@@ -89,6 +87,7 @@ export default class extends Endpoint { // eslint-
private cacheService: CacheService,
private queryService: QueryService,
private userFollowingService: UserFollowingService,
+ private metaService: MetaService,
private fanoutTimelineEndpointService: FanoutTimelineEndpointService,
) {
super(meta, paramDef, async (ps, me) => {
@@ -102,7 +101,9 @@ export default class extends Endpoint { // eslint-
if (ps.withReplies && ps.withFiles) throw new ApiError(meta.errors.bothWithRepliesAndWithFiles);
- if (!this.serverSettings.enableFanoutTimeline) {
+ const serverSettings = await this.metaService.fetch();
+
+ if (!serverSettings.enableFanoutTimeline) {
const timeline = await this.getFromDb({
untilId,
sinceId,
@@ -155,7 +156,7 @@ export default class extends Endpoint