From 3fa92e77efd8863b076c7605f67d40013805ad35 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 24 Aug 2024 10:26:08 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix=20:=20=EC=A4=91=EB=B3=B5=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/exception/PhoneDuplicationException.java | 11 +++++++++++ .../auth/service/MessageVerificationService.java | 14 +++++++++++--- .../member/repository/MemberQueryRepository.java | 1 + .../repository/MemberQueryRepositoryImpl.java | 10 ++++++++++ .../core/global/error/ErrorCode.java | 1 + 5 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/exception/PhoneDuplicationException.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/exception/PhoneDuplicationException.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/exception/PhoneDuplicationException.java new file mode 100644 index 000000000..1baf2a80c --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/exception/PhoneDuplicationException.java @@ -0,0 +1,11 @@ +package site.timecapsulearchive.core.domain.auth.exception; + +import site.timecapsulearchive.core.global.error.ErrorCode; +import site.timecapsulearchive.core.global.error.exception.BusinessException; + +public class PhoneDuplicationException extends BusinessException { + + public PhoneDuplicationException() { + super(ErrorCode.PHONE_DUPLICATION_ERROR); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationService.java index f52f94110..f5dddc39a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationService.java @@ -9,7 +9,9 @@ import site.timecapsulearchive.core.domain.auth.data.dto.VerificationMessageSendDto; import site.timecapsulearchive.core.domain.auth.exception.CertificationNumberNotFoundException; import site.timecapsulearchive.core.domain.auth.exception.CertificationNumberNotMatchException; +import site.timecapsulearchive.core.domain.auth.exception.PhoneDuplicationException; import site.timecapsulearchive.core.domain.auth.repository.MessageAuthenticationCacheRepository; +import site.timecapsulearchive.core.domain.member.repository.MemberRepository; import site.timecapsulearchive.core.global.security.encryption.HashEncryptionManager; import site.timecapsulearchive.core.infra.sms.data.response.SmsApiResponse; import site.timecapsulearchive.core.infra.sms.manager.SmsApiManager; @@ -27,6 +29,7 @@ public class MessageVerificationService { private final MessageAuthenticationCacheRepository messageAuthenticationCacheRepository; private final SmsApiManager smsApiManager; private final HashEncryptionManager hashEncryptionManager; + private final MemberRepository memberRepository; /** * 사용자 아이디와 수신자 핸드폰을 받아서 인증번호를 발송한다. @@ -40,13 +43,18 @@ public VerificationMessageSendDto sendVerificationMessage( final String receiver, final String appHashKey ) { + final byte[] plain = receiver.getBytes(StandardCharsets.UTF_8); + byte[] encrypt = hashEncryptionManager.encrypt(plain); + + boolean isDuplicated = memberRepository.checkPhoneHashDuplication(encrypt); + if (isDuplicated) { + throw new PhoneDuplicationException(); + } + final String code = generateRandomCode(); final String message = generateMessage(code, appHashKey); final SmsApiResponse apiResponse = smsApiManager.sendMessage(receiver, message); - final byte[] plain = receiver.getBytes(StandardCharsets.UTF_8); - byte[] encrypt = hashEncryptionManager.encrypt(plain); - messageAuthenticationCacheRepository.save(memberId, encrypt, code); return VerificationMessageSendDto.success(apiResponse.resultCode(), diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java index ce6fa17f4..c7aaae9bd 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java @@ -31,4 +31,5 @@ Optional findVerifiedCheckDtoByAuthIdAndSocialType( Optional findMemberPhoneHash(final Long memberId); + boolean checkPhoneHashDuplication(byte[] encrypt); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryImpl.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryImpl.java index 9bbe263a8..6fb2d3cb7 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryImpl.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryImpl.java @@ -151,4 +151,14 @@ public Optional findMemberPhoneHash(final Long memberId) { return Optional.empty(); } + + @Override + public boolean checkPhoneHashDuplication(final byte[] encrypt) { + final Integer count = jpaQueryFactory.selectOne() + .from(member) + .where(member.phoneHash.eq(encrypt)) + .fetchFirst(); + + return count != null; + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java index da198085d..237977303 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java @@ -22,6 +22,7 @@ public enum ErrorCode { AUTHENTICATION_ERROR(401, "AUTH-003", "인증에 실패했습니다. 인증 수단이 유효한지 확인하세요."), AUTHORIZATION_ERROR(403, "AUTH-004", "권한이 존재하지 않습니다."), CREDENTIALS_NOT_MATCHED_ERROR(401, "AUTH-005", "이메일과 비밀번호 인증에 실패했습니다."), + PHONE_DUPLICATION_ERROR(400, "AUTH-006", "중복된 전화번호입니다."), //message TOO_MANY_REQUEST_ERROR(429, "MESSAGE-001", "너무 많은 인증 메시지를 요청했습니다. 24시간 후 요청해주세요."), From 096dfc1544932f9cc0db7182680a6827cb57b51e Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 24 Aug 2024 10:43:02 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix=20:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MessageVerificationServiceTest.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationServiceTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationServiceTest.java index 047daf146..d38896fa6 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationServiceTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationServiceTest.java @@ -14,7 +14,9 @@ import site.timecapsulearchive.core.domain.auth.data.dto.VerificationMessageSendDto; import site.timecapsulearchive.core.domain.auth.exception.CertificationNumberNotFoundException; import site.timecapsulearchive.core.domain.auth.exception.CertificationNumberNotMatchException; +import site.timecapsulearchive.core.domain.auth.exception.PhoneDuplicationException; import site.timecapsulearchive.core.domain.auth.repository.MessageAuthenticationCacheRepository; +import site.timecapsulearchive.core.domain.member.repository.MemberRepository; import site.timecapsulearchive.core.infra.sms.manager.SmsApiManager; class MessageVerificationServiceTest { @@ -26,16 +28,33 @@ class MessageVerificationServiceTest { private final MessageAuthenticationCacheRepository messageAuthenticationCacheRepository = mock( MessageAuthenticationCacheRepository.class); private final SmsApiManager smsApiManager = UnitTestDependency.smsApiManager(); + private final MemberRepository memberRepository = mock(MemberRepository.class); private final MessageVerificationService messageVerificationService = new MessageVerificationService( messageAuthenticationCacheRepository, smsApiManager, - UnitTestDependency.hashEncryptionManager() + UnitTestDependency.hashEncryptionManager(), + memberRepository ); + @Test + void 중복된_번호가_있으면_예외가_발생한다() { + // given + given(memberRepository.checkPhoneHashDuplication(any())).willReturn(true); + + // when + // then + assertThatThrownBy( + () -> messageVerificationService.sendVerificationMessage(MEMBER_ID, RECEIVER, + APP_HASH_KEY)) + .isInstanceOf(PhoneDuplicationException.class); + } + @Test void 인증번호를_전송하면_성공한다() { //given + given(memberRepository.checkPhoneHashDuplication(any())).willReturn(false); + //when VerificationMessageSendDto verificationMessageSendDto = messageVerificationService.sendVerificationMessage( MEMBER_ID, RECEIVER, APP_HASH_KEY);