From 7131d11fad7790def670f4207420b0d886ff6607 Mon Sep 17 00:00:00 2001 From: pricelees Date: Tue, 29 Jul 2025 15:47:57 +0900 Subject: [PATCH] =?UTF-8?q?test:=20RoomescapeLogMaskingConverter=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?=EC=9E=98=EB=AA=BB=20=EC=9E=91=EC=84=B1=EB=90=9C=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../log/RoomescapeLogMaskingConverter.kt | 20 ++--- .../log/RoomescapeLogMaskingConverterTest.kt | 77 +++++++++++++++++++ 2 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 src/test/kotlin/roomescape/common/log/RoomescapeLogMaskingConverterTest.kt diff --git a/src/main/kotlin/roomescape/common/log/RoomescapeLogMaskingConverter.kt b/src/main/kotlin/roomescape/common/log/RoomescapeLogMaskingConverter.kt index 7778d96f..3fb696b1 100644 --- a/src/main/kotlin/roomescape/common/log/RoomescapeLogMaskingConverter.kt +++ b/src/main/kotlin/roomescape/common/log/RoomescapeLogMaskingConverter.kt @@ -36,7 +36,7 @@ class RoomescapeLogMaskingConverter : MessageConverter() { private fun maskedPlainMessage(message: String): String { val keys: String = SENSITIVE_KEYS.joinToString("|") - val regex = Regex("(?i)($keys)(\\s*=\\s*)(\\S+)") + val regex = Regex("(?i)($keys)(\\s*=\\s*)([^,\\s]+)") return regex.replace(message) { matchResult -> val key = matchResult.groupValues[1] @@ -47,19 +47,11 @@ class RoomescapeLogMaskingConverter : MessageConverter() { } } - private fun maskValue(value: String): String { - return if (value.length <= 2) { - MASK - } else { - "${value.first()}$MASK${value.last()}" - } - } - private fun maskRecursive(node: JsonNode?) { node?.forEachEntry { key, childNode -> when { childNode.isValueNode -> { - if (key in SENSITIVE_KEYS) (node as ObjectNode).put(key, MASK) + if (key in SENSITIVE_KEYS) (node as ObjectNode).put(key, maskValue(childNode.asText())) } childNode.isObject -> maskRecursive(childNode) @@ -78,4 +70,12 @@ class RoomescapeLogMaskingConverter : MessageConverter() { } } } + + private fun maskValue(value: String): String { + return if (value.length <= 2) { + MASK + } else { + "${value.first()}$MASK${value.last()}" + } + } } diff --git a/src/test/kotlin/roomescape/common/log/RoomescapeLogMaskingConverterTest.kt b/src/test/kotlin/roomescape/common/log/RoomescapeLogMaskingConverterTest.kt new file mode 100644 index 00000000..b4ed4462 --- /dev/null +++ b/src/test/kotlin/roomescape/common/log/RoomescapeLogMaskingConverterTest.kt @@ -0,0 +1,77 @@ +package roomescape.common.log + +import ch.qos.logback.classic.spi.ILoggingEvent +import io.kotest.assertions.assertSoftly +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.equals.shouldBeEqual +import io.kotest.matchers.string.shouldContain +import io.mockk.every +import io.mockk.mockk + +class RoomescapeLogMaskingConverterTest : FunSpec({ + + val converter = RoomescapeLogMaskingConverter() + val event: ILoggingEvent = mockk() + + context("평문 로그에서는 key=value 형식을 처리한다.") { + + test("2글자 초과이면 맨 앞, 맨 뒤를 제외한 나머지를 가린다.") { + val email = "a@a.a" + val password = "password12" + val accessToken = "accessToken12" + + every { + event.formattedMessage + } returns "email=${email}, password=${password}, accessToken = $accessToken" + + assertSoftly(converter.convert(event)) { + this shouldContain "email=${email}" + this shouldContain "password=${password.first()}****${password.last()}" + this shouldContain "accessToken = ${accessToken.first()}****${accessToken.last()}" + } + + } + + test("2글자 이하이면 전부 가린다.") { + val email = "a@a.a" + val password = "pa" + val accessToken = "a" + + every { + event.formattedMessage + } returns "email=${email}, password=${password}, accessToken = ${accessToken}" + + assertSoftly(converter.convert(event)) { + this shouldContain "email=${email}" + this shouldContain "password=****" + this shouldContain "accessToken = ****" + } + } + } + + context("JSON 형식 로그를 처리한다.") { + val json = "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"password12\"}}" + + test("2글자 초과이면 맨 앞, 맨 뒤를 제외한 나머지를 가린다.") { + val password = "password12" + val json = "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"${password}\"}}" + + every { + event.formattedMessage + } returns json + + converter.convert(event) shouldBeEqual "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"${password.first()}****${password.last()}\"}}" + } + + test("2글자 이하이면 전부 가린다.") { + val password = "pa" + val json = "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"${password}\"}}" + + every { + event.formattedMessage + } returns json + + converter.convert(event) shouldBeEqual "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"****\"}}" + } + } +})