summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src/server/api')
-rw-r--r--packages/backend/src/server/api/ApiCallService.ts89
-rw-r--r--packages/backend/src/server/api/AuthenticateService.ts16
-rw-r--r--packages/backend/src/server/api/EndpointsModule.ts28
-rw-r--r--packages/backend/src/server/api/RateLimiterService.ts20
-rw-r--r--packages/backend/src/server/api/SigninService.ts2
-rw-r--r--packages/backend/src/server/api/SignupApiService.ts76
-rw-r--r--packages/backend/src/server/api/StreamingApiServerService.ts32
-rw-r--r--packages/backend/src/server/api/endpoint-base.ts14
-rw-r--r--packages/backend/src/server/api/endpoints.ts14
-rw-r--r--packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/ad/create.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/admin/ad/list.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/ad/update.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/admin/announcements/list.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/announcements/update.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/drive/files.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/emoji/add.ts7
-rw-r--r--packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/emoji/list.ts8
-rw-r--r--packages/backend/src/server/api/endpoints/admin/emoji/update.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/invite/create.ts80
-rw-r--r--packages/backend/src/server/api/endpoints/admin/invite/list.ts70
-rw-r--r--packages/backend/src/server/api/endpoints/admin/meta.ts16
-rw-r--r--packages/backend/src/server/api/endpoints/admin/promo/create.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/admin/queue/promote.ts26
-rw-r--r--packages/backend/src/server/api/endpoints/admin/reset-password.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/admin/roles/update.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/admin/roles/users.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/show-user.ts6
-rw-r--r--packages/backend/src/server/api/endpoints/admin/show-users.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/admin/update-meta.ts17
-rw-r--r--packages/backend/src/server/api/endpoints/announcements.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/antennas/notes.ts10
-rw-r--r--packages/backend/src/server/api/endpoints/antennas/update.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/app/create.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/auth/accept.ts12
-rw-r--r--packages/backend/src/server/api/endpoints/auth/session/generate.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/blocking/create.ts10
-rw-r--r--packages/backend/src/server/api/endpoints/blocking/delete.ts12
-rw-r--r--packages/backend/src/server/api/endpoints/blocking/list.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/channels/featured.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/channels/followed.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/channels/owned.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/channels/search.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/channels/timeline.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/clips/add-note.ts10
-rw-r--r--packages/backend/src/server/api/endpoints/clips/favorite.ts10
-rw-r--r--packages/backend/src/server/api/endpoints/clips/notes.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/clips/remove-note.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/drive/files.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/drive/files/check-existence.ts10
-rw-r--r--packages/backend/src/server/api/endpoints/drive/files/update.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/drive/folders.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/drive/stream.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/emoji.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/emojis.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/federation/followers.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/federation/following.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/federation/instances.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/federation/users.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/flash/featured.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/flash/like.ts10
-rw-r--r--packages/backend/src/server/api/endpoints/flash/my-likes.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/flash/my.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/following/create.ts10
-rw-r--r--packages/backend/src/server/api/endpoints/following/delete.ts12
-rw-r--r--packages/backend/src/server/api/endpoints/following/invalidate.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/following/requests/list.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/gallery/featured.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/gallery/popular.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/gallery/posts.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/gallery/posts/like.ts10
-rw-r--r--packages/backend/src/server/api/endpoints/get-online-users-count.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/hashtags/list.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/hashtags/search.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/hashtags/trend.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/hashtags/users.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/i.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/i/2fa/key-done.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/2fa/update-key.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/favorites.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/gallery/likes.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/gallery/posts.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/import-antennas.ts8
-rw-r--r--packages/backend/src/server/api/endpoints/i/import-blocking.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/import-following.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/import-muting.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/import-user-lists.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/page-likes.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/pages.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/read-announcement.ts14
-rw-r--r--packages/backend/src/server/api/endpoints/i/revoke-token.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/i/signin-history.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/i/update-email.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/invite/create.ts82
-rw-r--r--packages/backend/src/server/api/endpoints/invite/delete.ts71
-rw-r--r--packages/backend/src/server/api/endpoints/invite/limit.ts (renamed from packages/backend/src/server/api/endpoints/invite.ts)31
-rw-r--r--packages/backend/src/server/api/endpoints/invite/list.ts58
-rw-r--r--packages/backend/src/server/api/endpoints/meta.ts25
-rw-r--r--packages/backend/src/server/api/endpoints/miauth/gen-token.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/mute/create.ts10
-rw-r--r--packages/backend/src/server/api/endpoints/mute/list.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes.ts18
-rw-r--r--packages/backend/src/server/api/endpoints/notes/children.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/conversation.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/create.ts20
-rw-r--r--packages/backend/src/server/api/endpoints/notes/favorites/create.ts10
-rw-r--r--packages/backend/src/server/api/endpoints/notes/featured.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/global-timeline.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/local-timeline.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/mentions.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/renotes.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/replies.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/search-by-tag.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/search.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/notes/show.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/timeline.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/translate.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/unrenote.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/pages/featured.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/pages/like.ts10
-rw-r--r--packages/backend/src/server/api/endpoints/promo/read.ts12
-rw-r--r--packages/backend/src/server/api/endpoints/renote-mute/list.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/request-reset-password.ts6
-rw-r--r--packages/backend/src/server/api/endpoints/roles/notes.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/roles/users.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/server-info.ts19
-rw-r--r--packages/backend/src/server/api/endpoints/sw/update-registration.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/users.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/users/clips.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/users/followers.ts12
-rw-r--r--packages/backend/src/server/api/endpoints/users/following.ts12
-rw-r--r--packages/backend/src/server/api/endpoints/users/gallery/posts.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts32
-rw-r--r--packages/backend/src/server/api/endpoints/users/lists/favorite.ts20
-rw-r--r--packages/backend/src/server/api/endpoints/users/lists/push.ts18
-rw-r--r--packages/backend/src/server/api/endpoints/users/lists/show.ts10
-rw-r--r--packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts10
-rw-r--r--packages/backend/src/server/api/endpoints/users/notes.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/users/pages.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/users/reactions.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/users/recommendation.ts4
-rw-r--r--packages/backend/src/server/api/endpoints/users/report-abuse.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts6
-rw-r--r--packages/backend/src/server/api/endpoints/users/search.ts9
-rw-r--r--packages/backend/src/server/api/endpoints/users/show.ts1
-rw-r--r--packages/backend/src/server/api/stream/ChannelsService.ts2
-rw-r--r--packages/backend/src/server/api/stream/channel.ts2
-rw-r--r--packages/backend/src/server/api/stream/channels/hashtag.ts2
-rw-r--r--packages/backend/src/server/api/stream/channels/home-timeline.ts2
-rw-r--r--packages/backend/src/server/api/stream/channels/role-timeline.ts4
-rw-r--r--packages/backend/src/server/api/stream/channels/user-list.ts12
-rw-r--r--packages/backend/src/server/api/stream/types.ts4
158 files changed, 1013 insertions, 398 deletions
diff --git a/packages/backend/src/server/api/ApiCallService.ts b/packages/backend/src/server/api/ApiCallService.ts
index dad1a4132a..c4c02e7afe 100644
--- a/packages/backend/src/server/api/ApiCallService.ts
+++ b/packages/backend/src/server/api/ApiCallService.ts
@@ -1,8 +1,8 @@
+import { randomUUID } from 'node:crypto';
import { pipeline } from 'node:stream';
import * as fs from 'node:fs';
import { promisify } from 'node:util';
import { Inject, Injectable } from '@nestjs/common';
-import { v4 as uuid } from 'uuid';
import { DI } from '@/di-symbols.js';
import { getIpHash } from '@/misc/get-ip-hash.js';
import type { LocalUser, User } from '@/models/entities/User.js';
@@ -53,44 +53,72 @@ export class ApiCallService implements OnApplicationShutdown {
}, 1000 * 60 * 60);
}
+ #sendApiError(reply: FastifyReply, err: ApiError): void {
+ let statusCode = err.httpStatusCode;
+ if (err.httpStatusCode === 401) {
+ reply.header('WWW-Authenticate', 'Bearer realm="Misskey"');
+ } else if (err.kind === 'client') {
+ reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="invalid_request", error_description="${err.message}"`);
+ statusCode = statusCode ?? 400;
+ } else if (err.kind === 'permission') {
+ // (ROLE_PERMISSION_DENIEDは関係ない)
+ if (err.code === 'PERMISSION_DENIED') {
+ reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="insufficient_scope", error_description="${err.message}"`);
+ }
+ statusCode = statusCode ?? 403;
+ } else if (!statusCode) {
+ statusCode = 500;
+ }
+ this.send(reply, statusCode, err);
+ }
+
+ #sendAuthenticationError(reply: FastifyReply, err: unknown): void {
+ if (err instanceof AuthenticationError) {
+ const message = 'Authentication failed. Please ensure your token is correct.';
+ reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="invalid_token", error_description="${message}"`);
+ this.send(reply, 401, new ApiError({
+ message: 'Authentication failed. Please ensure your token is correct.',
+ code: 'AUTHENTICATION_FAILED',
+ id: 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14',
+ }));
+ } else {
+ this.send(reply, 500, new ApiError());
+ }
+ }
+
@bindThis
public handleRequest(
endpoint: IEndpoint & { exec: any },
request: FastifyRequest<{ Body: Record<string, unknown> | undefined, Querystring: Record<string, unknown> }>,
reply: FastifyReply,
- ) {
+ ): void {
const body = request.method === 'GET'
? request.query
: request.body;
- const token = body?.['i'];
+ // https://datatracker.ietf.org/doc/html/rfc6750.html#section-2.1 (case sensitive)
+ const token = request.headers.authorization?.startsWith('Bearer ')
+ ? request.headers.authorization.slice(7)
+ : body?.['i'];
if (token != null && typeof token !== 'string') {
reply.code(400);
return;
}
this.authenticateService.authenticate(token).then(([user, app]) => {
this.call(endpoint, user, app, body, null, request).then((res) => {
- if (request.method === 'GET' && endpoint.meta.cacheSec && !body?.['i'] && !user) {
+ if (request.method === 'GET' && endpoint.meta.cacheSec && !token && !user) {
reply.header('Cache-Control', `public, max-age=${endpoint.meta.cacheSec}`);
}
this.send(reply, res);
}).catch((err: ApiError) => {
- this.send(reply, err.httpStatusCode ? err.httpStatusCode : err.kind === 'client' ? 400 : err.kind === 'permission' ? 403 : 500, err);
+ this.#sendApiError(reply, err);
});
if (user) {
this.logIp(request, user);
}
}).catch(err => {
- if (err instanceof AuthenticationError) {
- this.send(reply, 403, new ApiError({
- message: 'Authentication failed. Please ensure your token is correct.',
- code: 'AUTHENTICATION_FAILED',
- id: 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14',
- }));
- } else {
- this.send(reply, 500, new ApiError());
- }
+ this.#sendAuthenticationError(reply, err);
});
}
@@ -99,7 +127,7 @@ export class ApiCallService implements OnApplicationShutdown {
endpoint: IEndpoint & { exec: any },
request: FastifyRequest<{ Body: Record<string, unknown>, Querystring: Record<string, unknown> }>,
reply: FastifyReply,
- ) {
+ ): Promise<void> {
const multipartData = await request.file().catch(() => {
/* Fastify throws if the remote didn't send multipart data. Return 400 below. */
});
@@ -117,7 +145,10 @@ export class ApiCallService implements OnApplicationShutdown {
fields[k] = typeof v === 'object' && 'value' in v ? v.value : undefined;
}
- const token = fields['i'];
+ // https://datatracker.ietf.org/doc/html/rfc6750.html#section-2.1 (case sensitive)
+ const token = request.headers.authorization?.startsWith('Bearer ')
+ ? request.headers.authorization.slice(7)
+ : fields['i'];
if (token != null && typeof token !== 'string') {
reply.code(400);
return;
@@ -129,22 +160,14 @@ export class ApiCallService implements OnApplicationShutdown {
}, request).then((res) => {
this.send(reply, res);
}).catch((err: ApiError) => {
- this.send(reply, err.httpStatusCode ? err.httpStatusCode : err.kind === 'client' ? 400 : err.kind === 'permission' ? 403 : 500, err);
+ this.#sendApiError(reply, err);
});
if (user) {
this.logIp(request, user);
}
}).catch(err => {
- if (err instanceof AuthenticationError) {
- this.send(reply, 403, new ApiError({
- message: 'Authentication failed. Please ensure your token is correct.',
- code: 'AUTHENTICATION_FAILED',
- id: 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14',
- }));
- } else {
- this.send(reply, 500, new ApiError());
- }
+ this.#sendAuthenticationError(reply, err);
});
}
@@ -213,7 +236,7 @@ export class ApiCallService implements OnApplicationShutdown {
}
if (ep.meta.limit) {
- // koa will automatically load the `X-Forwarded-For` header if `proxy: true` is configured in the app.
+ // koa will automatically load the `X-Forwarded-For` header if `proxy: true` is configured in the app.
let limitActor: string;
if (user) {
limitActor = user.id;
@@ -255,8 +278,8 @@ export class ApiCallService implements OnApplicationShutdown {
throw new ApiError({
message: 'Your account has been suspended.',
code: 'YOUR_ACCOUNT_SUSPENDED',
+ kind: 'permission',
id: 'a8c724b3-6e9c-4b46-b1a8-bc3ed6258370',
- httpStatusCode: 403,
});
}
}
@@ -266,8 +289,8 @@ export class ApiCallService implements OnApplicationShutdown {
throw new ApiError({
message: 'You have moved your account.',
code: 'YOUR_ACCOUNT_MOVED',
+ kind: 'permission',
id: '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31',
- httpStatusCode: 403,
});
}
}
@@ -278,6 +301,7 @@ export class ApiCallService implements OnApplicationShutdown {
throw new ApiError({
message: 'You are not assigned to a moderator role.',
code: 'ROLE_PERMISSION_DENIED',
+ kind: 'permission',
id: 'd33d5333-db36-423d-a8f9-1a2b9549da41',
});
}
@@ -285,6 +309,7 @@ export class ApiCallService implements OnApplicationShutdown {
throw new ApiError({
message: 'You are not assigned to an administrator role.',
code: 'ROLE_PERMISSION_DENIED',
+ kind: 'permission',
id: 'c3d38592-54c0-429d-be96-5636b0431a61',
});
}
@@ -296,6 +321,7 @@ export class ApiCallService implements OnApplicationShutdown {
throw new ApiError({
message: 'You are not assigned to a required role.',
code: 'ROLE_PERMISSION_DENIED',
+ kind: 'permission',
id: '7f86f06f-7e15-4057-8561-f4b6d4ac755a',
});
}
@@ -305,6 +331,7 @@ export class ApiCallService implements OnApplicationShutdown {
throw new ApiError({
message: 'Your app does not have the necessary permissions to use this endpoint.',
code: 'PERMISSION_DENIED',
+ kind: 'permission',
id: '1370e5b7-d4eb-4566-bb1d-7748ee6a1838',
});
}
@@ -317,7 +344,7 @@ export class ApiCallService implements OnApplicationShutdown {
try {
data[k] = JSON.parse(data[k]);
} catch (e) {
- throw new ApiError({
+ throw new ApiError({
message: 'Invalid param.',
code: 'INVALID_PARAM',
id: '0b5f1631-7c1a-41a6-b399-cce335f34d85',
@@ -335,7 +362,7 @@ export class ApiCallService implements OnApplicationShutdown {
if (err instanceof ApiError || err instanceof AuthenticationError) {
throw err;
} else {
- const errId = uuid();
+ const errId = randomUUID();
this.logger.error(`Internal error occurred in ${ep.name}: ${err.message}`, {
ep: ep.name,
ps: data,
diff --git a/packages/backend/src/server/api/AuthenticateService.ts b/packages/backend/src/server/api/AuthenticateService.ts
index 4ad0197d87..8b0fff80d9 100644
--- a/packages/backend/src/server/api/AuthenticateService.ts
+++ b/packages/backend/src/server/api/AuthenticateService.ts
@@ -40,15 +40,15 @@ export class AuthenticateService implements OnApplicationShutdown {
if (token == null) {
return [null, null];
}
-
+
if (isNativeToken(token)) {
const user = await this.cacheService.localUserByNativeTokenCache.fetch(token,
() => this.usersRepository.findOneBy({ token }) as Promise<LocalUser | null>);
-
+
if (user == null) {
throw new AuthenticationError('user not found');
}
-
+
return [user, null];
} else {
const accessToken = await this.accessTokensRepository.findOne({
@@ -58,24 +58,24 @@ export class AuthenticateService implements OnApplicationShutdown {
token: token, // miauth
}],
});
-
+
if (accessToken == null) {
throw new AuthenticationError('invalid signature');
}
-
+
this.accessTokensRepository.update(accessToken.id, {
lastUsedAt: new Date(),
});
-
+
const user = await this.cacheService.localUserByIdCache.fetch(accessToken.userId,
() => this.usersRepository.findOneBy({
id: accessToken.userId,
}) as Promise<LocalUser>);
-
+
if (accessToken.appId) {
const app = await this.appCache.fetch(accessToken.appId,
() => this.appsRepository.findOneByOrFail({ id: accessToken.appId! }));
-
+
return [user, {
id: accessToken.id,
permission: app.permission,
diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts
index d1ff3fe925..4e6bc46e67 100644
--- a/packages/backend/src/server/api/EndpointsModule.ts
+++ b/packages/backend/src/server/api/EndpointsModule.ts
@@ -38,7 +38,8 @@ import * as ep___admin_federation_updateInstance from './endpoints/admin/federat
import * as ep___admin_getIndexStats from './endpoints/admin/get-index-stats.js';
import * as ep___admin_getTableStats from './endpoints/admin/get-table-stats.js';
import * as ep___admin_getUserIps from './endpoints/admin/get-user-ips.js';
-import * as ep___invite from './endpoints/invite.js';
+import * as ep___admin_invite_create from './endpoints/admin/invite/create.js';
+import * as ep___admin_invite_list from './endpoints/admin/invite/list.js';
import * as ep___admin_promo_create from './endpoints/admin/promo/create.js';
import * as ep___admin_queue_clear from './endpoints/admin/queue/clear.js';
import * as ep___admin_queue_deliverDelayed from './endpoints/admin/queue/deliver-delayed.js';
@@ -230,6 +231,10 @@ import * as ep___i_webhooks_show from './endpoints/i/webhooks/show.js';
import * as ep___i_webhooks_list from './endpoints/i/webhooks/list.js';
import * as ep___i_webhooks_update from './endpoints/i/webhooks/update.js';
import * as ep___i_webhooks_delete from './endpoints/i/webhooks/delete.js';
+import * as ep___invite_create from './endpoints/invite/create.js';
+import * as ep___invite_delete from './endpoints/invite/delete.js';
+import * as ep___invite_list from './endpoints/invite/list.js';
+import * as ep___invite_limit from './endpoints/invite/limit.js';
import * as ep___meta from './endpoints/meta.js';
import * as ep___emojis from './endpoints/emojis.js';
import * as ep___emoji from './endpoints/emoji.js';
@@ -378,7 +383,8 @@ const $admin_federation_updateInstance: Provider = { provide: 'ep:admin/federati
const $admin_getIndexStats: Provider = { provide: 'ep:admin/get-index-stats', useClass: ep___admin_getIndexStats.default };
const $admin_getTableStats: Provider = { provide: 'ep:admin/get-table-stats', useClass: ep___admin_getTableStats.default };
const $admin_getUserIps: Provider = { provide: 'ep:admin/get-user-ips', useClass: ep___admin_getUserIps.default };
-const $invite: Provider = { provide: 'ep:invite', useClass: ep___invite.default };
+const $admin_invite_create: Provider = { provide: 'ep:admin/invite/create', useClass: ep___admin_invite_create.default };
+const $admin_invite_list: Provider = { provide: 'ep:admin/invite/list', useClass: ep___admin_invite_list.default };
const $admin_promo_create: Provider = { provide: 'ep:admin/promo/create', useClass: ep___admin_promo_create.default };
const $admin_queue_clear: Provider = { provide: 'ep:admin/queue/clear', useClass: ep___admin_queue_clear.default };
const $admin_queue_deliverDelayed: Provider = { provide: 'ep:admin/queue/deliver-delayed', useClass: ep___admin_queue_deliverDelayed.default };
@@ -570,6 +576,10 @@ const $i_webhooks_list: Provider = { provide: 'ep:i/webhooks/list', useClass: ep
const $i_webhooks_show: Provider = { provide: 'ep:i/webhooks/show', useClass: ep___i_webhooks_show.default };
const $i_webhooks_update: Provider = { provide: 'ep:i/webhooks/update', useClass: ep___i_webhooks_update.default };
const $i_webhooks_delete: Provider = { provide: 'ep:i/webhooks/delete', useClass: ep___i_webhooks_delete.default };
+const $invite_create: Provider = { provide: 'ep:invite/create', useClass: ep___invite_create.default };
+const $invite_delete: Provider = { provide: 'ep:invite/delete', useClass: ep___invite_delete.default };
+const $invite_list: Provider = { provide: 'ep:invite/list', useClass: ep___invite_list.default };
+const $invite_limit: Provider = { provide: 'ep:invite/limit', useClass: ep___invite_limit.default };
const $meta: Provider = { provide: 'ep:meta', useClass: ep___meta.default };
const $emojis: Provider = { provide: 'ep:emojis', useClass: ep___emojis.default };
const $emoji: Provider = { provide: 'ep:emoji', useClass: ep___emoji.default };
@@ -722,7 +732,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_getIndexStats,
$admin_getTableStats,
$admin_getUserIps,
- $invite,
+ $admin_invite_create,
+ $admin_invite_list,
$admin_promo_create,
$admin_queue_clear,
$admin_queue_deliverDelayed,
@@ -914,6 +925,10 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$i_webhooks_show,
$i_webhooks_update,
$i_webhooks_delete,
+ $invite_create,
+ $invite_delete,
+ $invite_list,
+ $invite_limit,
$meta,
$emojis,
$emoji,
@@ -1060,7 +1075,8 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_getIndexStats,
$admin_getTableStats,
$admin_getUserIps,
- $invite,
+ $admin_invite_create,
+ $admin_invite_list,
$admin_promo_create,
$admin_queue_clear,
$admin_queue_deliverDelayed,
@@ -1252,6 +1268,10 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$i_webhooks_show,
$i_webhooks_update,
$i_webhooks_delete,
+ $invite_create,
+ $invite_delete,
+ $invite_list,
+ $invite_limit,
$meta,
$emojis,
$emoji,
diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts
index fe2db1d66a..f6ffbfab50 100644
--- a/packages/backend/src/server/api/RateLimiterService.ts
+++ b/packages/backend/src/server/api/RateLimiterService.ts
@@ -38,14 +38,14 @@ export class RateLimiterService {
max: 1,
db: this.redisClient,
});
-
+
minIntervalLimiter.get((err, info) => {
if (err) {
return reject('ERR');
}
-
+
this.logger.debug(`${actor} ${limitation.key} min remaining: ${info.remaining}`);
-
+
if (info.remaining === 0) {
reject('BRIEF_REQUEST_INTERVAL');
} else {
@@ -57,7 +57,7 @@ export class RateLimiterService {
}
});
};
-
+
// Long term limit
const max = (): void => {
const limiter = new Limiter({
@@ -66,14 +66,14 @@ export class RateLimiterService {
max: limitation.max! / factor,
db: this.redisClient,
});
-
+
limiter.get((err, info) => {
if (err) {
return reject('ERR');
}
-
+
this.logger.debug(`${actor} ${limitation.key} max remaining: ${info.remaining}`);
-
+
if (info.remaining === 0) {
reject('RATE_LIMIT_EXCEEDED');
} else {
@@ -81,13 +81,13 @@ export class RateLimiterService {
}
});
};
-
+
const hasShortTermLimit = typeof limitation.minInterval === 'number';
-
+
const hasLongTermLimit =
typeof limitation.duration === 'number' &&
typeof limitation.max === 'number';
-
+
if (hasShortTermLimit) {
min();
} else if (hasLongTermLimit) {
diff --git a/packages/backend/src/server/api/SigninService.ts b/packages/backend/src/server/api/SigninService.ts
index aaf1d10b42..96666f1f49 100644
--- a/packages/backend/src/server/api/SigninService.ts
+++ b/packages/backend/src/server/api/SigninService.ts
@@ -36,7 +36,7 @@ export class SigninService {
headers: request.headers as any,
success: true,
}).then(x => this.signinsRepository.findOneByOrFail(x.identifiers[0]));
-
+
// Publish signin event
this.globalEventService.publishMainStream(user.id, 'signin', await this.signinEntityService.pack(record));
});
diff --git a/packages/backend/src/server/api/SignupApiService.ts b/packages/backend/src/server/api/SignupApiService.ts
index b2bd7d82e7..7b215cea79 100644
--- a/packages/backend/src/server/api/SignupApiService.ts
+++ b/packages/backend/src/server/api/SignupApiService.ts
@@ -1,9 +1,8 @@
import { Inject, Injectable } from '@nestjs/common';
-import rndstr from 'rndstr';
import bcrypt from 'bcryptjs';
import { IsNull } from 'typeorm';
import { DI } from '@/di-symbols.js';
-import type { RegistrationTicketsRepository, UsedUsernamesRepository, UserPendingsRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js';
+import type { RegistrationTicketsRepository, UsedUsernamesRepository, UserPendingsRepository, UserProfilesRepository, UsersRepository, RegistrationTicket } from '@/models/index.js';
import type { Config } from '@/config.js';
import { MetaService } from '@/core/MetaService.js';
import { CaptchaService } from '@/core/CaptchaService.js';
@@ -14,6 +13,7 @@ import { EmailService } from '@/core/EmailService.js';
import { LocalUser } from '@/models/entities/User.js';
import { FastifyReplyError } from '@/misc/fastify-reply-error.js';
import { bindThis } from '@/decorators.js';
+import { L_CHARS, secureRndstr } from '@/misc/secure-rndstr.js';
import { SigninService } from './SigninService.js';
import type { FastifyRequest, FastifyReply } from 'fastify';
@@ -67,7 +67,7 @@ export class SignupApiService {
const body = request.body;
const instance = await this.metaService.fetch(true);
-
+
// Verify *Captcha
// ただしテスト時はこの機構は障害となるため無効にする
if (process.env.NODE_ENV !== 'test') {
@@ -76,7 +76,7 @@ export class SignupApiService {
throw new FastifyReplyError(400, err);
});
}
-
+
if (instance.enableRecaptcha && instance.recaptchaSecretKey) {
await this.captchaService.verifyRecaptcha(instance.recaptchaSecretKey, body['g-recaptcha-response']).catch(err => {
throw new FastifyReplyError(400, err);
@@ -89,51 +89,61 @@ export class SignupApiService {
});
}
}
-
+
const username = body['username'];
const password = body['password'];
const host: string | null = process.env.NODE_ENV === 'test' ? (body['host'] ?? null) : null;
const invitationCode = body['invitationCode'];
const emailAddress = body['emailAddress'];
-
+
if (instance.emailRequiredForSignup) {
if (emailAddress == null || typeof emailAddress !== 'string') {
reply.code(400);
return;
}
-
+
const res = await this.emailService.validateEmailForAccount(emailAddress);
if (!res.available) {
reply.code(400);
return;
}
}
-
+
+ let ticket: RegistrationTicket | null = null;
+
if (instance.disableRegistration) {
if (invitationCode == null || typeof invitationCode !== 'string') {
reply.code(400);
return;
}
-
- const ticket = await this.registrationTicketsRepository.findOneBy({
+
+ ticket = await this.registrationTicketsRepository.findOneBy({
code: invitationCode,
});
-
+
if (ticket == null) {
reply.code(400);
return;
}
-
- this.registrationTicketsRepository.delete(ticket.id);
+
+ if (ticket.expiresAt && ticket.expiresAt < new Date()) {
+ reply.code(400);
+ return;
+ }
+
+ if (ticket.usedAt) {
+ reply.code(400);
+ return;
+ }
}
-
+
if (instance.emailRequiredForSignup) {
- if (await this.usersRepository.findOneBy({ usernameLower: username.toLowerCase(), host: IsNull() })) {
+ if (await this.usersRepository.exist({ where: { usernameLower: username.toLowerCase(), host: IsNull() } })) {
throw new FastifyReplyError(400, 'DUPLICATED_USERNAME');
}
// Check deleted username duplication
- if (await this.usedUsernamesRepository.findOneBy({ username: username.toLowerCase() })) {
+ if (await this.usedUsernamesRepository.exist({ where: { username: username.toLowerCase() } })) {
throw new FastifyReplyError(400, 'USED_USERNAME');
}
@@ -142,20 +152,20 @@ export class SignupApiService {
throw new FastifyReplyError(400, 'DENIED_USERNAME');
}
- const code = rndstr('a-z0-9', 16);
+ const code = secureRndstr(16, { chars: L_CHARS });
// Generate hash of password
const salt = await bcrypt.genSalt(8);
const hash = await bcrypt.hash(password, salt);
- await this.userPendingsRepository.insert({
+ const pendingUser = await this.userPendingsRepository.insert({
id: this.idService.genId(),
createdAt: new Date(),
code,
email: emailAddress!,
username: username,
password: hash,
- });
+ }).then(x => this.userPendingsRepository.findOneByOrFail(x.identifiers[0]));
const link = `${this.config.url}/signup-complete/${code}`;
@@ -163,6 +173,13 @@ export class SignupApiService {
`To complete signup, please click this link:<br><a href="${link}">${link}</a>`,
`To complete signup, please click this link: ${link}`);
+ if (ticket) {
+ await this.registrationTicketsRepository.update(ticket.id, {
+ usedAt: new Date(),
+ pendingUserId: pendingUser.id,
+ });
+ }
+
reply.code(204);
return;
} else {
@@ -170,12 +187,20 @@ export class SignupApiService {
const { account, secret } = await this.signupService.signup({
username, password, host,
});
-
+
const res = await this.userEntityService.pack(account, account, {
detail: true,
includeSecrets: true,
});
-
+
+ if (ticket) {
+ await this.registrationTicketsRepository.update(ticket.id, {
+ usedAt: new Date(),
+ usedBy: account,
+ usedById: account.id,
+ });
+ }
+
return {
...res,
token: secret,
@@ -212,6 +237,15 @@ export class SignupApiService {
emailVerifyCode: null,
});
+ const ticket = await this.registrationTicketsRepository.findOneBy({ pendingUserId: pendingUser.id });
+ if (ticket) {
+ await this.registrationTicketsRepository.update(ticket.id, {
+ usedBy: account,
+ usedById: account.id,
+ pendingUserId: null,
+ });
+ }
+
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/StreamingApiServerService.ts b/packages/backend/src/server/api/StreamingApiServerService.ts
index d1394d6d76..e4291becf0 100644
--- a/packages/backend/src/server/api/StreamingApiServerService.ts
+++ b/packages/backend/src/server/api/StreamingApiServerService.ts
@@ -10,7 +10,7 @@ import { GlobalEventService } from '@/core/GlobalEventService.js';
import { NotificationService } from '@/core/NotificationService.js';
import { bindThis } from '@/decorators.js';
import { CacheService } from '@/core/CacheService.js';
-import { LocalUser } from '@/models/entities/User';
+import { LocalUser } from '@/models/entities/User.js';
import { AuthenticateService, AuthenticationError } from './AuthenticateService.js';
import MainStreamConnection from './stream/index.js';
import { ChannelsService } from './stream/ChannelsService.js';
@@ -58,11 +58,21 @@ export class StreamingApiServerService {
let user: LocalUser | null = null;
let app: AccessToken | null = null;
+ // https://datatracker.ietf.org/doc/html/rfc6750.html#section-2.1
+ // Note that the standard WHATWG WebSocket API does not support setting any headers,
+ // but non-browser apps may still be able to set it.
+ const token = request.headers.authorization?.startsWith('Bearer ')
+ ? request.headers.authorization.slice(7)
+ : q.get('i');
+
try {
- [user, app] = await this.authenticateService.authenticate(q.get('i'));
+ [user, app] = await this.authenticateService.authenticate(token);
} catch (e) {
if (e instanceof AuthenticationError) {
- socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
+ socket.write([
+ 'HTTP/1.1 401 Unauthorized',
+ 'WWW-Authenticate: Bearer realm="Misskey", error="invalid_token", error_description="Failed to authenticate"',
+ ].join('\r\n') + '\r\n\r\n');
} else {
socket.write('HTTP/1.1 500 Internal Server Error\r\n\r\n');
}
@@ -93,6 +103,13 @@ export class StreamingApiServerService {
});
});
+ const globalEv = new EventEmitter();
+
+ this.redisForSub.on('message', (_: string, data: string) => {
+ const parsed = JSON.parse(data);
+ globalEv.emit('message', parsed);
+ });
+
this.#wss.on('connection', async (connection: WebSocket.WebSocket, request: http.IncomingMessage, ctx: {
stream: MainStreamConnection,
user: LocalUser | null;
@@ -102,12 +119,11 @@ export class StreamingApiServerService {
const ev = new EventEmitter();
- async function onRedisMessage(_: string, data: string): Promise<void> {
- const parsed = JSON.parse(data);
- ev.emit(parsed.channel, parsed.message);
+ function onRedisMessage(data: any): void {
+ ev.emit(data.channel, data.message);
}
- this.redisForSub.on('message', onRedisMessage);
+ globalEv.on('message', onRedisMessage);
await stream.listen(ev, connection);
@@ -127,7 +143,7 @@ export class StreamingApiServerService {
connection.once('close', () => {
ev.removeAllListeners();
stream.dispose();
- this.redisForSub.off('message', onRedisMessage);
+ globalEv.off('message', onRedisMessage);
this.#connections.delete(connection);
if (userUpdateIntervalId) clearInterval(userUpdateIntervalId);
});
diff --git a/packages/backend/src/server/api/endpoint-base.ts b/packages/backend/src/server/api/endpoint-base.ts
index 1555a3ca46..364fa7a19b 100644
--- a/packages/backend/src/server/api/endpoint-base.ts
+++ b/packages/backend/src/server/api/endpoint-base.ts
@@ -1,11 +1,13 @@
import * as fs from 'node:fs';
-import Ajv from 'ajv';
+import _Ajv from 'ajv';
import type { Schema, SchemaType } from '@/misc/json-schema.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';
+const Ajv = _Ajv.default;
+
const ajv = new Ajv({
useDefaults: true,
});
@@ -32,23 +34,23 @@ export abstract class Endpoint<T extends IEndpointMeta, Ps extends Schema> {
this.exec = (params: any, user: T['requireCredential'] extends true ? LocalUser : LocalUser | null, token: AccessToken | null, file?: File, ip?: string | null, headers?: Record<string, string> | null) => {
let cleanup: undefined | (() => void) = undefined;
-
+
if (meta.requireFile) {
cleanup = () => {
if (file) fs.unlink(file.path, () => {});
};
-
+
if (file == null) return Promise.reject(new ApiError({
message: 'File required.',
code: 'FILE_REQUIRED',
id: '4267801e-70d1-416a-b011-4ee502885d8b',
}));
}
-
+
const valid = validate(params);
if (!valid) {
if (file) cleanup!();
-
+
const errors = validate.errors!;
const err = new ApiError({
message: 'Invalid param.',
@@ -60,7 +62,7 @@ export abstract class Endpoint<T extends IEndpointMeta, Ps extends Schema> {
});
return Promise.reject(err);
}
-
+
return cb(params as SchemaType<Ps>, user, token, file, cleanup, ip, headers);
};
}
diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts
index 94206ef870..41c3a29eec 100644
--- a/packages/backend/src/server/api/endpoints.ts
+++ b/packages/backend/src/server/api/endpoints.ts
@@ -38,7 +38,8 @@ import * as ep___admin_federation_updateInstance from './endpoints/admin/federat
import * as ep___admin_getIndexStats from './endpoints/admin/get-index-stats.js';
import * as ep___admin_getTableStats from './endpoints/admin/get-table-stats.js';
import * as ep___admin_getUserIps from './endpoints/admin/get-user-ips.js';
-import * as ep___invite from './endpoints/invite.js';
+import * as ep___admin_invite_create from './endpoints/admin/invite/create.js';
+import * as ep___admin_invite_list from './endpoints/admin/invite/list.js';
import * as ep___admin_promo_create from './endpoints/admin/promo/create.js';
import * as ep___admin_queue_clear from './endpoints/admin/queue/clear.js';
import * as ep___admin_queue_deliverDelayed from './endpoints/admin/queue/deliver-delayed.js';
@@ -230,6 +231,10 @@ import * as ep___i_webhooks_show from './endpoints/i/webhooks/show.js';
import * as ep___i_webhooks_list from './endpoints/i/webhooks/list.js';
import * as ep___i_webhooks_update from './endpoints/i/webhooks/update.js';
import * as ep___i_webhooks_delete from './endpoints/i/webhooks/delete.js';
+import * as ep___invite_create from './endpoints/invite/create.js';
+import * as ep___invite_delete from './endpoints/invite/delete.js';
+import * as ep___invite_list from './endpoints/invite/list.js';
+import * as ep___invite_limit from './endpoints/invite/limit.js';
import * as ep___meta from './endpoints/meta.js';
import * as ep___emojis from './endpoints/emojis.js';
import * as ep___emoji from './endpoints/emoji.js';
@@ -376,7 +381,8 @@ const eps = [
['admin/get-index-stats', ep___admin_getIndexStats],
['admin/get-table-stats', ep___admin_getTableStats],
['admin/get-user-ips', ep___admin_getUserIps],
- ['invite', ep___invite],
+ ['admin/invite/create', ep___admin_invite_create],
+ ['admin/invite/list', ep___admin_invite_list],
['admin/promo/create', ep___admin_promo_create],
['admin/queue/clear', ep___admin_queue_clear],
['admin/queue/deliver-delayed', ep___admin_queue_deliverDelayed],
@@ -568,6 +574,10 @@ const eps = [
['i/webhooks/show', ep___i_webhooks_show],
['i/webhooks/update', ep___i_webhooks_update],
['i/webhooks/delete', ep___i_webhooks_delete],
+ ['invite/create', ep___invite_create],
+ ['invite/delete', ep___invite_delete],
+ ['invite/list', ep___invite_list],
+ ['invite/limit', ep___invite_limit],
['meta', ep___meta],
['emojis', ep___emojis],
['emoji', ep___emoji],
diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts
index 9bba16166f..b8ea74b7c5 100644
--- a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts
+++ b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts
@@ -115,7 +115,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
case 'remote': query.andWhere('report.targetUserHost IS NOT NULL'); break;
}
- const reports = await query.take(ps.limit).getMany();
+ const reports = await query.limit(ps.limit).getMany();
return await this.abuseUserReportEntityService.packMany(reports);
});
diff --git a/packages/backend/src/server/api/endpoints/admin/ad/create.ts b/packages/backend/src/server/api/endpoints/admin/ad/create.ts
index 917242db3f..757030839e 100644
--- a/packages/backend/src/server/api/endpoints/admin/ad/create.ts
+++ b/packages/backend/src/server/api/endpoints/admin/ad/create.ts
@@ -22,8 +22,9 @@ export const paramDef = {
expiresAt: { type: 'integer' },
startsAt: { type: 'integer' },
imageUrl: { type: 'string', minLength: 1 },
+ dayOfWeek: { type: 'integer' },
},
- required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'imageUrl'],
+ required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'imageUrl', 'dayOfWeek'],
} as const;
// eslint-disable-next-line import/no-default-export
@@ -41,6 +42,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
createdAt: new Date(),
expiresAt: new Date(ps.expiresAt),
startsAt: new Date(ps.startsAt),
+ dayOfWeek: ps.dayOfWeek,
url: ps.url,
imageUrl: ps.imageUrl,
priority: ps.priority,
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 0b6d006052..725ddb58be 100644
--- a/packages/backend/src/server/api/endpoints/admin/ad/list.ts
+++ b/packages/backend/src/server/api/endpoints/admin/ad/list.ts
@@ -32,7 +32,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId);
- const ads = await query.take(ps.limit).getMany();
+ const ads = await query.limit(ps.limit).getMany();
return ads;
});
diff --git a/packages/backend/src/server/api/endpoints/admin/ad/update.ts b/packages/backend/src/server/api/endpoints/admin/ad/update.ts
index dbab7e9d4f..70082290ba 100644
--- a/packages/backend/src/server/api/endpoints/admin/ad/update.ts
+++ b/packages/backend/src/server/api/endpoints/admin/ad/update.ts
@@ -31,8 +31,9 @@ export const paramDef = {
ratio: { type: 'integer' },
expiresAt: { type: 'integer' },
startsAt: { type: 'integer' },
+ dayOfWeek: { type: 'integer' },
},
- required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt'],
+ required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'dayOfWeek'],
} as const;
// eslint-disable-next-line import/no-default-export
@@ -56,6 +57,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
imageUrl: ps.imageUrl,
expiresAt: new Date(ps.expiresAt),
startsAt: new Date(ps.startsAt),
+ dayOfWeek: ps.dayOfWeek,
});
});
}
diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts
index 9b20494129..11231f6e04 100644
--- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts
+++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts
@@ -80,7 +80,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
- const announcements = await query.take(ps.limit).getMany();
+ const announcements = await query.limit(ps.limit).getMany();
const reads = new Map<Announcement, number>();
diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts
index 12db1f78fb..8cf9341a71 100644
--- a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts
+++ b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts
@@ -47,7 +47,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
title: ps.title,
text: ps.text,
/* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- 空の文字列の場合、nullを渡すようにするため */
- imageUrl: ps.imageUrl || null,
+ imageUrl: ps.imageUrl || null,
});
});
}
diff --git a/packages/backend/src/server/api/endpoints/admin/drive/files.ts b/packages/backend/src/server/api/endpoints/admin/drive/files.ts
index 8a4498d5fa..2901fdb774 100644
--- a/packages/backend/src/server/api/endpoints/admin/drive/files.ts
+++ b/packages/backend/src/server/api/endpoints/admin/drive/files.ts
@@ -76,7 +76,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
}
- const files = await query.take(ps.limit).getMany();
+ const files = await query.limit(ps.limit).getMany();
return await this.driveFileEntityService.packMany(files, { detail: true, withUser: true, self: true });
});
diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts
index 509224e9c3..200ede0b06 100644
--- a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts
+++ b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts
@@ -1,10 +1,10 @@
import { Inject, Injectable } from '@nestjs/common';
-import rndstr from 'rndstr';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { DriveFilesRepository } from '@/models/index.js';
import { DI } from '@/di-symbols.js';
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
+import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
import { ApiError } from '../../../error.js';
export const meta = {
@@ -56,6 +56,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private customEmojiService: CustomEmojiService,
+ private emojiEntityService: EmojiEntityService,
private moderationLogService: ModerationLogService,
) {
super(meta, paramDef, async (ps, me) => {
@@ -78,9 +79,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
emojiId: emoji.id,
});
- return {
- id: emoji.id,
- };
+ return this.emojiEntityService.packDetailed(emoji);
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts
index df3c28deff..8d50413e95 100644
--- a/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts
+++ b/packages/backend/src/server/api/endpoints/admin/emoji/list-remote.ts
@@ -98,7 +98,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const emojis = await q
.orderBy('emoji.id', 'DESC')
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return this.emojiEntityService.packDetailedMany(emojis);
diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts
index 4aa4ad82b4..29b20fab86 100644
--- a/packages/backend/src/server/api/endpoints/admin/emoji/list.ts
+++ b/packages/backend/src/server/api/endpoints/admin/emoji/list.ts
@@ -84,14 +84,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (ps.query) {
//q.andWhere('emoji.name ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` });
- //const emojis = await q.take(ps.limit).getMany();
+ //const emojis = await q.limit(ps.limit).getMany();
emojis = await q.getMany();
const queryarry = ps.query.match(/\:([a-z0-9_]*)\:/g);
if (queryarry) {
- emojis = emojis.filter(emoji =>
- queryarry.includes(`:${emoji.name}:`)
+ emojis = emojis.filter(emoji =>
+ queryarry.includes(`:${emoji.name}:`),
);
} else {
emojis = emojis.filter(emoji =>
@@ -101,7 +101,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
emojis.splice(ps.limit + 1);
} else {
- emojis = await q.take(ps.limit).getMany();
+ emojis = await q.limit(ps.limit).getMany();
}
return this.emojiEntityService.packDetailedMany(emojis);
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 fb22bdc477..edc1af5a53 100644
--- a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts
+++ b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts
@@ -70,7 +70,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
driveFile = await this.driveFilesRepository.findOneBy({ id: ps.fileId });
if (driveFile == null) throw new ApiError(meta.errors.noSuchFile);
}
-
+
await this.customEmojiService.update(ps.id, {
driveFile,
name: ps.name,
diff --git a/packages/backend/src/server/api/endpoints/admin/invite/create.ts b/packages/backend/src/server/api/endpoints/admin/invite/create.ts
new file mode 100644
index 0000000000..664b4d819f
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/admin/invite/create.ts
@@ -0,0 +1,80 @@
+import { Inject, Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import type { RegistrationTicketsRepository } from '@/models/index.js';
+import { InviteCodeEntityService } from '@/core/entities/InviteCodeEntityService.js';
+import { IdService } from '@/core/IdService.js';
+import { DI } from '@/di-symbols.js';
+import { generateInviteCode } from '@/misc/generate-invite-code.js';
+import { ApiError } from '../../../error.js';
+
+export const meta = {
+ tags: ['admin'],
+
+ requireCredential: true,
+ requireModerator: true,
+
+ errors: {
+ invalidDateTime: {
+ message: 'Invalid date-time format',
+ code: 'INVALID_DATE_TIME',
+ id: 'f1380b15-3760-4c6c-a1db-5c3aaf1cbd49',
+ },
+ },
+
+ res: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'object',
+ optional: false, nullable: false,
+ properties: {
+ code: {
+ type: 'string',
+ optional: false, nullable: false,
+ example: 'GR6S02ERUA5VR',
+ },
+ },
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ count: { type: 'integer', minimum: 1, maximum: 100, default: 1 },
+ expiresAt: { type: 'string', nullable: true },
+ },
+ required: [],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.registrationTicketsRepository)
+ private registrationTicketsRepository: RegistrationTicketsRepository,
+
+ private inviteCodeEntityService: InviteCodeEntityService,
+ private idService: IdService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ if (ps.expiresAt && isNaN(Date.parse(ps.expiresAt))) {
+ throw new ApiError(meta.errors.invalidDateTime);
+ }
+
+ const ticketsPromises = [];
+
+ for (let i = 0; i < ps.count; i++) {
+ ticketsPromises.push(this.registrationTicketsRepository.insert({
+ id: this.idService.genId(),
+ createdAt: new Date(),
+ expiresAt: ps.expiresAt ? new Date(ps.expiresAt) : null,
+ code: generateInviteCode(),
+ }).then(x => this.registrationTicketsRepository.findOneByOrFail(x.identifiers[0])));
+ }
+
+ const tickets = await Promise.all(ticketsPromises);
+ return await this.inviteCodeEntityService.packMany(tickets, me);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/admin/invite/list.ts b/packages/backend/src/server/api/endpoints/admin/invite/list.ts
new file mode 100644
index 0000000000..5d7a7f632c
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/admin/invite/list.ts
@@ -0,0 +1,70 @@
+import { Inject, Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import type { RegistrationTicketsRepository } from '@/models/index.js';
+import { InviteCodeEntityService } from '@/core/entities/InviteCodeEntityService.js';
+import { DI } from '@/di-symbols.js';
+
+export const meta = {
+ tags: ['admin'],
+
+ requireCredential: true,
+ requireModerator: true,
+
+ res: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'object',
+ optional: false, nullable: false,
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
+ offset: { type: 'integer', default: 0 },
+ type: { type: 'string', enum: ['unused', 'used', 'expired', 'all'], default: 'all' },
+ sort: { type: 'string', enum: ['+createdAt', '-createdAt', '+usedAt', '-usedAt'] },
+ },
+ required: [],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.registrationTicketsRepository)
+ private registrationTicketsRepository: RegistrationTicketsRepository,
+
+ private inviteCodeEntityService: InviteCodeEntityService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const query = this.registrationTicketsRepository.createQueryBuilder('ticket')
+ .leftJoinAndSelect('ticket.createdBy', 'createdBy')
+ .leftJoinAndSelect('ticket.usedBy', 'usedBy');
+
+ switch (ps.type) {
+ case 'unused': query.andWhere('ticket.usedBy IS NULL'); break;
+ case 'used': query.andWhere('ticket.usedBy IS NOT NULL'); break;
+ case 'expired': query.andWhere('ticket.expiresAt < :now', { now: new Date() }); break;
+ }
+
+ switch (ps.sort) {
+ case '+createdAt': query.orderBy('ticket.createdAt', 'DESC'); break;
+ case '-createdAt': query.orderBy('ticket.createdAt', 'ASC'); break;
+ case '+usedAt': query.orderBy('ticket.usedAt', 'DESC', 'NULLS LAST'); break;
+ case '-usedAt': query.orderBy('ticket.usedAt', 'ASC', 'NULLS FIRST'); break;
+ default: query.orderBy('ticket.id', 'DESC'); break;
+ }
+
+ query.limit(ps.limit);
+ query.skip(ps.offset);
+
+ const tickets = await query.getMany();
+
+ return await this.inviteCodeEntityService.packMany(tickets, me);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts
index 4cc1b6011f..084bdb598b 100644
--- a/packages/backend/src/server/api/endpoints/admin/meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/meta.ts
@@ -1,5 +1,4 @@
import { Inject, Injectable } from '@nestjs/common';
-import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { MetaService } from '@/core/MetaService.js';
import type { Config } from '@/config.js';
@@ -20,6 +19,10 @@ export const meta = {
type: 'boolean',
optional: false, nullable: false,
},
+ cacheRemoteSensitiveFiles: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
emailRequiredForSignup: {
type: 'boolean',
optional: false, nullable: false,
@@ -262,6 +265,14 @@ export const meta = {
type: 'boolean',
optional: false, nullable: false,
},
+ enableServerMachineStats: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ enableIdenticonGeneration: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
policies: {
type: 'object',
optional: false, nullable: false,
@@ -324,6 +335,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
enableServiceWorker: instance.enableServiceWorker,
translatorAvailable: instance.deeplAuthKey != null,
cacheRemoteFiles: instance.cacheRemoteFiles,
+ cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles,
pinnedUsers: instance.pinnedUsers,
hiddenTags: instance.hiddenTags,
blockedHosts: instance.blockedHosts,
@@ -364,6 +376,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
enableActiveEmailValidation: instance.enableActiveEmailValidation,
enableChartsForRemoteUser: instance.enableChartsForRemoteUser,
enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances,
+ enableServerMachineStats: instance.enableServerMachineStats,
+ enableIdenticonGeneration: instance.enableIdenticonGeneration,
policies: { ...DEFAULT_POLICIES, ...instance.policies },
};
});
diff --git a/packages/backend/src/server/api/endpoints/admin/promo/create.ts b/packages/backend/src/server/api/endpoints/admin/promo/create.ts
index bee1ffbaee..8401cf51d9 100644
--- a/packages/backend/src/server/api/endpoints/admin/promo/create.ts
+++ b/packages/backend/src/server/api/endpoints/admin/promo/create.ts
@@ -50,9 +50,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw e;
});
- const exist = await this.promoNotesRepository.findOneBy({ noteId: note.id });
+ const exist = await this.promoNotesRepository.exist({ where: { noteId: note.id } });
- if (exist != null) {
+ if (exist) {
throw new ApiError(meta.errors.alreadyPromoted);
}
diff --git a/packages/backend/src/server/api/endpoints/admin/queue/promote.ts b/packages/backend/src/server/api/endpoints/admin/queue/promote.ts
index 4e57e6613e..8330d6c82f 100644
--- a/packages/backend/src/server/api/endpoints/admin/queue/promote.ts
+++ b/packages/backend/src/server/api/endpoints/admin/queue/promote.ts
@@ -33,15 +33,35 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
delayedQueues = await this.queueService.deliverQueue.getDelayed();
for (let queueIndex = 0; queueIndex < delayedQueues.length; queueIndex++) {
const queue = delayedQueues[queueIndex];
- await queue.promote();
+ try {
+ await queue.promote();
+ } catch (e) {
+ if (e instanceof Error) {
+ if (e.message.indexOf('not in a delayed state') !== -1) {
+ throw e;
+ }
+ } else {
+ throw e;
+ }
+ }
}
break;
-
+
case 'inbox':
delayedQueues = await this.queueService.inboxQueue.getDelayed();
for (let queueIndex = 0; queueIndex < delayedQueues.length; queueIndex++) {
const queue = delayedQueues[queueIndex];
- await queue.promote();
+ try {
+ await queue.promote();
+ } catch (e) {
+ if (e instanceof Error) {
+ if (e.message.indexOf('not in a delayed state') !== -1) {
+ throw e;
+ }
+ } else {
+ throw e;
+ }
+ }
}
break;
}
diff --git a/packages/backend/src/server/api/endpoints/admin/reset-password.ts b/packages/backend/src/server/api/endpoints/admin/reset-password.ts
index d263f99f6e..e9c3b0e69f 100644
--- a/packages/backend/src/server/api/endpoints/admin/reset-password.ts
+++ b/packages/backend/src/server/api/endpoints/admin/reset-password.ts
@@ -1,9 +1,9 @@
import { Inject, Injectable } from '@nestjs/common';
import bcrypt from 'bcryptjs';
-import rndstr from 'rndstr';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UsersRepository, UserProfilesRepository } from '@/models/index.js';
import { DI } from '@/di-symbols.js';
+import { secureRndstr } from '@/misc/secure-rndstr.js';
export const meta = {
tags: ['admin'],
@@ -54,7 +54,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw new Error('cannot reset password of root');
}
- const passwd = rndstr('a-zA-Z0-9', 8);
+ const passwd = secureRndstr(8);
// Generate hash of password
const hash = bcrypt.hashSync(passwd);
diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update.ts b/packages/backend/src/server/api/endpoints/admin/roles/update.ts
index 467f157a61..1fedab4540 100644
--- a/packages/backend/src/server/api/endpoints/admin/roles/update.ts
+++ b/packages/backend/src/server/api/endpoints/admin/roles/update.ts
@@ -69,8 +69,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private globalEventService: GlobalEventService,
) {
super(meta, paramDef, async (ps) => {
- const role = await this.rolesRepository.findOneBy({ id: ps.roleId });
- if (role == null) {
+ const roleExist = await this.rolesRepository.exist({ where: { id: ps.roleId } });
+ if (!roleExist) {
throw new ApiError(meta.errors.noSuchRole);
}
diff --git a/packages/backend/src/server/api/endpoints/admin/roles/users.ts b/packages/backend/src/server/api/endpoints/admin/roles/users.ts
index 35edca5460..63650bb2bf 100644
--- a/packages/backend/src/server/api/endpoints/admin/roles/users.ts
+++ b/packages/backend/src/server/api/endpoints/admin/roles/users.ts
@@ -64,7 +64,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.innerJoinAndSelect('assign.user', 'user');
const assigns = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await Promise.all(assigns.map(async assign => ({
diff --git a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts
index 24335a21cc..69c95ef19c 100644
--- a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts
+++ b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts
@@ -74,7 +74,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.moderationLogsRepository.createQueryBuilder('report'), ps.sinceId, ps.untilId);
- const reports = await query.take(ps.limit).getMany();
+ const reports = await query.limit(ps.limit).getMany();
return await this.moderationLogEntityService.packMany(reports);
});
diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts
index f49d2a0966..6f805b6b4e 100644
--- a/packages/backend/src/server/api/endpoints/admin/show-user.ts
+++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts
@@ -61,6 +61,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const signins = await this.signinsRepository.findBy({ userId: user.id });
+ const roleAssigns = await this.roleService.getUserAssigns(user.id);
const roles = await this.roleService.getUserRoles(user.id);
return {
@@ -85,6 +86,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
signins,
policies: await this.roleService.getUserPolicies(user.id),
roles: await this.roleEntityService.packMany(roles, me),
+ roleAssigns: roleAssigns.map(a => ({
+ createdAt: a.createdAt.toISOString(),
+ expiresAt: a.expiresAt ? a.expiresAt.toISOString() : null,
+ roleId: a.roleId,
+ })),
};
});
}
diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts
index 426973f282..0a150d1dfd 100644
--- a/packages/backend/src/server/api/endpoints/admin/show-users.ts
+++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts
@@ -104,7 +104,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
default: query.orderBy('user.id', 'ASC'); break;
}
- query.take(ps.limit);
+ query.limit(ps.limit);
query.skip(ps.offset);
const users = await query.getMany();
diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
index 1de5e9efd3..144360a921 100644
--- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
@@ -43,6 +43,7 @@ export const paramDef = {
defaultLightTheme: { type: 'string', nullable: true },
defaultDarkTheme: { type: 'string', nullable: true },
cacheRemoteFiles: { type: 'boolean' },
+ cacheRemoteSensitiveFiles: { type: 'boolean' },
emailRequiredForSignup: { type: 'boolean' },
enableHcaptcha: { type: 'boolean' },
hcaptchaSiteKey: { type: 'string', nullable: true },
@@ -96,6 +97,8 @@ export const paramDef = {
enableActiveEmailValidation: { type: 'boolean' },
enableChartsForRemoteUser: { type: 'boolean' },
enableChartsForFederatedInstances: { type: 'boolean' },
+ enableServerMachineStats: { type: 'boolean' },
+ enableIdenticonGeneration: { type: 'boolean' },
serverRules: { type: 'array', items: { type: 'string' } },
preservedUsernames: { type: 'array', items: { type: 'string' } },
},
@@ -134,7 +137,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (Array.isArray(ps.sensitiveWords)) {
set.sensitiveWords = ps.sensitiveWords.filter(Boolean);
}
-
+
if (ps.themeColor !== undefined) {
set.themeColor = ps.themeColor;
}
@@ -191,6 +194,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
set.cacheRemoteFiles = ps.cacheRemoteFiles;
}
+ if (ps.cacheRemoteSensitiveFiles !== undefined) {
+ set.cacheRemoteSensitiveFiles = ps.cacheRemoteSensitiveFiles;
+ }
+
if (ps.emailRequiredForSignup !== undefined) {
set.emailRequiredForSignup = ps.emailRequiredForSignup;
}
@@ -399,6 +406,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
set.enableChartsForFederatedInstances = ps.enableChartsForFederatedInstances;
}
+ if (ps.enableServerMachineStats !== undefined) {
+ set.enableServerMachineStats = ps.enableServerMachineStats;
+ }
+
+ if (ps.enableIdenticonGeneration !== undefined) {
+ set.enableIdenticonGeneration = ps.enableIdenticonGeneration;
+ }
+
if (ps.serverRules !== undefined) {
set.serverRules = ps.serverRules;
}
diff --git a/packages/backend/src/server/api/endpoints/announcements.ts b/packages/backend/src/server/api/endpoints/announcements.ts
index 79788be4e2..735af51ee2 100644
--- a/packages/backend/src/server/api/endpoints/announcements.ts
+++ b/packages/backend/src/server/api/endpoints/announcements.ts
@@ -79,7 +79,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
- const announcements = await query.take(ps.limit).getMany();
+ const announcements = await query.limit(ps.limit).getMany();
if (me) {
const reads = (await this.announcementReadsRepository.findBy({
diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts
index e756a9b510..2c4247cb70 100644
--- a/packages/backend/src/server/api/endpoints/antennas/notes.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts
@@ -76,6 +76,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw new ApiError(meta.errors.noSuchAntenna);
}
+ this.antennasRepository.update(antenna.id, {
+ isActive: true,
+ lastUsedAt: new Date(),
+ });
+
const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1
const noteIdsRes = await this.redisClient.xrevrange(
`antennaTimeline:${antenna.id}`,
@@ -112,11 +117,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
this.noteReadService.read(me.id, notes);
}
- this.antennasRepository.update(antenna.id, {
- isActive: true,
- lastUsedAt: new Date(),
- });
-
return await this.noteEntityService.packMany(notes, me);
});
}
diff --git a/packages/backend/src/server/api/endpoints/antennas/update.ts b/packages/backend/src/server/api/endpoints/antennas/update.ts
index 5f980bdbeb..55218b644b 100644
--- a/packages/backend/src/server/api/endpoints/antennas/update.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/update.ts
@@ -112,6 +112,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
withReplies: ps.withReplies,
withFile: ps.withFile,
notify: ps.notify,
+ isActive: true,
+ lastUsedAt: new Date(),
});
this.globalEventService.publishInternalEvent('antennaUpdated', await this.antennasRepository.findOneByOrFail({ id: antenna.id }));
diff --git a/packages/backend/src/server/api/endpoints/app/create.ts b/packages/backend/src/server/api/endpoints/app/create.ts
index c1d0a9dd74..aaef02d03f 100644
--- a/packages/backend/src/server/api/endpoints/app/create.ts
+++ b/packages/backend/src/server/api/endpoints/app/create.ts
@@ -44,7 +44,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
) {
super(meta, paramDef, async (ps, me) => {
// Generate secret
- const secret = secureRndstr(32, true);
+ const secret = secureRndstr(32);
// for backward compatibility
const permission = unique(ps.permission.map(v => v.replace(/^(.+)(\/|-)(read|write)$/, '$3:$1')));
diff --git a/packages/backend/src/server/api/endpoints/auth/accept.ts b/packages/backend/src/server/api/endpoints/auth/accept.ts
index 05842460cf..aa199ab730 100644
--- a/packages/backend/src/server/api/endpoints/auth/accept.ts
+++ b/packages/backend/src/server/api/endpoints/auth/accept.ts
@@ -55,15 +55,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw new ApiError(meta.errors.noSuchSession);
}
- const accessToken = secureRndstr(32, true);
+ const accessToken = secureRndstr(32);
// Fetch exist access token
- const exist = await this.accessTokensRepository.findOneBy({
- appId: session.appId,
- userId: me.id,
+ const exist = await this.accessTokensRepository.exist({
+ where: {
+ appId: session.appId,
+ userId: me.id,
+ },
});
- if (exist == null) {
+ if (!exist) {
const app = await this.appsRepository.findOneByOrFail({ id: session.appId });
// Generate Hash
diff --git a/packages/backend/src/server/api/endpoints/auth/session/generate.ts b/packages/backend/src/server/api/endpoints/auth/session/generate.ts
index 6108d8202d..631fb4f024 100644
--- a/packages/backend/src/server/api/endpoints/auth/session/generate.ts
+++ b/packages/backend/src/server/api/endpoints/auth/session/generate.ts
@@ -1,4 +1,4 @@
-import { v4 as uuid } from 'uuid';
+import { randomUUID } from 'node:crypto';
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { AppsRepository, AuthSessionsRepository } from '@/models/index.js';
@@ -71,7 +71,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
// Generate token
- const token = uuid();
+ const token = randomUUID();
// Create session token document
const doc = await this.authSessionsRepository.insert({
diff --git a/packages/backend/src/server/api/endpoints/blocking/create.ts b/packages/backend/src/server/api/endpoints/blocking/create.ts
index d9ba99f209..4ad40c8f1c 100644
--- a/packages/backend/src/server/api/endpoints/blocking/create.ts
+++ b/packages/backend/src/server/api/endpoints/blocking/create.ts
@@ -84,12 +84,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
});
// Check if already blocking
- const exist = await this.blockingsRepository.findOneBy({
- blockerId: blocker.id,
- blockeeId: blockee.id,
+ const exist = await this.blockingsRepository.exist({
+ where: {
+ blockerId: blocker.id,
+ blockeeId: blockee.id,
+ },
});
- if (exist != null) {
+ if (exist) {
throw new ApiError(meta.errors.alreadyBlocking);
}
diff --git a/packages/backend/src/server/api/endpoints/blocking/delete.ts b/packages/backend/src/server/api/endpoints/blocking/delete.ts
index 46dd26a45a..ad3d9f22b3 100644
--- a/packages/backend/src/server/api/endpoints/blocking/delete.ts
+++ b/packages/backend/src/server/api/endpoints/blocking/delete.ts
@@ -5,8 +5,8 @@ import type { UsersRepository, BlockingsRepository } from '@/models/index.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { UserBlockingService } from '@/core/UserBlockingService.js';
import { DI } from '@/di-symbols.js';
-import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js';
+import { ApiError } from '../../error.js';
export const meta = {
tags: ['account'],
@@ -84,12 +84,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
});
// Check not blocking
- const exist = await this.blockingsRepository.findOneBy({
- blockerId: blocker.id,
- blockeeId: blockee.id,
+ const exist = await this.blockingsRepository.exist({
+ where: {
+ blockerId: blocker.id,
+ blockeeId: blockee.id,
+ },
});
- if (exist == null) {
+ if (!exist) {
throw new ApiError(meta.errors.notBlocking);
}
diff --git a/packages/backend/src/server/api/endpoints/blocking/list.ts b/packages/backend/src/server/api/endpoints/blocking/list.ts
index 969aae06f9..d61bb0d214 100644
--- a/packages/backend/src/server/api/endpoints/blocking/list.ts
+++ b/packages/backend/src/server/api/endpoints/blocking/list.ts
@@ -48,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('blocking.blockerId = :meId', { meId: me.id });
const blockings = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.blockingEntityService.packMany(blockings, me);
diff --git a/packages/backend/src/server/api/endpoints/channels/featured.ts b/packages/backend/src/server/api/endpoints/channels/featured.ts
index 1a8d1164c7..953f027aa2 100644
--- a/packages/backend/src/server/api/endpoints/channels/featured.ts
+++ b/packages/backend/src/server/api/endpoints/channels/featured.ts
@@ -41,7 +41,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('channel.isArchived = FALSE')
.orderBy('channel.lastNotedAt', 'DESC');
- const channels = await query.take(10).getMany();
+ const channels = await query.limit(10).getMany();
return await Promise.all(channels.map(x => this.channelEntityService.pack(x, me)));
});
diff --git a/packages/backend/src/server/api/endpoints/channels/followed.ts b/packages/backend/src/server/api/endpoints/channels/followed.ts
index f49f3105d5..a1656903aa 100644
--- a/packages/backend/src/server/api/endpoints/channels/followed.ts
+++ b/packages/backend/src/server/api/endpoints/channels/followed.ts
@@ -48,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere({ followerId: me.id });
const followings = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await Promise.all(followings.map(x => this.channelEntityService.pack(x.followeeId, me)));
diff --git a/packages/backend/src/server/api/endpoints/channels/owned.ts b/packages/backend/src/server/api/endpoints/channels/owned.ts
index 8fae972cb1..4561bb2e94 100644
--- a/packages/backend/src/server/api/endpoints/channels/owned.ts
+++ b/packages/backend/src/server/api/endpoints/channels/owned.ts
@@ -49,7 +49,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere({ userId: me.id });
const channels = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await Promise.all(channels.map(x => this.channelEntityService.pack(x, me)));
diff --git a/packages/backend/src/server/api/endpoints/channels/search.ts b/packages/backend/src/server/api/endpoints/channels/search.ts
index a3b40b0bbd..dfb6937964 100644
--- a/packages/backend/src/server/api/endpoints/channels/search.ts
+++ b/packages/backend/src/server/api/endpoints/channels/search.ts
@@ -61,7 +61,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
const channels = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await Promise.all(channels.map(x => this.channelEntityService.pack(x, me)));
diff --git a/packages/backend/src/server/api/endpoints/channels/timeline.ts b/packages/backend/src/server/api/endpoints/channels/timeline.ts
index c881074bab..e3119cc40f 100644
--- a/packages/backend/src/server/api/endpoints/channels/timeline.ts
+++ b/packages/backend/src/server/api/endpoints/channels/timeline.ts
@@ -77,7 +77,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const limit = ps.limit + (ps.untilId ? 1 : 0); // untilIdに指定したものも含まれるため+1
let noteIdsRes: [string, string[]][] = [];
-
+
if (!ps.sinceId && !ps.sinceDate) {
noteIdsRes = await this.redisClient.xrevrange(
`channelTimeline:${channel.id}`,
@@ -105,7 +105,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
//#endregion
- timeline = await query.take(ps.limit).getMany();
+ timeline = await query.limit(ps.limit).getMany();
} else {
const noteIds = noteIdsRes.map(x => x[1][1]).filter(x => x !== ps.untilId);
diff --git a/packages/backend/src/server/api/endpoints/clips/add-note.ts b/packages/backend/src/server/api/endpoints/clips/add-note.ts
index c3561e2a71..2837f2cf81 100644
--- a/packages/backend/src/server/api/endpoints/clips/add-note.ts
+++ b/packages/backend/src/server/api/endpoints/clips/add-note.ts
@@ -87,12 +87,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw e;
});
- const exist = await this.clipNotesRepository.findOneBy({
- noteId: note.id,
- clipId: clip.id,
+ const exist = await this.clipNotesRepository.exist({
+ where: {
+ noteId: note.id,
+ clipId: clip.id,
+ },
});
- if (exist != null) {
+ if (exist) {
throw new ApiError(meta.errors.alreadyClipped);
}
diff --git a/packages/backend/src/server/api/endpoints/clips/favorite.ts b/packages/backend/src/server/api/endpoints/clips/favorite.ts
index f08caaf8d7..ce09855531 100644
--- a/packages/backend/src/server/api/endpoints/clips/favorite.ts
+++ b/packages/backend/src/server/api/endpoints/clips/favorite.ts
@@ -58,12 +58,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw new ApiError(meta.errors.noSuchClip);
}
- const exist = await this.clipFavoritesRepository.findOneBy({
- clipId: clip.id,
- userId: me.id,
+ const exist = await this.clipFavoritesRepository.exist({
+ where: {
+ clipId: clip.id,
+ userId: me.id,
+ },
});
- if (exist != null) {
+ if (exist) {
throw new ApiError(meta.errors.alreadyFavorited);
}
diff --git a/packages/backend/src/server/api/endpoints/clips/notes.ts b/packages/backend/src/server/api/endpoints/clips/notes.ts
index dcb415b752..49607babee 100644
--- a/packages/backend/src/server/api/endpoints/clips/notes.ts
+++ b/packages/backend/src/server/api/endpoints/clips/notes.ts
@@ -88,7 +88,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
const notes = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.noteEntityService.packMany(notes, me);
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 50c5d758bd..d0ef795819 100644
--- a/packages/backend/src/server/api/endpoints/clips/remove-note.ts
+++ b/packages/backend/src/server/api/endpoints/clips/remove-note.ts
@@ -2,8 +2,8 @@ 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';
+import { ApiError } from '../../error.js';
export const meta = {
tags: ['account', 'notes', 'clips'],
diff --git a/packages/backend/src/server/api/endpoints/drive/files.ts b/packages/backend/src/server/api/endpoints/drive/files.ts
index 4609307774..f4343248b8 100644
--- a/packages/backend/src/server/api/endpoints/drive/files.ts
+++ b/packages/backend/src/server/api/endpoints/drive/files.ts
@@ -73,7 +73,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
case '-size': query.orderBy('file.size', 'ASC'); break;
}
- const files = await query.take(ps.limit).getMany();
+ const files = await query.limit(ps.limit).getMany();
return await this.driveFileEntityService.packMany(files, { detail: false, self: true });
});
diff --git a/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts b/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts
index 290cd4d2ce..cdcdde7e8a 100644
--- a/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts
+++ b/packages/backend/src/server/api/endpoints/drive/files/check-existence.ts
@@ -34,12 +34,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private driveFilesRepository: DriveFilesRepository,
) {
super(meta, paramDef, async (ps, me) => {
- const file = await this.driveFilesRepository.findOneBy({
- md5: ps.md5,
- userId: me.id,
+ const exist = await this.driveFilesRepository.exist({
+ where: {
+ md5: ps.md5,
+ userId: me.id,
+ },
});
- return file != null;
+ return exist;
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/drive/files/update.ts b/packages/backend/src/server/api/endpoints/drive/files/update.ts
index 3ecbba22b5..c43f812e2f 100644
--- a/packages/backend/src/server/api/endpoints/drive/files/update.ts
+++ b/packages/backend/src/server/api/endpoints/drive/files/update.ts
@@ -40,7 +40,7 @@ export const meta = {
code: 'NO_SUCH_FOLDER',
id: 'ea8fb7a5-af77-4a08-b608-c0218176cd73',
},
-
+
restrictedByRole: {
message: 'This feature is restricted by your role.',
code: 'RESTRICTED_BY_ROLE',
diff --git a/packages/backend/src/server/api/endpoints/drive/folders.ts b/packages/backend/src/server/api/endpoints/drive/folders.ts
index b41eaf4463..eb674f3e15 100644
--- a/packages/backend/src/server/api/endpoints/drive/folders.ts
+++ b/packages/backend/src/server/api/endpoints/drive/folders.ts
@@ -54,7 +54,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
query.andWhere('folder.parentId IS NULL');
}
- const folders = await query.take(ps.limit).getMany();
+ const folders = await query.limit(ps.limit).getMany();
return await Promise.all(folders.map(folder => this.driveFolderEntityService.pack(folder)));
});
diff --git a/packages/backend/src/server/api/endpoints/drive/stream.ts b/packages/backend/src/server/api/endpoints/drive/stream.ts
index 61bcfea0c3..a1c14a8e3f 100644
--- a/packages/backend/src/server/api/endpoints/drive/stream.ts
+++ b/packages/backend/src/server/api/endpoints/drive/stream.ts
@@ -56,7 +56,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
}
- const files = await query.take(ps.limit).getMany();
+ const files = await query.limit(ps.limit).getMany();
return await this.driveFileEntityService.packMany(files, { detail: false, self: true });
});
diff --git a/packages/backend/src/server/api/endpoints/emoji.ts b/packages/backend/src/server/api/endpoints/emoji.ts
index 681d3e649e..51027f35c0 100644
--- a/packages/backend/src/server/api/endpoints/emoji.ts
+++ b/packages/backend/src/server/api/endpoints/emoji.ts
@@ -36,7 +36,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.config)
private config: Config,
-
+
@Inject(DI.emojisRepository)
private emojisRepository: EmojisRepository,
diff --git a/packages/backend/src/server/api/endpoints/emojis.ts b/packages/backend/src/server/api/endpoints/emojis.ts
index 13cc709d31..3c2d0ce4a4 100644
--- a/packages/backend/src/server/api/endpoints/emojis.ts
+++ b/packages/backend/src/server/api/endpoints/emojis.ts
@@ -43,7 +43,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.config)
private config: Config,
-
+
@Inject(DI.emojisRepository)
private emojisRepository: EmojisRepository,
diff --git a/packages/backend/src/server/api/endpoints/federation/followers.ts b/packages/backend/src/server/api/endpoints/federation/followers.ts
index be1d6c8e58..1b2f9446f8 100644
--- a/packages/backend/src/server/api/endpoints/federation/followers.ts
+++ b/packages/backend/src/server/api/endpoints/federation/followers.ts
@@ -47,7 +47,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('following.followeeHost = :host', { host: ps.host });
const followings = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.followingEntityService.packMany(followings, me, { populateFollowee: true });
diff --git a/packages/backend/src/server/api/endpoints/federation/following.ts b/packages/backend/src/server/api/endpoints/federation/following.ts
index 74656ce863..c5aa1ec60b 100644
--- a/packages/backend/src/server/api/endpoints/federation/following.ts
+++ b/packages/backend/src/server/api/endpoints/federation/following.ts
@@ -47,7 +47,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('following.followerHost = :host', { host: ps.host });
const followings = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.followingEntityService.packMany(followings, me, { populateFollowee: true });
diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts
index 061c6eb5be..ddf1a178b1 100644
--- a/packages/backend/src/server/api/endpoints/federation/instances.ts
+++ b/packages/backend/src/server/api/endpoints/federation/instances.ts
@@ -126,7 +126,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
query.andWhere('instance.host like :host', { host: '%' + sqlLikeEscape(ps.host.toLowerCase()) + '%' });
}
- const instances = await query.take(ps.limit).skip(ps.offset).getMany();
+ const instances = await query.limit(ps.limit).skip(ps.offset).getMany();
return await this.instanceEntityService.packMany(instances);
});
diff --git a/packages/backend/src/server/api/endpoints/federation/users.ts b/packages/backend/src/server/api/endpoints/federation/users.ts
index a028930f21..06f252005b 100644
--- a/packages/backend/src/server/api/endpoints/federation/users.ts
+++ b/packages/backend/src/server/api/endpoints/federation/users.ts
@@ -47,7 +47,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('user.host = :host', { host: ps.host });
const users = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.userEntityService.packMany(users, me, { detail: true });
diff --git a/packages/backend/src/server/api/endpoints/flash/featured.ts b/packages/backend/src/server/api/endpoints/flash/featured.ts
index 570aef96d2..99c8763b11 100644
--- a/packages/backend/src/server/api/endpoints/flash/featured.ts
+++ b/packages/backend/src/server/api/endpoints/flash/featured.ts
@@ -40,7 +40,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('flash.likedCount > 0')
.orderBy('flash.likedCount', 'DESC');
- const flashs = await query.take(10).getMany();
+ const flashs = await query.limit(10).getMany();
return await this.flashEntityService.packMany(flashs, me);
});
diff --git a/packages/backend/src/server/api/endpoints/flash/like.ts b/packages/backend/src/server/api/endpoints/flash/like.ts
index 23de2f3970..57245f9f41 100644
--- a/packages/backend/src/server/api/endpoints/flash/like.ts
+++ b/packages/backend/src/server/api/endpoints/flash/like.ts
@@ -66,12 +66,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
// if already liked
- const exist = await this.flashLikesRepository.findOneBy({
- flashId: flash.id,
- userId: me.id,
+ const exist = await this.flashLikesRepository.exist({
+ where: {
+ flashId: flash.id,
+ userId: me.id,
+ },
});
- if (exist != null) {
+ if (exist) {
throw new ApiError(meta.errors.alreadyLiked);
}
diff --git a/packages/backend/src/server/api/endpoints/flash/my-likes.ts b/packages/backend/src/server/api/endpoints/flash/my-likes.ts
index f7716ea74a..7d1149ada9 100644
--- a/packages/backend/src/server/api/endpoints/flash/my-likes.ts
+++ b/packages/backend/src/server/api/endpoints/flash/my-likes.ts
@@ -59,7 +59,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.leftJoinAndSelect('like.flash', 'flash');
const likes = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return this.flashLikeEntityService.packMany(likes, me);
diff --git a/packages/backend/src/server/api/endpoints/flash/my.ts b/packages/backend/src/server/api/endpoints/flash/my.ts
index baed7f000f..45a3b50e08 100644
--- a/packages/backend/src/server/api/endpoints/flash/my.ts
+++ b/packages/backend/src/server/api/endpoints/flash/my.ts
@@ -48,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('flash.userId = :meId', { meId: me.id });
const flashs = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.flashEntityService.packMany(flashs);
diff --git a/packages/backend/src/server/api/endpoints/following/create.ts b/packages/backend/src/server/api/endpoints/following/create.ts
index 4ad16de911..009fc96f64 100644
--- a/packages/backend/src/server/api/endpoints/following/create.ts
+++ b/packages/backend/src/server/api/endpoints/following/create.ts
@@ -99,12 +99,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
});
// Check if already following
- const exist = await this.followingsRepository.findOneBy({
- followerId: follower.id,
- followeeId: followee.id,
+ const exist = await this.followingsRepository.exist({
+ where: {
+ followerId: follower.id,
+ followeeId: followee.id,
+ },
});
- if (exist != null) {
+ if (exist) {
throw new ApiError(meta.errors.alreadyFollowing);
}
diff --git a/packages/backend/src/server/api/endpoints/following/delete.ts b/packages/backend/src/server/api/endpoints/following/delete.ts
index 4f12db1273..77ef263169 100644
--- a/packages/backend/src/server/api/endpoints/following/delete.ts
+++ b/packages/backend/src/server/api/endpoints/following/delete.ts
@@ -5,8 +5,8 @@ import type { UsersRepository, FollowingsRepository } from '@/models/index.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
import { DI } from '@/di-symbols.js';
-import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js';
+import { ApiError } from '../../error.js';
export const meta = {
tags: ['following', 'users'],
@@ -84,12 +84,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
});
// Check not following
- const exist = await this.followingsRepository.findOneBy({
- followerId: follower.id,
- followeeId: followee.id,
+ const exist = await this.followingsRepository.exist({
+ where: {
+ followerId: follower.id,
+ followeeId: followee.id,
+ },
});
- if (exist == null) {
+ if (!exist) {
throw new ApiError(meta.errors.notFollowing);
}
diff --git a/packages/backend/src/server/api/endpoints/following/invalidate.ts b/packages/backend/src/server/api/endpoints/following/invalidate.ts
index 22304cacda..0e57f6328f 100644
--- a/packages/backend/src/server/api/endpoints/following/invalidate.ts
+++ b/packages/backend/src/server/api/endpoints/following/invalidate.ts
@@ -5,8 +5,8 @@ import type { UsersRepository, FollowingsRepository } from '@/models/index.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
import { DI } from '@/di-symbols.js';
-import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js';
+import { ApiError } from '../../error.js';
export const meta = {
tags: ['following', 'users'],
diff --git a/packages/backend/src/server/api/endpoints/following/requests/list.ts b/packages/backend/src/server/api/endpoints/following/requests/list.ts
index d68248fab9..29588e8731 100644
--- a/packages/backend/src/server/api/endpoints/following/requests/list.ts
+++ b/packages/backend/src/server/api/endpoints/following/requests/list.ts
@@ -64,7 +64,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('request.followeeId = :meId', { meId: me.id });
const requests = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await Promise.all(requests.map(req => this.followRequestEntityService.pack(req)));
diff --git a/packages/backend/src/server/api/endpoints/gallery/featured.ts b/packages/backend/src/server/api/endpoints/gallery/featured.ts
index 9994ce90d7..46347247f0 100644
--- a/packages/backend/src/server/api/endpoints/gallery/featured.ts
+++ b/packages/backend/src/server/api/endpoints/gallery/featured.ts
@@ -41,7 +41,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('post.likedCount > 0')
.orderBy('post.likedCount', 'DESC');
- const posts = await query.take(10).getMany();
+ const posts = await query.limit(10).getMany();
return await this.galleryPostEntityService.packMany(posts, me);
});
diff --git a/packages/backend/src/server/api/endpoints/gallery/popular.ts b/packages/backend/src/server/api/endpoints/gallery/popular.ts
index 55d3dabfb0..4ee3d68a92 100644
--- a/packages/backend/src/server/api/endpoints/gallery/popular.ts
+++ b/packages/backend/src/server/api/endpoints/gallery/popular.ts
@@ -40,7 +40,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('post.likedCount > 0')
.orderBy('post.likedCount', 'DESC');
- const posts = await query.take(10).getMany();
+ const posts = await query.limit(10).getMany();
return await this.galleryPostEntityService.packMany(posts, me);
});
diff --git a/packages/backend/src/server/api/endpoints/gallery/posts.ts b/packages/backend/src/server/api/endpoints/gallery/posts.ts
index e94003eb79..b9aac3fb34 100644
--- a/packages/backend/src/server/api/endpoints/gallery/posts.ts
+++ b/packages/backend/src/server/api/endpoints/gallery/posts.ts
@@ -43,7 +43,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const query = this.queryService.makePaginationQuery(this.galleryPostsRepository.createQueryBuilder('post'), ps.sinceId, ps.untilId)
.innerJoinAndSelect('post.user', 'user');
- const posts = await query.take(ps.limit).getMany();
+ const posts = await query.limit(ps.limit).getMany();
return await this.galleryPostEntityService.packMany(posts, me);
});
diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts
index 6ac5fa8606..c0bb55f640 100644
--- a/packages/backend/src/server/api/endpoints/gallery/posts/like.ts
+++ b/packages/backend/src/server/api/endpoints/gallery/posts/like.ts
@@ -66,12 +66,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
// if already liked
- const exist = await this.galleryLikesRepository.findOneBy({
- postId: post.id,
- userId: me.id,
+ const exist = await this.galleryLikesRepository.exist({
+ where: {
+ postId: post.id,
+ userId: me.id,
+ },
});
- if (exist != null) {
+ if (exist) {
throw new ApiError(meta.errors.alreadyLiked);
}
diff --git a/packages/backend/src/server/api/endpoints/get-online-users-count.ts b/packages/backend/src/server/api/endpoints/get-online-users-count.ts
index dea0f4799c..810bde03e8 100644
--- a/packages/backend/src/server/api/endpoints/get-online-users-count.ts
+++ b/packages/backend/src/server/api/endpoints/get-online-users-count.ts
@@ -9,6 +9,8 @@ export const meta = {
tags: ['meta'],
requireCredential: false,
+ allowGet: true,
+ cacheSec: 60 * 1,
} as const;
export const paramDef = {
diff --git a/packages/backend/src/server/api/endpoints/hashtags/list.ts b/packages/backend/src/server/api/endpoints/hashtags/list.ts
index 226a11de0b..693d938bf0 100644
--- a/packages/backend/src/server/api/endpoints/hashtags/list.ts
+++ b/packages/backend/src/server/api/endpoints/hashtags/list.ts
@@ -73,7 +73,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
'tag.attachedRemoteUsersCount',
]);
- const tags = await query.take(ps.limit).getMany();
+ const tags = await query.limit(ps.limit).getMany();
return this.hashtagEntityService.packMany(tags);
});
diff --git a/packages/backend/src/server/api/endpoints/hashtags/search.ts b/packages/backend/src/server/api/endpoints/hashtags/search.ts
index 4f5f979767..e2e00def79 100644
--- a/packages/backend/src/server/api/endpoints/hashtags/search.ts
+++ b/packages/backend/src/server/api/endpoints/hashtags/search.ts
@@ -41,7 +41,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.where('tag.name like :q', { q: sqlLikeEscape(ps.query.toLowerCase()) + '%' })
.orderBy('tag.count', 'DESC')
.groupBy('tag.id')
- .take(ps.limit)
+ .limit(ps.limit)
.skip(ps.offset)
.getMany();
diff --git a/packages/backend/src/server/api/endpoints/hashtags/trend.ts b/packages/backend/src/server/api/endpoints/hashtags/trend.ts
index cf45cc6c24..ce1cd9f01f 100644
--- a/packages/backend/src/server/api/endpoints/hashtags/trend.ts
+++ b/packages/backend/src/server/api/endpoints/hashtags/trend.ts
@@ -26,6 +26,8 @@ export const meta = {
tags: ['hashtags'],
requireCredential: false,
+ allowGet: true,
+ cacheSec: 60 * 1,
res: {
type: 'array',
diff --git a/packages/backend/src/server/api/endpoints/hashtags/users.ts b/packages/backend/src/server/api/endpoints/hashtags/users.ts
index dd3549020e..b00b005add 100644
--- a/packages/backend/src/server/api/endpoints/hashtags/users.ts
+++ b/packages/backend/src/server/api/endpoints/hashtags/users.ts
@@ -39,7 +39,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
-
+
private userEntityService: UserEntityService,
) {
super(meta, paramDef, async (ps, me) => {
@@ -68,7 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
case '-updatedAt': query.orderBy('user.updatedAt', 'ASC'); break;
}
- const users = await query.take(ps.limit).getMany();
+ const users = await query.limit(ps.limit).getMany();
return await this.userEntityService.packMany(users, me, { detail: true });
});
diff --git a/packages/backend/src/server/api/endpoints/i.ts b/packages/backend/src/server/api/endpoints/i.ts
index a3e3e02a12..4d593542db 100644
--- a/packages/backend/src/server/api/endpoints/i.ts
+++ b/packages/backend/src/server/api/endpoints/i.ts
@@ -23,7 +23,7 @@ export const meta = {
id: 'e5b3b9f0-2b8f-4b9f-9c1f-8c5c1b2e1b1a',
kind: 'permission',
},
- }
+ },
} as const;
export const paramDef = {
@@ -68,7 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
});
userProfile.loggedInDates = [...userProfile.loggedInDates, today];
}
-
+
return await this.userEntityService.pack<true, true>(userProfile.user!, userProfile.user!, {
detail: true,
includeSecrets: isSecure,
diff --git a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts
index e8985a9cd8..a7e39fc028 100644
--- a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts
+++ b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts
@@ -103,7 +103,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const procedures = this.twoFactorAuthenticationService.getProcedures();
if (!(procedures as any)[attestation.fmt]) {
- throw new Error('unsupported fmt');
+ throw new Error(`unsupported fmt: ${attestation.fmt}. Supported ones: ${Object.keys(procedures)}`);
}
const verificationData = (procedures as any)[attestation.fmt].verify({
diff --git a/packages/backend/src/server/api/endpoints/i/2fa/update-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/update-key.ts
index d98f60fa5f..2ef5e5a279 100644
--- a/packages/backend/src/server/api/endpoints/i/2fa/update-key.ts
+++ b/packages/backend/src/server/api/endpoints/i/2fa/update-key.ts
@@ -61,7 +61,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (key.userId !== me.id) {
throw new ApiError(meta.errors.accessDenied);
}
-
+
await this.userSecurityKeysRepository.update(key.id, {
name: ps.name,
});
diff --git a/packages/backend/src/server/api/endpoints/i/favorites.ts b/packages/backend/src/server/api/endpoints/i/favorites.ts
index ce8ab4962a..bdfb63974a 100644
--- a/packages/backend/src/server/api/endpoints/i/favorites.ts
+++ b/packages/backend/src/server/api/endpoints/i/favorites.ts
@@ -49,7 +49,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.leftJoinAndSelect('favorite.note', 'note');
const favorites = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.noteFavoriteEntityService.packMany(favorites, me);
diff --git a/packages/backend/src/server/api/endpoints/i/gallery/likes.ts b/packages/backend/src/server/api/endpoints/i/gallery/likes.ts
index d1b04cb655..915639e5f7 100644
--- a/packages/backend/src/server/api/endpoints/i/gallery/likes.ts
+++ b/packages/backend/src/server/api/endpoints/i/gallery/likes.ts
@@ -60,7 +60,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.leftJoinAndSelect('like.post', 'post');
const likes = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.galleryLikeEntityService.packMany(likes, me);
diff --git a/packages/backend/src/server/api/endpoints/i/gallery/posts.ts b/packages/backend/src/server/api/endpoints/i/gallery/posts.ts
index 32d14293f7..5ba9afd4a8 100644
--- a/packages/backend/src/server/api/endpoints/i/gallery/posts.ts
+++ b/packages/backend/src/server/api/endpoints/i/gallery/posts.ts
@@ -48,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('post.userId = :meId', { meId: me.id });
const posts = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.galleryPostEntityService.packMany(posts, me);
diff --git a/packages/backend/src/server/api/endpoints/i/import-antennas.ts b/packages/backend/src/server/api/endpoints/i/import-antennas.ts
index efb5ce4223..8582e98f76 100644
--- a/packages/backend/src/server/api/endpoints/i/import-antennas.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-antennas.ts
@@ -54,7 +54,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor (
@Inject(DI.driveFilesRepository)
private driveFilesRepository: DriveFilesRepository,
-
+
@Inject(DI.antennasRepository)
private antennasRepository: AntennasRepository,
@@ -66,8 +66,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private downloadService: DownloadService,
) {
super(meta, paramDef, async (ps, me) => {
- const users = await this.usersRepository.findOneBy({ id: me.id });
- if (users === null) throw new ApiError(meta.errors.noSuchUser);
+ const userExist = await this.usersRepository.exist({ where: { id: me.id } });
+ if (!userExist) throw new ApiError(meta.errors.noSuchUser);
const file = await this.driveFilesRepository.findOneBy({ id: ps.fileId });
if (file === null) throw new ApiError(meta.errors.noSuchFile);
if (file.size === 0) throw new ApiError(meta.errors.emptyFile);
@@ -79,6 +79,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
this.queueService.createImportAntennasJob(me, antennas);
});
}
-}
+}
export type Antenna = (_Antenna & { userListAccts: string[] | null })[];
diff --git a/packages/backend/src/server/api/endpoints/i/import-blocking.ts b/packages/backend/src/server/api/endpoints/i/import-blocking.ts
index 811971591a..32c16300fb 100644
--- a/packages/backend/src/server/api/endpoints/i/import-blocking.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-blocking.ts
@@ -72,7 +72,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const checkMoving = await this.accountMoveService.validateAlsoKnownAs(
me,
(old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > (new Date()).getTime(),
- true
+ true,
);
if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile);
diff --git a/packages/backend/src/server/api/endpoints/i/import-following.ts b/packages/backend/src/server/api/endpoints/i/import-following.ts
index 8af278c883..1926a1f503 100644
--- a/packages/backend/src/server/api/endpoints/i/import-following.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-following.ts
@@ -71,7 +71,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const checkMoving = await this.accountMoveService.validateAlsoKnownAs(
me,
(old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > (new Date()).getTime(),
- true
+ true,
);
if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile);
diff --git a/packages/backend/src/server/api/endpoints/i/import-muting.ts b/packages/backend/src/server/api/endpoints/i/import-muting.ts
index eb0f9ba474..34f2627563 100644
--- a/packages/backend/src/server/api/endpoints/i/import-muting.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-muting.ts
@@ -72,7 +72,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const checkMoving = await this.accountMoveService.validateAlsoKnownAs(
me,
(old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > (new Date()).getTime(),
- true
+ true,
);
if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile);
diff --git a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts
index 4568e93901..1b3cb5359d 100644
--- a/packages/backend/src/server/api/endpoints/i/import-user-lists.ts
+++ b/packages/backend/src/server/api/endpoints/i/import-user-lists.ts
@@ -71,7 +71,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const checkMoving = await this.accountMoveService.validateAlsoKnownAs(
me,
(old, src) => !!src.movedAt && src.movedAt.getTime() + 1000 * 60 * 60 * 2 > (new Date()).getTime(),
- true
+ true,
);
if (checkMoving ? file.size > 32 * 1024 * 1024 : file.size > 64 * 1024) throw new ApiError(meta.errors.tooBigFile);
diff --git a/packages/backend/src/server/api/endpoints/i/page-likes.ts b/packages/backend/src/server/api/endpoints/i/page-likes.ts
index 70e6e0a6a8..9f073ba596 100644
--- a/packages/backend/src/server/api/endpoints/i/page-likes.ts
+++ b/packages/backend/src/server/api/endpoints/i/page-likes.ts
@@ -59,7 +59,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.leftJoinAndSelect('like.page', 'page');
const likes = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return this.pageLikeEntityService.packMany(likes, me);
diff --git a/packages/backend/src/server/api/endpoints/i/pages.ts b/packages/backend/src/server/api/endpoints/i/pages.ts
index 285aa34e91..772486befc 100644
--- a/packages/backend/src/server/api/endpoints/i/pages.ts
+++ b/packages/backend/src/server/api/endpoints/i/pages.ts
@@ -48,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('page.userId = :meId', { meId: me.id });
const pages = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.pageEntityService.packMany(pages);
diff --git a/packages/backend/src/server/api/endpoints/i/read-announcement.ts b/packages/backend/src/server/api/endpoints/i/read-announcement.ts
index b8922b91e5..352fe54c5d 100644
--- a/packages/backend/src/server/api/endpoints/i/read-announcement.ts
+++ b/packages/backend/src/server/api/endpoints/i/read-announcement.ts
@@ -47,19 +47,21 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
) {
super(meta, paramDef, async (ps, me) => {
// Check if announcement exists
- const announcement = await this.announcementsRepository.findOneBy({ id: ps.announcementId });
+ const announcementExist = await this.announcementsRepository.exist({ where: { id: ps.announcementId } });
- if (announcement == null) {
+ if (!announcementExist) {
throw new ApiError(meta.errors.noSuchAnnouncement);
}
// Check if already read
- const read = await this.announcementReadsRepository.findOneBy({
- announcementId: ps.announcementId,
- userId: me.id,
+ const alreadyRead = await this.announcementReadsRepository.exist({
+ where: {
+ announcementId: ps.announcementId,
+ userId: me.id,
+ },
});
- if (read != null) {
+ if (alreadyRead) {
return;
}
diff --git a/packages/backend/src/server/api/endpoints/i/revoke-token.ts b/packages/backend/src/server/api/endpoints/i/revoke-token.ts
index 93daeb0cd7..415a60147b 100644
--- a/packages/backend/src/server/api/endpoints/i/revoke-token.ts
+++ b/packages/backend/src/server/api/endpoints/i/revoke-token.ts
@@ -28,9 +28,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private globalEventService: GlobalEventService,
) {
super(meta, paramDef, async (ps, me) => {
- const token = await this.accessTokensRepository.findOneBy({ id: ps.tokenId });
+ const tokenExist = await this.accessTokensRepository.exist({ where: { id: ps.tokenId } });
- if (token) {
+ if (tokenExist) {
await this.accessTokensRepository.delete({
id: ps.tokenId,
userId: me.id,
diff --git a/packages/backend/src/server/api/endpoints/i/signin-history.ts b/packages/backend/src/server/api/endpoints/i/signin-history.ts
index 9b30a24336..aa8cb5cf42 100644
--- a/packages/backend/src/server/api/endpoints/i/signin-history.ts
+++ b/packages/backend/src/server/api/endpoints/i/signin-history.ts
@@ -35,7 +35,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const query = this.queryService.makePaginationQuery(this.signinsRepository.createQueryBuilder('signin'), ps.sinceId, ps.untilId)
.andWhere('signin.userId = :meId', { meId: me.id });
- const history = await query.take(ps.limit).getMany();
+ const history = await query.limit(ps.limit).getMany();
return await Promise.all(history.map(record => this.signinEntityService.pack(record)));
});
diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts
index 4f543a6472..58e056bd37 100644
--- a/packages/backend/src/server/api/endpoints/i/update-email.ts
+++ b/packages/backend/src/server/api/endpoints/i/update-email.ts
@@ -1,5 +1,4 @@
import { Inject, Injectable } from '@nestjs/common';
-import rndstr from 'rndstr';
import ms from 'ms';
import bcrypt from 'bcryptjs';
import { Endpoint } from '@/server/api/endpoint-base.js';
@@ -9,6 +8,7 @@ import { EmailService } from '@/core/EmailService.js';
import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
+import { L_CHARS, secureRndstr } from '@/misc/secure-rndstr.js';
import { ApiError } from '../../error.js';
export const meta = {
@@ -94,7 +94,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
this.globalEventService.publishMainStream(me.id, 'meUpdated', iObj);
if (ps.email != null) {
- const code = rndstr('a-z0-9', 16);
+ const code = secureRndstr(16, { chars: L_CHARS });
await this.userProfilesRepository.update(me.id, {
emailVerifyCode: code,
diff --git a/packages/backend/src/server/api/endpoints/invite/create.ts b/packages/backend/src/server/api/endpoints/invite/create.ts
new file mode 100644
index 0000000000..a64184be10
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/invite/create.ts
@@ -0,0 +1,82 @@
+import { MoreThan } from 'typeorm';
+import { Inject, Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import type { RegistrationTicketsRepository } from '@/models/index.js';
+import { InviteCodeEntityService } from '@/core/entities/InviteCodeEntityService.js';
+import { IdService } from '@/core/IdService.js';
+import { RoleService } from '@/core/RoleService.js';
+import { DI } from '@/di-symbols.js';
+import { generateInviteCode } from '@/misc/generate-invite-code.js';
+import { ApiError } from '../../error.js';
+
+export const meta = {
+ tags: ['meta'],
+
+ requireCredential: true,
+ requireRolePolicy: 'canInvite',
+
+ errors: {
+ exceededCreateLimit: {
+ message: 'You have exceeded the limit for creating an invitation code.',
+ code: 'EXCEEDED_LIMIT_OF_CREATE_INVITE_CODE',
+ id: '8b165dd3-6f37-4557-8db1-73175d63c641',
+ },
+ },
+
+ res: {
+ type: 'object',
+ optional: false, nullable: false,
+ properties: {
+ code: {
+ type: 'string',
+ optional: false, nullable: false,
+ example: 'GR6S02ERUA5VR',
+ },
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {},
+ required: [],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.registrationTicketsRepository)
+ private registrationTicketsRepository: RegistrationTicketsRepository,
+
+ private inviteCodeEntityService: InviteCodeEntityService,
+ private idService: IdService,
+ private roleService: RoleService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const policies = await this.roleService.getUserPolicies(me.id);
+
+ if (policies.inviteLimit) {
+ const count = await this.registrationTicketsRepository.countBy({
+ createdAt: MoreThan(new Date(Date.now() - (policies.inviteLimitCycle * 1000 * 60))),
+ createdById: me.id,
+ });
+
+ if (count >= policies.inviteLimit) {
+ throw new ApiError(meta.errors.exceededCreateLimit);
+ }
+ }
+
+ const ticket = await this.registrationTicketsRepository.insert({
+ id: this.idService.genId(),
+ createdAt: new Date(),
+ createdBy: me,
+ createdById: me.id,
+ expiresAt: policies.inviteExpirationTime ? new Date(Date.now() + (policies.inviteExpirationTime * 1000 * 60)) : null,
+ code: generateInviteCode(),
+ }).then(x => this.registrationTicketsRepository.findOneByOrFail(x.identifiers[0]));
+
+ return await this.inviteCodeEntityService.pack(ticket, me);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/invite/delete.ts b/packages/backend/src/server/api/endpoints/invite/delete.ts
new file mode 100644
index 0000000000..afca44954d
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/invite/delete.ts
@@ -0,0 +1,71 @@
+import { Inject, Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import type { RegistrationTicketsRepository } from '@/models/index.js';
+import { RoleService } from '@/core/RoleService.js';
+import { DI } from '@/di-symbols.js';
+import { ApiError } from '../../error.js';
+
+export const meta = {
+ tags: ['meta'],
+
+ requireCredential: true,
+ requireRolePolicy: 'canInvite',
+
+ errors: {
+ noSuchCode: {
+ message: 'No such invite code.',
+ code: 'NO_SUCH_INVITE_CODE',
+ id: 'cd4f9ae4-7854-4e3e-8df9-c296f051e634',
+ },
+
+ cantDelete: {
+ message: 'You can\'t delete this invite code.',
+ code: 'CAN_NOT_DELETE_INVITE_CODE',
+ id: 'ff17af39-000c-4d4e-abdf-848fa30fc1ce',
+ },
+
+ accessDenied: {
+ message: 'Access denied.',
+ code: 'ACCESS_DENIED',
+ id: '5eb8d909-2540-4970-90b8-dd6f86088121',
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ inviteId: { type: 'string', format: 'misskey:id' },
+ },
+ required: ['inviteId'],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.registrationTicketsRepository)
+ private registrationTicketsRepository: RegistrationTicketsRepository,
+
+ private roleService: RoleService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const ticket = await this.registrationTicketsRepository.findOneBy({ id: ps.inviteId });
+ const isModerator = await this.roleService.isModerator(me);
+
+ if (ticket == null) {
+ throw new ApiError(meta.errors.noSuchCode);
+ }
+
+ if (ticket.createdById !== me.id && !isModerator) {
+ throw new ApiError(meta.errors.accessDenied);
+ }
+
+ if (ticket.usedAt && !isModerator) {
+ throw new ApiError(meta.errors.cantDelete);
+ }
+
+ await this.registrationTicketsRepository.delete(ticket.id);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/invite.ts b/packages/backend/src/server/api/endpoints/invite/limit.ts
index 5d2c479e79..9a213b7b25 100644
--- a/packages/backend/src/server/api/endpoints/invite.ts
+++ b/packages/backend/src/server/api/endpoints/invite/limit.ts
@@ -1,8 +1,8 @@
-import rndstr from 'rndstr';
import { Inject, Injectable } from '@nestjs/common';
+import { MoreThan } from 'typeorm';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { RegistrationTicketsRepository } from '@/models/index.js';
-import { IdService } from '@/core/IdService.js';
+import { RoleService } from '@/core/RoleService.js';
import { DI } from '@/di-symbols.js';
export const meta = {
@@ -15,12 +15,9 @@ export const meta = {
type: 'object',
optional: false, nullable: false,
properties: {
- code: {
- type: 'string',
- optional: false, nullable: false,
- example: '2ERUA5VR',
- maxLength: 8,
- minLength: 8,
+ remaining: {
+ type: 'integer',
+ optional: false, nullable: true,
},
},
},
@@ -39,22 +36,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
@Inject(DI.registrationTicketsRepository)
private registrationTicketsRepository: RegistrationTicketsRepository,
- private idService: IdService,
+ private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
- const code = rndstr({
- length: 8,
- chars: '2-9A-HJ-NP-Z', // [0-9A-Z] w/o [01IO] (32 patterns)
- });
+ const policies = await this.roleService.getUserPolicies(me.id);
- await this.registrationTicketsRepository.insert({
- id: this.idService.genId(),
- createdAt: new Date(),
- code,
- });
+ const count = policies.inviteLimit ? await this.registrationTicketsRepository.countBy({
+ createdAt: MoreThan(new Date(Date.now() - (policies.inviteExpirationTime * 60 * 1000))),
+ createdById: me.id,
+ }) : null;
return {
- code,
+ remaining: count !== null ? Math.max(0, policies.inviteLimit - count) : null,
};
});
}
diff --git a/packages/backend/src/server/api/endpoints/invite/list.ts b/packages/backend/src/server/api/endpoints/invite/list.ts
new file mode 100644
index 0000000000..e047790261
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/invite/list.ts
@@ -0,0 +1,58 @@
+import { Inject, Injectable } from '@nestjs/common';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import type { RegistrationTicketsRepository } from '@/models/index.js';
+import { InviteCodeEntityService } from '@/core/entities/InviteCodeEntityService.js';
+import { QueryService } from '@/core/QueryService.js';
+import { DI } from '@/di-symbols.js';
+import { ApiError } from '../../error.js';
+
+export const meta = {
+ tags: ['meta'],
+
+ requireCredential: true,
+ requireRolePolicy: 'canInvite',
+
+ res: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'object',
+ optional: false, nullable: false,
+ },
+ },
+} as const;
+
+export const paramDef = {
+ type: 'object',
+ properties: {
+ limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
+ sinceId: { type: 'string', format: 'misskey:id' },
+ untilId: { type: 'string', format: 'misskey:id' },
+ },
+ required: [],
+} as const;
+
+// eslint-disable-next-line import/no-default-export
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.registrationTicketsRepository)
+ private registrationTicketsRepository: RegistrationTicketsRepository,
+
+ private inviteCodeEntityService: InviteCodeEntityService,
+ private queryService: QueryService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ const query = this.queryService.makePaginationQuery(this.registrationTicketsRepository.createQueryBuilder('ticket'), ps.sinceId, ps.untilId)
+ .andWhere('ticket.createdById = :meId', { meId: me.id })
+ .leftJoinAndSelect('ticket.createdBy', 'createdBy')
+ .leftJoinAndSelect('ticket.usedBy', 'usedBy');
+
+ const tickets = await query
+ .limit(ps.limit)
+ .getMany();
+
+ return await this.inviteCodeEntityService.packMany(tickets, me);
+ });
+ }
+}
diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts
index 3b3c5caa00..adfa579558 100644
--- a/packages/backend/src/server/api/endpoints/meta.ts
+++ b/packages/backend/src/server/api/endpoints/meta.ts
@@ -1,4 +1,4 @@
-import { IsNull, LessThanOrEqual, MoreThan } from 'typeorm';
+import { IsNull, LessThanOrEqual, MoreThan, Brackets } from 'typeorm';
import { Inject, Injectable } from '@nestjs/common';
import JSON5 from 'json5';
import type { AdsRepository, UsersRepository } from '@/models/index.js';
@@ -83,6 +83,10 @@ export const meta = {
type: 'boolean',
optional: false, nullable: false,
},
+ cacheRemoteSensitiveFiles: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
emailRequiredForSignup: {
type: 'boolean',
optional: false, nullable: false,
@@ -250,7 +254,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.config)
private config: Config,
-
+
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -263,12 +267,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
super(meta, paramDef, async (ps, me) => {
const instance = await this.metaService.fetch(true);
- const ads = await this.adsRepository.find({
- where: {
- expiresAt: MoreThan(new Date()),
- startsAt: LessThanOrEqual(new Date()),
- },
- });
+ const ads = await this.adsRepository.createQueryBuilder('ads')
+ .where('ads.expiresAt > :now', { now: new Date() })
+ .andWhere('ads.startsAt <= :now', { now: new Date() })
+ .andWhere(new Brackets(qb => {
+ // 曜日のビットフラグを確認する
+ qb.where('ads.dayOfWeek & :dayOfWeek > 0', { dayOfWeek: 1 << new Date().getDay() })
+ .orWhere('ads.dayOfWeek = 0');
+ }))
+ .getMany();
const response: any = {
maintainerName: instance.maintainerName,
@@ -311,6 +318,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
place: ad.place,
ratio: ad.ratio,
imageUrl: ad.imageUrl,
+ dayOfWeek: ad.dayOfWeek,
})),
enableEmail: instance.enableEmail,
enableServiceWorker: instance.enableServiceWorker,
@@ -325,6 +333,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
...(ps.detail ? {
cacheRemoteFiles: instance.cacheRemoteFiles,
+ cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles,
requireSetup: (await this.usersRepository.countBy({
host: IsNull(),
})) === 0,
diff --git a/packages/backend/src/server/api/endpoints/miauth/gen-token.ts b/packages/backend/src/server/api/endpoints/miauth/gen-token.ts
index 97def86262..0ea29f04dc 100644
--- a/packages/backend/src/server/api/endpoints/miauth/gen-token.ts
+++ b/packages/backend/src/server/api/endpoints/miauth/gen-token.ts
@@ -49,7 +49,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
) {
super(meta, paramDef, async (ps, me) => {
// Generate access token
- const accessToken = secureRndstr(32, true);
+ const accessToken = secureRndstr(32);
const now = new Date();
diff --git a/packages/backend/src/server/api/endpoints/mute/create.ts b/packages/backend/src/server/api/endpoints/mute/create.ts
index ee358d5c6c..ef53f9ef41 100644
--- a/packages/backend/src/server/api/endpoints/mute/create.ts
+++ b/packages/backend/src/server/api/endpoints/mute/create.ts
@@ -79,12 +79,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
});
// Check if already muting
- const exist = await this.mutingsRepository.findOneBy({
- muterId: muter.id,
- muteeId: mutee.id,
+ const exist = await this.mutingsRepository.exist({
+ where: {
+ muterId: muter.id,
+ muteeId: mutee.id,
+ },
});
- if (exist != null) {
+ if (exist) {
throw new ApiError(meta.errors.alreadyMuting);
}
diff --git a/packages/backend/src/server/api/endpoints/mute/list.ts b/packages/backend/src/server/api/endpoints/mute/list.ts
index 9ec6d17273..4711e86d6b 100644
--- a/packages/backend/src/server/api/endpoints/mute/list.ts
+++ b/packages/backend/src/server/api/endpoints/mute/list.ts
@@ -48,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('muting.muterId = :meId', { meId: me.id });
const mutings = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.mutingEntityService.packMany(mutings, me);
diff --git a/packages/backend/src/server/api/endpoints/notes.ts b/packages/backend/src/server/api/endpoints/notes.ts
index 5fbc7aba58..9013b300e7 100644
--- a/packages/backend/src/server/api/endpoints/notes.ts
+++ b/packages/backend/src/server/api/endpoints/notes.ts
@@ -53,34 +53,34 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.leftJoinAndSelect('note.renote', 'renote')
.leftJoinAndSelect('reply.user', 'replyUser')
.leftJoinAndSelect('renote.user', 'renoteUser');
-
+
if (ps.local) {
query.andWhere('note.userHost IS NULL');
}
-
+
if (ps.reply !== undefined) {
query.andWhere(ps.reply ? 'note.replyId IS NOT NULL' : 'note.replyId IS NULL');
}
-
+
if (ps.renote !== undefined) {
query.andWhere(ps.renote ? 'note.renoteId IS NOT NULL' : 'note.renoteId IS NULL');
}
-
+
if (ps.withFiles !== undefined) {
query.andWhere(ps.withFiles ? 'note.fileIds != \'{}\'' : 'note.fileIds = \'{}\'');
}
-
+
if (ps.poll !== undefined) {
query.andWhere(ps.poll ? 'note.hasPoll = TRUE' : 'note.hasPoll = FALSE');
}
-
+
// TODO
//if (bot != undefined) {
// query.isBot = bot;
//}
-
- const notes = await query.take(ps.limit).getMany();
-
+
+ const notes = await query.limit(ps.limit).getMany();
+
return await this.noteEntityService.packMany(notes);
});
}
diff --git a/packages/backend/src/server/api/endpoints/notes/children.ts b/packages/backend/src/server/api/endpoints/notes/children.ts
index 26f2d6772d..5f03fd4b74 100644
--- a/packages/backend/src/server/api/endpoints/notes/children.ts
+++ b/packages/backend/src/server/api/endpoints/notes/children.ts
@@ -68,7 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
this.queryService.generateBlockedUserQuery(query, me);
}
- const notes = await query.take(ps.limit).getMany();
+ const notes = await query.limit(ps.limit).getMany();
return await this.noteEntityService.packMany(notes, me);
});
diff --git a/packages/backend/src/server/api/endpoints/notes/conversation.ts b/packages/backend/src/server/api/endpoints/notes/conversation.ts
index 5ecf7cf458..10f43b04c0 100644
--- a/packages/backend/src/server/api/endpoints/notes/conversation.ts
+++ b/packages/backend/src/server/api/endpoints/notes/conversation.ts
@@ -4,8 +4,8 @@ import type { NotesRepository } from '@/models/index.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { DI } from '@/di-symbols.js';
-import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js';
+import { ApiError } from '../../error.js';
export const meta = {
tags: ['notes'],
diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts
index 96be5ed844..739316997a 100644
--- a/packages/backend/src/server/api/endpoints/notes/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/create.ts
@@ -217,11 +217,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
// Check blocking
if (renote.userId !== me.id) {
- const block = await this.blockingsRepository.findOneBy({
- blockerId: renote.userId,
- blockeeId: me.id,
+ const blockExist = await this.blockingsRepository.exist({
+ where: {
+ blockerId: renote.userId,
+ blockeeId: me.id,
+ },
});
- if (block) {
+ if (blockExist) {
throw new ApiError(meta.errors.youHaveBeenBlocked);
}
}
@@ -240,11 +242,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
// Check blocking
if (reply.userId !== me.id) {
- const block = await this.blockingsRepository.findOneBy({
- blockerId: reply.userId,
- blockeeId: me.id,
+ const blockExist = await this.blockingsRepository.exist({
+ where: {
+ blockerId: reply.userId,
+ blockeeId: me.id,
+ },
});
- if (block) {
+ if (blockExist) {
throw new ApiError(meta.errors.youHaveBeenBlocked);
}
}
diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts
index 611ea19560..9299d66039 100644
--- a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts
@@ -63,12 +63,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
});
// if already favorited
- const exist = await this.noteFavoritesRepository.findOneBy({
- noteId: note.id,
- userId: me.id,
+ const exist = await this.noteFavoritesRepository.exist({
+ where: {
+ noteId: note.id,
+ userId: me.id,
+ },
});
- if (exist != null) {
+ if (exist) {
throw new ApiError(meta.errors.alreadyFavorited);
}
diff --git a/packages/backend/src/server/api/endpoints/notes/featured.ts b/packages/backend/src/server/api/endpoints/notes/featured.ts
index bdb06498bc..3a3cb0739b 100644
--- a/packages/backend/src/server/api/endpoints/notes/featured.ts
+++ b/packages/backend/src/server/api/endpoints/notes/featured.ts
@@ -65,7 +65,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
let notes = await query
.orderBy('note.score', 'DESC')
- .take(100)
+ .limit(100)
.getMany();
notes.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts
index 88c1ca7f58..4ce2fdaec7 100644
--- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts
@@ -88,7 +88,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
//#endregion
- const timeline = await query.take(ps.limit).getMany();
+ const timeline = await query.limit(ps.limit).getMany();
process.nextTick(() => {
if (me) {
diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts
index 7a3581e6e4..af94cf6087 100644
--- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts
@@ -137,7 +137,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
//#endregion
- const timeline = await query.take(ps.limit).getMany();
+ const timeline = await query.limit(ps.limit).getMany();
process.nextTick(() => {
this.activeUsersChart.read(me);
diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts
index 2ee549232c..fe7407f48a 100644
--- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts
@@ -110,7 +110,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
//#endregion
- const timeline = await query.take(ps.limit).getMany();
+ const timeline = await query.limit(ps.limit).getMany();
process.nextTick(() => {
if (me) {
diff --git a/packages/backend/src/server/api/endpoints/notes/mentions.ts b/packages/backend/src/server/api/endpoints/notes/mentions.ts
index 4e9f604d8d..6ee9de1e23 100644
--- a/packages/backend/src/server/api/endpoints/notes/mentions.ts
+++ b/packages/backend/src/server/api/endpoints/notes/mentions.ts
@@ -79,7 +79,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
query.setParameters(followingQuery.getParameters());
}
- const mentions = await query.take(ps.limit).getMany();
+ const mentions = await query.limit(ps.limit).getMany();
this.noteReadService.read(me.id, mentions);
diff --git a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts
index 6cdc9b902c..0b4ccdcf20 100644
--- a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts
+++ b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts
@@ -82,7 +82,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const polls = await query
.orderBy('poll.noteId', 'DESC')
- .take(ps.limit)
+ .limit(ps.limit)
.skip(ps.offset)
.getMany();
diff --git a/packages/backend/src/server/api/endpoints/notes/renotes.ts b/packages/backend/src/server/api/endpoints/notes/renotes.ts
index d406855660..4ee12b3353 100644
--- a/packages/backend/src/server/api/endpoints/notes/renotes.ts
+++ b/packages/backend/src/server/api/endpoints/notes/renotes.ts
@@ -71,7 +71,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (me) this.queryService.generateMutedUserQuery(query, me);
if (me) this.queryService.generateBlockedUserQuery(query, me);
- const renotes = await query.take(ps.limit).getMany();
+ const renotes = await query.limit(ps.limit).getMany();
return await this.noteEntityService.packMany(renotes, me);
});
diff --git a/packages/backend/src/server/api/endpoints/notes/replies.ts b/packages/backend/src/server/api/endpoints/notes/replies.ts
index f2af71d55f..900c40d32a 100644
--- a/packages/backend/src/server/api/endpoints/notes/replies.ts
+++ b/packages/backend/src/server/api/endpoints/notes/replies.ts
@@ -55,7 +55,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (me) this.queryService.generateMutedUserQuery(query, me);
if (me) this.queryService.generateBlockedUserQuery(query, me);
- const timeline = await query.take(ps.limit).getMany();
+ const timeline = await query.limit(ps.limit).getMany();
return await this.noteEntityService.packMany(timeline, me);
});
diff --git a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts
index 742df0ca95..dc0a5dceee 100644
--- a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts
+++ b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts
@@ -130,7 +130,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
// Search notes
- const notes = await query.take(ps.limit).getMany();
+ const notes = await query.limit(ps.limit).getMany();
return await this.noteEntityService.packMany(notes, me);
});
diff --git a/packages/backend/src/server/api/endpoints/notes/search.ts b/packages/backend/src/server/api/endpoints/notes/search.ts
index f6385400c3..cd0e351e45 100644
--- a/packages/backend/src/server/api/endpoints/notes/search.ts
+++ b/packages/backend/src/server/api/endpoints/notes/search.ts
@@ -58,7 +58,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.config)
private config: Config,
-
+
private noteEntityService: NoteEntityService,
private searchService: SearchService,
private roleService: RoleService,
@@ -68,7 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (!policies.canSearchNotes) {
throw new ApiError(meta.errors.unavailable);
}
-
+
const notes = await this.searchService.searchNote(ps.query, me, {
userId: ps.userId,
channelId: ps.channelId,
diff --git a/packages/backend/src/server/api/endpoints/notes/show.ts b/packages/backend/src/server/api/endpoints/notes/show.ts
index 6b1b84a18e..2aec7d64dd 100644
--- a/packages/backend/src/server/api/endpoints/notes/show.ts
+++ b/packages/backend/src/server/api/endpoints/notes/show.ts
@@ -3,8 +3,8 @@ import type { NotesRepository } from '@/models/index.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { DI } from '@/di-symbols.js';
-import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js';
+import { ApiError } from '../../error.js';
export const meta = {
tags: ['notes'],
diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts
index e1f286439b..7e9bf85d88 100644
--- a/packages/backend/src/server/api/endpoints/notes/timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts
@@ -123,7 +123,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
//#endregion
- const timeline = await query.take(ps.limit).getMany();
+ const timeline = await query.limit(ps.limit).getMany();
process.nextTick(() => {
this.activeUsersChart.read(me);
diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts
index 66655234a1..b91bc7b5ec 100644
--- a/packages/backend/src/server/api/endpoints/notes/translate.ts
+++ b/packages/backend/src/server/api/endpoints/notes/translate.ts
@@ -44,7 +44,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.config)
private config: Config,
-
+
@Inject(DI.notesRepository)
private notesRepository: NotesRepository,
diff --git a/packages/backend/src/server/api/endpoints/notes/unrenote.ts b/packages/backend/src/server/api/endpoints/notes/unrenote.ts
index 74e459b426..e9581beedc 100644
--- a/packages/backend/src/server/api/endpoints/notes/unrenote.ts
+++ b/packages/backend/src/server/api/endpoints/notes/unrenote.ts
@@ -4,8 +4,8 @@ import type { UsersRepository, NotesRepository } from '@/models/index.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { NoteDeleteService } from '@/core/NoteDeleteService.js';
import { DI } from '@/di-symbols.js';
-import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js';
+import { ApiError } from '../../error.js';
export const meta = {
tags: ['notes'],
diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts
index afc9bc4213..4c19e1a553 100644
--- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts
@@ -127,7 +127,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
//#endregion
- const timeline = await query.take(ps.limit).getMany();
+ const timeline = await query.limit(ps.limit).getMany();
this.activeUsersChart.read(me);
diff --git a/packages/backend/src/server/api/endpoints/pages/featured.ts b/packages/backend/src/server/api/endpoints/pages/featured.ts
index 31844165e2..b1c056124e 100644
--- a/packages/backend/src/server/api/endpoints/pages/featured.ts
+++ b/packages/backend/src/server/api/endpoints/pages/featured.ts
@@ -41,7 +41,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('page.likedCount > 0')
.orderBy('page.likedCount', 'DESC');
- const pages = await query.take(10).getMany();
+ const pages = await query.limit(10).getMany();
return await this.pageEntityService.packMany(pages, me);
});
diff --git a/packages/backend/src/server/api/endpoints/pages/like.ts b/packages/backend/src/server/api/endpoints/pages/like.ts
index 543c126d9c..bc66488103 100644
--- a/packages/backend/src/server/api/endpoints/pages/like.ts
+++ b/packages/backend/src/server/api/endpoints/pages/like.ts
@@ -66,12 +66,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}
// if already liked
- const exist = await this.pageLikesRepository.findOneBy({
- pageId: page.id,
- userId: me.id,
+ const exist = await this.pageLikesRepository.exist({
+ where: {
+ pageId: page.id,
+ userId: me.id,
+ },
});
- if (exist != null) {
+ if (exist) {
throw new ApiError(meta.errors.alreadyLiked);
}
diff --git a/packages/backend/src/server/api/endpoints/promo/read.ts b/packages/backend/src/server/api/endpoints/promo/read.ts
index 90febdbce7..a76866fe14 100644
--- a/packages/backend/src/server/api/endpoints/promo/read.ts
+++ b/packages/backend/src/server/api/endpoints/promo/read.ts
@@ -3,8 +3,8 @@ import type { PromoReadsRepository } from '@/models/index.js';
import { IdService } from '@/core/IdService.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
-import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js';
+import { ApiError } from '../../error.js';
export const meta = {
tags: ['notes'],
@@ -44,12 +44,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw err;
});
- const exist = await this.promoReadsRepository.findOneBy({
- noteId: note.id,
- userId: me.id,
+ const exist = await this.promoReadsRepository.exist({
+ where: {
+ noteId: note.id,
+ userId: me.id,
+ },
});
- if (exist != null) {
+ if (exist) {
return;
}
diff --git a/packages/backend/src/server/api/endpoints/renote-mute/list.ts b/packages/backend/src/server/api/endpoints/renote-mute/list.ts
index b2d7addb64..cb4e1feba4 100644
--- a/packages/backend/src/server/api/endpoints/renote-mute/list.ts
+++ b/packages/backend/src/server/api/endpoints/renote-mute/list.ts
@@ -48,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('muting.muterId = :meId', { meId: me.id });
const mutings = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.renoteMutingEntityService.packMany(mutings, me);
diff --git a/packages/backend/src/server/api/endpoints/request-reset-password.ts b/packages/backend/src/server/api/endpoints/request-reset-password.ts
index 3b6ebfe281..284ed8410d 100644
--- a/packages/backend/src/server/api/endpoints/request-reset-password.ts
+++ b/packages/backend/src/server/api/endpoints/request-reset-password.ts
@@ -1,4 +1,3 @@
-import rndstr from 'rndstr';
import ms from 'ms';
import { IsNull } from 'typeorm';
import { Inject, Injectable } from '@nestjs/common';
@@ -8,6 +7,7 @@ import { IdService } from '@/core/IdService.js';
import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js';
import { EmailService } from '@/core/EmailService.js';
+import { L_CHARS, secureRndstr } from '@/misc/secure-rndstr.js';
export const meta = {
tags: ['reset password'],
@@ -41,7 +41,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.config)
private config: Config,
-
+
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -77,7 +77,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
return;
}
- const token = rndstr('a-z0-9', 64);
+ const token = secureRndstr(64, { chars: L_CHARS });
await this.passwordResetRequestsRepository.insert({
id: this.idService.genId(),
diff --git a/packages/backend/src/server/api/endpoints/roles/notes.ts b/packages/backend/src/server/api/endpoints/roles/notes.ts
index 42e36cb04a..a30c31b727 100644
--- a/packages/backend/src/server/api/endpoints/roles/notes.ts
+++ b/packages/backend/src/server/api/endpoints/roles/notes.ts
@@ -71,7 +71,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (role == null) {
throw new ApiError(meta.errors.noSuchRole);
}
- if (!role.isExplorable) {
+ if (!role.isExplorable) {
return [];
}
const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1
diff --git a/packages/backend/src/server/api/endpoints/roles/users.ts b/packages/backend/src/server/api/endpoints/roles/users.ts
index b2cb8b42a8..cc27201886 100644
--- a/packages/backend/src/server/api/endpoints/roles/users.ts
+++ b/packages/backend/src/server/api/endpoints/roles/users.ts
@@ -65,7 +65,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.innerJoinAndSelect('assign.user', 'user');
const assigns = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await Promise.all(assigns.map(async assign => ({
diff --git a/packages/backend/src/server/api/endpoints/server-info.ts b/packages/backend/src/server/api/endpoints/server-info.ts
index 1620e8ae52..552441e430 100644
--- a/packages/backend/src/server/api/endpoints/server-info.ts
+++ b/packages/backend/src/server/api/endpoints/server-info.ts
@@ -2,9 +2,12 @@ import * as os from 'node:os';
import si from 'systeminformation';
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
+import { MetaService } from '@/core/MetaService.js';
export const meta = {
requireCredential: false,
+ allowGet: true,
+ cacheSec: 60 * 1,
tags: ['meta'],
} as const;
@@ -19,8 +22,24 @@ export const paramDef = {
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
+ private metaService: MetaService,
) {
super(meta, paramDef, async () => {
+ if (!(await this.metaService.fetch()).enableServerMachineStats) return {
+ machine: '?',
+ cpu: {
+ model: '?',
+ cores: 0,
+ },
+ mem: {
+ total: 0,
+ },
+ fs: {
+ total: 0,
+ used: 0,
+ },
+ };
+
const memStats = await si.mem();
const fsStats = await si.fsSize();
diff --git a/packages/backend/src/server/api/endpoints/sw/update-registration.ts b/packages/backend/src/server/api/endpoints/sw/update-registration.ts
index 9f08c8148d..b82c4bf49d 100644
--- a/packages/backend/src/server/api/endpoints/sw/update-registration.ts
+++ b/packages/backend/src/server/api/endpoints/sw/update-registration.ts
@@ -35,7 +35,7 @@ export const meta = {
code: 'NO_SUCH_REGISTRATION',
id: ' b09d8066-8064-5613-efb6-0e963b21d012',
},
- }
+ },
} as const;
export const paramDef = {
diff --git a/packages/backend/src/server/api/endpoints/users.ts b/packages/backend/src/server/api/endpoints/users.ts
index 28cd9f6ce5..2582932e3a 100644
--- a/packages/backend/src/server/api/endpoints/users.ts
+++ b/packages/backend/src/server/api/endpoints/users.ts
@@ -80,7 +80,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (me) this.queryService.generateMutedUserQueryForUsers(query, me);
if (me) this.queryService.generateBlockQueryForUsers(query, me);
- query.take(ps.limit);
+ query.limit(ps.limit);
query.skip(ps.offset);
const users = await query.getMany();
diff --git a/packages/backend/src/server/api/endpoints/users/clips.ts b/packages/backend/src/server/api/endpoints/users/clips.ts
index c5aa93baaf..c2ad420cb5 100644
--- a/packages/backend/src/server/api/endpoints/users/clips.ts
+++ b/packages/backend/src/server/api/endpoints/users/clips.ts
@@ -48,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('clip.isPublic = true');
const clips = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.clipEntityService.packMany(clips, me);
diff --git a/packages/backend/src/server/api/endpoints/users/followers.ts b/packages/backend/src/server/api/endpoints/users/followers.ts
index 97f1310c36..18d66500ab 100644
--- a/packages/backend/src/server/api/endpoints/users/followers.ts
+++ b/packages/backend/src/server/api/endpoints/users/followers.ts
@@ -97,11 +97,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (me == null) {
throw new ApiError(meta.errors.forbidden);
} else if (me.id !== user.id) {
- const following = await this.followingsRepository.findOneBy({
- followeeId: user.id,
- followerId: me.id,
+ const isFollowing = await this.followingsRepository.exist({
+ where: {
+ followeeId: user.id,
+ followerId: me.id,
+ },
});
- if (following == null) {
+ if (!isFollowing) {
throw new ApiError(meta.errors.forbidden);
}
}
@@ -112,7 +114,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.innerJoinAndSelect('following.follower', 'follower');
const followings = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.followingEntityService.packMany(followings, me, { populateFollower: true });
diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts
index d406594a2e..6ea7b923d6 100644
--- a/packages/backend/src/server/api/endpoints/users/following.ts
+++ b/packages/backend/src/server/api/endpoints/users/following.ts
@@ -97,11 +97,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (me == null) {
throw new ApiError(meta.errors.forbidden);
} else if (me.id !== user.id) {
- const following = await this.followingsRepository.findOneBy({
- followeeId: user.id,
- followerId: me.id,
+ const isFollowing = await this.followingsRepository.exist({
+ where: {
+ followeeId: user.id,
+ followerId: me.id,
+ },
});
- if (following == null) {
+ if (!isFollowing) {
throw new ApiError(meta.errors.forbidden);
}
}
@@ -112,7 +114,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.innerJoinAndSelect('following.followee', 'followee');
const followings = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.followingEntityService.packMany(followings, me, { populateFollowee: true });
diff --git a/packages/backend/src/server/api/endpoints/users/gallery/posts.ts b/packages/backend/src/server/api/endpoints/users/gallery/posts.ts
index 6e57eee5fb..3ee01953d4 100644
--- a/packages/backend/src/server/api/endpoints/users/gallery/posts.ts
+++ b/packages/backend/src/server/api/endpoints/users/gallery/posts.ts
@@ -47,7 +47,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('post.userId = :userId', { userId: ps.userId });
const posts = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.galleryPostEntityService.packMany(posts, me);
diff --git a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts
index 09f6acde9c..b4c1e2ec87 100644
--- a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts
+++ b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts
@@ -5,8 +5,8 @@ import type { NotesRepository, UsersRepository } from '@/models/index.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { DI } from '@/di-symbols.js';
-import { ApiError } from '../../error.js';
import { GetterService } from '@/server/api/GetterService.js';
+import { ApiError } from '../../error.js';
export const meta = {
tags: ['users'],
diff --git a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts
index 8591e4ab96..beb0ba85ff 100644
--- a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts
+++ b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts
@@ -84,18 +84,20 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
- const list = await this.userListsRepository.findOneBy({
- id: ps.listId,
- isPublic: true,
+ const listExist = await this.userListsRepository.exist({
+ where: {
+ id: ps.listId,
+ isPublic: true,
+ },
});
- if (list === null) throw new ApiError(meta.errors.noSuchList);
+ if (!listExist) throw new ApiError(meta.errors.noSuchList);
const currentCount = await this.userListsRepository.countBy({
userId: me.id,
});
if (currentCount > (await this.roleService.getUserPolicies(me.id)).userListLimit) {
throw new ApiError(meta.errors.tooManyUserLists);
}
-
+
const userList = await this.userListsRepository.insert({
id: this.idService.genId(),
createdAt: new Date(),
@@ -114,20 +116,24 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
});
if (currentUser.id !== me.id) {
- const block = await this.blockingsRepository.findOneBy({
- blockerId: currentUser.id,
- blockeeId: me.id,
+ const blockExist = await this.blockingsRepository.exist({
+ where: {
+ blockerId: currentUser.id,
+ blockeeId: me.id,
+ },
});
- if (block) {
+ if (blockExist) {
throw new ApiError(meta.errors.youHaveBeenBlocked);
}
}
- const exist = await this.userListJoiningsRepository.findOneBy({
- userListId: userList.id,
- userId: currentUser.id,
+ const exist = await this.userListJoiningsRepository.exist({
+ where: {
+ userListId: userList.id,
+ userId: currentUser.id,
+ },
});
-
+
if (exist) {
throw new ApiError(meta.errors.alreadyAdded);
}
diff --git a/packages/backend/src/server/api/endpoints/users/lists/favorite.ts b/packages/backend/src/server/api/endpoints/users/lists/favorite.ts
index 263852fde1..2c09a47fef 100644
--- a/packages/backend/src/server/api/endpoints/users/lists/favorite.ts
+++ b/packages/backend/src/server/api/endpoints/users/lists/favorite.ts
@@ -41,21 +41,25 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private idService: IdService,
) {
super(meta, paramDef, async (ps, me) => {
- const userList = await this.userListsRepository.findOneBy({
- id: ps.listId,
- isPublic: true,
+ const userListExist = await this.userListsRepository.exist({
+ where: {
+ id: ps.listId,
+ isPublic: true,
+ },
});
- if (userList === null) {
+ if (!userListExist) {
throw new ApiError(meta.errors.noSuchList);
}
- const exist = await this.userListFavoritesRepository.findOneBy({
- userId: me.id,
- userListId: ps.listId,
+ const exist = await this.userListFavoritesRepository.exist({
+ where: {
+ userId: me.id,
+ userListId: ps.listId,
+ },
});
- if (exist !== null) {
+ if (exist) {
throw new ApiError(meta.errors.alreadyFavorited);
}
diff --git a/packages/backend/src/server/api/endpoints/users/lists/push.ts b/packages/backend/src/server/api/endpoints/users/lists/push.ts
index 925037e484..6e1f6b2c62 100644
--- a/packages/backend/src/server/api/endpoints/users/lists/push.ts
+++ b/packages/backend/src/server/api/endpoints/users/lists/push.ts
@@ -100,18 +100,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
// Check blocking
if (user.id !== me.id) {
- const block = await this.blockingsRepository.findOneBy({
- blockerId: user.id,
- blockeeId: me.id,
+ const blockExist = await this.blockingsRepository.exist({
+ where: {
+ blockerId: user.id,
+ blockeeId: me.id,
+ },
});
- if (block) {
+ if (blockExist) {
throw new ApiError(meta.errors.youHaveBeenBlocked);
}
}
- const exist = await this.userListJoiningsRepository.findOneBy({
- userListId: userList.id,
- userId: user.id,
+ const exist = await this.userListJoiningsRepository.exist({
+ where: {
+ userListId: userList.id,
+ userId: user.id,
+ },
});
if (exist) {
diff --git a/packages/backend/src/server/api/endpoints/users/lists/show.ts b/packages/backend/src/server/api/endpoints/users/lists/show.ts
index 8077841c8c..3fd418d04e 100644
--- a/packages/backend/src/server/api/endpoints/users/lists/show.ts
+++ b/packages/backend/src/server/api/endpoints/users/lists/show.ts
@@ -69,10 +69,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
userListId: ps.listId,
});
if (me !== null) {
- additionalProperties.isLiked = (await this.userListFavoritesRepository.findOneBy({
- userId: me.id,
- userListId: ps.listId,
- }) !== null);
+ additionalProperties.isLiked = await this.userListFavoritesRepository.exist({
+ where: {
+ userId: me.id,
+ userListId: ps.listId,
+ },
+ });
} else {
additionalProperties.isLiked = false;
}
diff --git a/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts b/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts
index be8e317816..a7c3b58947 100644
--- a/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts
+++ b/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts
@@ -39,12 +39,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
private userListFavoritesRepository: UserListFavoritesRepository,
) {
super(meta, paramDef, async (ps, me) => {
- const userList = await this.userListsRepository.findOneBy({
- id: ps.listId,
- isPublic: true,
+ const userListExist = await this.userListsRepository.exist({
+ where: {
+ id: ps.listId,
+ isPublic: true,
+ },
});
- if (userList === null) {
+ if (!userListExist) {
throw new ApiError(meta.errors.noSuchList);
}
diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts
index aaf94734a3..f42f84e6a7 100644
--- a/packages/backend/src/server/api/endpoints/users/notes.ts
+++ b/packages/backend/src/server/api/endpoints/users/notes.ts
@@ -120,7 +120,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
//#endregion
- const timeline = await query.take(ps.limit).getMany();
+ const timeline = await query.limit(ps.limit).getMany();
return await this.noteEntityService.packMany(timeline, me);
});
diff --git a/packages/backend/src/server/api/endpoints/users/pages.ts b/packages/backend/src/server/api/endpoints/users/pages.ts
index a105103f16..e9d13ba00f 100644
--- a/packages/backend/src/server/api/endpoints/users/pages.ts
+++ b/packages/backend/src/server/api/endpoints/users/pages.ts
@@ -48,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
.andWhere('page.visibility = \'public\'');
const pages = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await this.pageEntityService.packMany(pages);
diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts
index ac401a60ee..37fc854c33 100644
--- a/packages/backend/src/server/api/endpoints/users/reactions.ts
+++ b/packages/backend/src/server/api/endpoints/users/reactions.ts
@@ -73,7 +73,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
this.queryService.generateVisibilityQuery(query, me);
const reactions = await query
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
return await Promise.all(reactions.map(reaction => this.noteReactionEntityService.pack(reaction, me, { withNote: true })));
diff --git a/packages/backend/src/server/api/endpoints/users/recommendation.ts b/packages/backend/src/server/api/endpoints/users/recommendation.ts
index 5498b8c854..d39657059a 100644
--- a/packages/backend/src/server/api/endpoints/users/recommendation.ts
+++ b/packages/backend/src/server/api/endpoints/users/recommendation.ts
@@ -44,7 +44,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
@Inject(DI.followingsRepository)
private followingsRepository: FollowingsRepository,
-
+
private userEntityService: UserEntityService,
private queryService: QueryService,
) {
@@ -70,7 +70,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
query.setParameters(followingQuery.getParameters());
- const users = await query.take(ps.limit).skip(ps.offset).getMany();
+ const users = await query.limit(ps.limit).skip(ps.offset).getMany();
return await this.userEntityService.packMany(users, me, { detail: true });
});
diff --git a/packages/backend/src/server/api/endpoints/users/report-abuse.ts b/packages/backend/src/server/api/endpoints/users/report-abuse.ts
index d19d4007d6..be361e02c4 100644
--- a/packages/backend/src/server/api/endpoints/users/report-abuse.ts
+++ b/packages/backend/src/server/api/endpoints/users/report-abuse.ts
@@ -1,4 +1,4 @@
-import * as sanitizeHtml from 'sanitize-html';
+import sanitizeHtml from 'sanitize-html';
import { Inject, Injectable } from '@nestjs/common';
import type { UsersRepository, AbuseUserReportsRepository } from '@/models/index.js';
import { IdService } from '@/core/IdService.js';
diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
index b001159ee8..1d0c7d0c1d 100644
--- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
+++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
@@ -97,7 +97,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
users = await query
.orderBy('user.usernameLower', 'ASC')
- .take(ps.limit)
+ .limit(ps.limit)
.getMany();
if (users.length < ps.limit) {
@@ -110,7 +110,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const otherUsers = await otherQuery
.orderBy('user.updatedAt', 'DESC')
- .take(ps.limit - users.length)
+ .limit(ps.limit - users.length)
.getMany();
users = users.concat(otherUsers);
@@ -122,7 +122,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
users = await query
.orderBy('user.updatedAt', 'DESC')
- .take(ps.limit - users.length)
+ .limit(ps.limit - users.length)
.getMany();
}
diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts
index d7a60f0437..1180de3611 100644
--- a/packages/backend/src/server/api/endpoints/users/search.ts
+++ b/packages/backend/src/server/api/endpoints/users/search.ts
@@ -52,6 +52,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
super(meta, paramDef, async (ps, me) => {
const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日
+ ps.query = ps.query.trim();
const isUsername = ps.query.startsWith('@');
let users: User[] = [];
@@ -73,12 +74,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
users = await usernameQuery
.orderBy('user.updatedAt', 'DESC', 'NULLS LAST')
- .take(ps.limit)
+ .limit(ps.limit)
.skip(ps.offset)
.getMany();
} else {
const nameQuery = this.usersRepository.createQueryBuilder('user')
- .where(new Brackets(qb => {
+ .where(new Brackets(qb => {
qb.where('user.name ILIKE :query', { query: '%' + sqlLikeEscape(ps.query) + '%' });
// Also search username if it qualifies as username
@@ -100,7 +101,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
users = await nameQuery
.orderBy('user.updatedAt', 'DESC', 'NULLS LAST')
- .take(ps.limit)
+ .limit(ps.limit)
.skip(ps.offset)
.getMany();
@@ -126,7 +127,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
users = users.concat(await query
.orderBy('user.updatedAt', 'DESC', 'NULLS LAST')
- .take(ps.limit)
+ .limit(ps.limit)
.skip(ps.offset)
.getMany(),
);
diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts
index ba432c273b..8e25af64fe 100644
--- a/packages/backend/src/server/api/endpoints/users/show.ts
+++ b/packages/backend/src/server/api/endpoints/users/show.ts
@@ -91,6 +91,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
let user;
const isModerator = await this.roleService.isModerator(me);
+ ps.username = ps.username?.trim();
if (ps.userIds) {
if (ps.userIds.length === 0) {
diff --git a/packages/backend/src/server/api/stream/ChannelsService.ts b/packages/backend/src/server/api/stream/ChannelsService.ts
index c77ba66028..4a544fadfe 100644
--- a/packages/backend/src/server/api/stream/ChannelsService.ts
+++ b/packages/backend/src/server/api/stream/ChannelsService.ts
@@ -52,7 +52,7 @@ export class ChannelsService {
case 'serverStats': return this.serverStatsChannelService;
case 'queueStats': return this.queueStatsChannelService;
case 'admin': return this.adminChannelService;
-
+
default:
throw new Error(`no such channel: ${name}`);
}
diff --git a/packages/backend/src/server/api/stream/channel.ts b/packages/backend/src/server/api/stream/channel.ts
index e67aec9ecd..94b92e02ef 100644
--- a/packages/backend/src/server/api/stream/channel.ts
+++ b/packages/backend/src/server/api/stream/channel.ts
@@ -1,5 +1,5 @@
import { bindThis } from '@/decorators.js';
-import type Connection from '.';
+import type Connection from './index.js';
/**
* Stream channel
diff --git a/packages/backend/src/server/api/stream/channels/hashtag.ts b/packages/backend/src/server/api/stream/channels/hashtag.ts
index 0268fdedde..94ebf86418 100644
--- a/packages/backend/src/server/api/stream/channels/hashtag.ts
+++ b/packages/backend/src/server/api/stream/channels/hashtag.ts
@@ -49,7 +49,7 @@ class HashtagChannel extends Channel {
if (isUserRelated(note, this.userIdsWhoMeMuting)) return;
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
if (isUserRelated(note, this.userIdsWhoBlockingMe)) return;
-
+
if (note.renote && !note.text && isUserRelated(note, this.userIdsWhoMeMutingRenotes)) return;
this.connection.cacheNote(note);
diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts
index 1755aa94cf..fe0cc37b6b 100644
--- a/packages/backend/src/server/api/stream/channels/home-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts
@@ -26,7 +26,7 @@ class HomeTimelineChannel extends Channel {
@bindThis
public async init(params: any) {
this.withReplies = params.withReplies as boolean;
-
+
this.subscriber.on('notesStream', this.onNote);
}
diff --git a/packages/backend/src/server/api/stream/channels/role-timeline.ts b/packages/backend/src/server/api/stream/channels/role-timeline.ts
index ab9c1aa0b5..6218fada97 100644
--- a/packages/backend/src/server/api/stream/channels/role-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/role-timeline.ts
@@ -3,16 +3,16 @@ import { isUserRelated } from '@/misc/is-user-related.js';
import type { Packed } from '@/misc/json-schema.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
+import { RoleService } from '@/core/RoleService.js';
import Channel from '../channel.js';
import { StreamMessages } from '../types.js';
-import { RoleService } from '@/core/RoleService.js';
class RoleTimelineChannel extends Channel {
public readonly chName = 'roleTimeline';
public static shouldShare = false;
public static requireCredential = false;
private roleId: string;
-
+
constructor(
private noteEntityService: NoteEntityService,
private roleservice: RoleService,
diff --git a/packages/backend/src/server/api/stream/channels/user-list.ts b/packages/backend/src/server/api/stream/channels/user-list.ts
index 8802fc5ab8..ea4cff0bc0 100644
--- a/packages/backend/src/server/api/stream/channels/user-list.ts
+++ b/packages/backend/src/server/api/stream/channels/user-list.ts
@@ -20,7 +20,7 @@ class UserListChannel extends Channel {
private userListsRepository: UserListsRepository,
private userListJoiningsRepository: UserListJoiningsRepository,
private noteEntityService: NoteEntityService,
-
+
id: string,
connection: Channel['connection'],
) {
@@ -34,11 +34,13 @@ class UserListChannel extends Channel {
this.listId = params.listId as string;
// Check existence and owner
- const list = await this.userListsRepository.findOneBy({
- id: this.listId,
- userId: this.user!.id,
+ const listExist = await this.userListsRepository.exist({
+ where: {
+ id: this.listId,
+ userId: this.user!.id,
+ },
});
- if (!list) return;
+ if (!listExist) return;
// Subscribe stream
this.subscriber.on(`userListStream:${this.listId}`, this.send);
diff --git a/packages/backend/src/server/api/stream/types.ts b/packages/backend/src/server/api/stream/types.ts
index d9dba682cd..f239b06637 100644
--- a/packages/backend/src/server/api/stream/types.ts
+++ b/packages/backend/src/server/api/stream/types.ts
@@ -12,7 +12,7 @@ import type { Page } from '@/models/entities/Page.js';
import type { Packed } from '@/misc/json-schema.js';
import type { Webhook } from '@/models/entities/Webhook.js';
import type { Meta } from '@/models/entities/Meta.js';
-import { Role, RoleAssignment } from '@/models';
+import { Role, RoleAssignment } from '@/models/index.js';
import type Emitter from 'strict-event-emitter-types';
import type { EventEmitter } from 'events';
@@ -233,7 +233,7 @@ export type StreamMessages = {
// API event definitions
// ストリームごとのEmitterの辞書を用意
-type EventEmitterDictionary = { [x in keyof StreamMessages]: Emitter<EventEmitter, { [y in StreamMessages[x]['name']]: (e: StreamMessages[x]['payload']) => void }> };
+type EventEmitterDictionary = { [x in keyof StreamMessages]: Emitter.default<EventEmitter, { [y in StreamMessages[x]['name']]: (e: StreamMessages[x]['payload']) => void }> };
// 共用体型を交差型にする型 https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
// Emitter辞書から共用体型を作り、UnionToIntersectionで交差型にする