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

fuzzing-case-sensitivity #30

Merged
merged 1 commit into from
Jan 2, 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
6 changes: 6 additions & 0 deletions src/test/java/dev/blaauwendraad/masker/json/FuzzingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ private static Stream<JsonMaskingConfig> jsonMaskingConfigs() {
JsonMaskingConfig.custom(DEFAULT_TARGET_KEYS, JsonMaskingConfig.TargetKeyMode.MASK)
.maskNumericValuesWith(1)
.build(),
JsonMaskingConfig.custom(DEFAULT_TARGET_KEYS, JsonMaskingConfig.TargetKeyMode.MASK)
.caseSensitiveTargetKeys()
.build(),
JsonMaskingConfig.custom(DEFAULT_TARGET_KEYS, JsonMaskingConfig.TargetKeyMode.MASK)
.obfuscationLength(3)
.build(),
Expand All @@ -68,6 +71,9 @@ private static Stream<JsonMaskingConfig> jsonMaskingConfigs() {
.maskNumericValuesWith(3)
.build(),
JsonMaskingConfig.custom(DEFAULT_TARGET_KEYS, JsonMaskingConfig.TargetKeyMode.ALLOW).build(),
JsonMaskingConfig.custom(DEFAULT_TARGET_KEYS, JsonMaskingConfig.TargetKeyMode.ALLOW)
.caseSensitiveTargetKeys()
.build(),
JsonMaskingConfig.custom(DEFAULT_TARGET_KEYS, JsonMaskingConfig.TargetKeyMode.ALLOW)
.maskNumericValuesWith(2)
.build(),
Expand Down
63 changes: 49 additions & 14 deletions src/test/java/dev/blaauwendraad/masker/json/ParseAndMaskUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.math.BigInteger;
import java.util.Iterator;
import java.util.Set;
import java.util.stream.Collectors;

public final class ParseAndMaskUtil {

Expand All @@ -31,17 +32,38 @@ static JsonNode mask(String jsonString, JsonMaskingConfig jsonMaskingConfig) thr

@Nonnull
static JsonNode mask(JsonNode jsonNode, JsonMaskingConfig jsonMaskingConfig) {
Set<String> targetKeys = jsonMaskingConfig.getTargetKeys();
if (targetKeys.isEmpty()) {
Set<String> casingAppliedTargetKeys;
if (jsonMaskingConfig.caseSensitiveTargetKeys()) {
casingAppliedTargetKeys = jsonMaskingConfig.getTargetKeys();
} else {
casingAppliedTargetKeys = jsonMaskingConfig.getTargetKeys()
.stream()
.map(String::toLowerCase)
.collect(Collectors.toSet());
}
if (casingAppliedTargetKeys.isEmpty()) {
return jsonNode;
}
if (jsonNode instanceof ObjectNode objectNode) {
objectNode.fieldNames().forEachRemaining(
key -> {
if (jsonMaskingConfig.isInMaskMode() && targetKeys.contains(key)
|| jsonMaskingConfig.isInAllowMode() && !targetKeys.contains(key)) {
objectNode.replace(key, maskJsonValue(objectNode.get(key), jsonMaskingConfig));
} else if (!jsonMaskingConfig.isInAllowMode() || !targetKeys.contains(key)) {
String casingAppliedKey = jsonMaskingConfig.caseSensitiveTargetKeys()
? key
: key.toLowerCase();
if (jsonMaskingConfig.isInMaskMode()
&& casingAppliedTargetKeys.contains(casingAppliedKey)
|| jsonMaskingConfig.isInAllowMode() && !casingAppliedTargetKeys.contains(
casingAppliedKey)) {
objectNode.replace(
key,
maskJsonValue(
objectNode.get(key),
jsonMaskingConfig,
casingAppliedTargetKeys
)
);
} else if (!jsonMaskingConfig.isInAllowMode()
|| !casingAppliedTargetKeys.contains(casingAppliedKey)) {
mask(jsonNode.get(key), jsonMaskingConfig);
}
}
Expand All @@ -57,12 +79,16 @@ static JsonNode mask(JsonNode jsonNode, JsonMaskingConfig jsonMaskingConfig) {
}

@Nonnull
private static JsonNode maskJsonValue(JsonNode jsonNode, JsonMaskingConfig jsonMaskingConfig) {
private static JsonNode maskJsonValue(
JsonNode jsonNode,
JsonMaskingConfig jsonMaskingConfig,
Set<String> casingAppliedTargetKeys
) {
return switch (jsonNode.getNodeType()) {
case STRING -> maskTextNode((TextNode) jsonNode, jsonMaskingConfig);
case NUMBER -> maskNumericNode((NumericNode) jsonNode, jsonMaskingConfig);
case ARRAY -> maskArrayNodeValue((ArrayNode) jsonNode, jsonMaskingConfig);
case OBJECT -> maskObjectNodeValue((ObjectNode) jsonNode, jsonMaskingConfig);
case ARRAY -> maskArrayNodeValue((ArrayNode) jsonNode, jsonMaskingConfig, casingAppliedTargetKeys);
case OBJECT -> maskObjectNodeValue((ObjectNode) jsonNode, jsonMaskingConfig, casingAppliedTargetKeys);
default -> jsonNode;
};
}
Expand All @@ -87,27 +113,36 @@ private static NumericNode maskNumericNode(NumericNode numericNode, JsonMaskingC
}

@Nonnull
private static ArrayNode maskArrayNodeValue(ArrayNode arrayNode, JsonMaskingConfig jsonMaskingConfig) {
private static ArrayNode maskArrayNodeValue(
ArrayNode arrayNode,
JsonMaskingConfig jsonMaskingConfig,
Set<String> casingAppliedTargetKeys
) {
ArrayNode maskedArrayNode = JsonNodeFactory.instance.arrayNode();
for (JsonNode element : arrayNode) {
maskedArrayNode.add(maskJsonValue(element, jsonMaskingConfig));
maskedArrayNode.add(maskJsonValue(element, jsonMaskingConfig, casingAppliedTargetKeys));
}
return maskedArrayNode;
}

@Nonnull
private static ObjectNode maskObjectNodeValue(ObjectNode objectNode, JsonMaskingConfig jsonMaskingConfig) {
private static ObjectNode maskObjectNodeValue(
ObjectNode objectNode,
JsonMaskingConfig jsonMaskingConfig,
Set<String> casingAppliedTargetKeys
) {
ObjectNode maskedObjectNode = JsonNodeFactory.instance.objectNode();
Iterator<String> fieldNames = objectNode.fieldNames();

while (fieldNames.hasNext()) {
String fieldName = fieldNames.next();
if (jsonMaskingConfig.isInAllowMode() && jsonMaskingConfig.getTargetKeys().contains(fieldName)) {
if (jsonMaskingConfig.isInAllowMode() && casingAppliedTargetKeys
.contains(jsonMaskingConfig.caseSensitiveTargetKeys() ? fieldName : fieldName.toLowerCase())) {
// field is explicitly allowed, so just put the original field back
maskedObjectNode.set(fieldName, objectNode.get(fieldName));
} else {
JsonNode fieldValue = objectNode.get(fieldName);
maskedObjectNode.set(fieldName, maskJsonValue(fieldValue, jsonMaskingConfig));
maskedObjectNode.set(fieldName, maskJsonValue(fieldValue, jsonMaskingConfig, casingAppliedTargetKeys));
}
}
return maskedObjectNode;
Expand Down
22 changes: 19 additions & 3 deletions src/test/java/randomgen/json/RandomJsonGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,24 @@ private String randomKey() {

private String getRandomTargetKey() {
int rnd = random.nextInt(config.getTargetKeys().size());
return (String) config.getTargetKeys().toArray()[rnd];
return randomizeCase((String) config.getTargetKeys().toArray()[rnd]);
}

private String randomizeCase(String input) {
StringBuilder resultBuilder = new StringBuilder();

for (char c : input.toCharArray()) {
// Generate a random boolean to decide whether to convert to uppercase or lowercase
boolean toUpperCase = random.nextBoolean();

// Convert the character to uppercase or lowercase based on the random boolean
char convertedChar = toUpperCase ? Character.toUpperCase(c) : Character.toLowerCase(c);

// Append the converted character to the result string
resultBuilder.append(convertedChar);
}

return resultBuilder.toString();
}

private String getRandomString() {
Expand Down Expand Up @@ -168,8 +185,7 @@ private ArrayNode createRandomArrayNode(Context context, int depth) {
}

private boolean reachedTargetSize(int estimatedSizeBytes) {
boolean didIt = config.hasTargetSize() && estimatedSizeBytes >= config.getTargetJsonSizeBytes();
return didIt;
return config.hasTargetSize() && estimatedSizeBytes >= config.getTargetJsonSizeBytes();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks for fixing some leftovers after my debugging 😅

}

private int sizeOf(JsonNode node) {
Expand Down
6 changes: 3 additions & 3 deletions src/test/java/randomgen/json/RandomJsonGeneratorConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,14 @@ public boolean hasTargetSize() {
}

public static class Builder {
private int maxArraySize = 3;
private int maxArraySize = 5;
private float maxFloat = Float.MAX_VALUE;
private double maxDouble = Double.MAX_VALUE;
private long maxLong = Long.MAX_VALUE; // because we already have long, we don't add byte, short and int
private BigInteger maxBigInt = BigInteger.valueOf(Long.MAX_VALUE).multiply(BigInteger.valueOf(Long.MAX_VALUE));
private int maxStringLength = 4;
private int maxStringLength = 8;
private int maxObjectKeys = 5;
private int maxNodeDepth = 3;
private int maxNodeDepth = 4;
private double targetKeyPercentage = 0.2;
private Set<Character> allowedCharacters = mergeCharSets(
getPrintableAsciiCharacters(),
Expand Down