diff --git a/src/main/java/com/project/notification/controller/dto/response/MessageLogDetailResponse.java b/src/main/java/com/project/notification/controller/dto/response/MessageLogDetailResponse.java index 619a0ee..0bd5b51 100644 --- a/src/main/java/com/project/notification/controller/dto/response/MessageLogDetailResponse.java +++ b/src/main/java/com/project/notification/controller/dto/response/MessageLogDetailResponse.java @@ -25,6 +25,10 @@ public record TemplateSnapshot( String groupId, String groupName, Channel channel, int version) {} public static MessageLogDetailResponse from(MessageLog log) { + return from(log, log.getRecipientEnc()); + } + + public static MessageLogDetailResponse from(MessageLog log, String recipientMasked) { // 템플릿 정보가 있을 경우에만 Snapshot 생성 TemplateSnapshot snapshot = null; TemplateVersion templateVersion = log.getTemplateVersion(); @@ -42,7 +46,7 @@ public static MessageLogDetailResponse from(MessageLog log) { log.getId(), log.getTraceId(), log.getSubscription().getSubId(), - log.getRecipientEnc(), + recipientMasked, (templateVersion != null) ? templateVersion.getId() : null, log.getChannel(), log.getStatus(), diff --git a/src/main/java/com/project/notification/service/MessageLogService.java b/src/main/java/com/project/notification/service/MessageLogService.java index 578e7ed..81ebb24 100644 --- a/src/main/java/com/project/notification/service/MessageLogService.java +++ b/src/main/java/com/project/notification/service/MessageLogService.java @@ -5,8 +5,11 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import com.project.core.controller.dto.response.MaskingUtil; import com.project.global.exception.ApplicationException; import com.project.global.exception.code.domain.core.CoreErrorCode; +import com.project.global.exception.core.OperationFailedException; +import com.project.global.util.AesUtil; import com.project.notification.controller.dto.request.MessageLogSearchRequest; import com.project.notification.controller.dto.response.MessageLogDetailResponse; import com.project.notification.controller.dto.response.MessageLogResponse; @@ -14,13 +17,16 @@ import com.project.notification.infra.repository.MessageLogRepository; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; @Service @RequiredArgsConstructor @Transactional(readOnly = true) +@Slf4j public class MessageLogService { private final MessageLogRepository messageLogRepository; + private final AesUtil aesUtil; /** 로그 목록 검색 */ public Slice searchLogs( @@ -35,6 +41,31 @@ public MessageLogDetailResponse getLogDetail(Long logId) { .findDetailById(logId) .orElseThrow(() -> new ApplicationException(CoreErrorCode.LOG_NOT_FOUND)); - return MessageLogDetailResponse.from(log); + String decryptedRecipient = safeDecrypt(log.getRecipientEnc()); + String maskedRecipient = maskRecipient(decryptedRecipient); + + return MessageLogDetailResponse.from(log, maskedRecipient); + } + + private String safeDecrypt(String encrypted) { + if (encrypted == null) { + return null; + } + try { + return aesUtil.decrypt(encrypted); + } catch (OperationFailedException e) { + log.warn("Failed to decrypt recipient. value: {}", encrypted, e); + return encrypted; + } + } + + private String maskRecipient(String recipient) { + if (recipient == null || recipient.isBlank()) { + return recipient; + } + if (recipient.contains("@")) { + return MaskingUtil.maskEmail(recipient); + } + return MaskingUtil.maskPhone(recipient); } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 7be2722..29bdc1a 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -85,4 +85,8 @@ logging: org.springframework.web: INFO org.hibernate.SQL: WARN pattern: - level: "%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]" \ No newline at end of file + level: "%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]" + +debug: + crypto: + enabled: true