diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2021-07-20 12:11:07 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2021-07-20 12:11:07 +0900 |
| commit | acb92442058fa2458967425efb7324ab0646a335 (patch) | |
| tree | afc2ac62a7bbddce5756fc49f1caba9f7cba5407 /src/server/api | |
| parent | Merge branch 'develop' (diff) | |
| parent | 12.84.0 (diff) | |
| download | misskey-acb92442058fa2458967425efb7324ab0646a335.tar.gz misskey-acb92442058fa2458967425efb7324ab0646a335.tar.bz2 misskey-acb92442058fa2458967425efb7324ab0646a335.zip | |
Merge branch 'develop'
Diffstat (limited to 'src/server/api')
| -rw-r--r-- | src/server/api/api-handler.ts | 18 | ||||
| -rw-r--r-- | src/server/api/authenticate.ts | 24 | ||||
| -rw-r--r-- | src/server/api/common/read-notification.ts | 23 | ||||
| -rw-r--r-- | src/server/api/endpoints/admin/emoji/copy.ts | 9 | ||||
| -rw-r--r-- | src/server/api/endpoints/admin/suspend-user.ts | 6 | ||||
| -rw-r--r-- | src/server/api/endpoints/i/delete-account.ts | 4 | ||||
| -rw-r--r-- | src/server/api/endpoints/i/regenerate-token.ts | 7 | ||||
| -rw-r--r-- | src/server/api/endpoints/i/revoke-token.ts | 9 | ||||
| -rw-r--r-- | src/server/api/endpoints/pinned-users.ts | 2 | ||||
| -rw-r--r-- | src/server/api/limiter.ts | 2 | ||||
| -rw-r--r-- | src/server/api/private/signin.ts | 7 | ||||
| -rw-r--r-- | src/server/api/stream/channels/messaging.ts | 8 | ||||
| -rw-r--r-- | src/server/api/stream/index.ts | 5 | ||||
| -rw-r--r-- | src/server/api/streaming.ts | 5 |
14 files changed, 94 insertions, 35 deletions
diff --git a/src/server/api/api-handler.ts b/src/server/api/api-handler.ts index 80a4fd97c8..cbace8917e 100644 --- a/src/server/api/api-handler.ts +++ b/src/server/api/api-handler.ts @@ -1,7 +1,7 @@ import * as Koa from 'koa'; import { IEndpoint } from './endpoints'; -import authenticate from './authenticate'; +import authenticate, { AuthenticationError } from './authenticate'; import call from './call'; import { ApiError } from './error'; @@ -37,11 +37,15 @@ export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise((res) => { }).catch((e: ApiError) => { reply(e.httpStatusCode ? e.httpStatusCode : e.kind === 'client' ? 400 : 500, e); }); - }).catch(() => { - reply(403, new ApiError({ - message: 'Authentication failed. Please ensure your token is correct.', - code: 'AUTHENTICATION_FAILED', - id: 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14' - })); + }).catch(e => { + if (e instanceof AuthenticationError) { + reply(403, new ApiError({ + message: 'Authentication failed. Please ensure your token is correct.', + code: 'AUTHENTICATION_FAILED', + id: 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14' + })); + } else { + reply(500, new ApiError()); + } }); }); diff --git a/src/server/api/authenticate.ts b/src/server/api/authenticate.ts index 6ea5a111bc..6148ad33c5 100644 --- a/src/server/api/authenticate.ts +++ b/src/server/api/authenticate.ts @@ -2,36 +2,30 @@ import isNativeToken from './common/is-native-token'; import { User } from '../../models/entities/user'; import { Users, AccessTokens, Apps } from '../../models'; import { AccessToken } from '../../models/entities/access-token'; -import { Cache } from '@/misc/cache'; -// TODO: TypeORMのカスタムキャッシュプロバイダを使っても良いかも -// ref. https://github.com/typeorm/typeorm/blob/master/docs/caching.md -const cache = new Cache<User>(1000 * 60 * 60); +export class AuthenticationError extends Error { + constructor(message: string) { + super(message); + this.name = 'AuthenticationError'; + } +} -export default async (token: string): Promise<[User | null | undefined, AccessToken | null | undefined]> => { +export default async (token: string): Promise<[User | null | undefined, App | null | undefined]> => { if (token == null) { return [null, null]; } if (isNativeToken(token)) { - const cached = cache.get(token); - if (cached) { - return [cached, null]; - } - // Fetch user const user = await Users .findOne({ token }); if (user == null) { - throw new Error('user not found'); + throw new AuthenticationError('user not found'); } - cache.set(token, user); - return [user, null]; } else { - // TODO: cache const accessToken = await AccessTokens.findOne({ where: [{ hash: token.toLowerCase() // app @@ -41,7 +35,7 @@ export default async (token: string): Promise<[User | null | undefined, AccessTo }); if (accessToken == null) { - throw new Error('invalid signature'); + throw new AuthenticationError('invalid signature'); } AccessTokens.update(accessToken.id, { diff --git a/src/server/api/common/read-notification.ts b/src/server/api/common/read-notification.ts index f686446c5c..effa61e8b5 100644 --- a/src/server/api/common/read-notification.ts +++ b/src/server/api/common/read-notification.ts @@ -4,9 +4,6 @@ import { Notification } from '../../../models/entities/notification'; import { Notifications, Users } from '../../../models'; import { In } from 'typeorm'; -/** - * Mark notifications as read - */ export async function readNotification( userId: User['id'], notificationIds: Notification['id'][] @@ -19,6 +16,26 @@ export async function readNotification( isRead: true }); + post(userId); +} + +export async function readNotificationByQuery( + userId: User['id'], + query: Record<string, any> +) { + // Update documents + await Notifications.update({ + ...query, + notifieeId: userId, + isRead: false + }, { + isRead: true + }); + + post(userId); +} + +async function post(userId: User['id']) { if (!await Users.getHasUnreadNotification(userId)) { // 全ての(いままで未読だった)通知を(これで)読みましたよというイベントを発行 publishMainStream(userId, 'readAllNotifications'); diff --git a/src/server/api/endpoints/admin/emoji/copy.ts b/src/server/api/endpoints/admin/emoji/copy.ts index 1a784f4061..72c2b014a4 100644 --- a/src/server/api/endpoints/admin/emoji/copy.ts +++ b/src/server/api/endpoints/admin/emoji/copy.ts @@ -7,6 +7,7 @@ import { ApiError } from '../../../error'; import { DriveFile } from '../../../../../models/entities/drive-file'; import { ID } from '@/misc/cafy-id'; import uploadFromUrl from '../../../../../services/drive/upload-from-url'; +import { publishBroadcastStream } from '@/services/stream'; export const meta = { tags: ['admin'], @@ -57,7 +58,7 @@ export default define(meta, async (ps, me) => { throw new ApiError(); } - const copied = await Emojis.save({ + const copied = await Emojis.insert({ id: genId(), updatedAt: new Date(), name: emoji.name, @@ -66,10 +67,14 @@ export default define(meta, async (ps, me) => { url: driveFile.url, type: driveFile.type, fileId: driveFile.id, - }); + }).then(x => Emojis.findOneOrFail(x.identifiers[0])); await getConnection().queryResultCache!.remove(['meta_emojis']); + publishBroadcastStream('emojiAdded', { + emoji: await Emojis.pack(copied.id) + }); + return { id: copied.id }; diff --git a/src/server/api/endpoints/admin/suspend-user.ts b/src/server/api/endpoints/admin/suspend-user.ts index 9f3c8eb6f8..912d6a5162 100644 --- a/src/server/api/endpoints/admin/suspend-user.ts +++ b/src/server/api/endpoints/admin/suspend-user.ts @@ -6,6 +6,7 @@ import { Users, Followings, Notifications } from '../../../../models'; import { User } from '../../../../models/entities/user'; import { insertModerationLog } from '../../../../services/insert-moderation-log'; import { doPostSuspend } from '../../../../services/suspend-user'; +import { publishUserEvent } from '@/services/stream'; export const meta = { tags: ['admin'], @@ -43,6 +44,11 @@ export default define(meta, async (ps, me) => { targetId: user.id, }); + // Terminate streaming + if (Users.isLocalUser(user)) { + publishUserEvent(user.id, 'terminate', {}); + } + (async () => { await doPostSuspend(user).catch(e => {}); await unFollowAll(user).catch(e => {}); diff --git a/src/server/api/endpoints/i/delete-account.ts b/src/server/api/endpoints/i/delete-account.ts index 0f04c4c92d..f5f0f32a4a 100644 --- a/src/server/api/endpoints/i/delete-account.ts +++ b/src/server/api/endpoints/i/delete-account.ts @@ -3,6 +3,7 @@ import * as bcrypt from 'bcryptjs'; import define from '../../define'; import { Users, UserProfiles } from '../../../../models'; import { doPostSuspend } from '../../../../services/suspend-user'; +import { publishUserEvent } from '@/services/stream'; export const meta = { requireCredential: true as const, @@ -30,4 +31,7 @@ export default define(meta, async (ps, user) => { await doPostSuspend(user).catch(e => {}); await Users.delete(user.id); + + // Terminate streaming + publishUserEvent(user.id, 'terminate', {}); }); diff --git a/src/server/api/endpoints/i/regenerate-token.ts b/src/server/api/endpoints/i/regenerate-token.ts index 3596e20197..3665ed0532 100644 --- a/src/server/api/endpoints/i/regenerate-token.ts +++ b/src/server/api/endpoints/i/regenerate-token.ts @@ -1,6 +1,6 @@ import $ from 'cafy'; import * as bcrypt from 'bcryptjs'; -import { publishMainStream } from '../../../../services/stream'; +import { publishMainStream, publishUserEvent } from '../../../../services/stream'; import generateUserToken from '../../common/generate-native-user-token'; import define from '../../define'; import { Users, UserProfiles } from '../../../../models'; @@ -36,4 +36,9 @@ export default define(meta, async (ps, user) => { // Publish event publishMainStream(user.id, 'myTokenRegenerated'); + + // Terminate streaming + setTimeout(() => { + publishUserEvent(user.id, 'terminate', {}); + }, 5000); }); diff --git a/src/server/api/endpoints/i/revoke-token.ts b/src/server/api/endpoints/i/revoke-token.ts index d71a1bd135..d22d9ca693 100644 --- a/src/server/api/endpoints/i/revoke-token.ts +++ b/src/server/api/endpoints/i/revoke-token.ts @@ -2,6 +2,7 @@ import $ from 'cafy'; import define from '../../define'; import { AccessTokens } from '../../../../models'; import { ID } from '@/misc/cafy-id'; +import { publishUserEvent } from '@/services/stream'; export const meta = { requireCredential: true as const, @@ -19,6 +20,12 @@ export default define(meta, async (ps, user) => { const token = await AccessTokens.findOne(ps.tokenId); if (token) { - AccessTokens.delete(token.id); + await AccessTokens.delete({ + id: ps.tokenId, + userId: user.id, + }); + + // Terminate streaming + publishUserEvent(user.id, 'terminate'); } }); diff --git a/src/server/api/endpoints/pinned-users.ts b/src/server/api/endpoints/pinned-users.ts index ae165ab46d..bcef072fed 100644 --- a/src/server/api/endpoints/pinned-users.ts +++ b/src/server/api/endpoints/pinned-users.ts @@ -1,7 +1,7 @@ import define from '../define'; import { Users } from '../../../models'; import { fetchMeta } from '@/misc/fetch-meta'; -import parseAcct from '@/misc/acct/parse'; +import { parseAcct } from '@/misc/acct'; import { User } from '../../../models/entities/user'; export const meta = { diff --git a/src/server/api/limiter.ts b/src/server/api/limiter.ts index 1e8715a7c4..540ca24994 100644 --- a/src/server/api/limiter.ts +++ b/src/server/api/limiter.ts @@ -1,7 +1,7 @@ import * as Limiter from 'ratelimiter'; import { redisClient } from '../../db/redis'; import { IEndpoint } from './endpoints'; -import getAcct from '@/misc/acct/render'; +import { getAcct } from '@/misc/acct'; import { User } from '../../models/entities/user'; import Logger from '../../services/logger'; diff --git a/src/server/api/private/signin.ts b/src/server/api/private/signin.ts index 0a17b0bd02..c01c1f265a 100644 --- a/src/server/api/private/signin.ts +++ b/src/server/api/private/signin.ts @@ -46,6 +46,13 @@ export default async (ctx: Koa.Context) => { return; } + if (user.isSuspended) { + ctx.throw(403, { + error: 'user is suspended' + }); + return; + } + const profile = await UserProfiles.findOneOrFail(user.id); // Compare password diff --git a/src/server/api/stream/channels/messaging.ts b/src/server/api/stream/channels/messaging.ts index 4c41dc820b..58427e2771 100644 --- a/src/server/api/stream/channels/messaging.ts +++ b/src/server/api/stream/channels/messaging.ts @@ -10,7 +10,7 @@ export default class extends Channel { public static requireCredential = true; private otherpartyId: string | null; - private otherparty?: User; + private otherparty: User | null; private groupId: string | null; private subCh: string; private typers: Record<User['id'], Date> = {}; @@ -18,9 +18,9 @@ export default class extends Channel { @autobind public async init(params: any) { - this.otherpartyId = params.otherparty as string; - this.otherparty = await Users.findOne({ id: this.otherpartyId }); - this.groupId = params.group as string; + this.otherpartyId = params.otherparty; + this.otherparty = this.otherpartyId ? await Users.findOneOrFail({ id: this.otherpartyId }) : null; + this.groupId = params.group; // Check joining if (this.groupId) { diff --git a/src/server/api/stream/index.ts b/src/server/api/stream/index.ts index 647b890ff8..75d82cfe66 100644 --- a/src/server/api/stream/index.ts +++ b/src/server/api/stream/index.ts @@ -92,6 +92,11 @@ export default class Connection { this.userProfile = body; break; + case 'terminate': + this.wsConnection.close(); + this.dispose(); + break; + default: break; } diff --git a/src/server/api/streaming.ts b/src/server/api/streaming.ts index 57e8c90860..b431bc5ad3 100644 --- a/src/server/api/streaming.ts +++ b/src/server/api/streaming.ts @@ -22,6 +22,11 @@ module.exports = (server: http.Server) => { // (現状はエラーがキャッチされておらずサーバーのログに流れて邪魔なので) const [user, app] = await authenticate(q.i as string); + if (user?.isSuspended) { + request.reject(400); + return; + } + const connection = request.accept(); const ev = new EventEmitter(); |