Class ValueMaskers

java.lang.Object
dev.blaauwendraad.masker.json.ValueMaskers

public final class ValueMaskers extends Object
Provides out-of-the-box implementations of ValueMasker.
  • Method Details

    • describe

      public static <T extends ValueMasker> T describe(String description, T delegate)
      Provides information about the ValueMasker implementation. Which is useful for debugging and testing purposes.
      See Also:
      • DescriptiveValueMasker
    • with

      public static ValueMasker.AnyValueMasker with(String value)
      Masks a target value with a static string value.

      For example, "maskMe": "secret" -> "maskMe": "***".

    • with

      public static ValueMasker.AnyValueMasker with(int value)
      Masks a target value with a static integer value.

      For example, "maskMe": 12345 -> "maskMe": 0.

    • with

      public static ValueMasker.AnyValueMasker with(boolean value)
      Masks a target value with a static boolean value.

      For example, "maskMe": true -> "maskMe": false.

    • withNull

      public static ValueMasker.AnyValueMasker withNull()
      Masks a target value with null.
    • eachCharacterWith

      public static ValueMasker.StringMasker eachCharacterWith(String value)
      Masks all characters of a target string value with a static string value.

      For example, "maskMe": "secret" -> "maskMe": "******".

      Note: this implementation only replaces visible characters with a mask, meaning that JSON escape character ('\') will not count towards the length of the masked value and the unicode characters ('\u1000'), including 4-byte UTF-8 characters ('\uD83D \uDCA9'), will only count as a single character in the masked value.

    • eachDigitWith

      public static ValueMasker.NumberMasker eachDigitWith(int digit)
      Masks all digits of a target numeric value with a static digit.

      For example, "maskMe": 12345 -> "maskMe": 88888.

    • eachDigitWith

      public static ValueMasker.NumberMasker eachDigitWith(String value)
      Masks all digits of a target numeric value with a static String (which can also be a single character).

      For example, "maskMe": 12345 -> "maskMe": "*****".

      Or, for example "maskMe": 123 -> "maskMe": "NoNoNo".

    • noop

      public static ValueMasker.AnyValueMasker noop()
      Does not mask a target value (no-operation). Can be used if certain JSON value types do not need to be masked, for example, not masking booleans or numbers.
      See Also:
    • email

      public static ValueMasker.StringMasker email(int keepPrefixLength, int keepSuffixLength, boolean keepDomain, String mask)
      Masks a target string value (containing an email) while keeping some number of the prefix or suffix characters and the ability to keep the domain unmasked.

      For example:

      Parameters:
      keepPrefixLength - amount of prefix characters to keep unmasked
      keepDomain - if true - the email domain will remain unmasked
      mask - the static mask applied to the rest of the value
    • withRawValueFunction

      public static ValueMasker.AnyValueMasker withRawValueFunction(Function<String,String> masker)
      Masks a target value with the provided Function. The target value (as raw JSON literal) is passed into the function as a string regardless of the JSON type (string, numeric or a boolean). In case the target value is a JSON string the value the function will receive a JSON encoded value as it appears in the JSON, including the opening and closing quotes, and the value containing escaped the control characters (e.g. \n, \t, etc.), quotation marks ("), escape character itself (\), and unicode-encoded characters (\uXXXX).

      Consequently, the return value of the provided function must be a valid JSON encoded literal (of any JSON type), otherwise the masking will result in an invalid JSON. If the return value is null, the target value will be replaced with null JSON literal.

      It is strongly advised to use an equivalent function withTextFunction(Function) which operates on a decoded string values and can never produce an invalid JSON.

      The table below contains a couple examples for the masking

      Examples of using withRawValueFunction
      Input JSON Function Masked JSON
      { "maskMe": "a secret" } value -> value.replaceAll("secret", "***") { "maskMe": "a ***" }
      { "maskMe": 12345 } value -> value.startsWith("123") ? "0" : value { "maskMe": 0 }
      { "maskMe": "12345" } value -> value.startsWith("123") ? "0" : value { "maskMe": "12345" }
      { "maskMe": "12345" } value -> value.startsWith("\"123") ? "0" : value { "maskMe": 0 }
      { "maskMe": "secret" } value -> "***" { "maskMe": *** } (invalid JSON)
      { "maskMe": "secret" } value -> "\"***\"" { "maskMe": "***" } (valid JSON)
      { "maskMe": "secret value" } value -> value.substring(0, 3) + "***" { "maskMe": "se*** } (invalid JSON
      { "maskMe": "secret value" } value -> value.startsWith("\"") ? value.substring(0, 4) + "***\"" : value { "maskMe": "sec***" } (valid JSON)
      { "maskMe": "Andrii \"Juice\" Pilshchykov" } value -> value.replaceAll("\"", "(quote)") { "maskMe": "Andrii \(quote)Juice\(quote) Pilshchykov" } (invalid JSON)
      { "maskMe": "Andrii \"Juice\" Pilshchykov" } value -> value.replaceAll("\\\"", "(quote)") { "maskMe": "Andrii (quote)Juice(quote) Pilshchykov" } (valid JSON)

      Note: usually the ValueMasker operates on a byte level without parsing JSON values into intermediate objects. This implementation, however, needs to allocate a String before passing it into the function and then turn it back into a byte array for the replacement, which introduces some performance overhead.

      See Also:
    • withTextFunction

      public static ValueMasker.AnyValueMasker withTextFunction(Function<String,String> masker)
      Masks a target value by applying the provided Function on the textual representation of the original value. The target is passed into the function as a string regardless of the JSON type (string, numeric or a boolean). In case the original value was a JSON string, the Function will receive a decoded string value without the quotes.

      A non-null return value of the provided function will be encoded into a JSON string regardless of the JSON type of the original value. Any character that MUST be escaped (as per RFC 8259, section 7) will be escaped. Characters that MAY be escaped (as per RFC 8259) WILL NOT be escaped. If the return value is null, the target value will be replaced with null JSON literal.

      The table below contains a couple examples for the masking

      Examples of using withTextFunction
      Input JSON Function Masked JSON
      { "maskMe": "a secret" } value -> value.replaceAll("secret", "***") { "maskMe": "a ***" }
      { "maskMe": 12345 } value -> value.startsWith("123") ? "0" : value { "maskMe": "0" }
      { "maskMe": 12345 } value -> value { "maskMe": "12345" }
      { "maskMe": "secret" } value -> "***" { "maskMe": "***" }
      { "maskMe": "secret value" } value -> value.substring(0, 3) + "***" { "maskMe": "sec***" }
      { "maskMe": "Andrii \"Juice\" Pilshchykov" } value -> value.replaceAll("\"", "(quote)") { "maskMe": "Andrii (quote)Juice(quote) Pilshchykov" }

      Note: in all other cases, the ValueMasker operates on a byte level without parsing JSON values into intermediate objects. This implementation, however, needs to allocate a String before passing it to the Function and then turn it back into a byte array for the replacement, which introduces some performance overhead.