Skip to content

Commit

Permalink
Merge pull request #1244 from NarekDW/feature/custom-masker
Browse files Browse the repository at this point in the history
feature: Add ability to define custom masker function for @Masked annotation
  • Loading branch information
dos65 authored Apr 23, 2024
2 parents 2e19a8b + cc69d43 commit bac92d6
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ object MaskMode {
def this(length: Int) = this(0, length)
}
case class Regexp(pattern: Regex) extends MaskMode

/** Allows to define a custom masker function */
case class Custom(f: String => String) extends MaskMode
}

object masking {
Expand Down Expand Up @@ -54,6 +57,8 @@ object masking {
.getOrElse(shown)
case MaskMode.ForLength(offset, maxLength) =>
loop(shown.toCharArray, shown.length min (offset max 0), if (maxLength == -1) shown.length else maxLength)
case MaskMode.Custom(f) =>
f(shown)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package derivation
import derevo.derive
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import tofu.logging.derivation.MaskMode.Custom

class DerivedLoggableSuite extends AnyFlatSpec with Matchers {

Expand Down Expand Up @@ -85,6 +86,18 @@ class DerivedLoggableSuite extends AnyFlatSpec with Matchers {
"maybeStr2=<none>" +
"}"
}

it should "show mask fields with custom masker function" in {
val maskedCustom = MaskedCustom(
sensitiveField = "som sensitive data",
firstName = Some("John"),
age = 42
)

json(maskedCustom) shouldBe """{"sensitiveField":"*","firstName":"J***","age":"**"}"""
Loggable[MaskedCustom].logShow(maskedCustom) shouldBe
"MaskedCustom{sensitiveField=*,firstName=Some(J***),age=**}"
}
}

object DerivedLoggableSuite {
Expand Down Expand Up @@ -120,4 +133,17 @@ object DerivedLoggableSuite {
@masked maybeDouble: Option[Double],
@masked maybeStr2: Option[String]
)

@derive(loggable)
final case class MaskedCustom(
@masked(Custom(_ => "*")) sensitiveField: String,
@masked(Custom(maskName)) firstName: Option[String],
@masked(Custom(maskAge)) age: Int
)

def maskName(name: String): String =
name.take(1) + "***"

def maskAge(i: String): String =
"*" * i.length
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package derivation

import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import tofu.logging.derivation.MaskMode.Custom

class DerivedLoggableSuite extends AnyFlatSpec with Matchers {

Expand Down Expand Up @@ -67,6 +68,35 @@ class DerivedLoggableSuite extends AnyFlatSpec with Matchers {
Loggable[MaskedBaz].logShow(MaskedBaz(None)) shouldBe "MaskedBaz{kek=<none>}"
}

it should "show mask Option values in logShow" in {
val maybeMasked = MaskedOptBaz(
maybeStr = Some("str"),
maybeInt = Some(123),
maybeBool = Some(true),
maybeDouble = Some(100.001),
maybeStr2 = None
)
Loggable[MaskedOptBaz].logShow(maybeMasked) shouldBe
"MaskedOptBaz{" +
"maybeStr=Some(***)," +
"maybeInt=Some(###)," +
"maybeBool=Some(****)," +
"maybeDouble=Some(###.###)," +
"maybeStr2=<none>" +
"}"
}

it should "show mask fields with custom masker function" in {
val maskedCustom = MaskedCustom(
sensitiveField = "som sensitive data",
firstName = Some("John"),
age = 42
)

json(maskedCustom) shouldBe """{"sensitiveField":"*","firstName":"J***","age":"**"}"""
Loggable[MaskedCustom].logShow(maskedCustom) shouldBe
"MaskedCustom{sensitiveField=*,firstName=Some(J***),age=**}"
}
}

object DerivedLoggableSuite {
Expand All @@ -89,4 +119,25 @@ object DerivedLoggableSuite {
derives Loggable

final case class MaskedBaz(@masked kek: Option[String], @ignoreOpt a: Option[String] = None) derives Loggable

final case class MaskedOptBaz(
@masked maybeStr: Option[String],
@masked maybeInt: Option[Int],
@masked maybeBool: Option[Boolean],
@masked maybeDouble: Option[Double],
@masked maybeStr2: Option[String]
) derives Loggable

final case class MaskedCustom(
@masked(Custom(_ => "*")) sensitiveField: String,
@masked(Custom(maskName)) firstName: Option[String],
@masked(Custom(maskAge)) age: Int
) derives Loggable

def maskName(name: String): String =
name.take(1) + "***"

def maskAge(i: String): String =
"*" * i.length

}

0 comments on commit bac92d6

Please sign in to comment.