Skip to content

Commit

Permalink
feat: 행사 비밀번호 암호화 추가 (#429)
Browse files Browse the repository at this point in the history
* feat: 행사 비밀번호 암호화 추가

* refactor: 비밀번호 암호화 로직 수정

* fix: MessageDigest를 싱글톤으로 관리하지 않도록 수정

---------

Co-authored-by: 3juhwan <[email protected]>
  • Loading branch information
khabh and 3Juhwan authored Aug 21, 2024
1 parent 44ff15d commit 817c965
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ private void updateMemberName(Event event, String beforeName, String afterName)

public void validatePassword(EventLoginAppRequest request) throws HaengdongException {
Event event = getEvent(request.token());
if (event.isNotSamePassword(request.password())) {
if (event.isPasswordMismatch(request.password())) {
throw new AuthenticationException(HaengdongErrorCode.PASSWORD_INVALID);
}
}
Expand Down
25 changes: 9 additions & 16 deletions server/src/main/java/server/haengdong/domain/event/Event.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package server.haengdong.domain.event;

import jakarta.persistence.AttributeOverride;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand All @@ -19,25 +20,24 @@ public class Event {

public static final int MIN_NAME_LENGTH = 1;
public static final int MAX_NAME_LENGTH = 20;
public static final int PASSWORD_LENGTH = 4;
private static final String SPACES = " ";
private static final Pattern PASSWORD_PATTERN = Pattern.compile(String.format("^\\d{%d}$", PASSWORD_LENGTH));

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

private String password;
@Embedded
@AttributeOverride(name = "value", column = @Column(name = "password"))
private Password password;

private String token;

public Event(String name, String password, String token) {
validateName(name);
validatePassword(password);
this.name = name;
this.password = password;
this.password = new Password(password);
this.token = token;
}

Expand All @@ -56,13 +56,6 @@ private void validateName(String name) {
}
}

private void validatePassword(String password) {
Matcher matcher = PASSWORD_PATTERN.matcher(password);
if (!matcher.matches()) {
throw new HaengdongException(HaengdongErrorCode.EVENT_PASSWORD_FORMAT_INVALID, "비밀번호는 4자리 숫자만 가능합니다.");
}
}

private boolean isBlankContinuous(String name) {
return name.contains(SPACES);
}
Expand All @@ -71,7 +64,7 @@ public boolean isTokenMismatch(String token) {
return !this.token.equals(token);
}

public boolean isNotSamePassword(String password) {
return !this.password.equals(password);
public boolean isPasswordMismatch(String rawPassword) {
return !password.matches(rawPassword);
}
}
52 changes: 52 additions & 0 deletions server/src/main/java/server/haengdong/domain/event/Password.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package server.haengdong.domain.event;

import jakarta.persistence.Embeddable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import server.haengdong.exception.HaengdongErrorCode;
import server.haengdong.exception.HaengdongException;

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Embeddable
public class Password {

public static final int PASSWORD_LENGTH = 4;
private static final Pattern PASSWORD_PATTERN = Pattern.compile(String.format("^\\d{%d}$", PASSWORD_LENGTH));
private static final String HASH_ALGORITHM = "SHA-256";

private String value;

public Password(String password) {
validatePassword(password);
this.value = encode(password);
}

private void validatePassword(String password) {
Matcher matcher = PASSWORD_PATTERN.matcher(password);
if (!matcher.matches()) {
throw new HaengdongException(HaengdongErrorCode.EVENT_PASSWORD_FORMAT_INVALID);
}
}

private String encode(String rawPassword) {
try {
MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
byte[] hashedPassword = digest.digest(rawPassword.getBytes());
return Base64.getEncoder().encodeToString(hashedPassword);
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException("해시 알고리즘이 존재하지 않습니다.");
}
}

public boolean matches(String rawPassword) {
String hashedPassword = encode(rawPassword);
return value.equals(hashedPassword);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import server.haengdong.domain.action.BillAction;
import server.haengdong.domain.action.MemberAction;
import server.haengdong.domain.event.Event;
import server.haengdong.domain.event.Password;

@Getter
public enum HaengdongErrorCode {
Expand All @@ -15,7 +16,7 @@ public enum HaengdongErrorCode {
Event.MIN_NAME_LENGTH,
Event.MAX_NAME_LENGTH)),
EVENT_NAME_CONSECUTIVE_SPACES("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s"),
EVENT_PASSWORD_FORMAT_INVALID(String.format("비밀번호는 %d자리 숫자만 가능합니다.", Event.PASSWORD_LENGTH)),
EVENT_PASSWORD_FORMAT_INVALID(String.format("비밀번호는 %d자리 숫자만 가능합니다.", Password.PASSWORD_LENGTH)),

ACTION_NOT_FOUND("존재하지 않는 액션입니다."),

Expand Down
20 changes: 20 additions & 0 deletions server/src/test/java/server/haengdong/domain/event/EventTest.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package server.haengdong.domain.event;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import server.haengdong.exception.HaengdongException;
Expand Down Expand Up @@ -42,4 +44,22 @@ void validatePassword(String password) {
assertThatCode(() -> new Event("이름", password, "TEST_TOKEN"))
.isInstanceOf(HaengdongException.class);
}

@DisplayName("비밀번호가 다른지 검증한다.")
@Test
void isNotSamePassword() {
String rawPassword = "1234";
Event event = new Event("이름", rawPassword, "TEST_TOKEN");

assertThat(event.isPasswordMismatch(rawPassword)).isFalse();
}

@DisplayName("비밀번호가 다른지 검증한다.")
@Test
void isNotSamePassword1() {
String rawPassword = "1234";
Event event = new Event("이름", "5678", "TEST_TOKEN");

assertThat(event.isPasswordMismatch(rawPassword)).isTrue();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package server.haengdong.domain.event;

import static org.assertj.core.api.Assertions.assertThatCode;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import server.haengdong.exception.HaengdongException;

class PasswordTest {

@DisplayName("비밀번호는 4자리 숫자 입니다.")
@ParameterizedTest
@ValueSource(strings = {"1", "12", "123", "12345", "adgd"})
void validatePassword(String rawPassword) {
assertThatCode(() -> new Password(rawPassword))
.isInstanceOf(HaengdongException.class);
}
}

0 comments on commit 817c965

Please sign in to comment.