From a4ca127ebd300047fa51056eef9921f2add99b34 Mon Sep 17 00:00:00 2001
From: RyotaK <49341894+Ry0taK@users.noreply.github.com>
Date: Thu, 9 Mar 2023 12:57:34 +0900
Subject: [PATCH] =?UTF-8?q?fix:=20=E7=99=BB=E9=8C=B2=E3=83=A1=E3=83=BC?=
 =?UTF-8?q?=E3=83=AB=E9=80=81=E4=BF=A1=E6=99=82=E3=81=AB=E9=87=8D=E8=A4=87?=
 =?UTF-8?q?=E7=A2=BA=E8=AA=8D=E3=82=92=E8=A1=8C=E3=81=86=20(#10231)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix: 登録メール送信時に重複確認を行う

* try-catchを使う必要はない

* Remove spaces
---
 .../src/server/api/SignupApiService.ts        | 25 ++++++++++++++-----
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/packages/backend/src/server/api/SignupApiService.ts b/packages/backend/src/server/api/SignupApiService.ts
index 41e8365d08..fbabf47aff 100644
--- a/packages/backend/src/server/api/SignupApiService.ts
+++ b/packages/backend/src/server/api/SignupApiService.ts
@@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
 import rndstr from 'rndstr';
 import bcrypt from 'bcryptjs';
 import { DI } from '@/di-symbols.js';
-import type { RegistrationTicketsRepository, UserPendingsRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js';
+import type { RegistrationTicketsRepository, UsedUsernamesRepository, UserPendingsRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js';
 import type { Config } from '@/config.js';
 import { MetaService } from '@/core/MetaService.js';
 import { CaptchaService } from '@/core/CaptchaService.js';
@@ -15,6 +15,7 @@ import { FastifyReplyError } from '@/misc/fastify-reply-error.js';
 import { bindThis } from '@/decorators.js';
 import { SigninService } from './SigninService.js';
 import type { FastifyRequest, FastifyReply } from 'fastify';
+import { IsNull } from 'typeorm';
 
 @Injectable()
 export class SignupApiService {
@@ -31,6 +32,9 @@ export class SignupApiService {
 		@Inject(DI.userPendingsRepository)
 		private userPendingsRepository: UserPendingsRepository,
 
+		@Inject(DI.usedUsernamesRepository)
+		private usedUsernamesRepository: UsedUsernamesRepository,
+
 		@Inject(DI.registrationTicketsRepository)
 		private registrationTicketsRepository: RegistrationTicketsRepository,
 
@@ -124,12 +128,21 @@ export class SignupApiService {
 		}
 	
 		if (instance.emailRequiredForSignup) {
+			if (await this.usersRepository.findOneBy({ usernameLower: username.toLowerCase(), host: IsNull() })) {
+				throw new FastifyReplyError(400, 'DUPLICATED_USERNAME');
+			}
+
+			// Check deleted username duplication
+			if (await this.usedUsernamesRepository.findOneBy({ username: username.toLowerCase() })) {
+				throw new FastifyReplyError(400, 'USED_USERNAME');
+			}
+
 			const code = rndstr('a-z0-9', 16);
-	
+
 			// Generate hash of password
 			const salt = await bcrypt.genSalt(8);
 			const hash = await bcrypt.hash(password, salt);
-	
+
 			await this.userPendingsRepository.insert({
 				id: this.idService.genId(),
 				createdAt: new Date(),
@@ -138,13 +151,13 @@ export class SignupApiService {
 				username: username,
 				password: hash,
 			});
-	
+
 			const link = `${this.config.url}/signup-complete/${code}`;
-	
+
 			this.emailService.sendEmail(emailAddress!, 'Signup',
 				`To complete signup, please click this link:<br><a href="${link}">${link}</a>`,
 				`To complete signup, please click this link: ${link}`);
-	
+
 			reply.code(204);
 			return;
 		} else {