summaryrefslogtreecommitdiff
path: root/src/server/api
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2021-07-20 12:11:07 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2021-07-20 12:11:07 +0900
commitacb92442058fa2458967425efb7324ab0646a335 (patch)
treeafc2ac62a7bbddce5756fc49f1caba9f7cba5407 /src/server/api
parentMerge branch 'develop' (diff)
parent12.84.0 (diff)
downloadmisskey-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.ts18
-rw-r--r--src/server/api/authenticate.ts24
-rw-r--r--src/server/api/common/read-notification.ts23
-rw-r--r--src/server/api/endpoints/admin/emoji/copy.ts9
-rw-r--r--src/server/api/endpoints/admin/suspend-user.ts6
-rw-r--r--src/server/api/endpoints/i/delete-account.ts4
-rw-r--r--src/server/api/endpoints/i/regenerate-token.ts7
-rw-r--r--src/server/api/endpoints/i/revoke-token.ts9
-rw-r--r--src/server/api/endpoints/pinned-users.ts2
-rw-r--r--src/server/api/limiter.ts2
-rw-r--r--src/server/api/private/signin.ts7
-rw-r--r--src/server/api/stream/channels/messaging.ts8
-rw-r--r--src/server/api/stream/index.ts5
-rw-r--r--src/server/api/streaming.ts5
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();