diff --git a/CHANGELOG.md b/CHANGELOG.md index 2454a3b609..ff0a0e6b60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ --> +## 12.x.x (unreleased) + +### Improvements +- リモートユーザーのDeleteアクティビティに対応 + +### Bugfixes + +## 12.90.1 (2021/09/05) + +### Bugfixes +- Dockerfileを修正 +- ノート翻訳時に公開範囲が考慮されていない問題を修正 + ## 12.90.0 (2021/09/04) ### Improvements diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index e22f50668f..b9623ef0d0 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1150,6 +1150,10 @@ _permissions: "write:user-groups": "ユーザーグループを操作する" "read:channels": "チャンネルを見る" "write:channels": "チャンネルを操作する" + "read:gallery": "ギャラリーを見る" + "write:gallery": "ギャラリーを操作する" + "read:gallery-likes": "ギャラリーのいいねを見る" + "write:gallery-likes": "ギャラリーのいいねを操作する" _auth: shareAccess: "「{name}」がアカウントにアクセスすることを許可しますか?" diff --git a/package.json b/package.json index 0f93ae03e9..ab24a1c7ec 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "misskey", "author": "syuilo ", - "version": "12.90.0", + "version": "12.90.1", "codename": "indigo", "repository": { "type": "git", diff --git a/src/misc/api-permissions.ts b/src/misc/api-permissions.ts index eb20c3d289..160cdf9fd6 100644 --- a/src/misc/api-permissions.ts +++ b/src/misc/api-permissions.ts @@ -32,3 +32,4 @@ export const kinds = [ 'read:gallery-likes', 'write:gallery-likes', ]; +// IF YOU ADD KINDS(PERMISSIONS), YOU MUST ADD TRANSLATIONS (under _permissions). diff --git a/src/models/repositories/note.ts b/src/models/repositories/note.ts index a8e356abf2..9e0f5e55f0 100644 --- a/src/models/repositories/note.ts +++ b/src/models/repositories/note.ts @@ -18,7 +18,57 @@ export class NoteRepository extends Repository { return x.trim().length <= 100; } + public async isVisibleForMe(note: Note, meId: User['id'] | null): Promise { + // visibility が specified かつ自分が指定されていなかったら非表示 + if (note.visibility === 'specified') { + if (meId == null) { + return false; + } else if (meId === note.userId) { + return true; + } else { + // 指定されているかどうか + const specified = note.visibleUserIds.some((id: any) => meId === id); + + if (specified) { + return true; + } else { + return false; + } + } + } + + // visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示 + if (note.visibility === 'followers') { + if (meId == null) { + return false; + } else if (meId === note.userId) { + return true; + } else if (note.reply && (meId === note.reply.userId)) { + // 自分の投稿に対するリプライ + return true; + } else if (note.mentions && note.mentions.some(id => meId === id)) { + // 自分へのメンション + return true; + } else { + // フォロワーかどうか + const following = await Followings.findOne({ + followeeId: note.userId, + followerId: meId + }); + + if (following == null) { + return false; + } else { + return true; + } + } + } + + return true; + } + private async hideNote(packedNote: PackedNote, meId: User['id'] | null) { + // TODO: isVisibleForMe を使うようにしても良さそう(型違うけど) let hide = false; // visibility が specified かつ自分が指定されていなかったら非表示 diff --git a/src/models/repositories/notification.ts b/src/models/repositories/notification.ts index 55af96b6d7..4d13940c76 100644 --- a/src/models/repositories/notification.ts +++ b/src/models/repositories/notification.ts @@ -7,6 +7,7 @@ import { Note } from '@/models/entities/note'; import { NoteReaction } from '@/models/entities/note-reaction'; import { User } from '@/models/entities/user'; import { aggregateNoteEmojis, prefetchEmojis } from '@/misc/populate-emojis'; +import { notificationTypes } from '@/types'; export type PackedNotification = SchemaType; @@ -124,20 +125,41 @@ export const packedNotificationSchema = { optional: false as const, nullable: false as const, format: 'date-time', }, + isRead: { + type: 'boolean' as const, + optional: false as const, nullable: false as const, + }, type: { type: 'string' as const, optional: false as const, nullable: false as const, - enum: ['follow', 'followRequestAccepted', 'receiveFollowRequest', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote'], - }, - userId: { - type: 'string' as const, - optional: true as const, nullable: true as const, - format: 'id', + enum: [...notificationTypes], }, user: { type: 'object' as const, ref: 'User', optional: true as const, nullable: true as const, }, + userId: { + type: 'string' as const, + optional: true as const, nullable: true as const, + format: 'id', + }, + note: { + type: 'object' as const, + ref: 'Note', + optional: true as const, nullable: true as const, + }, + reaction: { + type: 'string' as const, + optional: true as const, nullable: true as const, + }, + body: { + type: 'string' as const, + optional: true as const, nullable: true as const, + }, + icon: { + type: 'string' as const, + optional: true as const, nullable: true as const, + }, } }; diff --git a/src/remote/activitypub/kernel/delete/actor.ts b/src/remote/activitypub/kernel/delete/actor.ts new file mode 100644 index 0000000000..502f8d5ab5 --- /dev/null +++ b/src/remote/activitypub/kernel/delete/actor.ts @@ -0,0 +1,26 @@ +import { apLogger } from '../../logger'; +import { createDeleteAccountJob } from '@/queue'; +import { IRemoteUser } from '@/models/entities/user'; +import { Users } from '@/models/index'; + +const logger = apLogger; + +export async function deleteActor(actor: IRemoteUser, uri: string): Promise { + logger.info(`Deleting the Actor: ${uri}`); + + if (actor.uri !== uri) { + return `skip: delete actor ${actor.uri} !== ${uri}`; + } + + if (actor.isDeleted) { + logger.info(`skip: already deleted`); + } + + const job = await createDeleteAccountJob(actor); + + await Users.update(actor.id, { + isDeleted: true, + }); + + return `ok: queued ${job.name} ${job.id}`; +} diff --git a/src/remote/activitypub/kernel/delete/index.ts b/src/remote/activitypub/kernel/delete/index.ts index 474f3f6d60..86a452de76 100644 --- a/src/remote/activitypub/kernel/delete/index.ts +++ b/src/remote/activitypub/kernel/delete/index.ts @@ -2,6 +2,7 @@ import deleteNote from './note'; import { IRemoteUser } from '@/models/entities/user'; import { IDelete, getApId, isTombstone, IObject, validPost, validActor } from '../../type'; import { toSingle } from '@/prelude/array'; +import { deleteActor } from './actor'; /** * 削除アクティビティを捌きます @@ -41,7 +42,7 @@ export default async (actor: IRemoteUser, activity: IDelete): Promise => if (validPost.includes(formarType)) { return await deleteNote(actor, uri); } else if (validActor.includes(formarType)) { - return `Delete Actor is not implanted`; + return await deleteActor(actor, uri); } else { return `Unknown type ${formarType}`; } diff --git a/src/server/api/endpoints/notes/translate.ts b/src/server/api/endpoints/notes/translate.ts index e4bc6bb060..b56b1debdd 100644 --- a/src/server/api/endpoints/notes/translate.ts +++ b/src/server/api/endpoints/notes/translate.ts @@ -8,6 +8,7 @@ import config from '@/config/index'; import { getAgentByUrl } from '@/misc/fetch'; import { URLSearchParams } from 'url'; import { fetchMeta } from '@/misc/fetch-meta'; +import { Notes } from '@/models'; export const meta = { tags: ['notes'], @@ -43,6 +44,10 @@ export default define(meta, async (ps, user) => { throw e; }); + if (!(await Notes.isVisibleForMe(note, user ? user.id : null))) { + return 204; // TODO: 良い感じのエラー返す + } + if (note.text == null) { return 204; }