| 1 | package com.renomad.minum.utils; | |
| 2 | ||
| 3 | import java.net.URLDecoder; | |
| 4 | import java.net.URLEncoder; | |
| 5 | import java.security.SecureRandom; | |
| 6 | import java.util.List; | |
| 7 | import java.util.stream.Collectors; | |
| 8 | import java.util.stream.IntStream; | |
| 9 | ||
| 10 | import static com.renomad.minum.utils.Invariants.mustNotBeNull; | |
| 11 | import static java.nio.charset.StandardCharsets.UTF_8; | |
| 12 | ||
| 13 | /** | |
| 14 | * Some helper methods for Strings. | |
| 15 | */ | |
| 16 | public final class StringUtils { | |
| 17 | ||
| 18 | private StringUtils() { | |
| 19 | // making this private to be clearer it isn't supposed to be instantiated. | |
| 20 | } | |
| 21 | ||
| 22 | ||
| 23 | /** | |
| 24 | * Returns text that has three symbols replaced - | |
| 25 | * the less-than, greater-than, and ampersand. | |
| 26 | * See <a href="https://www.w3.org/International/questions/qa-escapes#use">...</a> | |
| 27 | * <br> | |
| 28 | * <pre>{@code | |
| 29 | * This will protect against something like <div>$USERNAME</div> allowing | |
| 30 | * a username of | |
| 31 | * <script>alert(1)</script> | |
| 32 | * becoming | |
| 33 | * <div><script>alert(1)</script</div> | |
| 34 | * and instead becomes | |
| 35 | * <div><script>alert(1)</script></div> | |
| 36 | * }</pre> | |
| 37 | * If the text is going inside an attribute (e.g. {@code <div class="TEXT_GOES_HERE">} ) | |
| 38 | * Then you need to escape slightly differently. In that case see [safeAttr] | |
| 39 | */ | |
| 40 | public static String safeHtml(String input) { | |
| 41 |
1
1. safeHtml : negated conditional → KILLED |
if (input == null) { |
| 42 | return ""; | |
| 43 | } | |
| 44 |
1
1. safeHtml : replaced return value with "" for com/renomad/minum/utils/StringUtils::safeHtml → KILLED |
return input.replace("&", "&") |
| 45 | .replace("<", "<") | |
| 46 | .replace(">", ">"); | |
| 47 | } | |
| 48 | ||
| 49 | /** | |
| 50 | * Replace dangerous text that would go inside an HTML attribute. | |
| 51 | * See {@link #safeHtml(String)} | |
| 52 | * <br><br> | |
| 53 | * If we get a null string, just return an empty string | |
| 54 | * <br><br> | |
| 55 | * <pre>{@code | |
| 56 | * example: | |
| 57 | * Given | |
| 58 | * alert('XSS Attack') | |
| 59 | * Get | |
| 60 | * alert('XSS Attack') | |
| 61 | * }</pre> | |
| 62 | */ | |
| 63 | public static String safeAttr(String input) { | |
| 64 |
1
1. safeAttr : negated conditional → KILLED |
if (input == null) { |
| 65 | return ""; | |
| 66 | } | |
| 67 |
1
1. safeAttr : replaced return value with "" for com/renomad/minum/utils/StringUtils::safeAttr → KILLED |
return input.replace("&", "&") |
| 68 | .replace("<", "<") | |
| 69 | .replace("\"", """) | |
| 70 | .replace("'", "'"); | |
| 71 | } | |
| 72 | ||
| 73 | /** | |
| 74 | * Encodes UTF-8 text using URL-encoding | |
| 75 | */ | |
| 76 | public static String encode(String str) { | |
| 77 |
1
1. encode : negated conditional → KILLED |
if (str == null) { |
| 78 |
1
1. encode : replaced return value with "" for com/renomad/minum/utils/StringUtils::encode → KILLED |
return "%NULL%"; |
| 79 | } | |
| 80 |
1
1. encode : replaced return value with "" for com/renomad/minum/utils/StringUtils::encode → KILLED |
return URLEncoder.encode(str, UTF_8); |
| 81 | } | |
| 82 | ||
| 83 | /** | |
| 84 | * Decodes URL-encoded UTF-8 text, except that we | |
| 85 | * first check if the string value is the token %NULL%, | |
| 86 | * which is our way to signify null. | |
| 87 | */ | |
| 88 | public static String decode(String str) { | |
| 89 | mustNotBeNull(str); | |
| 90 |
1
1. decode : negated conditional → KILLED |
if (str.equals("%NULL%")) { |
| 91 |
1
1. decode : replaced return value with "" for com/renomad/minum/utils/StringUtils::decode → KILLED |
return null; |
| 92 | } | |
| 93 |
1
1. decode : replaced return value with "" for com/renomad/minum/utils/StringUtils::decode → KILLED |
return URLDecoder.decode(str, UTF_8); |
| 94 | } | |
| 95 | ||
| 96 | public static String generateSecureRandomString(int length) { | |
| 97 | final var allowedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | |
| 98 | final var sr = new SecureRandom(); | |
| 99 | ||
| 100 |
2
1. generateSecureRandomString : Replaced integer addition with subtraction → KILLED 2. generateSecureRandomString : replaced return value with "" for com/renomad/minum/utils/StringUtils::generateSecureRandomString → KILLED |
return IntStream.range(1, length+1) |
| 101 |
1
1. lambda$generateSecureRandomString$0 : replaced Character return value with 0 for com/renomad/minum/utils/StringUtils::lambda$generateSecureRandomString$0 → KILLED |
.mapToObj (x -> allowedChars.charAt(sr.nextInt(allowedChars.length()))) |
| 102 | .map(Object::toString) | |
| 103 | .collect(Collectors.joining()); | |
| 104 | } | |
| 105 | ||
| 106 | /** | |
| 107 | * Converts a list of bytes to a string. Returns null if the input is null. | |
| 108 | */ | |
| 109 | public static String byteListToString(List<Byte> byteList) { | |
| 110 |
2
1. byteListToString : negated conditional → KILLED 2. byteListToString : replaced return value with "" for com/renomad/minum/utils/StringUtils::byteListToString → KILLED |
if (byteList == null) return null; |
| 111 | final int size = byteList.size(); | |
| 112 | final var buf = new byte[size]; | |
| 113 |
2
1. byteListToString : changed conditional boundary → KILLED 2. byteListToString : negated conditional → KILLED |
for (int i = 0; i < size; i++) { |
| 114 | buf[i] = byteList.get(i); | |
| 115 | } | |
| 116 |
1
1. byteListToString : replaced return value with "" for com/renomad/minum/utils/StringUtils::byteListToString → KILLED |
return new String(buf, UTF_8); |
| 117 | } | |
| 118 | ||
| 119 | /** | |
| 120 | * Converts an array of bytes to a string. Returns null if the input is null. | |
| 121 | */ | |
| 122 | public static String byteArrayToString(byte[] byteArray) { | |
| 123 |
2
1. byteArrayToString : negated conditional → KILLED 2. byteArrayToString : replaced return value with "" for com/renomad/minum/utils/StringUtils::byteArrayToString → KILLED |
if (byteArray == null) return null; |
| 124 |
1
1. byteArrayToString : replaced return value with "" for com/renomad/minum/utils/StringUtils::byteArrayToString → KILLED |
return new String(byteArray, UTF_8); |
| 125 | } | |
| 126 | ||
| 127 | ||
| 128 | } | |
| 129 | ||
Mutations | ||
| 41 |
1.1 |
|
| 44 |
1.1 |
|
| 64 |
1.1 |
|
| 67 |
1.1 |
|
| 77 |
1.1 |
|
| 78 |
1.1 |
|
| 80 |
1.1 |
|
| 90 |
1.1 |
|
| 91 |
1.1 |
|
| 93 |
1.1 |
|
| 100 |
1.1 2.2 |
|
| 101 |
1.1 |
|
| 110 |
1.1 2.2 |
|
| 113 |
1.1 2.2 |
|
| 116 |
1.1 |
|
| 123 |
1.1 2.2 |
|
| 124 |
1.1 |