From 0879ab50b8596da92dda32845037924adb2bc0b5 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 12 Feb 2023 14:00:15 +0900 Subject: [PATCH 01/92] fix(client): call checkMissingMention immediately --- packages/frontend/src/components/MkPostForm.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index f15906c1c..620b12682 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -228,7 +228,7 @@ const hashtags = $computed(defaultStore.makeGetterSetter('postFormHashtags')); watch($$(text), () => { checkMissingMention(); -}); +}, { immediate: true }); watch($$(visibleUsers), () => { checkMissingMention(); From b3d8134c7a17bad3693ab37c3d42d99aae4918b1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 12 Feb 2023 14:25:34 +0900 Subject: [PATCH 02/92] :art: --- packages/frontend/src/components/MkUserPreview.vue | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/MkUserPreview.vue b/packages/frontend/src/components/MkUserPreview.vue index eacc66de4..1238a39cf 100644 --- a/packages/frontend/src/components/MkUserPreview.vue +++ b/packages/frontend/src/components/MkUserPreview.vue @@ -183,8 +183,10 @@ onMounted(() => { > .menu { position: absolute; top: 8px; - right: 42px; - padding: 8px; + right: 44px; + padding: 6px; + background: var(--panel); + border-radius: 999px; } > .koudoku-button { From fdb745b4a86fabd27b62ffb83c60310f3151b92d Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 12 Feb 2023 14:31:00 +0900 Subject: [PATCH 03/92] :art: --- packages/frontend/src/components/MkUserPreview.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkUserPreview.vue b/packages/frontend/src/components/MkUserPreview.vue index 1238a39cf..1086a2c65 100644 --- a/packages/frontend/src/components/MkUserPreview.vue +++ b/packages/frontend/src/components/MkUserPreview.vue @@ -89,7 +89,7 @@ onMounted(() => { + + From 451bc0b44483840da4b82394d077d07a35b5c71a Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 12 Feb 2023 18:47:30 +0900 Subject: [PATCH 10/92] refactor: fix types --- .../backend/src/core/AccountUpdateService.ts | 2 +- packages/backend/src/core/MessagingService.ts | 8 +- .../backend/src/core/NoteCreateService.ts | 2 +- .../backend/src/core/NoteDeleteService.ts | 4 +- .../backend/src/core/NotePiningService.ts | 2 +- packages/backend/src/core/PollService.ts | 2 +- packages/backend/src/core/ReactionService.ts | 6 +- packages/backend/src/core/RelayService.ts | 4 +- .../backend/src/core/UserBlockingService.ts | 12 +-- packages/backend/src/core/UserCacheService.ts | 6 +- .../backend/src/core/UserFollowingService.ts | 16 ++-- .../backend/src/core/UserSuspendService.ts | 4 +- .../core/activitypub/ApDbResolverService.ts | 4 +- .../src/core/activitypub/ApInboxService.ts | 6 +- .../src/core/activitypub/ApRendererService.ts | 94 +++++++++---------- .../src/core/activitypub/ApResolverService.ts | 15 +-- .../core/activitypub/models/ApNoteService.ts | 6 +- .../activitypub/models/ApPersonService.ts | 6 +- packages/backend/src/core/activitypub/type.ts | 30 +++++- .../core/entities/DriveFileEntityService.ts | 10 +- packages/backend/src/models/entities/User.ts | 1 + .../src/server/ActivityPubServerService.ts | 28 +++--- .../admin/resolve-abuse-user-report.ts | 2 +- .../server/api/endpoints/notes/polls/vote.ts | 2 +- 24 files changed, 142 insertions(+), 130 deletions(-) diff --git a/packages/backend/src/core/AccountUpdateService.ts b/packages/backend/src/core/AccountUpdateService.ts index 5f6dfca0c..d8ba7b169 100644 --- a/packages/backend/src/core/AccountUpdateService.ts +++ b/packages/backend/src/core/AccountUpdateService.ts @@ -32,7 +32,7 @@ export class AccountUpdateService { // フォロワーがリモートユーザーかつ投稿者がローカルユーザーならUpdateを配信 if (this.userEntityService.isLocalUser(user)) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderUpdate(await this.apRendererService.renderPerson(user), user)); + const content = this.apRendererService.addContext(this.apRendererService.renderUpdate(await this.apRendererService.renderPerson(user), user)); this.apDeliverManagerService.deliverToFollowers(user, content); this.relayService.deliverToRelays(user, content); } diff --git a/packages/backend/src/core/MessagingService.ts b/packages/backend/src/core/MessagingService.ts index f4a109065..1c36d04d4 100644 --- a/packages/backend/src/core/MessagingService.ts +++ b/packages/backend/src/core/MessagingService.ts @@ -135,7 +135,7 @@ export class MessagingService { }))), } as Note; - const activity = this.apRendererService.renderActivity(this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false, true), note)); + const activity = this.apRendererService.addContext(this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false, true), note)); this.queueService.deliver(user, activity, recipientUser.inbox); } @@ -158,7 +158,7 @@ export class MessagingService { if (this.userEntityService.isLocalUser(recipient)) this.globalEventService.publishMessagingStream(message.recipientId, message.userId, 'deleted', message.id); if (this.userEntityService.isLocalUser(user) && this.userEntityService.isRemoteUser(recipient)) { - const activity = this.apRendererService.renderActivity(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${message.id}`), user)); + const activity = this.apRendererService.addContext(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${message.id}`), user)); this.queueService.deliver(user, activity, recipient.inbox); } } else if (message.groupId) { @@ -297,10 +297,10 @@ export class MessagingService { if (contents.length > 1) { const collection = this.apRendererService.renderOrderedCollection(null, contents.length, undefined, undefined, contents); - this.queueService.deliver(user, this.apRendererService.renderActivity(collection), recipient.inbox); + this.queueService.deliver(user, this.apRendererService.addContext(collection), recipient.inbox); } else { for (const content of contents) { - this.queueService.deliver(user, this.apRendererService.renderActivity(content), recipient.inbox); + this.queueService.deliver(user, this.apRendererService.addContext(content), recipient.inbox); } } } diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 4a81f764d..04c057f6c 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -711,7 +711,7 @@ export class NoteCreateService { ? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note) : this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false), note); - return this.apRendererService.renderActivity(content); + return this.apRendererService.addContext(content); } @bindThis diff --git a/packages/backend/src/core/NoteDeleteService.ts b/packages/backend/src/core/NoteDeleteService.ts index 4dad82509..fbcac2eff 100644 --- a/packages/backend/src/core/NoteDeleteService.ts +++ b/packages/backend/src/core/NoteDeleteService.ts @@ -78,7 +78,7 @@ export class NoteDeleteService { }); } - const content = this.apRendererService.renderActivity(renote + const content = this.apRendererService.addContext(renote ? this.apRendererService.renderUndo(this.apRendererService.renderAnnounce(renote.uri ?? `${this.config.url}/notes/${renote.id}`, note), user) : this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${note.id}`), user)); @@ -90,7 +90,7 @@ export class NoteDeleteService { for (const cascadingNote of cascadingNotes) { if (!cascadingNote.user) continue; if (!this.userEntityService.isLocalUser(cascadingNote.user)) continue; - const content = this.apRendererService.renderActivity(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${cascadingNote.id}`), cascadingNote.user)); + const content = this.apRendererService.addContext(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${cascadingNote.id}`), cascadingNote.user)); this.deliverToConcerned(cascadingNote.user, cascadingNote, content); } //#endregion diff --git a/packages/backend/src/core/NotePiningService.ts b/packages/backend/src/core/NotePiningService.ts index bb6def1ed..3a9f832ac 100644 --- a/packages/backend/src/core/NotePiningService.ts +++ b/packages/backend/src/core/NotePiningService.ts @@ -115,7 +115,7 @@ export class NotePiningService { const target = `${this.config.url}/users/${user.id}/collections/featured`; const item = `${this.config.url}/notes/${noteId}`; - const content = this.apRendererService.renderActivity(isAddition ? this.apRendererService.renderAdd(user, target, item) : this.apRendererService.renderRemove(user, target, item)); + const content = this.apRendererService.addContext(isAddition ? this.apRendererService.renderAdd(user, target, item) : this.apRendererService.renderRemove(user, target, item)); this.apDeliverManagerService.deliverToFollowers(user, content); this.relayService.deliverToRelays(user, content); diff --git a/packages/backend/src/core/PollService.ts b/packages/backend/src/core/PollService.ts index 042dcb3e6..018e83f8c 100644 --- a/packages/backend/src/core/PollService.ts +++ b/packages/backend/src/core/PollService.ts @@ -97,7 +97,7 @@ export class PollService { if (user == null) throw new Error('note not found'); if (this.userEntityService.isLocalUser(user)) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderUpdate(await this.apRendererService.renderNote(note, false), user)); + const content = this.apRendererService.addContext(this.apRendererService.renderUpdate(await this.apRendererService.renderNote(note, false), user)); this.apDeliverManagerService.deliverToFollowers(user, content); this.relayService.deliverToRelays(user, content); } diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index 380659005..9ac3058ef 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -85,7 +85,7 @@ export class ReactionService { } @bindThis - public async create(user: { id: User['id']; host: User['host']; isBot: User['isBot'] }, note: Note, reaction?: string) { + public async create(user: { id: User['id']; host: User['host']; isBot: User['isBot'] }, note: Note, reaction?: string | null) { // Check blocking if (note.userId !== user.id) { const blocked = await this.userBlockingService.checkBlocked(note.userId, user.id); @@ -177,7 +177,7 @@ export class ReactionService { //#region 配信 if (this.userEntityService.isLocalUser(user) && !note.localOnly) { - const content = this.apRendererService.renderActivity(await this.apRendererService.renderLike(record, note)); + const content = this.apRendererService.addContext(await this.apRendererService.renderLike(record, note)); const dm = this.apDeliverManagerService.createDeliverManager(user, content); if (note.userHost !== null) { const reactee = await this.usersRepository.findOneBy({ id: note.userId }); @@ -235,7 +235,7 @@ export class ReactionService { //#region 配信 if (this.userEntityService.isLocalUser(user) && !note.localOnly) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(await this.apRendererService.renderLike(exist, note), user)); + const content = this.apRendererService.addContext(this.apRendererService.renderUndo(await this.apRendererService.renderLike(exist, note), user)); const dm = this.apDeliverManagerService.createDeliverManager(user, content); if (note.userHost !== null) { const reactee = await this.usersRepository.findOneBy({ id: note.userId }); diff --git a/packages/backend/src/core/RelayService.ts b/packages/backend/src/core/RelayService.ts index a7408649b..326fd0af1 100644 --- a/packages/backend/src/core/RelayService.ts +++ b/packages/backend/src/core/RelayService.ts @@ -56,7 +56,7 @@ export class RelayService { const relayActor = await this.getRelayActor(); const follow = await this.apRendererService.renderFollowRelay(relay, relayActor); - const activity = this.apRendererService.renderActivity(follow); + const activity = this.apRendererService.addContext(follow); this.queueService.deliver(relayActor, activity, relay.inbox); return relay; @@ -75,7 +75,7 @@ export class RelayService { const relayActor = await this.getRelayActor(); const follow = this.apRendererService.renderFollowRelay(relay, relayActor); const undo = this.apRendererService.renderUndo(follow, relayActor); - const activity = this.apRendererService.renderActivity(undo); + const activity = this.apRendererService.addContext(undo); this.queueService.deliver(relayActor, activity, relay.inbox); await this.relaysRepository.delete(relay.id); diff --git a/packages/backend/src/core/UserBlockingService.ts b/packages/backend/src/core/UserBlockingService.ts index d73432866..89de72b9a 100644 --- a/packages/backend/src/core/UserBlockingService.ts +++ b/packages/backend/src/core/UserBlockingService.ts @@ -117,7 +117,7 @@ export class UserBlockingService implements OnApplicationShutdown { }); if (this.userEntityService.isLocalUser(blocker) && this.userEntityService.isRemoteUser(blockee)) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderBlock(blocking)); + const content = this.apRendererService.addContext(this.apRendererService.renderBlock(blocking)); this.queueService.deliver(blocker, content, blockee.inbox); } } @@ -162,13 +162,13 @@ export class UserBlockingService implements OnApplicationShutdown { // リモートにフォローリクエストをしていたらUndoFollow送信 if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower)); + const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower)); this.queueService.deliver(follower, content, followee.inbox); } // リモートからフォローリクエストを受けていたらReject送信 if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee, request.requestId!), followee)); + const content = this.apRendererService.addContext(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee, request.requestId!), followee)); this.queueService.deliver(followee, content, follower.inbox); } } @@ -210,13 +210,13 @@ export class UserBlockingService implements OnApplicationShutdown { // リモートにフォローをしていたらUndoFollow送信 if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower)); + const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower)); this.queueService.deliver(follower, content, followee.inbox); } // リモートからフォローをされていたらRejectFollow送信 if (this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower)) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee), followee)); + const content = this.apRendererService.addContext(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee), followee)); this.queueService.deliver(followee, content, follower.inbox); } } @@ -261,7 +261,7 @@ export class UserBlockingService implements OnApplicationShutdown { // deliver if remote bloking if (this.userEntityService.isLocalUser(blocker) && this.userEntityService.isRemoteUser(blockee)) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderBlock(blocking), blocker)); + const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderBlock(blocking), blocker)); this.queueService.deliver(blocker, content, blockee.inbox); } } diff --git a/packages/backend/src/core/UserCacheService.ts b/packages/backend/src/core/UserCacheService.ts index 29a64f584..52cedbd10 100644 --- a/packages/backend/src/core/UserCacheService.ts +++ b/packages/backend/src/core/UserCacheService.ts @@ -45,10 +45,10 @@ export class UserCacheService implements OnApplicationShutdown { case 'userChangeSuspendedState': case 'remoteUserUpdated': { const user = await this.usersRepository.findOneByOrFail({ id: body.id }); - this.userByIdCache.set(user.id, user); + this.userByIdCache.set(user.id, user as CacheableUser); for (const [k, v] of this.uriPersonCache.cache.entries()) { if (v.value?.id === user.id) { - this.uriPersonCache.set(k, user); + this.uriPersonCache.set(k, user as CacheableUser); } } if (this.userEntityService.isLocalUser(user)) { @@ -78,7 +78,7 @@ export class UserCacheService implements OnApplicationShutdown { @bindThis public findById(userId: User['id']) { - return this.userByIdCache.fetch(userId, () => this.usersRepository.findOneByOrFail({ id: userId })); + return this.userByIdCache.fetch(userId, () => this.usersRepository.findOneByOrFail({ id: userId }) as Promise); } @bindThis diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index 2214a4862..a50f19a47 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -81,7 +81,7 @@ export class UserFollowingService { if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee) && blocked) { // リモートフォローを受けてブロックしていた場合は、エラーにするのではなくRejectを送り返しておしまい。 - const content = this.apRendererService.renderActivity(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee, requestId), followee)); + const content = this.apRendererService.addContext(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee, requestId), followee)); this.queueService.deliver(followee, content, follower.inbox); return; } else if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee) && blocking) { @@ -130,7 +130,7 @@ export class UserFollowingService { await this.insertFollowingDoc(followee, follower); if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee)); + const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee)); this.queueService.deliver(followee, content, follower.inbox); } } @@ -293,13 +293,13 @@ export class UserFollowingService { } if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower)); + const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower)); this.queueService.deliver(follower, content, followee.inbox); } if (this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower)) { // local user has null host - const content = this.apRendererService.renderActivity(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee), followee)); + const content = this.apRendererService.addContext(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee), followee)); this.queueService.deliver(followee, content, follower.inbox); } } @@ -388,7 +388,7 @@ export class UserFollowingService { } if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderFollow(follower, followee)); + const content = this.apRendererService.addContext(this.apRendererService.renderFollow(follower, followee)); this.queueService.deliver(follower, content, followee.inbox); } } @@ -403,7 +403,7 @@ export class UserFollowingService { }, ): Promise { if (this.userEntityService.isRemoteUser(followee)) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower)); + const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower)); if (this.userEntityService.isLocalUser(follower)) { // 本来このチェックは不要だけどTSに怒られるので this.queueService.deliver(follower, content, followee.inbox); @@ -448,7 +448,7 @@ export class UserFollowingService { await this.insertFollowingDoc(followee, follower); if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) { - const content = this.apRendererService.renderActivity(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, request.requestId!), followee)); + const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, request.requestId!), followee)); this.queueService.deliver(followee, content, follower.inbox); } @@ -556,7 +556,7 @@ export class UserFollowingService { followerId: follower.id, }); - const content = this.apRendererService.renderActivity(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee, request?.requestId ?? undefined), followee)); + const content = this.apRendererService.addContext(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee, request?.requestId ?? undefined), followee)); this.queueService.deliver(followee, content, follower.inbox); } diff --git a/packages/backend/src/core/UserSuspendService.ts b/packages/backend/src/core/UserSuspendService.ts index df1664942..02903a059 100644 --- a/packages/backend/src/core/UserSuspendService.ts +++ b/packages/backend/src/core/UserSuspendService.ts @@ -35,7 +35,7 @@ export class UserSuspendService { if (this.userEntityService.isLocalUser(user)) { // 知り得る全SharedInboxにDelete配信 - const content = this.apRendererService.renderActivity(this.apRendererService.renderDelete(`${this.config.url}/users/${user.id}`, user)); + const content = this.apRendererService.addContext(this.apRendererService.renderDelete(`${this.config.url}/users/${user.id}`, user)); const queue: string[] = []; @@ -65,7 +65,7 @@ export class UserSuspendService { if (this.userEntityService.isLocalUser(user)) { // 知り得る全SharedInboxにUndo Delete配信 - const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderDelete(`${this.config.url}/users/${user.id}`, user), user)); + const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderDelete(`${this.config.url}/users/${user.id}`, user), user)); const queue: string[] = []; diff --git a/packages/backend/src/core/activitypub/ApDbResolverService.ts b/packages/backend/src/core/activitypub/ApDbResolverService.ts index 1d0c2d5da..b057f39b0 100644 --- a/packages/backend/src/core/activitypub/ApDbResolverService.ts +++ b/packages/backend/src/core/activitypub/ApDbResolverService.ts @@ -130,11 +130,11 @@ export class ApDbResolverService { return await this.userCacheService.userByIdCache.fetchMaybe(parsed.id, () => this.usersRepository.findOneBy({ id: parsed.id, - }).then(x => x ?? undefined)) ?? null; + }).then(x => (x as CacheableUser | null) ?? undefined)) ?? null; } else { return await this.userCacheService.uriPersonCache.fetch(parsed.uri, () => this.usersRepository.findOneBy({ uri: parsed.uri, - })); + }) as Promise); } } diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index 76c8bf68d..02bb0ca4e 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { In } from 'typeorm'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; -import type { CacheableRemoteUser } from '@/models/entities/User.js'; +import type { CacheableRemoteUser, CacheableUser } from '@/models/entities/User.js'; import { UserFollowingService } from '@/core/UserFollowingService.js'; import { ReactionService } from '@/core/ReactionService.js'; import { RelayService } from '@/core/RelayService.js'; @@ -22,6 +22,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { QueueService } from '@/core/QueueService.js'; import { MessagingService } from '@/core/MessagingService.js'; import type { UsersRepository, NotesRepository, FollowingsRepository, MessagingMessagesRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/index.js'; +import { bindThis } from '@/decorators.js'; import { getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isPost, isRead, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js'; import { ApNoteService } from './models/ApNoteService.js'; import { ApLoggerService } from './ApLoggerService.js'; @@ -32,7 +33,6 @@ import { ApPersonService } from './models/ApPersonService.js'; import { ApQuestionService } from './models/ApQuestionService.js'; import type { Resolver } from './ApResolverService.js'; import type { IAccept, IAdd, IAnnounce, IBlock, ICreate, IDelete, IFlag, IFollow, ILike, IObject, IRead, IReject, IRemove, IUndo, IUpdate } from './type.js'; -import { bindThis } from '@/decorators.js'; @Injectable() export class ApInboxService { @@ -687,7 +687,7 @@ export class ApInboxService { return 'skip: ブロック解除しようとしているユーザーはローカルユーザーではありません'; } - await this.userBlockingService.unblock(await this.usersRepository.findOneByOrFail({ id: actor.id }), blockee); + await this.userBlockingService.unblock(await this.usersRepository.findOneByOrFail({ id: actor.id }) as CacheableUser, blockee); return 'ok'; } diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 648f30229..b87aee880 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -24,7 +24,7 @@ import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFil import { bindThis } from '@/decorators.js'; import { LdSignatureService } from './LdSignatureService.js'; import { ApMfmService } from './ApMfmService.js'; -import type { IActivity, IObject } from './type.js'; +import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IObject, IQuestion, IRead, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js'; import type { IIdentifier } from './models/identifier.js'; @Injectable() @@ -61,7 +61,7 @@ export class ApRendererService { } @bindThis - public renderAccept(object: any, user: { id: User['id']; host: null }) { + public renderAccept(object: any, user: { id: User['id']; host: null }): IAccept { return { type: 'Accept', actor: `${this.config.url}/users/${user.id}`, @@ -70,7 +70,7 @@ export class ApRendererService { } @bindThis - public renderAdd(user: ILocalUser, target: any, object: any) { + public renderAdd(user: ILocalUser, target: any, object: any): IAdd { return { type: 'Add', actor: `${this.config.url}/users/${user.id}`, @@ -80,7 +80,7 @@ export class ApRendererService { } @bindThis - public renderAnnounce(object: any, note: Note) { + public renderAnnounce(object: any, note: Note): IAnnounce { const attributedTo = `${this.config.url}/users/${note.userId}`; let to: string[] = []; @@ -93,7 +93,7 @@ export class ApRendererService { to = [`${attributedTo}/followers`]; cc = ['https://www.w3.org/ns/activitystreams#Public']; } else { - return null; + throw new Error('renderAnnounce: cannot render non-public note'); } return { @@ -113,7 +113,7 @@ export class ApRendererService { * @param block The block to be rendered. The blockee relation must be loaded. */ @bindThis - public renderBlock(block: Blocking) { + public renderBlock(block: Blocking): IBlock { if (block.blockee?.uri == null) { throw new Error('renderBlock: missing blockee uri'); } @@ -127,14 +127,14 @@ export class ApRendererService { } @bindThis - public renderCreate(object: any, note: Note) { + public renderCreate(object: IObject, note: Note): ICreate { const activity = { id: `${this.config.url}/notes/${note.id}/activity`, actor: `${this.config.url}/users/${note.userId}`, type: 'Create', published: note.createdAt.toISOString(), object, - } as any; + } as ICreate; if (object.to) activity.to = object.to; if (object.cc) activity.cc = object.cc; @@ -143,7 +143,7 @@ export class ApRendererService { } @bindThis - public renderDelete(object: any, user: { id: User['id']; host: null }) { + public renderDelete(object: IObject | string, user: { id: User['id']; host: null }): IDelete { return { type: 'Delete', actor: `${this.config.url}/users/${user.id}`, @@ -153,7 +153,7 @@ export class ApRendererService { } @bindThis - public renderDocument(file: DriveFile) { + public renderDocument(file: DriveFile): IApDocument { return { type: 'Document', mediaType: file.type, @@ -163,12 +163,12 @@ export class ApRendererService { } @bindThis - public renderEmoji(emoji: Emoji) { + public renderEmoji(emoji: Emoji): IApEmoji { return { id: `${this.config.url}/emojis/${emoji.name}`, type: 'Emoji', name: `:${emoji.name}:`, - updated: emoji.updatedAt != null ? emoji.updatedAt.toISOString() : new Date().toISOString, + updated: emoji.updatedAt != null ? emoji.updatedAt.toISOString() : new Date().toISOString(), icon: { type: 'Image', mediaType: emoji.type ?? 'image/png', @@ -181,7 +181,7 @@ export class ApRendererService { // to anonymise reporters, the reporting actor must be a system user // object has to be a uri or array of uris @bindThis - public renderFlag(user: ILocalUser, object: [string], content: string) { + public renderFlag(user: ILocalUser, object: IObject, content: string): IFlag { return { type: 'Flag', actor: `${this.config.url}/users/${user.id}`, @@ -191,15 +191,13 @@ export class ApRendererService { } @bindThis - public renderFollowRelay(relay: Relay, relayActor: ILocalUser) { - const follow = { + public renderFollowRelay(relay: Relay, relayActor: ILocalUser): IFollow { + return { id: `${this.config.url}/activities/follow-relay/${relay.id}`, type: 'Follow', actor: `${this.config.url}/users/${relayActor.id}`, object: 'https://www.w3.org/ns/activitystreams#Public', }; - - return follow; } /** @@ -217,19 +215,17 @@ export class ApRendererService { follower: { id: User['id']; host: User['host']; uri: User['host'] }, followee: { id: User['id']; host: User['host']; uri: User['host'] }, requestId?: string, - ) { - const follow = { + ): IFollow { + return { id: requestId ?? `${this.config.url}/follows/${follower.id}/${followee.id}`, type: 'Follow', - actor: this.userEntityService.isLocalUser(follower) ? `${this.config.url}/users/${follower.id}` : follower.uri, - object: this.userEntityService.isLocalUser(followee) ? `${this.config.url}/users/${followee.id}` : followee.uri, - } as any; - - return follow; + actor: this.userEntityService.isLocalUser(follower) ? `${this.config.url}/users/${follower.id}` : follower.uri!, + object: this.userEntityService.isLocalUser(followee) ? `${this.config.url}/users/${followee.id}` : followee.uri!, + }; } @bindThis - public renderHashtag(tag: string) { + public renderHashtag(tag: string): IApHashtag { return { type: 'Hashtag', href: `${this.config.url}/tags/${encodeURIComponent(tag)}`, @@ -238,7 +234,7 @@ export class ApRendererService { } @bindThis - public renderImage(file: DriveFile) { + public renderImage(file: DriveFile): IApImage { return { type: 'Image', url: this.driveFileEntityService.getPublicUrl(file), @@ -248,7 +244,7 @@ export class ApRendererService { } @bindThis - public renderKey(user: ILocalUser, key: UserKeypair, postfix?: string) { + public renderKey(user: ILocalUser, key: UserKeypair, postfix?: string): IKey { return { id: `${this.config.url}/users/${user.id}${postfix ?? '/publickey'}`, type: 'Key', @@ -261,7 +257,7 @@ export class ApRendererService { } @bindThis - public async renderLike(noteReaction: NoteReaction, note: { uri: string | null }) { + public async renderLike(noteReaction: NoteReaction, note: { uri: string | null }): Promise { const reaction = noteReaction.reaction; const object = { @@ -271,10 +267,11 @@ export class ApRendererService { object: note.uri ? note.uri : `${this.config.url}/notes/${noteReaction.noteId}`, content: reaction, _misskey_reaction: reaction, - } as any; + } as ILike; if (reaction.startsWith(':')) { const name = reaction.replaceAll(':', ''); + // TODO: cache const emoji = await this.emojisRepository.findOneBy({ name, host: IsNull(), @@ -287,10 +284,10 @@ export class ApRendererService { } @bindThis - public renderMention(mention: User) { + public renderMention(mention: User): IApMention { return { type: 'Mention', - href: this.userEntityService.isRemoteUser(mention) ? mention.uri : `${this.config.url}/users/${(mention as ILocalUser).id}`, + href: this.userEntityService.isRemoteUser(mention) ? mention.uri! : `${this.config.url}/users/${(mention as ILocalUser).id}`, name: this.userEntityService.isRemoteUser(mention) ? `@${mention.username}@${mention.host}` : `@${(mention as ILocalUser).username}`, }; } @@ -518,8 +515,8 @@ export class ApRendererService { } @bindThis - public async renderQuestion(user: { id: User['id'] }, note: Note, poll: Poll) { - const question = { + public async renderQuestion(user: { id: User['id'] }, note: Note, poll: Poll): IQuestion { + return { type: 'Question', id: `${this.config.url}/questions/${note.id}`, actor: `${this.config.url}/users/${user.id}`, @@ -533,21 +530,19 @@ export class ApRendererService { }, })), }; - - return question; } @bindThis - public renderRead(user: { id: User['id'] }, message: MessagingMessage) { + public renderRead(user: { id: User['id'] }, message: MessagingMessage): IRead { return { type: 'Read', actor: `${this.config.url}/users/${user.id}`, - object: message.uri, + object: message.uri!, }; } @bindThis - public renderReject(object: any, user: { id: User['id'] }) { + public renderReject(object: any, user: { id: User['id'] }): IReject { return { type: 'Reject', actor: `${this.config.url}/users/${user.id}`, @@ -556,7 +551,7 @@ export class ApRendererService { } @bindThis - public renderRemove(user: { id: User['id'] }, target: any, object: any) { + public renderRemove(user: { id: User['id'] }, target: any, object: any): IRemove { return { type: 'Remove', actor: `${this.config.url}/users/${user.id}`, @@ -566,7 +561,7 @@ export class ApRendererService { } @bindThis - public renderTombstone(id: string) { + public renderTombstone(id: string): ITombstone { return { id, type: 'Tombstone', @@ -574,8 +569,7 @@ export class ApRendererService { } @bindThis - public renderUndo(object: any, user: { id: User['id'] }) { - if (object == null) return null; + public renderUndo(object: any, user: { id: User['id'] }): IUndo { const id = typeof object.id === 'string' && object.id.startsWith(this.config.url) ? `${object.id}/undo` : undefined; return { @@ -588,21 +582,19 @@ export class ApRendererService { } @bindThis - public renderUpdate(object: any, user: { id: User['id'] }) { - const activity = { + public renderUpdate(object: any, user: { id: User['id'] }): IUpdate { + return { id: `${this.config.url}/users/${user.id}#updates/${new Date().getTime()}`, actor: `${this.config.url}/users/${user.id}`, type: 'Update', to: ['https://www.w3.org/ns/activitystreams#Public'], object, published: new Date().toISOString(), - } as any; - - return activity; + }; } @bindThis - public renderVote(user: { id: User['id'] }, vote: PollVote, note: Note, poll: Poll, pollOwner: IRemoteUser) { + public renderVote(user: { id: User['id'] }, vote: PollVote, note: Note, poll: Poll, pollOwner: IRemoteUser): ICreate { return { id: `${this.config.url}/users/${user.id}#votes/${vote.id}/activity`, actor: `${this.config.url}/users/${user.id}`, @@ -621,9 +613,7 @@ export class ApRendererService { } @bindThis - public renderActivity(x: any): IActivity | null { - if (x == null) return null; - + public addContext(x: T): T & { '@context': any; id: string; } { if (typeof x === 'object' && x.id == null) { x.id = `${this.config.url}/${uuid()}`; } @@ -659,7 +649,7 @@ export class ApRendererService { vcard: 'http://www.w3.org/2006/vcard/ns#', }, ], - }, x); + }, x as T & { id: string; }); } @bindThis diff --git a/packages/backend/src/core/activitypub/ApResolverService.ts b/packages/backend/src/core/activitypub/ApResolverService.ts index 7e962cb12..65026cc4c 100644 --- a/packages/backend/src/core/activitypub/ApResolverService.ts +++ b/packages/backend/src/core/activitypub/ApResolverService.ts @@ -38,8 +38,7 @@ export class Resolver { private recursionLimit = 100, ) { this.history = new Set(); - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - this.logger = this.loggerService?.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる + this.logger = this.loggerService.getLogger('ap-resolve'); } @bindThis @@ -124,10 +123,10 @@ export class Resolver { switch (parsed.type) { case 'notes': return this.notesRepository.findOneByOrFail({ id: parsed.id }) - .then(note => { + .then(async note => { if (parsed.rest === 'activity') { // this refers to the create activity and not the note itself - return this.apRendererService.renderActivity(this.apRendererService.renderCreate(this.apRendererService.renderNote(note), note)); + return this.apRendererService.addContext(this.apRendererService.renderCreate(await this.apRendererService.renderNote(note), note)); } else { return this.apRendererService.renderNote(note); } @@ -143,8 +142,8 @@ export class Resolver { ]) .then(([note, poll]) => this.apRendererService.renderQuestion({ id: note.userId }, note, poll)); case 'likes': - return this.noteReactionsRepository.findOneByOrFail({ id: parsed.id }).then(reaction => - this.apRendererService.renderActivity(this.apRendererService.renderLike(reaction, { uri: null }))!); + return this.noteReactionsRepository.findOneByOrFail({ id: parsed.id }).then(async reaction => + this.apRendererService.addContext(await this.apRendererService.renderLike(reaction, { uri: null }))); case 'follows': // rest should be if (parsed.rest == null || !/^\w+$/.test(parsed.rest)) throw new Error('resolveLocal: invalid follow URI'); @@ -152,7 +151,7 @@ export class Resolver { return Promise.all( [parsed.id, parsed.rest].map(id => this.usersRepository.findOneByOrFail({ id })), ) - .then(([follower, followee]) => this.apRendererService.renderActivity(this.apRendererService.renderFollow(follower, followee, url))); + .then(([follower, followee]) => this.apRendererService.addContext(this.apRendererService.renderFollow(follower, followee, url))); default: throw new Error(`resolveLocal: type ${parsed.type} unhandled`); } @@ -184,6 +183,7 @@ export class ApResolverService { private httpRequestService: HttpRequestService, private apRendererService: ApRendererService, private apDbResolverService: ApDbResolverService, + private loggerService: LoggerService, ) { } @@ -202,6 +202,7 @@ export class ApResolverService { this.httpRequestService, this.apRendererService, this.apDbResolverService, + this.loggerService, ); } } diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index 813415e6f..dc47fdf80 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -114,7 +114,7 @@ export class ApNoteService { public async createNote(value: string | IObject, resolver?: Resolver, silent = false): Promise { if (resolver == null) resolver = this.apResolverService.createResolver(); - const object: any = await resolver.resolve(value); + const object = await resolver.resolve(value); const entryUri = getApId(value); const err = this.validateNote(object, entryUri); @@ -129,7 +129,7 @@ export class ApNoteService { throw new Error('invalid note'); } - const note: IPost = object; + const note: IPost = object as any; this.logger.debug(`Note fetched: ${JSON.stringify(note, null, 2)}`); @@ -146,7 +146,7 @@ export class ApNoteService { this.logger.info(`Creating the Note: ${note.id}`); // 投稿者をフェッチ - const actor = await this.apPersonService.resolvePerson(getOneApId(note.attributedTo), resolver) as CacheableRemoteUser; + const actor = await this.apPersonService.resolvePerson(getOneApId(note.attributedTo!), resolver) as CacheableRemoteUser; // 投稿者が凍結されていたらスキップ if (actor.isSuspended) { diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index 76f820cda..4869656f1 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -206,13 +206,13 @@ export class ApPersonService implements OnModuleInit { // URIがこのサーバーを指しているならデータベースからフェッチ if (uri.startsWith(this.config.url + '/')) { const id = uri.split('/').pop(); - const u = await this.usersRepository.findOneBy({ id }); + const u = await this.usersRepository.findOneBy({ id }) as null | CacheableUser; if (u) this.userCacheService.uriPersonCache.set(uri, u); return u; } //#region このサーバーに既に登録されていたらそれを返す - const exist = await this.usersRepository.findOneBy({ uri }); + const exist = await this.usersRepository.findOneBy({ uri }) as null | CacheableUser; if (exist) { this.userCacheService.uriPersonCache.set(uri, exist); @@ -513,7 +513,7 @@ export class ApPersonService implements OnModuleInit { // リモートサーバーからフェッチしてきて登録 if (resolver == null) resolver = this.apResolverService.createResolver(); - return await this.createPerson(uri, resolver); + return await this.createPerson(uri, resolver) as CacheableUser; } @bindThis diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts index dcc5110aa..b900e375b 100644 --- a/packages/backend/src/core/activitypub/type.ts +++ b/packages/backend/src/core/activitypub/type.ts @@ -2,24 +2,24 @@ export type obj = { [x: string]: any }; export type ApObject = IObject | string | (IObject | string)[]; export interface IObject { - '@context': string | string[] | obj | obj[]; + '@context'?: string | string[] | obj | obj[]; type: string | string[]; id?: string; + name?: string | null; summary?: string; published?: string; cc?: ApObject; to?: ApObject; - attributedTo: ApObject; + attributedTo?: ApObject; attachment?: any[]; inReplyTo?: any; replies?: ICollection; content?: string; - name?: string; startTime?: Date; endTime?: Date; icon?: any; image?: any; - url?: ApObject; + url?: ApObject | string; href?: string; tag?: IObject | IObject[]; sensitive?: boolean; @@ -118,6 +118,7 @@ export interface IPost extends IObject { export interface IQuestion extends IObject { type: 'Note' | 'Question'; + actor: string; source?: { content: string; mediaType: string; @@ -200,6 +201,7 @@ export const isPropertyValue = (object: IObject): object is IApPropertyValue => export interface IApMention extends IObject { type: 'Mention'; href: string; + name: string; } export const isMention = (object: IObject): object is IApMention => @@ -217,12 +219,30 @@ export const isHashtag = (object: IObject): object is IApHashtag => export interface IApEmoji extends IObject { type: 'Emoji'; - updated: Date; + name: string; + updated: string; } export const isEmoji = (object: IObject): object is IApEmoji => getApType(object) === 'Emoji' && !Array.isArray(object.icon) && object.icon.url != null; +export interface IKey extends IObject { + type: 'Key'; + owner: string; + publicKeyPem: string | Buffer; +} + +export interface IApDocument extends IObject { + type: 'Document'; + name: string | null; + mediaType: string; +} + +export interface IApImage extends IObject { + type: 'Image'; + name: string | null; +} + export interface ICreate extends IActivity { type: 'Create'; } diff --git a/packages/backend/src/core/entities/DriveFileEntityService.ts b/packages/backend/src/core/entities/DriveFileEntityService.ts index b8550cd73..38af51a19 100644 --- a/packages/backend/src/core/entities/DriveFileEntityService.ts +++ b/packages/backend/src/core/entities/DriveFileEntityService.ts @@ -11,9 +11,9 @@ import type { DriveFile } from '@/models/entities/DriveFile.js'; import { appendQuery, query } from '@/misc/prelude/url.js'; import { deepClone } from '@/misc/clone.js'; import { UtilityService } from '../UtilityService.js'; +import { VideoProcessingService } from '../VideoProcessingService.js'; import { UserEntityService } from './UserEntityService.js'; import { DriveFolderEntityService } from './DriveFolderEntityService.js'; -import { VideoProcessingService } from '../VideoProcessingService.js'; type PackOptions = { detail?: boolean, @@ -74,14 +74,14 @@ export class DriveFileEntityService { } @bindThis - private getProxiedUrl(url: string, mode?: 'static' | 'avatar'): string | null { + private getProxiedUrl(url: string, mode?: 'static' | 'avatar'): string { return appendQuery( `${this.config.mediaProxy}/${mode ?? 'image'}.webp`, query({ url, ...(mode ? { [mode]: '1' } : {}), - }) - ) + }), + ); } @bindThis @@ -110,7 +110,7 @@ export class DriveFileEntityService { } @bindThis - public getPublicUrl(file: DriveFile, mode?: 'avatar'): string | null { // static = thumbnail + public getPublicUrl(file: DriveFile, mode?: 'avatar'): string { // static = thumbnail // リモートかつメディアプロキシ if (file.uri != null && file.userHost != null && this.config.externalMediaProxyEnabled) { return this.getProxiedUrl(file.uri, mode); diff --git a/packages/backend/src/models/entities/User.ts b/packages/backend/src/models/entities/User.ts index 1cfcc814e..9cfe79787 100644 --- a/packages/backend/src/models/entities/User.ts +++ b/packages/backend/src/models/entities/User.ts @@ -221,6 +221,7 @@ export interface ILocalUser extends User { export interface IRemoteUser extends User { host: string; + uri: string; } export type CacheableLocalUser = ILocalUser; diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts index 5480395ee..c3795223a 100644 --- a/packages/backend/src/server/ActivityPubServerService.ts +++ b/packages/backend/src/server/ActivityPubServerService.ts @@ -183,13 +183,13 @@ export class ActivityPubServerService { ); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(rendered)); + return (this.apRendererService.addContext(rendered)); } else { // index page const rendered = this.apRendererService.renderOrderedCollection(partOf, user.followersCount, `${partOf}?page=true`); reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(rendered)); + return (this.apRendererService.addContext(rendered)); } } @@ -271,13 +271,13 @@ export class ActivityPubServerService { ); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(rendered)); + return (this.apRendererService.addContext(rendered)); } else { // index page const rendered = this.apRendererService.renderOrderedCollection(partOf, user.followingCount, `${partOf}?page=true`); reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(rendered)); + return (this.apRendererService.addContext(rendered)); } } @@ -312,7 +312,7 @@ export class ActivityPubServerService { reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(rendered)); + return (this.apRendererService.addContext(rendered)); } @bindThis @@ -389,7 +389,7 @@ export class ActivityPubServerService { ); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(rendered)); + return (this.apRendererService.addContext(rendered)); } else { // index page const rendered = this.apRendererService.renderOrderedCollection(partOf, user.notesCount, @@ -398,7 +398,7 @@ export class ActivityPubServerService { ); reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(rendered)); + return (this.apRendererService.addContext(rendered)); } } @@ -411,7 +411,7 @@ export class ActivityPubServerService { reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(await this.apRendererService.renderPerson(user as ILocalUser))); + return (this.apRendererService.addContext(await this.apRendererService.renderPerson(user as ILocalUser))); } @bindThis @@ -481,7 +481,7 @@ export class ActivityPubServerService { reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(await this.apRendererService.renderNote(note, false))); + return this.apRendererService.addContext(await this.apRendererService.renderNote(note, false)); }); // note activity @@ -502,7 +502,7 @@ export class ActivityPubServerService { reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(await this.packActivity(note))); + return (this.apRendererService.addContext(await this.packActivity(note))); }); // outbox @@ -545,7 +545,7 @@ export class ActivityPubServerService { if (this.userEntityService.isLocalUser(user)) { reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(this.apRendererService.renderKey(user, keypair))); + return (this.apRendererService.addContext(this.apRendererService.renderKey(user, keypair))); } else { reply.code(400); return; @@ -589,7 +589,7 @@ export class ActivityPubServerService { reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(await this.apRendererService.renderEmoji(emoji))); + return (this.apRendererService.addContext(await this.apRendererService.renderEmoji(emoji))); }); // like @@ -610,7 +610,7 @@ export class ActivityPubServerService { reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(await this.apRendererService.renderLike(reaction, note))); + return (this.apRendererService.addContext(await this.apRendererService.renderLike(reaction, note))); }); // follow @@ -636,7 +636,7 @@ export class ActivityPubServerService { reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); - return (this.apRendererService.renderActivity(this.apRendererService.renderFollow(follower, followee))); + return (this.apRendererService.addContext(this.apRendererService.renderFollow(follower, followee))); }); done(); 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 cdaec13a3..84fcc05ed 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 @@ -49,7 +49,7 @@ export default class extends Endpoint { const actor = await this.instanceActorService.getInstanceActor(); const targetUser = await this.usersRepository.findOneByOrFail({ id: report.targetUserId }); - this.queueService.deliver(actor, this.apRendererService.renderActivity(this.apRendererService.renderFlag(actor, [targetUser.uri!], report.comment)), targetUser.inbox); + this.queueService.deliver(actor, this.apRendererService.addContext(this.apRendererService.renderFlag(actor, [targetUser.uri!], report.comment)), targetUser.inbox); } await this.abuseUserReportsRepository.update(report.id, { diff --git a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts index befaea466..d8e1a1149 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts @@ -162,7 +162,7 @@ export default class extends Endpoint { if (note.userHost != null) { const pollOwner = await this.usersRepository.findOneByOrFail({ id: note.userId }) as IRemoteUser; - this.queueService.deliver(me, this.apRendererService.renderActivity(await this.apRendererService.renderVote(me, vote, note, poll, pollOwner)), pollOwner.inbox); + this.queueService.deliver(me, this.apRendererService.addContext(await this.apRendererService.renderVote(me, vote, note, poll, pollOwner)), pollOwner.inbox); } // リモートフォロワーにUpdate配信 From 5d3d5cd59cd10cf9fbba40c04caf5ab8675632e1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 12 Feb 2023 18:54:38 +0900 Subject: [PATCH 11/92] refactor: fix types --- packages/backend/src/core/UserFollowingService.ts | 2 +- packages/backend/src/core/activitypub/type.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index a50f19a47..c0347c60e 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -434,7 +434,7 @@ export class UserFollowingService { followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, - follower: CacheableUser, + follower: User | CacheableUser, ): Promise { const request = await this.followRequestsRepository.findOneBy({ followeeId: followee.id, diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts index b900e375b..9dc7ed4e3 100644 --- a/packages/backend/src/core/activitypub/type.ts +++ b/packages/backend/src/core/activitypub/type.ts @@ -14,7 +14,7 @@ export interface IObject { attachment?: any[]; inReplyTo?: any; replies?: ICollection; - content?: string; + content?: string | null; startTime?: Date; endTime?: Date; icon?: any; From a71682f6f0639bcedcc664f89615a54cbe397b68 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 12 Feb 2023 20:06:10 +0900 Subject: [PATCH 12/92] refactor: fix types --- .../backend/src/core/activitypub/ApRendererService.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index b87aee880..996ff625e 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -24,7 +24,7 @@ import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFil import { bindThis } from '@/decorators.js'; import { LdSignatureService } from './LdSignatureService.js'; import { ApMfmService } from './ApMfmService.js'; -import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IObject, IQuestion, IRead, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js'; +import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IObject, IPost, IQuestion, IRead, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js'; import type { IIdentifier } from './models/identifier.js'; @Injectable() @@ -293,7 +293,7 @@ export class ApRendererService { } @bindThis - public async renderNote(note: Note, dive = true, isTalk = false): Promise { + public async renderNote(note: Note, dive = true, isTalk = false): Promise { const getPromisedFiles = async (ids: string[]) => { if (!ids || ids.length === 0) return []; const items = await this.driveFilesRepository.findBy({ id: In(ids) }); @@ -406,11 +406,11 @@ export class ApRendererService { totalItems: poll!.votes[i], }, })), - } : {}; + } as const : {}; const asTalk = isTalk ? { _misskey_talk: true, - } : {}; + } as const : {}; return { id: `${this.config.url}/notes/${note.id}`, @@ -515,7 +515,7 @@ export class ApRendererService { } @bindThis - public async renderQuestion(user: { id: User['id'] }, note: Note, poll: Poll): IQuestion { + public renderQuestion(user: { id: User['id'] }, note: Note, poll: Poll): IQuestion { return { type: 'Question', id: `${this.config.url}/questions/${note.id}`, From 9f0e0dc8ce9ca2a04f8bfbfb95c33a7b20288e21 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Sun, 12 Feb 2023 16:31:37 +0100 Subject: [PATCH 13/92] refactor(sw): Fix type errors in packages/sw (#9909) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix type errors in packages/sw * mouhitotsu * @typesは越境しない * Update packages/sw/src/scripts/create-notification.ts --------- Co-authored-by: tamaina --- packages/sw/src/@types/global.d.ts | 7 ++++ .../sw/src/scripts/create-notification.ts | 24 ++++++------- packages/sw/src/scripts/get-user-name.ts | 4 +++ packages/sw/src/scripts/notification-read.ts | 2 +- packages/sw/src/sw.ts | 34 +++++++++---------- 5 files changed, 41 insertions(+), 30 deletions(-) create mode 100644 packages/sw/src/@types/global.d.ts diff --git a/packages/sw/src/@types/global.d.ts b/packages/sw/src/@types/global.d.ts new file mode 100644 index 000000000..5aaef9412 --- /dev/null +++ b/packages/sw/src/@types/global.d.ts @@ -0,0 +1,7 @@ +type FIXME = any; + +declare const _LANGS_: string[][]; +declare const _VERSION_: string; +declare const _ENV_: string; +declare const _DEV_: boolean; +declare const _PERF_PREFIX_: string; diff --git a/packages/sw/src/scripts/create-notification.ts b/packages/sw/src/scripts/create-notification.ts index 6744687fc..6e7845f66 100644 --- a/packages/sw/src/scripts/create-notification.ts +++ b/packages/sw/src/scripts/create-notification.ts @@ -30,7 +30,7 @@ export async function createNotification(data: pushNotificationDataMap[K]): Promise<[string, NotificationOptions] | null> { +async function composeNotification(data: pushNotificationDataMap[keyof pushNotificationDataMap]): Promise<[string, NotificationOptions] | null> { if (!swLang.i18n) swLang.fetchLocale(); const i18n = await swLang.i18n as I18n; const { t } = i18n; @@ -66,7 +66,7 @@ async function composeNotification(data case 'mention': return [t('_notification.youGotMention', { name: getUserName(data.body.user) }), { - body: data.body.note.text || '', + body: data.body.note.text ?? '', icon: data.body.user.avatarUrl, badge: iconUrl('at'), data, @@ -80,7 +80,7 @@ async function composeNotification(data case 'reply': return [t('_notification.youGotReply', { name: getUserName(data.body.user) }), { - body: data.body.note.text || '', + body: data.body.note.text ?? '', icon: data.body.user.avatarUrl, badge: iconUrl('arrow-back-up'), data, @@ -94,7 +94,7 @@ async function composeNotification(data case 'renote': return [t('_notification.youRenoted', { name: getUserName(data.body.user) }), { - body: data.body.note.text || '', + body: data.body.note.text ?? '', icon: data.body.user.avatarUrl, badge: iconUrl('repeat'), data, @@ -108,7 +108,7 @@ async function composeNotification(data case 'quote': return [t('_notification.youGotQuote', { name: getUserName(data.body.user) }), { - body: data.body.note.text || '', + body: data.body.note.text ?? '', icon: data.body.user.avatarUrl, badge: iconUrl('quote'), data, @@ -162,7 +162,7 @@ async function composeNotification(data } return [`${reaction} ${getUserName(data.body.user)}`, { - body: data.body.note.text || '', + body: data.body.note.text ?? '', icon: data.body.user.avatarUrl, badge, data, @@ -227,9 +227,9 @@ async function composeNotification(data }]; case 'app': - return [data.body.header || data.body.body, { - body: data.body.header && data.body.body, - icon: data.body.icon, + return [data.body.header ?? data.body.body, { + body: data.body.header ? data.body.body : '', + icon: data.body.icon ?? undefined, data, }]; @@ -246,7 +246,7 @@ async function composeNotification(data renotify: true, }]; } - return [t('_notification.youGotMessagingMessageFromGroup', { name: data.body.group.name }), { + return [t('_notification.youGotMessagingMessageFromGroup', { name: data.body.group?.name ?? '' }), { icon: data.body.user.avatarUrl, badge: iconUrl('messages'), tag: `messaging:group:${data.body.groupId}`, @@ -255,7 +255,7 @@ async function composeNotification(data }]; case 'unreadAntennaNote': return [t('_notification.unreadAntennaNote', { name: data.body.antenna.name }), { - body: `${getUserName(data.body.note.user)}: ${data.body.note.text || ''}`, + body: `${getUserName(data.body.note.user)}: ${data.body.note.text ?? ''}`, icon: data.body.note.user.avatarUrl, badge: iconUrl('antenna'), tag: `antenna:${data.body.antenna.id}`, @@ -272,7 +272,7 @@ export async function createEmptyNotification() { if (!swLang.i18n) swLang.fetchLocale(); const i18n = await swLang.i18n as I18n; const { t } = i18n; - + await self.registration.showNotification( t('_notification.emptyPushNotificationMessage'), { diff --git a/packages/sw/src/scripts/get-user-name.ts b/packages/sw/src/scripts/get-user-name.ts index d499ea020..ccc38c298 100644 --- a/packages/sw/src/scripts/get-user-name.ts +++ b/packages/sw/src/scripts/get-user-name.ts @@ -1,3 +1,7 @@ export default function(user: { name?: string | null, username: string }): string { + // Show username if name is empty. + // XXX: typescript-eslint has no configuration to allow using `||` against string. + // https://github.com/typescript-eslint/typescript-eslint/issues/4906 + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing return user.name || user.username; } diff --git a/packages/sw/src/scripts/notification-read.ts b/packages/sw/src/scripts/notification-read.ts index 5ad748b84..3b1dde0cd 100644 --- a/packages/sw/src/scripts/notification-read.ts +++ b/packages/sw/src/scripts/notification-read.ts @@ -28,7 +28,7 @@ class SwNotificationReadManager { } // プッシュ通知の既読をサーバーに送信 - public async read(data: pushNotificationDataMap[K]) { + public async read(data: pushNotificationDataMap[keyof pushNotificationDataMap]) { if (data.type !== 'notification' || !(data.userId in this.accounts)) return; const account = this.accounts[data.userId]; diff --git a/packages/sw/src/sw.ts b/packages/sw/src/sw.ts index d47563939..55f881cd4 100644 --- a/packages/sw/src/sw.ts +++ b/packages/sw/src/sw.ts @@ -5,11 +5,11 @@ import { pushNotificationDataMap } from '@/types'; import * as swos from '@/scripts/operations'; import { acct as getAcct } from '@/filters/user'; -self.addEventListener('install', ev => { +globalThis.addEventListener('install', ev => { ev.waitUntil(self.skipWaiting()); }); -self.addEventListener('activate', ev => { +globalThis.addEventListener('activate', ev => { ev.waitUntil( caches.keys() .then(cacheNames => Promise.all( @@ -21,7 +21,7 @@ self.addEventListener('activate', ev => { ); }); -self.addEventListener('fetch', ev => { +globalThis.addEventListener('fetch', ev => { let isHTMLRequest = false; if (ev.request.headers.get('sec-fetch-dest') === 'document') { isHTMLRequest = true; @@ -38,13 +38,13 @@ self.addEventListener('fetch', ev => { ); }); -self.addEventListener('push', ev => { +globalThis.addEventListener('push', ev => { // クライアント取得 ev.waitUntil(self.clients.matchAll({ includeUncontrolled: true, type: 'window' - }).then(async (clients: readonly WindowClient[]) => { - const data: pushNotificationDataMap[K] = ev.data?.json(); + }).then(async (clients: readonly WindowClient[]) => { + const data: pushNotificationDataMap[keyof pushNotificationDataMap] = ev.data?.json(); switch (data.type) { // case 'driveFileCreated': @@ -104,17 +104,17 @@ self.addEventListener('push', ev => { })); }); -self.addEventListener('notificationclick', (ev: ServiceWorkerGlobalScopeEventMap['notificationclick']) => { +globalThis.addEventListener('notificationclick', (ev: ServiceWorkerGlobalScopeEventMap['notificationclick']) => { ev.waitUntil((async () => { if (_DEV_) { console.log('notificationclick', ev.action, ev.notification.data); } - + const { action, notification } = ev; - const data: pushNotificationDataMap[K] = notification.data; + const data: pushNotificationDataMap[keyof pushNotificationDataMap] = notification.data; const { userId: loginId } = data; let client: WindowClient | null = null; - + switch (data.type) { case 'notification': switch (action) { @@ -180,27 +180,27 @@ self.addEventListener('notificationclick', that.read(data)); } - + notification.close(); })()); }); -self.addEventListener('notificationclose', (ev: ServiceWorkerGlobalScopeEventMap['notificationclose']) => { - const data: pushNotificationDataMap[K] = ev.notification.data; +globalThis.addEventListener('notificationclose', (ev: ServiceWorkerGlobalScopeEventMap['notificationclose']) => { + const data: pushNotificationDataMap[keyof pushNotificationDataMap] = ev.notification.data; if (data.type === 'notification') { swNotificationRead.then(that => that.read(data)); } }); -self.addEventListener('message', (ev: ServiceWorkerGlobalScopeEventMap['message']) => { +globalThis.addEventListener('message', (ev: ServiceWorkerGlobalScopeEventMap['message']) => { ev.waitUntil((async () => { switch (ev.data) { case 'clear': @@ -211,11 +211,11 @@ self.addEventListener('message', (ev: ServiceWorkerGlobalScopeEventMap['message' )); return; // TODO } - + if (typeof ev.data === 'object') { // E.g. '[object Array]' → 'array' const otype = Object.prototype.toString.call(ev.data).slice(8, -1).toLowerCase(); - + if (otype === 'object') { if (ev.data.msg === 'initialize') { swLang.setLang(ev.data.lang); From 2f41f12aea9f3a1e0ed5da28d703a718e5de3a1a Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Sun, 12 Feb 2023 16:40:36 +0100 Subject: [PATCH 14/92] fix(client): Make `isTimelineAvailable` a reference (#9906) * Make `isTimelineAvailable` a reference * Update b.vue --- packages/frontend/src/ui/visitor/b.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/ui/visitor/b.vue b/packages/frontend/src/ui/visitor/b.vue index 058a9482f..42283fe95 100644 --- a/packages/frontend/src/ui/visitor/b.vue +++ b/packages/frontend/src/ui/visitor/b.vue @@ -83,7 +83,7 @@ const announcements = { limit: 10, }; -const isTimelineAvailable = instance.policies.ltlAvailable || instance.policies.gtlAvailable; +const isTimelineAvailable = $ref(instance.policies?.ltlAvailable || instance.policies?.gtlAvailable); let showMenu = $ref(false); let isDesktop = $ref(window.innerWidth >= DESKTOP_THRESHOLD); From 8d4c5deb8dc173d59975e998dc1295c698af362b Mon Sep 17 00:00:00 2001 From: tamaina Date: Sun, 12 Feb 2023 15:48:56 +0000 Subject: [PATCH 15/92] =?UTF-8?q?perf(sw):=20skipWaiting=E3=81=97=E3=81=AA?= =?UTF-8?q?=E3=81=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/sw/src/sw.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sw/src/sw.ts b/packages/sw/src/sw.ts index 55f881cd4..7bcf4d597 100644 --- a/packages/sw/src/sw.ts +++ b/packages/sw/src/sw.ts @@ -6,7 +6,7 @@ import * as swos from '@/scripts/operations'; import { acct as getAcct } from '@/filters/user'; globalThis.addEventListener('install', ev => { - ev.waitUntil(self.skipWaiting()); + //ev.waitUntil(self.skipWaiting()); }); globalThis.addEventListener('activate', ev => { From f34f9f6ea583a5455600eea9dbf5ffdf38802d21 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 13 Feb 2023 15:28:07 +0900 Subject: [PATCH 16/92] refactor: fix types --- packages/backend/src/core/MessagingService.ts | 4 +- packages/backend/src/core/PollService.ts | 5 +- packages/backend/src/core/RoleService.ts | 2 +- .../backend/src/core/UserBlockingService.ts | 4 +- packages/backend/src/core/UserCacheService.ts | 24 ++++---- .../backend/src/core/UserFollowingService.ts | 4 +- .../src/core/activitypub/ApAudienceService.ts | 16 ++--- .../core/activitypub/ApDbResolverService.ts | 16 ++--- .../src/core/activitypub/ApInboxService.ts | 58 +++++++++---------- .../core/activitypub/models/ApImageService.ts | 6 +- .../activitypub/models/ApMentionService.ts | 9 ++- .../core/activitypub/models/ApNoteService.ts | 4 +- .../activitypub/models/ApPersonService.ts | 12 ++-- packages/backend/src/models/entities/User.ts | 7 +-- .../queue/processors/InboxProcessorService.ts | 4 +- .../backend/src/server/api/ApiCallService.ts | 4 +- .../src/server/api/AuthenticateService.ts | 4 +- .../backend/src/server/api/endpoint-base.ts | 8 +-- .../src/server/api/endpoints/ap/show.ts | 6 +- 19 files changed, 95 insertions(+), 102 deletions(-) diff --git a/packages/backend/src/core/MessagingService.ts b/packages/backend/src/core/MessagingService.ts index 1c36d04d4..0721f63d5 100644 --- a/packages/backend/src/core/MessagingService.ts +++ b/packages/backend/src/core/MessagingService.ts @@ -5,7 +5,7 @@ import type { Config } from '@/config.js'; import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { MessagingMessage } from '@/models/entities/MessagingMessage.js'; import type { Note } from '@/models/entities/Note.js'; -import type { User, CacheableUser, IRemoteUser } from '@/models/entities/User.js'; +import type { User, IRemoteUser } from '@/models/entities/User.js'; import type { UserGroup } from '@/models/entities/UserGroup.js'; import { QueueService } from '@/core/QueueService.js'; import { toArray } from '@/misc/prelude/array.js'; @@ -48,7 +48,7 @@ export class MessagingService { } @bindThis - public async createMessage(user: { id: User['id']; host: User['host']; }, recipientUser: CacheableUser | undefined, recipientGroup: UserGroup | undefined, text: string | null | undefined, file: DriveFile | null, uri?: string) { + public async createMessage(user: { id: User['id']; host: User['host']; }, recipientUser: User | undefined, recipientGroup: UserGroup | undefined, text: string | null | undefined, file: DriveFile | null, uri?: string) { const message = { id: this.idService.genId(), createdAt: new Date(), diff --git a/packages/backend/src/core/PollService.ts b/packages/backend/src/core/PollService.ts index 018e83f8c..94adbf275 100644 --- a/packages/backend/src/core/PollService.ts +++ b/packages/backend/src/core/PollService.ts @@ -1,10 +1,9 @@ import { Inject, Injectable } from '@nestjs/common'; import { Not } from 'typeorm'; import { DI } from '@/di-symbols.js'; -import type { NotesRepository, UsersRepository, PollsRepository, PollVotesRepository } from '@/models/index.js'; +import type { NotesRepository, UsersRepository, PollsRepository, PollVotesRepository, User } from '@/models/index.js'; import type { Note } from '@/models/entities/Note.js'; import { RelayService } from '@/core/RelayService.js'; -import type { CacheableUser } from '@/models/entities/User.js'; import { IdService } from '@/core/IdService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; @@ -39,7 +38,7 @@ export class PollService { } @bindThis - public async vote(user: CacheableUser, note: Note, choice: number) { + public async vote(user: User, note: Note, choice: number) { const poll = await this.pollsRepository.findOneBy({ noteId: note.id }); if (poll == null) throw new Error('poll not found'); diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 9a782780d..b84d5e758 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -3,7 +3,7 @@ import Redis from 'ioredis'; import { In } from 'typeorm'; import type { Role, RoleAssignment, RoleAssignmentsRepository, RolesRepository, UsersRepository } from '@/models/index.js'; import { Cache } from '@/misc/cache.js'; -import type { CacheableLocalUser, CacheableUser, ILocalUser, User } from '@/models/entities/User.js'; +import type { User } from '@/models/entities/User.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import { MetaService } from '@/core/MetaService.js'; diff --git a/packages/backend/src/core/UserBlockingService.ts b/packages/backend/src/core/UserBlockingService.ts index 89de72b9a..be37bad52 100644 --- a/packages/backend/src/core/UserBlockingService.ts +++ b/packages/backend/src/core/UserBlockingService.ts @@ -2,7 +2,7 @@ import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import Redis from 'ioredis'; import { IdService } from '@/core/IdService.js'; -import type { CacheableUser, User } from '@/models/entities/User.js'; +import type { User } from '@/models/entities/User.js'; import type { Blocking } from '@/models/entities/Blocking.js'; import { QueueService } from '@/core/QueueService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; @@ -236,7 +236,7 @@ export class UserBlockingService implements OnApplicationShutdown { } @bindThis - public async unblock(blocker: CacheableUser, blockee: CacheableUser) { + public async unblock(blocker: User, blockee: User) { const blocking = await this.blockingsRepository.findOneBy({ blockerId: blocker.id, blockeeId: blockee.id, diff --git a/packages/backend/src/core/UserCacheService.ts b/packages/backend/src/core/UserCacheService.ts index 52cedbd10..5f0a91908 100644 --- a/packages/backend/src/core/UserCacheService.ts +++ b/packages/backend/src/core/UserCacheService.ts @@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'; import Redis from 'ioredis'; import type { UsersRepository } from '@/models/index.js'; import { Cache } from '@/misc/cache.js'; -import type { CacheableLocalUser, CacheableUser, ILocalUser, User } from '@/models/entities/User.js'; +import type { ILocalUser, User } from '@/models/entities/User.js'; import { DI } from '@/di-symbols.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; @@ -11,10 +11,10 @@ import type { OnApplicationShutdown } from '@nestjs/common'; @Injectable() export class UserCacheService implements OnApplicationShutdown { - public userByIdCache: Cache; - public localUserByNativeTokenCache: Cache; - public localUserByIdCache: Cache; - public uriPersonCache: Cache; + public userByIdCache: Cache; + public localUserByNativeTokenCache: Cache; + public localUserByIdCache: Cache; + public uriPersonCache: Cache; constructor( @Inject(DI.redisSubscriber) @@ -27,10 +27,10 @@ export class UserCacheService implements OnApplicationShutdown { ) { //this.onMessage = this.onMessage.bind(this); - this.userByIdCache = new Cache(Infinity); - this.localUserByNativeTokenCache = new Cache(Infinity); - this.localUserByIdCache = new Cache(Infinity); - this.uriPersonCache = new Cache(Infinity); + this.userByIdCache = new Cache(Infinity); + this.localUserByNativeTokenCache = new Cache(Infinity); + this.localUserByIdCache = new Cache(Infinity); + this.uriPersonCache = new Cache(Infinity); this.redisSubscriber.on('message', this.onMessage); } @@ -45,10 +45,10 @@ export class UserCacheService implements OnApplicationShutdown { case 'userChangeSuspendedState': case 'remoteUserUpdated': { const user = await this.usersRepository.findOneByOrFail({ id: body.id }); - this.userByIdCache.set(user.id, user as CacheableUser); + this.userByIdCache.set(user.id, user); for (const [k, v] of this.uriPersonCache.cache.entries()) { if (v.value?.id === user.id) { - this.uriPersonCache.set(k, user as CacheableUser); + this.uriPersonCache.set(k, user); } } if (this.userEntityService.isLocalUser(user)) { @@ -78,7 +78,7 @@ export class UserCacheService implements OnApplicationShutdown { @bindThis public findById(userId: User['id']) { - return this.userByIdCache.fetch(userId, () => this.usersRepository.findOneByOrFail({ id: userId }) as Promise); + return this.userByIdCache.fetch(userId, () => this.usersRepository.findOneByOrFail({ id: userId })); } @bindThis diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index c0347c60e..589842a41 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -1,5 +1,5 @@ import { Inject, Injectable } from '@nestjs/common'; -import type { CacheableUser, ILocalUser, IRemoteUser, User } from '@/models/entities/User.js'; +import type { ILocalUser, IRemoteUser, User } from '@/models/entities/User.js'; import { IdentifiableError } from '@/misc/identifiable-error.js'; import { QueueService } from '@/core/QueueService.js'; import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js'; @@ -434,7 +434,7 @@ export class UserFollowingService { followee: { id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']; }, - follower: User | CacheableUser, + follower: User, ): Promise { const request = await this.followRequestsRepository.findOneBy({ followeeId: followee.id, diff --git a/packages/backend/src/core/activitypub/ApAudienceService.ts b/packages/backend/src/core/activitypub/ApAudienceService.ts index 64f01644a..ee14f4ddd 100644 --- a/packages/backend/src/core/activitypub/ApAudienceService.ts +++ b/packages/backend/src/core/activitypub/ApAudienceService.ts @@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { In } from 'typeorm'; import promiseLimit from 'promise-limit'; import { DI } from '@/di-symbols.js'; -import type { CacheableRemoteUser, CacheableUser } from '@/models/entities/User.js'; +import type { IRemoteUser, User } from '@/models/entities/User.js'; import { concat, toArray, toSingle, unique } from '@/misc/prelude/array.js'; import { bindThis } from '@/decorators.js'; import { getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isPost, isRead, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js'; @@ -14,8 +14,8 @@ type Visibility = 'public' | 'home' | 'followers' | 'specified'; type AudienceInfo = { visibility: Visibility, - mentionedUsers: CacheableUser[], - visibleUsers: CacheableUser[], + mentionedUsers: User[], + visibleUsers: User[], }; @Injectable() @@ -26,16 +26,16 @@ export class ApAudienceService { } @bindThis - public async parseAudience(actor: CacheableRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise { + public async parseAudience(actor: IRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise { const toGroups = this.groupingAudience(getApIds(to), actor); const ccGroups = this.groupingAudience(getApIds(cc), actor); const others = unique(concat([toGroups.other, ccGroups.other])); - const limit = promiseLimit(2); + const limit = promiseLimit(2); const mentionedUsers = (await Promise.all( others.map(id => limit(() => this.apPersonService.resolvePerson(id, resolver).catch(() => null))), - )).filter((x): x is CacheableUser => x != null); + )).filter((x): x is User => x != null); if (toGroups.public.length > 0) { return { @@ -69,7 +69,7 @@ export class ApAudienceService { } @bindThis - private groupingAudience(ids: string[], actor: CacheableRemoteUser) { + private groupingAudience(ids: string[], actor: IRemoteUser) { const groups = { public: [] as string[], followers: [] as string[], @@ -101,7 +101,7 @@ export class ApAudienceService { } @bindThis - private isFollowers(id: string, actor: CacheableRemoteUser) { + private isFollowers(id: string, actor: IRemoteUser) { return ( id === (actor.followersUri ?? `${actor.uri}/followers`) ); diff --git a/packages/backend/src/core/activitypub/ApDbResolverService.ts b/packages/backend/src/core/activitypub/ApDbResolverService.ts index b057f39b0..5af9e2906 100644 --- a/packages/backend/src/core/activitypub/ApDbResolverService.ts +++ b/packages/backend/src/core/activitypub/ApDbResolverService.ts @@ -3,13 +3,13 @@ import escapeRegexp from 'escape-regexp'; import { DI } from '@/di-symbols.js'; import type { MessagingMessagesRepository, NotesRepository, UserPublickeysRepository, UsersRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; -import type { CacheableRemoteUser, CacheableUser } from '@/models/entities/User.js'; import { Cache } from '@/misc/cache.js'; import type { UserPublickey } from '@/models/entities/UserPublickey.js'; import { UserCacheService } from '@/core/UserCacheService.js'; import type { Note } from '@/models/entities/Note.js'; import type { MessagingMessage } from '@/models/entities/MessagingMessage.js'; import { bindThis } from '@/decorators.js'; +import { IRemoteUser, User } from '@/models/entities/User.js'; import { getApId } from './type.js'; import { ApPersonService } from './models/ApPersonService.js'; import type { IObject } from './type.js'; @@ -122,7 +122,7 @@ export class ApDbResolverService { * AP Person => Misskey User in DB */ @bindThis - public async getUserFromApId(value: string | IObject): Promise { + public async getUserFromApId(value: string | IObject): Promise { const parsed = this.parseUri(value); if (parsed.local) { @@ -130,11 +130,11 @@ export class ApDbResolverService { return await this.userCacheService.userByIdCache.fetchMaybe(parsed.id, () => this.usersRepository.findOneBy({ id: parsed.id, - }).then(x => (x as CacheableUser | null) ?? undefined)) ?? null; + }).then(x => x ?? undefined)) ?? null; } else { return await this.userCacheService.uriPersonCache.fetch(parsed.uri, () => this.usersRepository.findOneBy({ uri: parsed.uri, - }) as Promise); + })); } } @@ -143,7 +143,7 @@ export class ApDbResolverService { */ @bindThis public async getAuthUserFromKeyId(keyId: string): Promise<{ - user: CacheableRemoteUser; + user: IRemoteUser; key: UserPublickey; } | null> { const key = await this.publicKeyCache.fetch(keyId, async () => { @@ -159,7 +159,7 @@ export class ApDbResolverService { if (key == null) return null; return { - user: await this.userCacheService.findById(key.userId) as CacheableRemoteUser, + user: await this.userCacheService.findById(key.userId) as IRemoteUser, key, }; } @@ -169,10 +169,10 @@ export class ApDbResolverService { */ @bindThis public async getAuthUserFromApId(uri: string): Promise<{ - user: CacheableRemoteUser; + user: IRemoteUser; key: UserPublickey | null; } | null> { - const user = await this.apPersonService.resolvePerson(uri) as CacheableRemoteUser; + const user = await this.apPersonService.resolvePerson(uri) as IRemoteUser; if (user == null) return null; diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index 02bb0ca4e..d514e9845 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -2,7 +2,6 @@ import { Inject, Injectable } from '@nestjs/common'; import { In } from 'typeorm'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; -import type { CacheableRemoteUser, CacheableUser } from '@/models/entities/User.js'; import { UserFollowingService } from '@/core/UserFollowingService.js'; import { ReactionService } from '@/core/ReactionService.js'; import { RelayService } from '@/core/RelayService.js'; @@ -23,6 +22,7 @@ import { QueueService } from '@/core/QueueService.js'; import { MessagingService } from '@/core/MessagingService.js'; import type { UsersRepository, NotesRepository, FollowingsRepository, MessagingMessagesRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/index.js'; import { bindThis } from '@/decorators.js'; +import type { IRemoteUser } from '@/models/entities/User.js'; import { getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isPost, isRead, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js'; import { ApNoteService } from './models/ApNoteService.js'; import { ApLoggerService } from './ApLoggerService.js'; @@ -87,7 +87,7 @@ export class ApInboxService { } @bindThis - public async performActivity(actor: CacheableRemoteUser, activity: IObject) { + public async performActivity(actor: IRemoteUser, activity: IObject) { if (isCollectionOrOrderedCollection(activity)) { const resolver = this.apResolverService.createResolver(); for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) { @@ -115,7 +115,7 @@ export class ApInboxService { } @bindThis - public async performOneActivity(actor: CacheableRemoteUser, activity: IObject): Promise { + public async performOneActivity(actor: IRemoteUser, activity: IObject): Promise { if (actor.isSuspended) return; if (isCreate(activity)) { @@ -152,7 +152,7 @@ export class ApInboxService { } @bindThis - private async follow(actor: CacheableRemoteUser, activity: IFollow): Promise { + private async follow(actor: IRemoteUser, activity: IFollow): Promise { const followee = await this.apDbResolverService.getUserFromApId(activity.object); if (followee == null) { @@ -168,7 +168,7 @@ export class ApInboxService { } @bindThis - private async like(actor: CacheableRemoteUser, activity: ILike): Promise { + private async like(actor: IRemoteUser, activity: ILike): Promise { const targetUri = getApId(activity.object); const note = await this.apNoteService.fetchNote(targetUri); @@ -186,7 +186,7 @@ export class ApInboxService { } @bindThis - private async read(actor: CacheableRemoteUser, activity: IRead): Promise { + private async read(actor: IRemoteUser, activity: IRead): Promise { const id = await getApId(activity.object); if (!this.utilityService.isSelfHost(this.utilityService.extractDbHost(id))) { @@ -209,7 +209,7 @@ export class ApInboxService { } @bindThis - private async accept(actor: CacheableRemoteUser, activity: IAccept): Promise { + private async accept(actor: IRemoteUser, activity: IAccept): Promise { const uri = activity.id ?? activity; this.logger.info(`Accept: ${uri}`); @@ -227,7 +227,7 @@ export class ApInboxService { } @bindThis - private async acceptFollow(actor: CacheableRemoteUser, activity: IFollow): Promise { + private async acceptFollow(actor: IRemoteUser, activity: IFollow): Promise { // ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある const follower = await this.apDbResolverService.getUserFromApId(activity.actor); @@ -251,7 +251,7 @@ export class ApInboxService { } @bindThis - private async add(actor: CacheableRemoteUser, activity: IAdd): Promise { + private async add(actor: IRemoteUser, activity: IAdd): Promise { if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } @@ -271,7 +271,7 @@ export class ApInboxService { } @bindThis - private async announce(actor: CacheableRemoteUser, activity: IAnnounce): Promise { + private async announce(actor: IRemoteUser, activity: IAnnounce): Promise { const uri = getApId(activity); this.logger.info(`Announce: ${uri}`); @@ -282,7 +282,7 @@ export class ApInboxService { } @bindThis - private async announceNote(actor: CacheableRemoteUser, activity: IAnnounce, targetUri: string): Promise { + private async announceNote(actor: IRemoteUser, activity: IAnnounce, targetUri: string): Promise { const uri = getApId(activity); if (actor.isSuspended) { @@ -342,7 +342,7 @@ export class ApInboxService { } @bindThis - private async block(actor: CacheableRemoteUser, activity: IBlock): Promise { + private async block(actor: IRemoteUser, activity: IBlock): Promise { // ※ activity.objectにブロック対象があり、それは存在するローカルユーザーのはず const blockee = await this.apDbResolverService.getUserFromApId(activity.object); @@ -360,7 +360,7 @@ export class ApInboxService { } @bindThis - private async create(actor: CacheableRemoteUser, activity: ICreate): Promise { + private async create(actor: IRemoteUser, activity: ICreate): Promise { const uri = getApId(activity); this.logger.info(`Create: ${uri}`); @@ -396,7 +396,7 @@ export class ApInboxService { } @bindThis - private async createNote(resolver: Resolver, actor: CacheableRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise { + private async createNote(resolver: Resolver, actor: IRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise { const uri = getApId(note); if (typeof note === 'object') { @@ -431,7 +431,7 @@ export class ApInboxService { } @bindThis - private async delete(actor: CacheableRemoteUser, activity: IDelete): Promise { + private async delete(actor: IRemoteUser, activity: IDelete): Promise { if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } @@ -473,7 +473,7 @@ export class ApInboxService { } @bindThis - private async deleteActor(actor: CacheableRemoteUser, uri: string): Promise { + private async deleteActor(actor: IRemoteUser, uri: string): Promise { this.logger.info(`Deleting the Actor: ${uri}`); if (actor.uri !== uri) { @@ -495,7 +495,7 @@ export class ApInboxService { } @bindThis - private async deleteNote(actor: CacheableRemoteUser, uri: string): Promise { + private async deleteNote(actor: IRemoteUser, uri: string): Promise { this.logger.info(`Deleting the Note: ${uri}`); const unlock = await this.appLockService.getApLock(uri); @@ -528,7 +528,7 @@ export class ApInboxService { } @bindThis - private async flag(actor: CacheableRemoteUser, activity: IFlag): Promise { + private async flag(actor: IRemoteUser, activity: IFlag): Promise { // objectは `(User|Note) | (User|Note)[]` だけど、全パターンDBスキーマと対応させられないので // 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する const uris = getApIds(activity.object); @@ -553,7 +553,7 @@ export class ApInboxService { } @bindThis - private async reject(actor: CacheableRemoteUser, activity: IReject): Promise { + private async reject(actor: IRemoteUser, activity: IReject): Promise { const uri = activity.id ?? activity; this.logger.info(`Reject: ${uri}`); @@ -571,7 +571,7 @@ export class ApInboxService { } @bindThis - private async rejectFollow(actor: CacheableRemoteUser, activity: IFollow): Promise { + private async rejectFollow(actor: IRemoteUser, activity: IFollow): Promise { // ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある const follower = await this.apDbResolverService.getUserFromApId(activity.actor); @@ -595,7 +595,7 @@ export class ApInboxService { } @bindThis - private async remove(actor: CacheableRemoteUser, activity: IRemove): Promise { + private async remove(actor: IRemoteUser, activity: IRemove): Promise { if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } @@ -615,7 +615,7 @@ export class ApInboxService { } @bindThis - private async undo(actor: CacheableRemoteUser, activity: IUndo): Promise { + private async undo(actor: IRemoteUser, activity: IUndo): Promise { if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } @@ -641,7 +641,7 @@ export class ApInboxService { } @bindThis - private async undoAccept(actor: CacheableRemoteUser, activity: IAccept): Promise { + private async undoAccept(actor: IRemoteUser, activity: IAccept): Promise { const follower = await this.apDbResolverService.getUserFromApId(activity.object); if (follower == null) { return 'skip: follower not found'; @@ -661,7 +661,7 @@ export class ApInboxService { } @bindThis - private async undoAnnounce(actor: CacheableRemoteUser, activity: IAnnounce): Promise { + private async undoAnnounce(actor: IRemoteUser, activity: IAnnounce): Promise { const uri = getApId(activity); const note = await this.notesRepository.findOneBy({ @@ -676,7 +676,7 @@ export class ApInboxService { } @bindThis - private async undoBlock(actor: CacheableRemoteUser, activity: IBlock): Promise { + private async undoBlock(actor: IRemoteUser, activity: IBlock): Promise { const blockee = await this.apDbResolverService.getUserFromApId(activity.object); if (blockee == null) { @@ -687,12 +687,12 @@ export class ApInboxService { return 'skip: ブロック解除しようとしているユーザーはローカルユーザーではありません'; } - await this.userBlockingService.unblock(await this.usersRepository.findOneByOrFail({ id: actor.id }) as CacheableUser, blockee); + await this.userBlockingService.unblock(await this.usersRepository.findOneByOrFail({ id: actor.id }), blockee); return 'ok'; } @bindThis - private async undoFollow(actor: CacheableRemoteUser, activity: IFollow): Promise { + private async undoFollow(actor: IRemoteUser, activity: IFollow): Promise { const followee = await this.apDbResolverService.getUserFromApId(activity.object); if (followee == null) { return 'skip: followee not found'; @@ -726,7 +726,7 @@ export class ApInboxService { } @bindThis - private async undoLike(actor: CacheableRemoteUser, activity: ILike): Promise { + private async undoLike(actor: IRemoteUser, activity: ILike): Promise { const targetUri = getApId(activity.object); const note = await this.apNoteService.fetchNote(targetUri); @@ -741,7 +741,7 @@ export class ApInboxService { } @bindThis - private async update(actor: CacheableRemoteUser, activity: IUpdate): Promise { + private async update(actor: IRemoteUser, activity: IUpdate): Promise { if ('actor' in activity && actor.uri !== activity.actor) { return 'skip: invalid actor'; } diff --git a/packages/backend/src/core/activitypub/models/ApImageService.ts b/packages/backend/src/core/activitypub/models/ApImageService.ts index 928ef1ae7..f14b15013 100644 --- a/packages/backend/src/core/activitypub/models/ApImageService.ts +++ b/packages/backend/src/core/activitypub/models/ApImageService.ts @@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; import type { DriveFilesRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; -import type { CacheableRemoteUser } from '@/models/entities/User.js'; +import type { IRemoteUser } from '@/models/entities/User.js'; import type { DriveFile } from '@/models/entities/DriveFile.js'; import { MetaService } from '@/core/MetaService.js'; import { truncate } from '@/misc/truncate.js'; @@ -36,7 +36,7 @@ export class ApImageService { * Imageを作成します。 */ @bindThis - public async createImage(actor: CacheableRemoteUser, value: any): Promise { + public async createImage(actor: IRemoteUser, value: any): Promise { // 投稿者が凍結されていたらスキップ if (actor.isSuspended) { throw new Error('actor has been suspended'); @@ -88,7 +88,7 @@ export class ApImageService { * リモートサーバーからフェッチしてMisskeyに登録しそれを返します。 */ @bindThis - public async resolveImage(actor: CacheableRemoteUser, value: any): Promise { + public async resolveImage(actor: IRemoteUser, value: any): Promise { // TODO // リモートサーバーからフェッチしてきて登録 diff --git a/packages/backend/src/core/activitypub/models/ApMentionService.ts b/packages/backend/src/core/activitypub/models/ApMentionService.ts index 41e6c6b14..1ed9fb89d 100644 --- a/packages/backend/src/core/activitypub/models/ApMentionService.ts +++ b/packages/backend/src/core/activitypub/models/ApMentionService.ts @@ -1,15 +1,14 @@ import { Inject, Injectable } from '@nestjs/common'; import promiseLimit from 'promise-limit'; import { DI } from '@/di-symbols.js'; -import type { UsersRepository } from '@/models/index.js'; +import type { User, UsersRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; import { toArray, unique } from '@/misc/prelude/array.js'; -import type { CacheableUser } from '@/models/entities/User.js'; +import { bindThis } from '@/decorators.js'; import { isMention } from '../type.js'; import { ApResolverService, Resolver } from '../ApResolverService.js'; import { ApPersonService } from './ApPersonService.js'; import type { IObject, IApMention } from '../type.js'; -import { bindThis } from '@/decorators.js'; @Injectable() export class ApMentionService { @@ -26,10 +25,10 @@ export class ApMentionService { public async extractApMentions(tags: IObject | IObject[] | null | undefined, resolver: Resolver) { const hrefs = unique(this.extractApMentionObjects(tags).map(x => x.href as string)); - const limit = promiseLimit(2); + const limit = promiseLimit(2); const mentionedUsers = (await Promise.all( hrefs.map(x => limit(() => this.apPersonService.resolvePerson(x, resolver).catch(() => null))), - )).filter((x): x is CacheableUser => x != null); + )).filter((x): x is User => x != null); return mentionedUsers; } diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index dc47fdf80..0292a27d9 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -3,7 +3,7 @@ import promiseLimit from 'promise-limit'; import { DI } from '@/di-symbols.js'; import type { MessagingMessagesRepository, PollsRepository, EmojisRepository, UsersRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; -import type { CacheableRemoteUser } from '@/models/entities/User.js'; +import type { IRemoteUser } from '@/models/entities/User.js'; import type { Note } from '@/models/entities/Note.js'; import { toArray, toSingle, unique } from '@/misc/prelude/array.js'; import type { Emoji } from '@/models/entities/Emoji.js'; @@ -146,7 +146,7 @@ export class ApNoteService { this.logger.info(`Creating the Note: ${note.id}`); // 投稿者をフェッチ - const actor = await this.apPersonService.resolvePerson(getOneApId(note.attributedTo!), resolver) as CacheableRemoteUser; + const actor = await this.apPersonService.resolvePerson(getOneApId(note.attributedTo!), resolver) as IRemoteUser; // 投稿者が凍結されていたらスキップ if (actor.isSuspended) { diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index 4869656f1..9dca06552 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -5,7 +5,7 @@ import { ModuleRef } from '@nestjs/core'; import { DI } from '@/di-symbols.js'; import type { FollowingsRepository, InstancesRepository, UserProfilesRepository, UserPublickeysRepository, UsersRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; -import type { CacheableUser, IRemoteUser } from '@/models/entities/User.js'; +import type { IRemoteUser } from '@/models/entities/User.js'; import { User } from '@/models/entities/User.js'; import { truncate } from '@/misc/truncate.js'; import type { UserCacheService } from '@/core/UserCacheService.js'; @@ -197,7 +197,7 @@ export class ApPersonService implements OnModuleInit { * Misskeyに対象のPersonが登録されていればそれを返します。 */ @bindThis - public async fetchPerson(uri: string, resolver?: Resolver): Promise { + public async fetchPerson(uri: string, resolver?: Resolver): Promise { if (typeof uri !== 'string') throw new Error('uri is not string'); const cached = this.userCacheService.uriPersonCache.get(uri); @@ -206,13 +206,13 @@ export class ApPersonService implements OnModuleInit { // URIがこのサーバーを指しているならデータベースからフェッチ if (uri.startsWith(this.config.url + '/')) { const id = uri.split('/').pop(); - const u = await this.usersRepository.findOneBy({ id }) as null | CacheableUser; + const u = await this.usersRepository.findOneBy({ id }); if (u) this.userCacheService.uriPersonCache.set(uri, u); return u; } //#region このサーバーに既に登録されていたらそれを返す - const exist = await this.usersRepository.findOneBy({ uri }) as null | CacheableUser; + const exist = await this.usersRepository.findOneBy({ uri }); if (exist) { this.userCacheService.uriPersonCache.set(uri, exist); @@ -500,7 +500,7 @@ export class ApPersonService implements OnModuleInit { * リモートサーバーからフェッチしてMisskeyに登録しそれを返します。 */ @bindThis - public async resolvePerson(uri: string, resolver?: Resolver): Promise { + public async resolvePerson(uri: string, resolver?: Resolver): Promise { if (typeof uri !== 'string') throw new Error('uri is not string'); //#region このサーバーに既に登録されていたらそれを返す @@ -513,7 +513,7 @@ export class ApPersonService implements OnModuleInit { // リモートサーバーからフェッチしてきて登録 if (resolver == null) resolver = this.apResolverService.createResolver(); - return await this.createPerson(uri, resolver) as CacheableUser; + return await this.createPerson(uri, resolver); } @bindThis diff --git a/packages/backend/src/models/entities/User.ts b/packages/backend/src/models/entities/User.ts index 9cfe79787..8d476ab0a 100644 --- a/packages/backend/src/models/entities/User.ts +++ b/packages/backend/src/models/entities/User.ts @@ -217,6 +217,7 @@ export class User { export interface ILocalUser extends User { host: null; + uri: null; } export interface IRemoteUser extends User { @@ -224,12 +225,6 @@ export interface IRemoteUser extends User { uri: string; } -export type CacheableLocalUser = ILocalUser; - -export type CacheableRemoteUser = IRemoteUser; - -export type CacheableUser = CacheableLocalUser | CacheableRemoteUser; - export const localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const; export const passwordSchema = { type: 'string', minLength: 1 } as const; export const nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts index f814368a7..a41222c48 100644 --- a/packages/backend/src/queue/processors/InboxProcessorService.ts +++ b/packages/backend/src/queue/processors/InboxProcessorService.ts @@ -16,7 +16,7 @@ import InstanceChart from '@/core/chart/charts/instance.js'; import ApRequestChart from '@/core/chart/charts/ap-request.js'; import FederationChart from '@/core/chart/charts/federation.js'; import { getApId } from '@/core/activitypub/type.js'; -import type { CacheableRemoteUser } from '@/models/entities/User.js'; +import type { IRemoteUser } from '@/models/entities/User.js'; import type { UserPublickey } from '@/models/entities/UserPublickey.js'; import { ApDbResolverService } from '@/core/activitypub/ApDbResolverService.js'; import { StatusError } from '@/misc/status-error.js'; @@ -87,7 +87,7 @@ export class InboxProcessorService { // HTTP-Signature keyIdを元にDBから取得 let authUser: { - user: CacheableRemoteUser; + user: IRemoteUser; key: UserPublickey | null; } | null = await this.apDbResolverService.getAuthUserFromKeyId(signature.keyId); diff --git a/packages/backend/src/server/api/ApiCallService.ts b/packages/backend/src/server/api/ApiCallService.ts index 2f3e7a44a..3a05413bc 100644 --- a/packages/backend/src/server/api/ApiCallService.ts +++ b/packages/backend/src/server/api/ApiCallService.ts @@ -5,7 +5,7 @@ import { promisify } from 'node:util'; import { Inject, Injectable } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; import { getIpHash } from '@/misc/get-ip-hash.js'; -import type { CacheableLocalUser, ILocalUser, User } from '@/models/entities/User.js'; +import type { ILocalUser, User } from '@/models/entities/User.js'; import type { AccessToken } from '@/models/entities/AccessToken.js'; import type Logger from '@/logger.js'; import type { UserIpsRepository } from '@/models/index.js'; @@ -194,7 +194,7 @@ export class ApiCallService implements OnApplicationShutdown { @bindThis private async call( ep: IEndpoint & { exec: any }, - user: CacheableLocalUser | null | undefined, + user: ILocalUser | null | undefined, token: AccessToken | null | undefined, data: any, file: { diff --git a/packages/backend/src/server/api/AuthenticateService.ts b/packages/backend/src/server/api/AuthenticateService.ts index 8b39f6c92..b9f6af4ff 100644 --- a/packages/backend/src/server/api/AuthenticateService.ts +++ b/packages/backend/src/server/api/AuthenticateService.ts @@ -1,7 +1,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; import type { AccessTokensRepository, AppsRepository, UsersRepository } from '@/models/index.js'; -import type { CacheableLocalUser, ILocalUser } from '@/models/entities/User.js'; +import type { ILocalUser } from '@/models/entities/User.js'; import type { AccessToken } from '@/models/entities/AccessToken.js'; import { Cache } from '@/misc/cache.js'; import type { App } from '@/models/entities/App.js'; @@ -36,7 +36,7 @@ export class AuthenticateService { } @bindThis - public async authenticate(token: string | null | undefined): Promise<[CacheableLocalUser | null | undefined, AccessToken | null | undefined]> { + public async authenticate(token: string | null | undefined): Promise<[ILocalUser | null | undefined, AccessToken | null | undefined]> { if (token == null) { return [null, null]; } diff --git a/packages/backend/src/server/api/endpoint-base.ts b/packages/backend/src/server/api/endpoint-base.ts index b27329b9a..56dad6286 100644 --- a/packages/backend/src/server/api/endpoint-base.ts +++ b/packages/backend/src/server/api/endpoint-base.ts @@ -1,7 +1,7 @@ import * as fs from 'node:fs'; import Ajv from 'ajv'; import type { Schema, SchemaType } from '@/misc/schema.js'; -import type { CacheableLocalUser } from '@/models/entities/User.js'; +import type { ILocalUser } from '@/models/entities/User.js'; import type { AccessToken } from '@/models/entities/AccessToken.js'; import { ApiError } from './error.js'; import type { IEndpointMeta } from './endpoints.js'; @@ -21,16 +21,16 @@ type File = { // TODO: paramsの型をT['params']のスキーマ定義から推論する type executor = - (params: SchemaType, user: T['requireCredential'] extends true ? CacheableLocalUser : CacheableLocalUser | null, token: AccessToken | null, file?: File, cleanup?: () => any, ip?: string | null, headers?: Record | null) => + (params: SchemaType, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: File, cleanup?: () => any, ip?: string | null, headers?: Record | null) => Promise>>; export abstract class Endpoint { - public exec: (params: any, user: T['requireCredential'] extends true ? CacheableLocalUser : CacheableLocalUser | null, token: AccessToken | null, file?: File, ip?: string | null, headers?: Record | null) => Promise; + public exec: (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: File, ip?: string | null, headers?: Record | null) => Promise; constructor(meta: T, paramDef: Ps, cb: executor) { const validate = ajv.compile(paramDef); - this.exec = (params: any, user: T['requireCredential'] extends true ? CacheableLocalUser : CacheableLocalUser | null, token: AccessToken | null, file?: File, ip?: string | null, headers?: Record | null) => { + this.exec = (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: File, ip?: string | null, headers?: Record | null) => { let cleanup: undefined | (() => void) = undefined; if (meta.requireFile) { diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts index 9470dd3cb..e758c5e3f 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 @@ import ms from 'ms'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { UsersRepository, NotesRepository } from '@/models/index.js'; import type { Note } from '@/models/entities/Note.js'; -import type { CacheableLocalUser, User } from '@/models/entities/User.js'; +import type { ILocalUser, User } from '@/models/entities/User.js'; import { isActor, isPost, getApId } from '@/core/activitypub/type.js'; import type { SchemaType } from '@/misc/schema.js'; import { ApResolverService } from '@/core/activitypub/ApResolverService.js'; @@ -114,7 +114,7 @@ export default class extends Endpoint { * URIからUserかNoteを解決する */ @bindThis - private async fetchAny(uri: string, me: CacheableLocalUser | null | undefined): Promise | null> { + private async fetchAny(uri: string, me: ILocalUser | null | undefined): Promise | null> { // ブロックしてたら中断 const fetchedMeta = await this.metaService.fetch(); if (this.utilityService.isBlockedHost(fetchedMeta.blockedHosts, this.utilityService.extractDbHost(uri))) return null; @@ -147,7 +147,7 @@ export default class extends Endpoint { } @bindThis - private async mergePack(me: CacheableLocalUser | null | undefined, user: User | null | undefined, note: Note | null | undefined): Promise | null> { + private async mergePack(me: ILocalUser | null | undefined, user: User | null | undefined, note: Note | null | undefined): Promise | null> { if (user != null) { return { type: 'User', From 1b21bad202db9d30adc3f71d2ffa11b3b5187482 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 13 Feb 2023 15:50:22 +0900 Subject: [PATCH 17/92] refactor --- packages/backend/src/core/DriveService.ts | 8 +-- .../backend/src/core/InstanceActorService.ts | 12 ++-- packages/backend/src/core/MessagingService.ts | 4 +- .../backend/src/core/NoteCreateService.ts | 8 +-- .../backend/src/core/NoteDeleteService.ts | 6 +- .../backend/src/core/ProxyAccountService.ts | 6 +- packages/backend/src/core/ReactionService.ts | 8 +-- packages/backend/src/core/RelayService.ts | 8 +-- .../src/core/RemoteUserResolveService.ts | 6 +- packages/backend/src/core/UserCacheService.ts | 12 ++-- .../backend/src/core/UserFollowingService.ts | 20 +++---- .../src/core/activitypub/ApAudienceService.ts | 8 +-- .../core/activitypub/ApDbResolverService.ts | 10 ++-- .../activitypub/ApDeliverManagerService.ts | 10 ++-- .../src/core/activitypub/ApInboxService.ts | 56 +++++++++---------- .../src/core/activitypub/ApRendererService.ts | 18 +++--- .../src/core/activitypub/ApResolverService.ts | 6 +- .../core/activitypub/models/ApImageService.ts | 6 +- .../core/activitypub/models/ApNoteService.ts | 4 +- .../activitypub/models/ApPersonService.ts | 10 ++-- .../src/core/entities/UserEntityService.ts | 6 +- packages/backend/src/models/entities/User.ts | 4 +- .../queue/processors/InboxProcessorService.ts | 4 +- .../src/server/ActivityPubServerService.ts | 4 +- .../backend/src/server/api/ApiCallService.ts | 6 +- .../src/server/api/AuthenticateService.ts | 8 +-- .../src/server/api/SigninApiService.ts | 4 +- .../backend/src/server/api/SigninService.ts | 4 +- .../src/server/api/SignupApiService.ts | 4 +- .../backend/src/server/api/endpoint-base.ts | 8 +-- .../src/server/api/endpoints/ap/show.ts | 6 +- .../server/api/endpoints/notes/polls/vote.ts | 4 +- .../server/api/stream/channels/messaging.ts | 4 +- 33 files changed, 146 insertions(+), 146 deletions(-) diff --git a/packages/backend/src/core/DriveService.ts b/packages/backend/src/core/DriveService.ts index 42a430ea7..b15c967c8 100644 --- a/packages/backend/src/core/DriveService.ts +++ b/packages/backend/src/core/DriveService.ts @@ -7,7 +7,7 @@ import { DI } from '@/di-symbols.js'; import type { DriveFilesRepository, UsersRepository, DriveFoldersRepository, UserProfilesRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; import Logger from '@/logger.js'; -import type { IRemoteUser, User } from '@/models/entities/User.js'; +import type { RemoteUser, User } from '@/models/entities/User.js'; import { MetaService } from '@/core/MetaService.js'; import { DriveFile } from '@/models/entities/DriveFile.js'; import { IdService } from '@/core/IdService.js'; @@ -255,7 +255,7 @@ export class DriveService { return { webpublic: null, thumbnail: null, - } + }; } try { @@ -399,7 +399,7 @@ export class DriveService { } @bindThis - private async deleteOldFile(user: IRemoteUser) { + private async deleteOldFile(user: RemoteUser) { const q = this.driveFilesRepository.createQueryBuilder('file') .where('file.userId = :userId', { userId: user.id }) .andWhere('file.isLink = FALSE'); @@ -500,7 +500,7 @@ export class DriveService { throw new IdentifiableError('c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6', 'No free space.'); } else { // (アバターまたはバナーを含まず)最も古いファイルを削除する - this.deleteOldFile(await this.usersRepository.findOneByOrFail({ id: user.id }) as IRemoteUser); + this.deleteOldFile(await this.usersRepository.findOneByOrFail({ id: user.id }) as RemoteUser); } } } diff --git a/packages/backend/src/core/InstanceActorService.ts b/packages/backend/src/core/InstanceActorService.ts index 0b4a83c63..ee9ae0733 100644 --- a/packages/backend/src/core/InstanceActorService.ts +++ b/packages/backend/src/core/InstanceActorService.ts @@ -1,6 +1,6 @@ import { Inject, Injectable } from '@nestjs/common'; import { IsNull } from 'typeorm'; -import type { ILocalUser } from '@/models/entities/User.js'; +import type { LocalUser } from '@/models/entities/User.js'; import type { UsersRepository } from '@/models/index.js'; import { Cache } from '@/misc/cache.js'; import { DI } from '@/di-symbols.js'; @@ -11,7 +11,7 @@ const ACTOR_USERNAME = 'instance.actor' as const; @Injectable() export class InstanceActorService { - private cache: Cache; + private cache: Cache; constructor( @Inject(DI.usersRepository) @@ -19,24 +19,24 @@ export class InstanceActorService { private createSystemUserService: CreateSystemUserService, ) { - this.cache = new Cache(Infinity); + this.cache = new Cache(Infinity); } @bindThis - public async getInstanceActor(): Promise { + public async getInstanceActor(): Promise { const cached = this.cache.get(null); if (cached) return cached; const user = await this.usersRepository.findOneBy({ host: IsNull(), username: ACTOR_USERNAME, - }) as ILocalUser | undefined; + }) as LocalUser | undefined; if (user) { this.cache.set(null, user); return user; } else { - const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME) as ILocalUser; + const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME) as LocalUser; this.cache.set(null, created); return created; } diff --git a/packages/backend/src/core/MessagingService.ts b/packages/backend/src/core/MessagingService.ts index 0721f63d5..3a8a25c60 100644 --- a/packages/backend/src/core/MessagingService.ts +++ b/packages/backend/src/core/MessagingService.ts @@ -5,7 +5,7 @@ import type { Config } from '@/config.js'; import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { MessagingMessage } from '@/models/entities/MessagingMessage.js'; import type { Note } from '@/models/entities/Note.js'; -import type { User, IRemoteUser } from '@/models/entities/User.js'; +import type { User, RemoteUser } from '@/models/entities/User.js'; import type { UserGroup } from '@/models/entities/UserGroup.js'; import { QueueService } from '@/core/QueueService.js'; import { toArray } from '@/misc/prelude/array.js'; @@ -291,7 +291,7 @@ export class MessagingService { } @bindThis - public async deliverReadActivity(user: { id: User['id']; host: null; }, recipient: IRemoteUser, messages: MessagingMessage | MessagingMessage[]) { + public async deliverReadActivity(user: { id: User['id']; host: null; }, recipient: RemoteUser, messages: MessagingMessage | MessagingMessage[]) { messages = toArray(messages).filter(x => x.uri); const contents = messages.map(x => this.apRendererService.renderRead(user, x)); diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 04c057f6c..2484cfc6c 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -11,7 +11,7 @@ import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { App } from '@/models/entities/App.js'; import { concat } from '@/misc/prelude/array.js'; import { IdService } from '@/core/IdService.js'; -import type { User, ILocalUser, IRemoteUser } from '@/models/entities/User.js'; +import type { User, LocalUser, RemoteUser } from '@/models/entities/User.js'; import type { IPoll } from '@/models/entities/Poll.js'; import { Poll } from '@/models/entities/Poll.js'; import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; @@ -52,7 +52,7 @@ class NotificationManager { private notifier: { id: User['id']; }; private note: Note; private queue: { - target: ILocalUser['id']; + target: LocalUser['id']; reason: NotificationType; }[]; @@ -68,7 +68,7 @@ class NotificationManager { } @bindThis - public push(notifiee: ILocalUser['id'], reason: NotificationType) { + public push(notifiee: LocalUser['id'], reason: NotificationType) { // 自分自身へは通知しない if (this.notifier.id === notifiee) return; @@ -605,7 +605,7 @@ export class NoteCreateService { // メンションされたリモートユーザーに配送 for (const u of mentionedUsers.filter(u => this.userEntityService.isRemoteUser(u))) { - dm.addDirectRecipe(u as IRemoteUser); + dm.addDirectRecipe(u as RemoteUser); } // 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送 diff --git a/packages/backend/src/core/NoteDeleteService.ts b/packages/backend/src/core/NoteDeleteService.ts index fbcac2eff..571b62552 100644 --- a/packages/backend/src/core/NoteDeleteService.ts +++ b/packages/backend/src/core/NoteDeleteService.ts @@ -1,6 +1,6 @@ import { Brackets, In } from 'typeorm'; import { Injectable, Inject } from '@nestjs/common'; -import type { User, ILocalUser, IRemoteUser } from '@/models/entities/User.js'; +import type { User, LocalUser, RemoteUser } from '@/models/entities/User.js'; import type { Note, IMentionedRemoteUsers } from '@/models/entities/Note.js'; import type { InstancesRepository, NotesRepository, UsersRepository } from '@/models/index.js'; import { RelayService } from '@/core/RelayService.js'; @@ -159,11 +159,11 @@ export class NoteDeleteService { return await this.usersRepository.find({ where, - }) as IRemoteUser[]; + }) as RemoteUser[]; } @bindThis - private async deliverToConcerned(user: { id: ILocalUser['id']; host: null; }, note: Note, content: any) { + private async deliverToConcerned(user: { id: LocalUser['id']; host: null; }, note: Note, content: any) { this.apDeliverManagerService.deliverToFollowers(user, content); this.relayService.deliverToRelays(user, content); const remoteUsers = await this.getMentionedRemoteUsers(note); diff --git a/packages/backend/src/core/ProxyAccountService.ts b/packages/backend/src/core/ProxyAccountService.ts index 55b70bfc9..7ed322ae6 100644 --- a/packages/backend/src/core/ProxyAccountService.ts +++ b/packages/backend/src/core/ProxyAccountService.ts @@ -1,6 +1,6 @@ import { Inject, Injectable } from '@nestjs/common'; import type { UsersRepository } from '@/models/index.js'; -import type { ILocalUser, User } from '@/models/entities/User.js'; +import type { LocalUser, User } from '@/models/entities/User.js'; import { DI } from '@/di-symbols.js'; import { MetaService } from '@/core/MetaService.js'; import { bindThis } from '@/decorators.js'; @@ -16,9 +16,9 @@ export class ProxyAccountService { } @bindThis - public async fetch(): Promise { + public async fetch(): Promise { const meta = await this.metaService.fetch(); if (meta.proxyAccountId == null) return null; - return await this.usersRepository.findOneByOrFail({ id: meta.proxyAccountId }) as ILocalUser; + return await this.usersRepository.findOneByOrFail({ id: meta.proxyAccountId }) as LocalUser; } } diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index 9ac3058ef..9fccc14ee 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -3,7 +3,7 @@ import { IsNull } from 'typeorm'; import { DI } from '@/di-symbols.js'; import type { EmojisRepository, BlockingsRepository, NoteReactionsRepository, UsersRepository, NotesRepository } from '@/models/index.js'; import { IdentifiableError } from '@/misc/identifiable-error.js'; -import type { IRemoteUser, User } from '@/models/entities/User.js'; +import type { RemoteUser, User } from '@/models/entities/User.js'; import type { Note } from '@/models/entities/Note.js'; import { IdService } from '@/core/IdService.js'; import type { NoteReaction } from '@/models/entities/NoteReaction.js'; @@ -181,7 +181,7 @@ export class ReactionService { const dm = this.apDeliverManagerService.createDeliverManager(user, content); if (note.userHost !== null) { const reactee = await this.usersRepository.findOneBy({ id: note.userId }); - dm.addDirectRecipe(reactee as IRemoteUser); + dm.addDirectRecipe(reactee as RemoteUser); } if (['public', 'home', 'followers'].includes(note.visibility)) { @@ -189,7 +189,7 @@ export class ReactionService { } else if (note.visibility === 'specified') { const visibleUsers = await Promise.all(note.visibleUserIds.map(id => this.usersRepository.findOneBy({ id }))); for (const u of visibleUsers.filter(u => u && this.userEntityService.isRemoteUser(u))) { - dm.addDirectRecipe(u as IRemoteUser); + dm.addDirectRecipe(u as RemoteUser); } } @@ -239,7 +239,7 @@ export class ReactionService { const dm = this.apDeliverManagerService.createDeliverManager(user, content); if (note.userHost !== null) { const reactee = await this.usersRepository.findOneBy({ id: note.userId }); - dm.addDirectRecipe(reactee as IRemoteUser); + dm.addDirectRecipe(reactee as RemoteUser); } dm.addFollowersRecipe(); dm.execute(); diff --git a/packages/backend/src/core/RelayService.ts b/packages/backend/src/core/RelayService.ts index 326fd0af1..2e07825e9 100644 --- a/packages/backend/src/core/RelayService.ts +++ b/packages/backend/src/core/RelayService.ts @@ -1,6 +1,6 @@ import { Inject, Injectable } from '@nestjs/common'; import { IsNull } from 'typeorm'; -import type { ILocalUser, User } from '@/models/entities/User.js'; +import type { LocalUser, User } from '@/models/entities/User.js'; import type { RelaysRepository, UsersRepository } from '@/models/index.js'; import { IdService } from '@/core/IdService.js'; import { Cache } from '@/misc/cache.js'; @@ -34,16 +34,16 @@ export class RelayService { } @bindThis - private async getRelayActor(): Promise { + private async getRelayActor(): Promise { const user = await this.usersRepository.findOneBy({ host: IsNull(), username: ACTOR_USERNAME, }); - if (user) return user as ILocalUser; + if (user) return user as LocalUser; const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME); - return created as ILocalUser; + return created as LocalUser; } @bindThis diff --git a/packages/backend/src/core/RemoteUserResolveService.ts b/packages/backend/src/core/RemoteUserResolveService.ts index dde409862..b72dce518 100644 --- a/packages/backend/src/core/RemoteUserResolveService.ts +++ b/packages/backend/src/core/RemoteUserResolveService.ts @@ -4,7 +4,7 @@ import chalk from 'chalk'; import { IsNull } from 'typeorm'; import { DI } from '@/di-symbols.js'; import type { UsersRepository } from '@/models/index.js'; -import type { IRemoteUser, User } from '@/models/entities/User.js'; +import type { RemoteUser, User } from '@/models/entities/User.js'; import type { Config } from '@/config.js'; import type Logger from '@/logger.js'; import { UtilityService } from '@/core/UtilityService.js'; @@ -60,7 +60,7 @@ export class RemoteUserResolveService { }); } - const user = await this.usersRepository.findOneBy({ usernameLower, host }) as IRemoteUser | null; + const user = await this.usersRepository.findOneBy({ usernameLower, host }) as RemoteUser | null; const acctLower = `${usernameLower}@${host}`; @@ -82,7 +82,7 @@ export class RemoteUserResolveService { const self = await this.resolveSelf(acctLower); if (user.uri !== self.href) { - // if uri mismatch, Fix (user@host <=> AP's Person id(IRemoteUser.uri)) mapping. + // if uri mismatch, Fix (user@host <=> AP's Person id(RemoteUser.uri)) mapping. this.logger.info(`uri missmatch: ${acctLower}`); this.logger.info(`recovery missmatch uri for (username=${username}, host=${host}) from ${user.uri} to ${self.href}`); diff --git a/packages/backend/src/core/UserCacheService.ts b/packages/backend/src/core/UserCacheService.ts index 5f0a91908..fc383d1c0 100644 --- a/packages/backend/src/core/UserCacheService.ts +++ b/packages/backend/src/core/UserCacheService.ts @@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'; import Redis from 'ioredis'; import type { UsersRepository } from '@/models/index.js'; import { Cache } from '@/misc/cache.js'; -import type { ILocalUser, User } from '@/models/entities/User.js'; +import type { LocalUser, User } from '@/models/entities/User.js'; import { DI } from '@/di-symbols.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; @@ -12,8 +12,8 @@ import type { OnApplicationShutdown } from '@nestjs/common'; @Injectable() export class UserCacheService implements OnApplicationShutdown { public userByIdCache: Cache; - public localUserByNativeTokenCache: Cache; - public localUserByIdCache: Cache; + public localUserByNativeTokenCache: Cache; + public localUserByIdCache: Cache; public uriPersonCache: Cache; constructor( @@ -28,8 +28,8 @@ export class UserCacheService implements OnApplicationShutdown { //this.onMessage = this.onMessage.bind(this); this.userByIdCache = new Cache(Infinity); - this.localUserByNativeTokenCache = new Cache(Infinity); - this.localUserByIdCache = new Cache(Infinity); + this.localUserByNativeTokenCache = new Cache(Infinity); + this.localUserByIdCache = new Cache(Infinity); this.uriPersonCache = new Cache(Infinity); this.redisSubscriber.on('message', this.onMessage); @@ -58,7 +58,7 @@ export class UserCacheService implements OnApplicationShutdown { break; } case 'userTokenRegenerated': { - const user = await this.usersRepository.findOneByOrFail({ id: body.id }) as ILocalUser; + const user = await this.usersRepository.findOneByOrFail({ id: body.id }) as LocalUser; this.localUserByNativeTokenCache.delete(body.oldToken); this.localUserByNativeTokenCache.set(body.newToken, user); break; diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index 589842a41..d8426512b 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -1,5 +1,5 @@ import { Inject, Injectable } from '@nestjs/common'; -import type { ILocalUser, IRemoteUser, User } from '@/models/entities/User.js'; +import type { LocalUser, RemoteUser, User } from '@/models/entities/User.js'; import { IdentifiableError } from '@/misc/identifiable-error.js'; import { QueueService } from '@/core/QueueService.js'; import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js'; @@ -21,16 +21,16 @@ import Logger from '../logger.js'; const logger = new Logger('following/create'); -type Local = ILocalUser | { - id: ILocalUser['id']; - host: ILocalUser['host']; - uri: ILocalUser['uri'] +type Local = LocalUser | { + id: LocalUser['id']; + host: LocalUser['host']; + uri: LocalUser['uri'] }; -type Remote = IRemoteUser | { - id: IRemoteUser['id']; - host: IRemoteUser['host']; - uri: IRemoteUser['uri']; - inbox: IRemoteUser['inbox']; +type Remote = RemoteUser | { + id: RemoteUser['id']; + host: RemoteUser['host']; + uri: RemoteUser['uri']; + inbox: RemoteUser['inbox']; }; type Both = Local | Remote; diff --git a/packages/backend/src/core/activitypub/ApAudienceService.ts b/packages/backend/src/core/activitypub/ApAudienceService.ts index ee14f4ddd..4c22297b3 100644 --- a/packages/backend/src/core/activitypub/ApAudienceService.ts +++ b/packages/backend/src/core/activitypub/ApAudienceService.ts @@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { In } from 'typeorm'; import promiseLimit from 'promise-limit'; import { DI } from '@/di-symbols.js'; -import type { IRemoteUser, User } from '@/models/entities/User.js'; +import type { RemoteUser, User } from '@/models/entities/User.js'; import { concat, toArray, toSingle, unique } from '@/misc/prelude/array.js'; import { bindThis } from '@/decorators.js'; import { getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isPost, isRead, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js'; @@ -26,7 +26,7 @@ export class ApAudienceService { } @bindThis - public async parseAudience(actor: IRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise { + public async parseAudience(actor: RemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise { const toGroups = this.groupingAudience(getApIds(to), actor); const ccGroups = this.groupingAudience(getApIds(cc), actor); @@ -69,7 +69,7 @@ export class ApAudienceService { } @bindThis - private groupingAudience(ids: string[], actor: IRemoteUser) { + private groupingAudience(ids: string[], actor: RemoteUser) { const groups = { public: [] as string[], followers: [] as string[], @@ -101,7 +101,7 @@ export class ApAudienceService { } @bindThis - private isFollowers(id: string, actor: IRemoteUser) { + private isFollowers(id: string, actor: RemoteUser) { return ( id === (actor.followersUri ?? `${actor.uri}/followers`) ); diff --git a/packages/backend/src/core/activitypub/ApDbResolverService.ts b/packages/backend/src/core/activitypub/ApDbResolverService.ts index 5af9e2906..9a894826c 100644 --- a/packages/backend/src/core/activitypub/ApDbResolverService.ts +++ b/packages/backend/src/core/activitypub/ApDbResolverService.ts @@ -9,7 +9,7 @@ import { UserCacheService } from '@/core/UserCacheService.js'; import type { Note } from '@/models/entities/Note.js'; import type { MessagingMessage } from '@/models/entities/MessagingMessage.js'; import { bindThis } from '@/decorators.js'; -import { IRemoteUser, User } from '@/models/entities/User.js'; +import { RemoteUser, User } from '@/models/entities/User.js'; import { getApId } from './type.js'; import { ApPersonService } from './models/ApPersonService.js'; import type { IObject } from './type.js'; @@ -143,7 +143,7 @@ export class ApDbResolverService { */ @bindThis public async getAuthUserFromKeyId(keyId: string): Promise<{ - user: IRemoteUser; + user: RemoteUser; key: UserPublickey; } | null> { const key = await this.publicKeyCache.fetch(keyId, async () => { @@ -159,7 +159,7 @@ export class ApDbResolverService { if (key == null) return null; return { - user: await this.userCacheService.findById(key.userId) as IRemoteUser, + user: await this.userCacheService.findById(key.userId) as RemoteUser, key, }; } @@ -169,10 +169,10 @@ export class ApDbResolverService { */ @bindThis public async getAuthUserFromApId(uri: string): Promise<{ - user: IRemoteUser; + user: RemoteUser; key: UserPublickey | null; } | null> { - const user = await this.apPersonService.resolvePerson(uri) as IRemoteUser; + const user = await this.apPersonService.resolvePerson(uri) as RemoteUser; if (user == null) return null; diff --git a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts index 256cf1265..5e6ea6984 100644 --- a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts +++ b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts @@ -3,7 +3,7 @@ import { IsNull, Not } from 'typeorm'; import { DI } from '@/di-symbols.js'; import type { FollowingsRepository, UsersRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; -import type { ILocalUser, IRemoteUser, User } from '@/models/entities/User.js'; +import type { LocalUser, RemoteUser, User } from '@/models/entities/User.js'; import { QueueService } from '@/core/QueueService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; @@ -18,7 +18,7 @@ interface IFollowersRecipe extends IRecipe { interface IDirectRecipe extends IRecipe { type: 'Direct'; - to: IRemoteUser; + to: RemoteUser; } const isFollowers = (recipe: any): recipe is IFollowersRecipe => @@ -50,7 +50,7 @@ export class ApDeliverManagerService { * @param from Followee */ @bindThis - public async deliverToFollowers(actor: { id: ILocalUser['id']; host: null; }, activity: any) { + public async deliverToFollowers(actor: { id: LocalUser['id']; host: null; }, activity: any) { const manager = new DeliverManager( this.userEntityService, this.followingsRepository, @@ -68,7 +68,7 @@ export class ApDeliverManagerService { * @param to Target user */ @bindThis - public async deliverToUser(actor: { id: ILocalUser['id']; host: null; }, activity: any, to: IRemoteUser) { + public async deliverToUser(actor: { id: LocalUser['id']; host: null; }, activity: any, to: RemoteUser) { const manager = new DeliverManager( this.userEntityService, this.followingsRepository, @@ -132,7 +132,7 @@ class DeliverManager { * @param to To */ @bindThis - public addDirectRecipe(to: IRemoteUser) { + public addDirectRecipe(to: RemoteUser) { const recipe = { type: 'Direct', to, diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index d514e9845..62f382734 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -22,7 +22,7 @@ import { QueueService } from '@/core/QueueService.js'; import { MessagingService } from '@/core/MessagingService.js'; import type { UsersRepository, NotesRepository, FollowingsRepository, MessagingMessagesRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/index.js'; import { bindThis } from '@/decorators.js'; -import type { IRemoteUser } from '@/models/entities/User.js'; +import type { RemoteUser } from '@/models/entities/User.js'; import { getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isPost, isRead, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js'; import { ApNoteService } from './models/ApNoteService.js'; import { ApLoggerService } from './ApLoggerService.js'; @@ -87,7 +87,7 @@ export class ApInboxService { } @bindThis - public async performActivity(actor: IRemoteUser, activity: IObject) { + public async performActivity(actor: RemoteUser, activity: IObject) { if (isCollectionOrOrderedCollection(activity)) { const resolver = this.apResolverService.createResolver(); for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) { @@ -115,7 +115,7 @@ export class ApInboxService { } @bindThis - public async performOneActivity(actor: IRemoteUser, activity: IObject): Promise { + public async performOneActivity(actor: RemoteUser, activity: IObject): Promise { if (actor.isSuspended) return; if (isCreate(activity)) { @@ -152,7 +152,7 @@ export class ApInboxService { } @bindThis - private async follow(actor: IRemoteUser, activity: IFollow): Promise { + private async follow(actor: RemoteUser, activity: IFollow): Promise { const followee = await this.apDbResolverService.getUserFromApId(activity.object); if (followee == null) { @@ -168,7 +168,7 @@ export class ApInboxService { } @bindThis - private async like(actor: IRemoteUser, activity: ILike): Promise { + private async like(actor: RemoteUser, activity: ILike): Promise { const targetUri = getApId(activity.object); const note = await this.apNoteService.fetchNote(targetUri); @@ -186,7 +186,7 @@ export class ApInboxService { } @bindThis - private async read(actor: IRemoteUser, activity: IRead): Promise { + private async read(actor: RemoteUser, activity: IRead): Promise { const id = await getApId(activity.object); if (!this.utilityService.isSelfHost(this.utilityService.extractDbHost(id))) { @@ -209,7 +209,7 @@ export class ApInboxService { } @bindThis - private async accept(actor: IRemoteUser, activity: IAccept): Promise { + private async accept(actor: RemoteUser, activity: IAccept): Promise { const uri = activity.id ?? activity; this.logger.info(`Accept: ${uri}`); @@ -227,7 +227,7 @@ export class ApInboxService { } @bindThis - private async acceptFollow(actor: IRemoteUser, activity: IFollow): Promise { + private async acceptFollow(actor: RemoteUser, activity: IFollow): Promise { // ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある const follower = await this.apDbResolverService.getUserFromApId(activity.actor); @@ -251,7 +251,7 @@ export class ApInboxService { } @bindThis - private async add(actor: IRemoteUser, activity: IAdd): Promise { + private async add(actor: RemoteUser, activity: IAdd): Promise { if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } @@ -271,7 +271,7 @@ export class ApInboxService { } @bindThis - private async announce(actor: IRemoteUser, activity: IAnnounce): Promise { + private async announce(actor: RemoteUser, activity: IAnnounce): Promise { const uri = getApId(activity); this.logger.info(`Announce: ${uri}`); @@ -282,7 +282,7 @@ export class ApInboxService { } @bindThis - private async announceNote(actor: IRemoteUser, activity: IAnnounce, targetUri: string): Promise { + private async announceNote(actor: RemoteUser, activity: IAnnounce, targetUri: string): Promise { const uri = getApId(activity); if (actor.isSuspended) { @@ -342,7 +342,7 @@ export class ApInboxService { } @bindThis - private async block(actor: IRemoteUser, activity: IBlock): Promise { + private async block(actor: RemoteUser, activity: IBlock): Promise { // ※ activity.objectにブロック対象があり、それは存在するローカルユーザーのはず const blockee = await this.apDbResolverService.getUserFromApId(activity.object); @@ -360,7 +360,7 @@ export class ApInboxService { } @bindThis - private async create(actor: IRemoteUser, activity: ICreate): Promise { + private async create(actor: RemoteUser, activity: ICreate): Promise { const uri = getApId(activity); this.logger.info(`Create: ${uri}`); @@ -396,7 +396,7 @@ export class ApInboxService { } @bindThis - private async createNote(resolver: Resolver, actor: IRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise { + private async createNote(resolver: Resolver, actor: RemoteUser, note: IObject, silent = false, activity?: ICreate): Promise { const uri = getApId(note); if (typeof note === 'object') { @@ -431,7 +431,7 @@ export class ApInboxService { } @bindThis - private async delete(actor: IRemoteUser, activity: IDelete): Promise { + private async delete(actor: RemoteUser, activity: IDelete): Promise { if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } @@ -473,7 +473,7 @@ export class ApInboxService { } @bindThis - private async deleteActor(actor: IRemoteUser, uri: string): Promise { + private async deleteActor(actor: RemoteUser, uri: string): Promise { this.logger.info(`Deleting the Actor: ${uri}`); if (actor.uri !== uri) { @@ -495,7 +495,7 @@ export class ApInboxService { } @bindThis - private async deleteNote(actor: IRemoteUser, uri: string): Promise { + private async deleteNote(actor: RemoteUser, uri: string): Promise { this.logger.info(`Deleting the Note: ${uri}`); const unlock = await this.appLockService.getApLock(uri); @@ -528,7 +528,7 @@ export class ApInboxService { } @bindThis - private async flag(actor: IRemoteUser, activity: IFlag): Promise { + private async flag(actor: RemoteUser, activity: IFlag): Promise { // objectは `(User|Note) | (User|Note)[]` だけど、全パターンDBスキーマと対応させられないので // 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する const uris = getApIds(activity.object); @@ -553,7 +553,7 @@ export class ApInboxService { } @bindThis - private async reject(actor: IRemoteUser, activity: IReject): Promise { + private async reject(actor: RemoteUser, activity: IReject): Promise { const uri = activity.id ?? activity; this.logger.info(`Reject: ${uri}`); @@ -571,7 +571,7 @@ export class ApInboxService { } @bindThis - private async rejectFollow(actor: IRemoteUser, activity: IFollow): Promise { + private async rejectFollow(actor: RemoteUser, activity: IFollow): Promise { // ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある const follower = await this.apDbResolverService.getUserFromApId(activity.actor); @@ -595,7 +595,7 @@ export class ApInboxService { } @bindThis - private async remove(actor: IRemoteUser, activity: IRemove): Promise { + private async remove(actor: RemoteUser, activity: IRemove): Promise { if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } @@ -615,7 +615,7 @@ export class ApInboxService { } @bindThis - private async undo(actor: IRemoteUser, activity: IUndo): Promise { + private async undo(actor: RemoteUser, activity: IUndo): Promise { if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } @@ -641,7 +641,7 @@ export class ApInboxService { } @bindThis - private async undoAccept(actor: IRemoteUser, activity: IAccept): Promise { + private async undoAccept(actor: RemoteUser, activity: IAccept): Promise { const follower = await this.apDbResolverService.getUserFromApId(activity.object); if (follower == null) { return 'skip: follower not found'; @@ -661,7 +661,7 @@ export class ApInboxService { } @bindThis - private async undoAnnounce(actor: IRemoteUser, activity: IAnnounce): Promise { + private async undoAnnounce(actor: RemoteUser, activity: IAnnounce): Promise { const uri = getApId(activity); const note = await this.notesRepository.findOneBy({ @@ -676,7 +676,7 @@ export class ApInboxService { } @bindThis - private async undoBlock(actor: IRemoteUser, activity: IBlock): Promise { + private async undoBlock(actor: RemoteUser, activity: IBlock): Promise { const blockee = await this.apDbResolverService.getUserFromApId(activity.object); if (blockee == null) { @@ -692,7 +692,7 @@ export class ApInboxService { } @bindThis - private async undoFollow(actor: IRemoteUser, activity: IFollow): Promise { + private async undoFollow(actor: RemoteUser, activity: IFollow): Promise { const followee = await this.apDbResolverService.getUserFromApId(activity.object); if (followee == null) { return 'skip: followee not found'; @@ -726,7 +726,7 @@ export class ApInboxService { } @bindThis - private async undoLike(actor: IRemoteUser, activity: ILike): Promise { + private async undoLike(actor: RemoteUser, activity: ILike): Promise { const targetUri = getApId(activity.object); const note = await this.apNoteService.fetchNote(targetUri); @@ -741,7 +741,7 @@ export class ApInboxService { } @bindThis - private async update(actor: IRemoteUser, activity: IUpdate): Promise { + private async update(actor: RemoteUser, activity: IUpdate): Promise { if ('actor' in activity && actor.uri !== activity.actor) { return 'skip: invalid actor'; } diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 996ff625e..308393f9f 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -5,7 +5,7 @@ import { v4 as uuid } from 'uuid'; import * as mfm from 'mfm-js'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; -import type { ILocalUser, IRemoteUser, User } from '@/models/entities/User.js'; +import type { LocalUser, RemoteUser, User } from '@/models/entities/User.js'; import type { IMentionedRemoteUsers, Note } from '@/models/entities/Note.js'; import type { Blocking } from '@/models/entities/Blocking.js'; import type { Relay } from '@/models/entities/Relay.js'; @@ -70,7 +70,7 @@ export class ApRendererService { } @bindThis - public renderAdd(user: ILocalUser, target: any, object: any): IAdd { + public renderAdd(user: LocalUser, target: any, object: any): IAdd { return { type: 'Add', actor: `${this.config.url}/users/${user.id}`, @@ -181,7 +181,7 @@ export class ApRendererService { // to anonymise reporters, the reporting actor must be a system user // object has to be a uri or array of uris @bindThis - public renderFlag(user: ILocalUser, object: IObject, content: string): IFlag { + public renderFlag(user: LocalUser, object: IObject, content: string): IFlag { return { type: 'Flag', actor: `${this.config.url}/users/${user.id}`, @@ -191,7 +191,7 @@ export class ApRendererService { } @bindThis - public renderFollowRelay(relay: Relay, relayActor: ILocalUser): IFollow { + public renderFollowRelay(relay: Relay, relayActor: LocalUser): IFollow { return { id: `${this.config.url}/activities/follow-relay/${relay.id}`, type: 'Follow', @@ -244,7 +244,7 @@ export class ApRendererService { } @bindThis - public renderKey(user: ILocalUser, key: UserKeypair, postfix?: string): IKey { + public renderKey(user: LocalUser, key: UserKeypair, postfix?: string): IKey { return { id: `${this.config.url}/users/${user.id}${postfix ?? '/publickey'}`, type: 'Key', @@ -287,8 +287,8 @@ export class ApRendererService { public renderMention(mention: User): IApMention { return { type: 'Mention', - href: this.userEntityService.isRemoteUser(mention) ? mention.uri! : `${this.config.url}/users/${(mention as ILocalUser).id}`, - name: this.userEntityService.isRemoteUser(mention) ? `@${mention.username}@${mention.host}` : `@${(mention as ILocalUser).username}`, + href: this.userEntityService.isRemoteUser(mention) ? mention.uri! : `${this.config.url}/users/${(mention as LocalUser).id}`, + name: this.userEntityService.isRemoteUser(mention) ? `@${mention.username}@${mention.host}` : `@${(mention as LocalUser).username}`, }; } @@ -438,7 +438,7 @@ export class ApRendererService { } @bindThis - public async renderPerson(user: ILocalUser) { + public async renderPerson(user: LocalUser) { const id = `${this.config.url}/users/${user.id}`; const isSystem = !!user.username.match(/\./); @@ -594,7 +594,7 @@ export class ApRendererService { } @bindThis - public renderVote(user: { id: User['id'] }, vote: PollVote, note: Note, poll: Poll, pollOwner: IRemoteUser): ICreate { + public renderVote(user: { id: User['id'] }, vote: PollVote, note: Note, poll: Poll, pollOwner: RemoteUser): ICreate { return { id: `${this.config.url}/users/${user.id}#votes/${vote.id}/activity`, actor: `${this.config.url}/users/${user.id}`, diff --git a/packages/backend/src/core/activitypub/ApResolverService.ts b/packages/backend/src/core/activitypub/ApResolverService.ts index 65026cc4c..df7bb4640 100644 --- a/packages/backend/src/core/activitypub/ApResolverService.ts +++ b/packages/backend/src/core/activitypub/ApResolverService.ts @@ -1,5 +1,5 @@ import { Inject, Injectable } from '@nestjs/common'; -import type { ILocalUser } from '@/models/entities/User.js'; +import type { LocalUser } from '@/models/entities/User.js'; import { InstanceActorService } from '@/core/InstanceActorService.js'; import type { NotesRepository, PollsRepository, NoteReactionsRepository, UsersRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; @@ -18,7 +18,7 @@ import type { IObject, ICollection, IOrderedCollection } from './type.js'; export class Resolver { private history: Set; - private user?: ILocalUser; + private user?: LocalUser; private logger: Logger; constructor( @@ -133,7 +133,7 @@ export class Resolver { }); case 'users': return this.usersRepository.findOneByOrFail({ id: parsed.id }) - .then(user => this.apRendererService.renderPerson(user as ILocalUser)); + .then(user => this.apRendererService.renderPerson(user as LocalUser)); case 'questions': // Polls are indexed by the note they are attached to. return Promise.all([ diff --git a/packages/backend/src/core/activitypub/models/ApImageService.ts b/packages/backend/src/core/activitypub/models/ApImageService.ts index f14b15013..3b671af12 100644 --- a/packages/backend/src/core/activitypub/models/ApImageService.ts +++ b/packages/backend/src/core/activitypub/models/ApImageService.ts @@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; import type { DriveFilesRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; -import type { IRemoteUser } from '@/models/entities/User.js'; +import type { RemoteUser } from '@/models/entities/User.js'; import type { DriveFile } from '@/models/entities/DriveFile.js'; import { MetaService } from '@/core/MetaService.js'; import { truncate } from '@/misc/truncate.js'; @@ -36,7 +36,7 @@ export class ApImageService { * Imageを作成します。 */ @bindThis - public async createImage(actor: IRemoteUser, value: any): Promise { + public async createImage(actor: RemoteUser, value: any): Promise { // 投稿者が凍結されていたらスキップ if (actor.isSuspended) { throw new Error('actor has been suspended'); @@ -88,7 +88,7 @@ export class ApImageService { * リモートサーバーからフェッチしてMisskeyに登録しそれを返します。 */ @bindThis - public async resolveImage(actor: IRemoteUser, value: any): Promise { + public async resolveImage(actor: RemoteUser, value: any): Promise { // TODO // リモートサーバーからフェッチしてきて登録 diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index 0292a27d9..d4c483688 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -3,7 +3,7 @@ import promiseLimit from 'promise-limit'; import { DI } from '@/di-symbols.js'; import type { MessagingMessagesRepository, PollsRepository, EmojisRepository, UsersRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; -import type { IRemoteUser } from '@/models/entities/User.js'; +import type { RemoteUser } from '@/models/entities/User.js'; import type { Note } from '@/models/entities/Note.js'; import { toArray, toSingle, unique } from '@/misc/prelude/array.js'; import type { Emoji } from '@/models/entities/Emoji.js'; @@ -146,7 +146,7 @@ export class ApNoteService { this.logger.info(`Creating the Note: ${note.id}`); // 投稿者をフェッチ - const actor = await this.apPersonService.resolvePerson(getOneApId(note.attributedTo!), resolver) as IRemoteUser; + const actor = await this.apPersonService.resolvePerson(getOneApId(note.attributedTo!), resolver) as RemoteUser; // 投稿者が凍結されていたらスキップ if (actor.isSuspended) { diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index 9dca06552..35d6985f7 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -5,7 +5,7 @@ import { ModuleRef } from '@nestjs/core'; import { DI } from '@/di-symbols.js'; import type { FollowingsRepository, InstancesRepository, UserProfilesRepository, UserPublickeysRepository, UsersRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; -import type { IRemoteUser } from '@/models/entities/User.js'; +import type { RemoteUser } from '@/models/entities/User.js'; import { User } from '@/models/entities/User.js'; import { truncate } from '@/misc/truncate.js'; import type { UserCacheService } from '@/core/UserCacheService.js'; @@ -259,7 +259,7 @@ export class ApPersonService implements OnModuleInit { } // Create user - let user: IRemoteUser; + let user: RemoteUser; try { // Start transaction await this.db.transaction(async transactionalEntityManager => { @@ -284,7 +284,7 @@ export class ApPersonService implements OnModuleInit { isBot, isCat: (person as any).isCat === true, showTimelineReplies: false, - })) as IRemoteUser; + })) as RemoteUser; await transactionalEntityManager.save(new UserProfile({ userId: user.id, @@ -313,7 +313,7 @@ export class ApPersonService implements OnModuleInit { }); if (u) { - user = u as IRemoteUser; + user = u as RemoteUser; } else { throw new Error('already registered'); } @@ -392,7 +392,7 @@ export class ApPersonService implements OnModuleInit { } //#region このサーバーに既に登録されているか - const exist = await this.usersRepository.findOneBy({ uri }) as IRemoteUser; + const exist = await this.usersRepository.findOneBy({ uri }) as RemoteUser; if (exist == null) { return; diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index eea9d5567..fa3337c01 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -10,7 +10,7 @@ import { awaitAll } from '@/misc/prelude/await-all.js'; import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const.js'; import { Cache } from '@/misc/cache.js'; import type { Instance } from '@/models/entities/Instance.js'; -import type { ILocalUser, IRemoteUser, User } from '@/models/entities/User.js'; +import type { LocalUser, RemoteUser, User } from '@/models/entities/User.js'; import { birthdaySchema, descriptionSchema, localUsernameSchema, locationSchema, nameSchema, passwordSchema } from '@/models/entities/User.js'; import type { UsersRepository, UserSecurityKeysRepository, FollowingsRepository, FollowRequestsRepository, BlockingsRepository, MutingsRepository, DriveFilesRepository, NoteUnreadsRepository, ChannelFollowingsRepository, NotificationsRepository, UserNotePiningsRepository, UserProfilesRepository, InstancesRepository, AnnouncementReadsRepository, MessagingMessagesRepository, UserGroupJoiningsRepository, AnnouncementsRepository, AntennaNotesRepository, PagesRepository, UserProfile } from '@/models/index.js'; import { bindThis } from '@/decorators.js'; @@ -32,13 +32,13 @@ type IsMeAndIsUserDetailed(user: T): user is T & { host: null; }; function isLocalUser(user: User | { host: User['host'] }): boolean { return user.host == null; } -function isRemoteUser(user: User): user is IRemoteUser; +function isRemoteUser(user: User): user is RemoteUser; function isRemoteUser(user: T): user is T & { host: string; }; function isRemoteUser(user: User | { host: User['host'] }): boolean { return !isLocalUser(user); diff --git a/packages/backend/src/models/entities/User.ts b/packages/backend/src/models/entities/User.ts index 8d476ab0a..0a8b89ea0 100644 --- a/packages/backend/src/models/entities/User.ts +++ b/packages/backend/src/models/entities/User.ts @@ -215,12 +215,12 @@ export class User { } } -export interface ILocalUser extends User { +export type LocalUser = User & { host: null; uri: null; } -export interface IRemoteUser extends User { +export type RemoteUser = User & { host: string; uri: string; } diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts index a41222c48..fb4ab0c62 100644 --- a/packages/backend/src/queue/processors/InboxProcessorService.ts +++ b/packages/backend/src/queue/processors/InboxProcessorService.ts @@ -16,7 +16,7 @@ import InstanceChart from '@/core/chart/charts/instance.js'; import ApRequestChart from '@/core/chart/charts/ap-request.js'; import FederationChart from '@/core/chart/charts/federation.js'; import { getApId } from '@/core/activitypub/type.js'; -import type { IRemoteUser } from '@/models/entities/User.js'; +import type { RemoteUser } from '@/models/entities/User.js'; import type { UserPublickey } from '@/models/entities/UserPublickey.js'; import { ApDbResolverService } from '@/core/activitypub/ApDbResolverService.js'; import { StatusError } from '@/misc/status-error.js'; @@ -87,7 +87,7 @@ export class InboxProcessorService { // HTTP-Signature keyIdを元にDBから取得 let authUser: { - user: IRemoteUser; + user: RemoteUser; key: UserPublickey | null; } | null = await this.apDbResolverService.getAuthUserFromKeyId(signature.keyId); diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts index c3795223a..da8d0114e 100644 --- a/packages/backend/src/server/ActivityPubServerService.ts +++ b/packages/backend/src/server/ActivityPubServerService.ts @@ -11,7 +11,7 @@ import * as url from '@/misc/prelude/url.js'; import type { Config } from '@/config.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { QueueService } from '@/core/QueueService.js'; -import type { ILocalUser, User } from '@/models/entities/User.js'; +import type { LocalUser, User } from '@/models/entities/User.js'; import { UserKeypairStoreService } from '@/core/UserKeypairStoreService.js'; import type { Following } from '@/models/entities/Following.js'; import { countIf } from '@/misc/prelude/array.js'; @@ -411,7 +411,7 @@ export class ActivityPubServerService { reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); - return (this.apRendererService.addContext(await this.apRendererService.renderPerson(user as ILocalUser))); + return (this.apRendererService.addContext(await this.apRendererService.renderPerson(user as LocalUser))); } @bindThis diff --git a/packages/backend/src/server/api/ApiCallService.ts b/packages/backend/src/server/api/ApiCallService.ts index 3a05413bc..4a8b8a1c1 100644 --- a/packages/backend/src/server/api/ApiCallService.ts +++ b/packages/backend/src/server/api/ApiCallService.ts @@ -5,7 +5,7 @@ import { promisify } from 'node:util'; import { Inject, Injectable } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; import { getIpHash } from '@/misc/get-ip-hash.js'; -import type { ILocalUser, User } from '@/models/entities/User.js'; +import type { LocalUser, User } from '@/models/entities/User.js'; import type { AccessToken } from '@/models/entities/AccessToken.js'; import type Logger from '@/logger.js'; import type { UserIpsRepository } from '@/models/index.js'; @@ -168,7 +168,7 @@ export class ApiCallService implements OnApplicationShutdown { } @bindThis - private async logIp(request: FastifyRequest, user: ILocalUser) { + private async logIp(request: FastifyRequest, user: LocalUser) { const meta = await this.metaService.fetch(); if (!meta.enableIpLogging) return; const ip = request.ip; @@ -194,7 +194,7 @@ export class ApiCallService implements OnApplicationShutdown { @bindThis private async call( ep: IEndpoint & { exec: any }, - user: ILocalUser | null | undefined, + user: LocalUser | null | undefined, token: AccessToken | null | undefined, data: any, file: { diff --git a/packages/backend/src/server/api/AuthenticateService.ts b/packages/backend/src/server/api/AuthenticateService.ts index b9f6af4ff..87438c348 100644 --- a/packages/backend/src/server/api/AuthenticateService.ts +++ b/packages/backend/src/server/api/AuthenticateService.ts @@ -1,7 +1,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; import type { AccessTokensRepository, AppsRepository, UsersRepository } from '@/models/index.js'; -import type { ILocalUser } from '@/models/entities/User.js'; +import type { LocalUser } from '@/models/entities/User.js'; import type { AccessToken } from '@/models/entities/AccessToken.js'; import { Cache } from '@/misc/cache.js'; import type { App } from '@/models/entities/App.js'; @@ -36,14 +36,14 @@ export class AuthenticateService { } @bindThis - public async authenticate(token: string | null | undefined): Promise<[ILocalUser | null | undefined, AccessToken | null | undefined]> { + public async authenticate(token: string | null | undefined): Promise<[LocalUser | null | undefined, AccessToken | null | undefined]> { if (token == null) { return [null, null]; } if (isNativeToken(token)) { const user = await this.userCacheService.localUserByNativeTokenCache.fetch(token, - () => this.usersRepository.findOneBy({ token }) as Promise); + () => this.usersRepository.findOneBy({ token }) as Promise); if (user == null) { throw new AuthenticationError('user not found'); @@ -70,7 +70,7 @@ export class AuthenticateService { const user = await this.userCacheService.localUserByIdCache.fetch(accessToken.userId, () => this.usersRepository.findOneBy({ id: accessToken.userId, - }) as Promise); + }) as Promise); if (accessToken.appId) { const app = await this.appCache.fetch(accessToken.appId, diff --git a/packages/backend/src/server/api/SigninApiService.ts b/packages/backend/src/server/api/SigninApiService.ts index d490097de..f1164b995 100644 --- a/packages/backend/src/server/api/SigninApiService.ts +++ b/packages/backend/src/server/api/SigninApiService.ts @@ -7,7 +7,7 @@ import { DI } from '@/di-symbols.js'; import type { UserSecurityKeysRepository, SigninsRepository, UserProfilesRepository, AttestationChallengesRepository, UsersRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; import { getIpHash } from '@/misc/get-ip-hash.js'; -import type { ILocalUser } from '@/models/entities/User.js'; +import type { LocalUser } from '@/models/entities/User.js'; import { IdService } from '@/core/IdService.js'; import { TwoFactorAuthenticationService } from '@/core/TwoFactorAuthenticationService.js'; import { bindThis } from '@/decorators.js'; @@ -105,7 +105,7 @@ export class SigninApiService { const user = await this.usersRepository.findOneBy({ usernameLower: username.toLowerCase(), host: IsNull(), - }) as ILocalUser; + }) as LocalUser; if (user == null) { return error(404, { diff --git a/packages/backend/src/server/api/SigninService.ts b/packages/backend/src/server/api/SigninService.ts index c78d9f85c..f821dbb50 100644 --- a/packages/backend/src/server/api/SigninService.ts +++ b/packages/backend/src/server/api/SigninService.ts @@ -3,7 +3,7 @@ import { DI } from '@/di-symbols.js'; import type { SigninsRepository, UsersRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; import { IdService } from '@/core/IdService.js'; -import type { ILocalUser } from '@/models/entities/User.js'; +import type { LocalUser } from '@/models/entities/User.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { SigninEntityService } from '@/core/entities/SigninEntityService.js'; import { bindThis } from '@/decorators.js'; @@ -25,7 +25,7 @@ export class SigninService { } @bindThis - public signin(request: FastifyRequest, reply: FastifyReply, user: ILocalUser) { + public signin(request: FastifyRequest, reply: FastifyReply, user: LocalUser) { setImmediate(async () => { // Append signin history const record = await this.signinsRepository.insert({ diff --git a/packages/backend/src/server/api/SignupApiService.ts b/packages/backend/src/server/api/SignupApiService.ts index ffd7e203e..41e8365d0 100644 --- a/packages/backend/src/server/api/SignupApiService.ts +++ b/packages/backend/src/server/api/SignupApiService.ts @@ -10,7 +10,7 @@ import { IdService } from '@/core/IdService.js'; import { SignupService } from '@/core/SignupService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { EmailService } from '@/core/EmailService.js'; -import { ILocalUser } from '@/models/entities/User.js'; +import { LocalUser } from '@/models/entities/User.js'; import { FastifyReplyError } from '@/misc/fastify-reply-error.js'; import { bindThis } from '@/decorators.js'; import { SigninService } from './SigninService.js'; @@ -194,7 +194,7 @@ export class SignupApiService { emailVerifyCode: null, }); - return this.signinService.signin(request, reply, account as ILocalUser); + return this.signinService.signin(request, reply, account as LocalUser); } catch (err) { throw new FastifyReplyError(400, typeof err === 'string' ? err : (err as Error).toString()); } diff --git a/packages/backend/src/server/api/endpoint-base.ts b/packages/backend/src/server/api/endpoint-base.ts index 56dad6286..115526d99 100644 --- a/packages/backend/src/server/api/endpoint-base.ts +++ b/packages/backend/src/server/api/endpoint-base.ts @@ -1,7 +1,7 @@ import * as fs from 'node:fs'; import Ajv from 'ajv'; import type { Schema, SchemaType } from '@/misc/schema.js'; -import type { ILocalUser } from '@/models/entities/User.js'; +import type { LocalUser } from '@/models/entities/User.js'; import type { AccessToken } from '@/models/entities/AccessToken.js'; import { ApiError } from './error.js'; import type { IEndpointMeta } from './endpoints.js'; @@ -21,16 +21,16 @@ type File = { // TODO: paramsの型をT['params']のスキーマ定義から推論する type executor = - (params: SchemaType, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: File, cleanup?: () => any, ip?: string | null, headers?: Record | null) => + (params: SchemaType, user: T['requireCredential'] extends true ? LocalUser : LocalUser | null, token: AccessToken | null, file?: File, cleanup?: () => any, ip?: string | null, headers?: Record | null) => Promise>>; export abstract class Endpoint { - public exec: (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: File, ip?: string | null, headers?: Record | null) => Promise; + public exec: (params: any, user: T['requireCredential'] extends true ? LocalUser : LocalUser | null, token: AccessToken | null, file?: File, ip?: string | null, headers?: Record | null) => Promise; constructor(meta: T, paramDef: Ps, cb: executor) { const validate = ajv.compile(paramDef); - this.exec = (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: File, ip?: string | null, headers?: Record | null) => { + this.exec = (params: any, user: T['requireCredential'] extends true ? LocalUser : LocalUser | null, token: AccessToken | null, file?: File, ip?: string | null, headers?: Record | null) => { let cleanup: undefined | (() => void) = undefined; if (meta.requireFile) { diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts index e758c5e3f..61e05531e 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 @@ import ms from 'ms'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { UsersRepository, NotesRepository } from '@/models/index.js'; import type { Note } from '@/models/entities/Note.js'; -import type { ILocalUser, User } from '@/models/entities/User.js'; +import type { LocalUser, User } from '@/models/entities/User.js'; import { isActor, isPost, getApId } from '@/core/activitypub/type.js'; import type { SchemaType } from '@/misc/schema.js'; import { ApResolverService } from '@/core/activitypub/ApResolverService.js'; @@ -114,7 +114,7 @@ export default class extends Endpoint { * URIからUserかNoteを解決する */ @bindThis - private async fetchAny(uri: string, me: ILocalUser | null | undefined): Promise | null> { + private async fetchAny(uri: string, me: LocalUser | null | undefined): Promise | null> { // ブロックしてたら中断 const fetchedMeta = await this.metaService.fetch(); if (this.utilityService.isBlockedHost(fetchedMeta.blockedHosts, this.utilityService.extractDbHost(uri))) return null; @@ -147,7 +147,7 @@ export default class extends Endpoint { } @bindThis - private async mergePack(me: ILocalUser | null | undefined, user: User | null | undefined, note: Note | null | undefined): Promise | null> { + private async mergePack(me: LocalUser | null | undefined, user: User | null | undefined, note: Note | null | undefined): Promise | null> { if (user != null) { return { type: 'User', diff --git a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts index d8e1a1149..f734e4e77 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts @@ -1,7 +1,7 @@ import { Not } from 'typeorm'; import { Inject, Injectable } from '@nestjs/common'; import type { UsersRepository, PollsRepository, PollVotesRepository } from '@/models/index.js'; -import type { IRemoteUser } from '@/models/entities/User.js'; +import type { RemoteUser } from '@/models/entities/User.js'; import { IdService } from '@/core/IdService.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { GetterService } from '@/server/api/GetterService.js'; @@ -160,7 +160,7 @@ export default class extends Endpoint { // リモート投票の場合リプライ送信 if (note.userHost != null) { - const pollOwner = await this.usersRepository.findOneByOrFail({ id: note.userId }) as IRemoteUser; + const pollOwner = await this.usersRepository.findOneByOrFail({ id: note.userId }) as RemoteUser; this.queueService.deliver(me, this.apRendererService.addContext(await this.apRendererService.renderVote(me, vote, note, poll, pollOwner)), pollOwner.inbox); } diff --git a/packages/backend/src/server/api/stream/channels/messaging.ts b/packages/backend/src/server/api/stream/channels/messaging.ts index 92af6b591..b544e297c 100644 --- a/packages/backend/src/server/api/stream/channels/messaging.ts +++ b/packages/backend/src/server/api/stream/channels/messaging.ts @@ -1,6 +1,6 @@ import { Inject, Injectable } from '@nestjs/common'; import type { UserGroupJoiningsRepository, UsersRepository, MessagingMessagesRepository } from '@/models/index.js'; -import type { User, ILocalUser, IRemoteUser } from '@/models/entities/User.js'; +import type { User, LocalUser, RemoteUser } from '@/models/entities/User.js'; import type { UserGroup } from '@/models/entities/UserGroup.js'; import { MessagingService } from '@/core/MessagingService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; @@ -89,7 +89,7 @@ class MessagingChannel extends Channel { // リモートユーザーからのメッセージだったら既読配信 if (this.userEntityService.isLocalUser(this.user!) && this.userEntityService.isRemoteUser(this.otherparty!)) { this.messagingMessagesRepository.findOneBy({ id: body.id }).then(message => { - if (message) this.messagingService.deliverReadActivity(this.user as ILocalUser, this.otherparty as IRemoteUser, message); + if (message) this.messagingService.deliverReadActivity(this.user as LocalUser, this.otherparty as RemoteUser, message); }); } } else if (this.groupId) { From e8d4f3eac35f39f664379b7c8b0a3c9db2f3a7ac Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 13 Feb 2023 16:19:29 +0900 Subject: [PATCH 18/92] refactor: fix types --- packages/backend/src/core/activitypub/ApRendererService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 308393f9f..92bc1869e 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -181,7 +181,7 @@ export class ApRendererService { // to anonymise reporters, the reporting actor must be a system user // object has to be a uri or array of uris @bindThis - public renderFlag(user: LocalUser, object: IObject, content: string): IFlag { + public renderFlag(user: LocalUser, object: IObject | string | string[], content: string): IFlag { return { type: 'Flag', actor: `${this.config.url}/users/${user.id}`, From 1c8419cea00ffea7e28161429f81873b26944c40 Mon Sep 17 00:00:00 2001 From: "Kohei Ota (inductor)" Date: Tue, 14 Feb 2023 09:59:50 +0900 Subject: [PATCH 19/92] Update Docker GHA (#9920) * Update Docker GHA * add id --- .github/workflows/docker-develop.yml | 8 +++++++- .github/workflows/docker.yml | 12 +++++++++++- Dockerfile | 14 ++++++++------ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/.github/workflows/docker-develop.yml b/.github/workflows/docker-develop.yml index a999dc51e..09a2c33e0 100644 --- a/.github/workflows/docker-develop.yml +++ b/.github/workflows/docker-develop.yml @@ -15,7 +15,10 @@ jobs: - name: Check out the repo uses: actions/checkout@v3.3.0 - name: Set up Docker Buildx + id: buildx uses: docker/setup-buildx-action@v2.3.0 + with: + platforms: linux/amd64,linux/arm64 - name: Docker meta id: meta uses: docker/metadata-action@v4 @@ -27,10 +30,13 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and Push to Docker Hub - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: + builder: ${{ steps.buildx.outputs.name }} context: . push: true + platforms: ${{ steps.buildx.outputs.platforms }} + provenance: false tags: misskey/misskey:develop labels: develop cache-from: type=gha diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index d7803ce3e..a465d92ea 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -13,6 +13,11 @@ jobs: steps: - name: Check out the repo uses: actions/checkout@v3.3.0 + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v2.3.0 + with: + platforms: linux/amd64,linux/arm64 - name: Docker meta id: meta uses: docker/metadata-action@v4 @@ -31,9 +36,14 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and Push to Docker Hub - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: + builder: ${{ steps.buildx.outputs.name }} context: . push: true + platforms: ${{ steps.buildx.outputs.platforms }} + provenance: false tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Dockerfile b/Dockerfile index 0bfd24bd9..b439716be 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,5 @@ +# syntax = docker/dockerfile:1.4 + ARG NODE_VERSION=18.13.0-bullseye FROM node:${NODE_VERSION} AS builder @@ -14,16 +16,16 @@ RUN corepack enable WORKDIR /misskey -COPY ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"] -COPY ["scripts", "./scripts"] -COPY ["packages/backend/package.json", "./packages/backend/"] -COPY ["packages/frontend/package.json", "./packages/frontend/"] -COPY ["packages/sw/package.json", "./packages/sw/"] +COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"] +COPY --link ["scripts", "./scripts"] +COPY --link ["packages/backend/package.json", "./packages/backend/"] +COPY --link ["packages/frontend/package.json", "./packages/frontend/"] +COPY --link ["packages/sw/package.json", "./packages/sw/"] RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \ pnpm i --frozen-lockfile --aggregate-output -COPY . ./ +COPY --link . ./ ARG NODE_ENV=production From 55d4d3418e8f1967a79f027f69849c6295a6864f Mon Sep 17 00:00:00 2001 From: tamaina Date: Tue, 14 Feb 2023 04:08:56 +0000 Subject: [PATCH 20/92] =?UTF-8?q?fix(server):=20HttpRequestService.send?= =?UTF-8?q?=E3=81=A7=E3=81=AF=E5=B8=B8=E3=81=ABUser-Agent=E3=82=92?= =?UTF-8?q?=E5=90=AB=E3=82=80=E3=82=88=E3=81=86=E3=81=AB=20Fix=20#9817=20(?= =?UTF-8?q?maybe)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/core/HttpRequestService.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/core/HttpRequestService.ts b/packages/backend/src/core/HttpRequestService.ts index e32026b04..375aa846c 100644 --- a/packages/backend/src/core/HttpRequestService.ts +++ b/packages/backend/src/core/HttpRequestService.ts @@ -99,7 +99,6 @@ export class HttpRequestService { const res = await this.send(url, { method: 'GET', headers: Object.assign({ - 'User-Agent': this.config.userAgent, Accept: accept, }, headers ?? {}), timeout: 5000, @@ -114,7 +113,6 @@ export class HttpRequestService { const res = await this.send(url, { method: 'GET', headers: Object.assign({ - 'User-Agent': this.config.userAgent, Accept: accept, }, headers ?? {}), timeout: 5000, @@ -144,7 +142,10 @@ export class HttpRequestService { const res = await fetch(url, { method: args.method ?? 'GET', - headers: args.headers, + headers: { + 'User-Agent': this.config.userAgent, + ...(args.headers ?? {}) + }, body: args.body, size: args.size ?? 10 * 1024 * 1024, agent: (url) => this.getAgentByUrl(url), From 7436a58ea17edf8758c29dfa9876816354ec6b1a Mon Sep 17 00:00:00 2001 From: Neko7sora <75793267+Neko7sora@users.noreply.github.com> Date: Tue, 14 Feb 2023 13:13:34 +0900 Subject: [PATCH 21/92] =?UTF-8?q?=E6=94=B9=E8=A1=8C=E3=82=B3=E3=83=BC?= =?UTF-8?q?=E3=83=89=E3=82=92LF=E3=81=AB=E7=B5=B1=E4=B8=80=20(#9926)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: update gitattribute editorconfig * Normalize all the line endings --- .editorconfig | 1 + .gitattributes | 1 + .github/workflows/check_copyright_year.yml | 36 ++--- .github/workflows/lint.yml | 108 ++++++------- .../server/api/endpoints/clips/remove-note.ts | 144 +++++++++--------- packages/frontend/assets/label-red.svg | Bin 441 -> 435 bytes packages/frontend/assets/label.svg | Bin 441 -> 435 bytes packages/frontend/assets/unread.svg | Bin 536 -> 529 bytes 8 files changed, 146 insertions(+), 144 deletions(-) diff --git a/.editorconfig b/.editorconfig index edccf3a9d..6db136764 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,6 +5,7 @@ indent_style = tab indent_size = 2 charset = utf-8 insert_final_newline = true +end_of_line = lf [*.yml] indent_style = space diff --git a/.gitattributes b/.gitattributes index a175917f3..246ecb0a6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,3 +5,4 @@ *.glb -diff -text *.blend -diff -text *.afdesign -diff -text +* text=auto eol=lf diff --git a/.github/workflows/check_copyright_year.yml b/.github/workflows/check_copyright_year.yml index 99799672f..8daea44a8 100644 --- a/.github/workflows/check_copyright_year.yml +++ b/.github/workflows/check_copyright_year.yml @@ -1,18 +1,18 @@ -name: Check copyright year - -on: - push: - branches: - - master - - develop - -jobs: - check_copyright_year: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3.2.0 - - run: | - if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then - echo "Please change copyright year!" - exit 1 - fi +name: Check copyright year + +on: + push: + branches: + - master + - develop + +jobs: + check_copyright_year: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3.2.0 + - run: | + if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then + echo "Please change copyright year!" + exit 1 + fi diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index b88b97ab0..6a579bffc 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,54 +1,54 @@ -name: Lint - -on: - push: - branches: - - master - - develop - pull_request: - -jobs: - pnpm_install: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3.3.0 - with: - fetch-depth: 0 - submodules: true - - uses: pnpm/action-setup@v2 - with: - version: 7 - run_install: false - - uses: actions/setup-node@v3.6.0 - with: - node-version: 18.x - cache: 'pnpm' - - run: corepack enable - - run: pnpm i --frozen-lockfile - - lint: - needs: [pnpm_install] - runs-on: ubuntu-latest - continue-on-error: true - strategy: - matrix: - workspace: - - backend - - frontend - - sw - steps: - - uses: actions/checkout@v3.3.0 - with: - fetch-depth: 0 - submodules: true - - uses: pnpm/action-setup@v2 - with: - version: 7 - run_install: false - - uses: actions/setup-node@v3.6.0 - with: - node-version: 18.x - cache: 'pnpm' - - run: corepack enable - - run: pnpm i --frozen-lockfile - - run: pnpm --filter ${{ matrix.workspace }} run lint +name: Lint + +on: + push: + branches: + - master + - develop + pull_request: + +jobs: + pnpm_install: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3.3.0 + with: + fetch-depth: 0 + submodules: true + - uses: pnpm/action-setup@v2 + with: + version: 7 + run_install: false + - uses: actions/setup-node@v3.6.0 + with: + node-version: 18.x + cache: 'pnpm' + - run: corepack enable + - run: pnpm i --frozen-lockfile + + lint: + needs: [pnpm_install] + runs-on: ubuntu-latest + continue-on-error: true + strategy: + matrix: + workspace: + - backend + - frontend + - sw + steps: + - uses: actions/checkout@v3.3.0 + with: + fetch-depth: 0 + submodules: true + - uses: pnpm/action-setup@v2 + with: + version: 7 + run_install: false + - uses: actions/setup-node@v3.6.0 + with: + node-version: 18.x + cache: 'pnpm' + - run: corepack enable + - run: pnpm i --frozen-lockfile + - run: pnpm --filter ${{ matrix.workspace }} run lint diff --git a/packages/backend/src/server/api/endpoints/clips/remove-note.ts b/packages/backend/src/server/api/endpoints/clips/remove-note.ts index 55778c7ec..5d88870ed 100644 --- a/packages/backend/src/server/api/endpoints/clips/remove-note.ts +++ b/packages/backend/src/server/api/endpoints/clips/remove-note.ts @@ -1,72 +1,72 @@ -import { Inject, Injectable } from '@nestjs/common'; -import { Endpoint } from '@/server/api/endpoint-base.js'; -import type { ClipNotesRepository, ClipsRepository } from '@/models/index.js'; -import { DI } from '@/di-symbols.js'; -import { ApiError } from '../../error.js'; -import { GetterService } from '@/server/api/GetterService.js'; - -export const meta = { - tags: ['account', 'notes', 'clips'], - - requireCredential: true, - - kind: 'write:account', - - errors: { - noSuchClip: { - message: 'No such clip.', - code: 'NO_SUCH_CLIP', - id: 'b80525c6-97f7-49d7-a42d-ebccd49cfd52', - }, - - noSuchNote: { - message: 'No such note.', - code: 'NO_SUCH_NOTE', - id: 'aff017de-190e-434b-893e-33a9ff5049d8', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - clipId: { type: 'string', format: 'misskey:id' }, - noteId: { type: 'string', format: 'misskey:id' }, - }, - required: ['clipId', 'noteId'], -} as const; - -// eslint-disable-next-line import/no-default-export -@Injectable() -export default class extends Endpoint { - constructor( - @Inject(DI.clipsRepository) - private clipsRepository: ClipsRepository, - - @Inject(DI.clipNotesRepository) - private clipNotesRepository: ClipNotesRepository, - - private getterService: GetterService, - ) { - super(meta, paramDef, async (ps, me) => { - const clip = await this.clipsRepository.findOneBy({ - id: ps.clipId, - userId: me.id, - }); - - if (clip == null) { - throw new ApiError(meta.errors.noSuchClip); - } - - const note = await this.getterService.getNote(ps.noteId).catch(err => { - if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw err; - }); - - await this.clipNotesRepository.delete({ - noteId: note.id, - clipId: clip.id, - }); - }); - } -} +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import type { ClipNotesRepository, ClipsRepository } from '@/models/index.js'; +import { DI } from '@/di-symbols.js'; +import { ApiError } from '../../error.js'; +import { GetterService } from '@/server/api/GetterService.js'; + +export const meta = { + tags: ['account', 'notes', 'clips'], + + requireCredential: true, + + kind: 'write:account', + + errors: { + noSuchClip: { + message: 'No such clip.', + code: 'NO_SUCH_CLIP', + id: 'b80525c6-97f7-49d7-a42d-ebccd49cfd52', + }, + + noSuchNote: { + message: 'No such note.', + code: 'NO_SUCH_NOTE', + id: 'aff017de-190e-434b-893e-33a9ff5049d8', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + clipId: { type: 'string', format: 'misskey:id' }, + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['clipId', 'noteId'], +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.clipsRepository) + private clipsRepository: ClipsRepository, + + @Inject(DI.clipNotesRepository) + private clipNotesRepository: ClipNotesRepository, + + private getterService: GetterService, + ) { + super(meta, paramDef, async (ps, me) => { + const clip = await this.clipsRepository.findOneBy({ + id: ps.clipId, + userId: me.id, + }); + + if (clip == null) { + throw new ApiError(meta.errors.noSuchClip); + } + + const note = await this.getterService.getNote(ps.noteId).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; + }); + + await this.clipNotesRepository.delete({ + noteId: note.id, + clipId: clip.id, + }); + }); + } +} diff --git a/packages/frontend/assets/label-red.svg b/packages/frontend/assets/label-red.svg index 45996aa9ce5c00fbad1f5f456e8fb86590bc4de0..c89d3f5f3a4106c660a73b5ff5167ce1cf56940a 100644 GIT binary patch delta 28 kcmdnVyqS4|+C=r_iQSnKzZOnTXY}CUve7RtOSj_!0HE3m7ytkO delta 38 rcmdnYypwr?8YAySwPYaCnF%C56*BTpPG Date: Tue, 14 Feb 2023 13:17:00 +0900 Subject: [PATCH 22/92] fix(client): use tabler icons (#9915) --- packages/frontend/src/components/MkNote.vue | 2 +- .../frontend/src/pages/antenna-timeline.vue | 2 +- packages/frontend/src/pages/explore.users.vue | 12 ++-- .../page-editor/els/page-editor.el.image.vue | 4 +- .../page-editor/els/page-editor.el.text.vue | 2 +- .../frontend/src/pages/settings/drive.vue | 2 +- .../frontend/src/pages/settings/sounds.vue | 2 +- .../frontend/src/pages/user-list-timeline.vue | 2 +- .../frontend/src/scripts/get-note-menu.ts | 2 +- packages/frontend/src/scripts/hpml/index.ts | 12 ++-- packages/frontend/src/scripts/hpml/lib.ts | 56 +++++++++---------- packages/frontend/src/scripts/search.ts | 2 +- packages/frontend/src/ui/classic.vue | 2 +- .../src/widgets/server-metric/mem.vue | 2 +- 14 files changed, 52 insertions(+), 52 deletions(-) diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index c9c512c36..dd2c358f1 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -9,7 +9,7 @@ >
{{ i18n.ts.pinnedNote }}
- +
diff --git a/packages/frontend/src/pages/antenna-timeline.vue b/packages/frontend/src/pages/antenna-timeline.vue index ff31c3ab2..5f0168ee3 100644 --- a/packages/frontend/src/pages/antenna-timeline.vue +++ b/packages/frontend/src/pages/antenna-timeline.vue @@ -72,7 +72,7 @@ watch(() => props.antennaId, async () => { }, { immediate: true }); const headerActions = $computed(() => antenna ? [{ - icon: 'fas fa-calendar-alt', + icon: 'ti ti-calendar-time', text: i18n.ts.jumpToSpecifiedDate, handler: timetravel, }, { diff --git a/packages/frontend/src/pages/explore.users.vue b/packages/frontend/src/pages/explore.users.vue index 3a74e8518..8defc35b7 100644 --- a/packages/frontend/src/pages/explore.users.vue +++ b/packages/frontend/src/pages/explore.users.vue @@ -7,15 +7,15 @@
diff --git a/packages/frontend/src/components/MkReactionsViewer.vue b/packages/frontend/src/components/MkReactionsViewer.vue index cdd6f528e..76faffe92 100644 --- a/packages/frontend/src/components/MkReactionsViewer.vue +++ b/packages/frontend/src/components/MkReactionsViewer.vue @@ -51,7 +51,7 @@ watch([() => props.note.reactions, () => props.maxNumber], ([newSource, maxNumbe ...Object.entries(newSource) .sort(([, a], [, b]) => b - a) .filter(([y], i) => i < maxNumber && !newReactionsNames.includes(y)), - ] + ]; newReactions = newReactions.slice(0, props.maxNumber); diff --git a/packages/frontend/src/components/global/MkPageHeader.tabs.vue b/packages/frontend/src/components/global/MkPageHeader.tabs.vue index d650122cf..b181b6298 100644 --- a/packages/frontend/src/components/global/MkPageHeader.tabs.vue +++ b/packages/frontend/src/components/global/MkPageHeader.tabs.vue @@ -8,8 +8,8 @@
{{ t.title }}
- +
{{ t.title }}
diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue index 803efb169..98233b02e 100644 --- a/packages/frontend/src/components/global/MkPageHeader.vue +++ b/packages/frontend/src/components/global/MkPageHeader.vue @@ -19,7 +19,7 @@
- +
@@ -40,7 +40,7 @@ import { scrollToTop } from '@/scripts/scroll'; import { globalEvents } from '@/events'; import { injectPageMetadata } from '@/scripts/page-metadata'; import { $i, openAccountMenu as openAccountMenu_ } from '@/account'; -import XTabs, { Tab } from './MkPageHeader.tabs.vue' +import XTabs, { Tab } from './MkPageHeader.tabs.vue'; const props = withDefaults(defineProps<{ tabs?: Tab[]; diff --git a/packages/frontend/src/ui/classic.vue b/packages/frontend/src/ui/classic.vue index d8b800b87..92997ffb6 100644 --- a/packages/frontend/src/ui/classic.vue +++ b/packages/frontend/src/ui/classic.vue @@ -124,7 +124,7 @@ function onAiClick(ev) { } if (window.innerWidth < 1024) { - const currentUI = miLocalStorage.getItem('ui') + const currentUI = miLocalStorage.getItem('ui'); miLocalStorage.setItem('ui_temp', currentUI || 'default'); miLocalStorage.setItem('ui', 'default'); location.reload(); From 8f9ce23e521d15ff1d7796d637d5bd64d9ee4375 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 17 Feb 2023 02:56:59 +0100 Subject: [PATCH 38/92] style(backend): fix all eslint errors (#9967) --- packages/backend/src/core/ImageProcessingService.ts | 2 +- packages/backend/src/core/PushNotificationService.ts | 1 - packages/backend/src/core/VideoProcessingService.ts | 2 +- packages/backend/src/core/entities/EmojiEntityService.ts | 2 +- packages/backend/src/server/FileServerService.ts | 6 +++--- packages/backend/src/server/api/endpoints/admin/ad/list.ts | 2 +- .../backend/src/server/api/endpoints/admin/emoji/delete.ts | 2 +- .../backend/src/server/api/endpoints/admin/emoji/update.ts | 4 ++-- packages/backend/src/server/api/endpoints/notes/create.ts | 2 +- 9 files changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/backend/src/core/ImageProcessingService.ts b/packages/backend/src/core/ImageProcessingService.ts index fbc02f504..7c88f5e9a 100644 --- a/packages/backend/src/core/ImageProcessingService.ts +++ b/packages/backend/src/core/ImageProcessingService.ts @@ -107,7 +107,7 @@ export class ImageProcessingService { withoutEnlargement: true, }) .rotate() - .webp(options) + .webp(options); return { data, diff --git a/packages/backend/src/core/PushNotificationService.ts b/packages/backend/src/core/PushNotificationService.ts index aff233a3e..75bf4b0e0 100644 --- a/packages/backend/src/core/PushNotificationService.ts +++ b/packages/backend/src/core/PushNotificationService.ts @@ -40,7 +40,6 @@ function truncateBody(type: T, body: pus }, } : {}), }; - } @Injectable() diff --git a/packages/backend/src/core/VideoProcessingService.ts b/packages/backend/src/core/VideoProcessingService.ts index dd6c51c21..eccfeb0e7 100644 --- a/packages/backend/src/core/VideoProcessingService.ts +++ b/packages/backend/src/core/VideoProcessingService.ts @@ -53,7 +53,7 @@ export class VideoProcessingService { thumbnail: '1', url, }) - ) + ); } } diff --git a/packages/backend/src/core/entities/EmojiEntityService.ts b/packages/backend/src/core/entities/EmojiEntityService.ts index cf5637a67..f4a01ab03 100644 --- a/packages/backend/src/core/entities/EmojiEntityService.ts +++ b/packages/backend/src/core/entities/EmojiEntityService.ts @@ -22,7 +22,7 @@ export class EmojiEntityService { src: Emoji['id'] | Emoji, opts: { omitHost?: boolean; omitId?: boolean; withUrl?: boolean; } = { omitHost: true, omitId: true, withUrl: true }, ): Promise> { - opts = { omitHost: true, omitId: true, withUrl: true, ...opts } + opts = { omitHost: true, omitId: true, withUrl: true, ...opts }; const emoji = typeof src === 'object' ? src : await this.emojisRepository.findOneByOrFail({ id: src }); diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts index f4bc568fd..c12ae9b82 100644 --- a/packages/backend/src/server/FileServerService.ts +++ b/packages/backend/src/server/FileServerService.ts @@ -395,7 +395,7 @@ export class FileServerService { state: 'remote', mime, ext, path, cleanup, - } + }; } catch (e) { cleanup(); throw e; @@ -429,7 +429,7 @@ export class FileServerService { url: file.uri, fileRole: isThumbnail ? 'thumbnail' : isWebpublic ? 'webpublic' : 'original', file, - } + }; } const path = this.internalStorageService.resolvePath(key); @@ -452,6 +452,6 @@ export class FileServerService { mime: file.type, ext: null, path, - } + }; } } diff --git a/packages/backend/src/server/api/endpoints/admin/ad/list.ts b/packages/backend/src/server/api/endpoints/admin/ad/list.ts index 905036c40..0b6d00605 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/list.ts @@ -31,7 +31,7 @@ export default class extends Endpoint { private queryService: QueryService, ) { super(meta, paramDef, async (ps, me) => { - const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId) + const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId); const ads = await query.take(ps.limit).getMany(); return ads; diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts index c1a60a277..c51e7fd1a 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/delete.ts @@ -57,7 +57,7 @@ export default class extends Endpoint { await this.db.queryResultCache!.remove(['meta_emojis']); this.globalEventService.publishBroadcastStream('emojiDeleted', { - emojis: [ await this.emojiEntityService.pack(emoji) ], + emojis: [await this.emojiEntityService.pack(emoji)], }); this.moderationLogService.insertModerationLog(me, 'deleteEmoji', { 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 22bedc710..af610ddf9 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts @@ -72,11 +72,11 @@ export default class extends Endpoint { if (emoji.name === ps.name) { this.globalEventService.publishBroadcastStream('emojiUpdated', { - emojis: [ updated ], + emojis: [updated], }); } else { this.globalEventService.publishBroadcastStream('emojiDeleted', { - emojis: [ await this.emojiEntityService.pack(emoji) ], + emojis: [await this.emojiEntityService.pack(emoji)], }); this.globalEventService.publishBroadcastStream('emojiAdded', { diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index 700921cd9..593444968 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -280,7 +280,7 @@ export default class extends Endpoint { files: files, poll: ps.poll ? { choices: ps.poll.choices, - multiple: ps.poll.multiple || false, + multiple: ps.poll.multiple ?? false, expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null, } : undefined, text: ps.text ?? undefined, From dd52be3a01fca4831cccb82d7fe1585cfbfd01cf Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Fri, 17 Feb 2023 02:57:40 +0100 Subject: [PATCH 39/92] ci: run typecheck and eslint separately (#9966) * ci: run typecheck and eslint separately * fix syntax --- .github/workflows/lint.yml | 5 ++++- packages/backend/package.json | 4 +++- packages/frontend/package.json | 4 +++- packages/sw/package.json | 4 +++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 6a579bffc..94d7d1371 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -36,6 +36,9 @@ jobs: - backend - frontend - sw + lint: + - typecheck + - eslint steps: - uses: actions/checkout@v3.3.0 with: @@ -51,4 +54,4 @@ jobs: cache: 'pnpm' - run: corepack enable - run: pnpm i --frozen-lockfile - - run: pnpm --filter ${{ matrix.workspace }} run lint + - run: pnpm --filter ${{ matrix.workspace }} run ${{ matrix.lint }} diff --git a/packages/backend/package.json b/packages/backend/package.json index 90acaac75..52b0d74ad 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -11,7 +11,9 @@ "watch:swc": "swc src -d built -D -w", "build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json", "watch": "node watch.mjs", - "lint": "tsc --noEmit && eslint --quiet \"src/**/*.ts\"", + "typecheck": "tsc --noEmit", + "eslint": "eslint --quiet \"src/**/*.ts\"", + "lint": "pnpm typecheck && pnpm eslint", "jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --runInBand", "jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --runInBand", "jest-clear": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --clearCache", diff --git a/packages/frontend/package.json b/packages/frontend/package.json index bf22f7aaa..61c0135ba 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -4,7 +4,9 @@ "scripts": { "watch": "vite", "build": "vite build", - "lint": "vue-tsc --noEmit && eslint --quiet \"src/**/*.{ts,vue}\"" + "typecheck": "vue-tsc --noEmit", + "eslint": "eslint --quiet \"src/**/*.{ts,vue}\"", + "lint": "pnpm typecheck && pnpm eslint" }, "dependencies": { "@discordapp/twemoji": "14.0.2", diff --git a/packages/sw/package.json b/packages/sw/package.json index 8650f9597..4de260fcf 100644 --- a/packages/sw/package.json +++ b/packages/sw/package.json @@ -4,7 +4,9 @@ "scripts": { "watch": "node build.js watch", "build": "node build.js", - "lint": "tsc --noEmit && eslint --quiet src/**/*.ts" + "typecheck": "tsc --noEmit", + "eslint": "eslint --quiet src/**/*.ts", + "lint": "pnpm typecheck && pnpm eslint" }, "dependencies": { "esbuild": "0.14.42", From e8c5307f669e0ff45b71e65384a182237a7a9ccd Mon Sep 17 00:00:00 2001 From: tamaina Date: Fri, 17 Feb 2023 12:38:30 +0900 Subject: [PATCH 40/92] =?UTF-8?q?perf(client):=20=E3=82=A6=E3=82=A7?= =?UTF-8?q?=E3=83=AB=E3=82=AB=E3=83=A0=E3=83=9A=E3=83=BC=E3=82=B8=E3=82=92?= =?UTF-8?q?=E6=9C=80=E9=81=A9=E5=8C=96=20(#9960)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf(client): ウェルカムページの最適化 * remove max --- .../api/endpoints/federation/instances.ts | 2 + .../server/api/endpoints/notes/featured.ts | 5 +- .../frontend/src/pages/welcome.entrance.a.vue | 30 ++--- .../frontend/src/pages/welcome.timeline.vue | 104 ++++++++---------- 4 files changed, 60 insertions(+), 81 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index e5d1df001..60b24e958 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -10,6 +10,8 @@ export const meta = { tags: ['federation'], requireCredential: false, + allowGet: true, + cacheSec: 3600, res: { type: 'array', diff --git a/packages/backend/src/server/api/endpoints/notes/featured.ts b/packages/backend/src/server/api/endpoints/notes/featured.ts index 76834cfde..8eff8fdb2 100644 --- a/packages/backend/src/server/api/endpoints/notes/featured.ts +++ b/packages/backend/src/server/api/endpoints/notes/featured.ts @@ -9,6 +9,8 @@ export const meta = { tags: ['notes'], requireCredential: false, + allowGet: true, + cacheSec: 3600, res: { type: 'array', @@ -41,7 +43,6 @@ export default class extends Endpoint { private queryService: QueryService, ) { super(meta, paramDef, async (ps, me) => { - const max = 30; const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで const query = this.notesRepository.createQueryBuilder('note') @@ -67,7 +68,7 @@ export default class extends Endpoint { let notes = await query .orderBy('note.score', 'DESC') - .take(max) + .take(ps.limit) .getMany(); notes.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()); diff --git a/packages/frontend/src/pages/welcome.entrance.a.vue b/packages/frontend/src/pages/welcome.entrance.a.vue index f43860319..05c55fdf3 100644 --- a/packages/frontend/src/pages/welcome.entrance.a.vue +++ b/packages/frontend/src/pages/welcome.entrance.a.vue @@ -32,7 +32,7 @@
-
+
@@ -56,33 +56,16 @@ import MkFeaturedPhotos from '@/components/MkFeaturedPhotos.vue'; import { instanceName } from '@/config'; import * as os from '@/os'; import { i18n } from '@/i18n'; +import { Instance } from 'misskey-js/built/entities'; -let meta = $ref(); -let stats = $ref(); -let tags = $ref(); -let onlineUsersCount = $ref(); -let instances = $ref(); +let meta = $ref(); +let instances = $ref(); os.api('meta', { detail: true }).then(_meta => { meta = _meta; }); -os.api('stats').then(_stats => { - stats = _stats; -}); - -os.api('get-online-users-count').then(res => { - onlineUsersCount = res.count; -}); - -os.api('hashtags/list', { - sort: '+mentionedLocalUsers', - limit: 8, -}).then(_tags => { - tags = _tags; -}); - -os.api('federation/instances', { +os.apiGet('federation/instances', { sort: '+pubSub', limit: 20, }).then(_instances => { @@ -147,8 +130,9 @@ function showMenu(ev) { bottom: 0; right: 64px; margin: auto; + padding: 128px 0; width: 500px; - height: calc(100% - 128px); + height: calc(100% - 256px); overflow: hidden; -webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 128px, rgba(0,0,0,1) calc(100% - 128px), rgba(0,0,0,0) 100%); mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 128px, rgba(0,0,0,1) calc(100% - 128px), rgba(0,0,0,0) 100%); diff --git a/packages/frontend/src/pages/welcome.timeline.vue b/packages/frontend/src/pages/welcome.timeline.vue index ed3c5a4af..c34d43dc1 100644 --- a/packages/frontend/src/pages/welcome.timeline.vue +++ b/packages/frontend/src/pages/welcome.timeline.vue @@ -1,62 +1,54 @@ - - From 14cff15c898fcead49de8e9688d166f2d7e567b5 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 17 Feb 2023 14:57:05 +0900 Subject: [PATCH 41/92] enhance(client): add quiz preset for play --- .../frontend/src/pages/flash/flash-edit.vue | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/packages/frontend/src/pages/flash/flash-edit.vue b/packages/frontend/src/pages/flash/flash-edit.vue index f8435c48f..2b7fcf74e 100644 --- a/packages/frontend/src/pages/flash/flash-edit.vue +++ b/packages/frontend/src/pages/flash/flash-edit.vue @@ -173,6 +173,119 @@ var cursor = 0 do() `; +const PRESET_QUIZ = `/// @ 0.12.4 +let title = '地理クイズ' + +let qas = [{ + q: 'オーストラリアの首都は?' + choices: ['シドニー' 'キャンベラ' 'メルボルン'] + a: 'キャンベラ' + aDescription: '最大の都市はシドニーですが首都はキャンベラです。' +} { + q: '国土面積2番目の国は?' + choices: ['カナダ' 'アメリカ' '中国'] + a: 'カナダ' + aDescription: '大きい順にロシア、カナダ、アメリカ、中国です。' +} { + q: '二重内陸国ではないのは?' + choices: ['リヒテンシュタイン' 'ウズベキスタン' 'レソト'] + a: 'レソト' + aDescription: 'レソトは(一重)内陸国です。' +} { + q: '閘門がない運河は?' + choices: ['キール運河' 'スエズ運河' 'パナマ運河'] + a: 'スエズ運河' + aDescription: 'スエズ運河は高低差がないので閘門はありません。' +}] + +let qaEls = [Ui:C:container({ + align: 'center' + children: [ + Ui:C:text({ + size: 1.5 + bold: true + text: title + }) + ] +})] + +var qn = 0 +each (let qa, qas) { + qn += 1 + qa.id = Util:uuid() + qaEls.push(Ui:C:container({ + align: 'center' + bgColor: '#000' + fgColor: '#fff' + padding: 16 + rounded: true + children: [ + Ui:C:text({ + text: \`Q{qn} {qa.q}\` + }) + Ui:C:select({ + items: qa.choices.map(@(c) {{ text: c, value: c }}) + onChange: @(v) { qa.userAnswer = v } + }) + Ui:C:container({ + children: [] + } \`{qa.id}:a\`) + ] + } qa.id)) +} + +@finish() { + var score = 0 + + each (let qa, qas) { + let correct = qa.userAnswer == qa.a + if (correct) score += 1 + let el = Ui:get(\`{qa.id}:a\`) + el.update({ + children: [ + Ui:C:text({ + size: 1.2 + bold: true + color: if (correct) '#f00' else '#00f' + text: if (correct) '🎉正解' else '不正解' + }) + Ui:C:text({ + text: qa.aDescription + }) + ] + }) + } + + let result = \`{title}の結果は{qas.len}問中{score}問正解でした。\` + Ui:get('footer').update({ + children: [ + Ui:C:postFormButton({ + text: '結果を共有' + rounded: true + primary: true + form: { + text: \`{result}{Str:lf}{THIS_URL}\` + } + }) + ] + }) +} + +qaEls.push(Ui:C:container({ + align: 'center' + children: [ + Ui:C:button({ + text: '答え合わせ' + primary: true + rounded: true + onClick: finish + }) + ] +} 'footer')) + +Ui:render(qaEls) +`; + const PRESET_TIMELINE = `/// @ 0.12.4 // APIリクエストを行いローカルタイムラインを表示するプリセット @@ -258,6 +371,11 @@ function selectPreset(ev: MouseEvent) { action: () => { script = PRESET_SHUFFLE; }, + }, { + text: 'Quiz', + action: () => { + script = PRESET_QUIZ; + }, }, { text: 'Timeline viewer', action: () => { From d4eb1def61ba1cf465fcaa528aaa600cac180f1d Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 17 Feb 2023 14:59:11 +0900 Subject: [PATCH 42/92] =?UTF-8?q?fix(client):=20MkHeader=E5=8F=8A=E3=81=B3?= =?UTF-8?q?=E3=83=87=E3=83=83=E3=82=AD=E3=81=AE=E3=82=AB=E3=83=A9=E3=83=A0?= =?UTF-8?q?=E3=81=A7=E3=83=81=E3=83=A3=E3=83=B3=E3=83=8D=E3=83=AB=E4=B8=80?= =?UTF-8?q?=E8=A6=A7=E3=82=92=E9=81=B8=E6=8A=9E=E3=81=97=E3=81=9F=E3=81=A8?= =?UTF-8?q?=E3=81=8D=E3=80=81=E6=9C=80=E5=A4=A75=E5=80=8B=E3=81=BE?= =?UTF-8?q?=E3=81=A7=E3=81=97=E3=81=8B=E8=A1=A8=E7=A4=BA=E3=81=95=E3=82=8C?= =?UTF-8?q?=E3=81=AA=E3=81=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #9904 --- packages/frontend/src/pages/timeline.vue | 6 ++++-- packages/frontend/src/ui/deck/channel-column.vue | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index a07136115..f9ad609f5 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -23,6 +23,7 @@ + + diff --git a/packages/frontend/src/pages/settings/2fa.vue b/packages/frontend/src/pages/settings/2fa.vue index e6ef09668..891934d70 100644 --- a/packages/frontend/src/pages/settings/2fa.vue +++ b/packages/frontend/src/pages/settings/2fa.vue @@ -1,216 +1,258 @@ diff --git a/packages/frontend/src/pages/settings/security.vue b/packages/frontend/src/pages/settings/security.vue index b09c4ffd2..0cc2df09c 100644 --- a/packages/frontend/src/pages/settings/security.vue +++ b/packages/frontend/src/pages/settings/security.vue @@ -5,11 +5,8 @@ {{ i18n.ts.changePassword }} - - - - - + + @@ -56,18 +53,21 @@ async function change() { const { canceled: canceled1, result: currentPassword } = await os.inputText({ title: i18n.ts.currentPassword, type: 'password', + autocomplete: 'current-password', }); if (canceled1) return; const { canceled: canceled2, result: newPassword } = await os.inputText({ title: i18n.ts.newPassword, type: 'password', + autocomplete: 'new-password', }); if (canceled2) return; const { canceled: canceled3, result: newPassword2 } = await os.inputText({ title: i18n.ts.newPasswordRetype, type: 'password', + autocomplete: 'new-password', }); if (canceled3) return; @@ -109,7 +109,7 @@ definePageMetadata({