Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] 행사 비밀번호 암호화 추가 #429

Merged
merged 4 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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("비밀번호가 다른지 검증한다.")
Comment on lines +48 to +57
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c: displayname이 똑같은데 같은 테스트인가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

동일한 메서드에 대한 테스트라서 따로 이름을 설정하지 않았습니다!

@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);
}
}
Loading