StringUtils.java
- package com.renomad.minum.utils;
- import java.net.URLDecoder;
- import java.net.URLEncoder;
- import java.security.SecureRandom;
- import java.util.List;
- import java.util.stream.Collectors;
- import java.util.stream.IntStream;
- import static com.renomad.minum.utils.Invariants.mustNotBeNull;
- import static java.nio.charset.StandardCharsets.UTF_8;
- /**
- * Some helper methods for Strings.
- */
- public final class StringUtils {
- private StringUtils() {
- // making this private to be clearer it isn't supposed to be instantiated.
- }
- /**
- * Returns text that has three symbols replaced -
- * the less-than, greater-than, and ampersand.
- * See <a href="https://www.w3.org/International/questions/qa-escapes#use">...</a>
- * <br>
- * <pre>{@code
- * This will protect against something like <div>$USERNAME</div> allowing
- * a username of
- * <script>alert(1)</script>
- * becoming
- * <div><script>alert(1)</script</div>
- * and instead becomes
- * <div><script>alert(1)</script></div>
- * }</pre>
- * If the text is going inside an attribute (e.g. {@code <div class="TEXT_GOES_HERE">} )
- * Then you need to escape slightly differently. In that case see [safeAttr]
- */
- public static String safeHtml(String input) {
- if (input == null) {
- return "";
- }
- return input.replace("&", "&")
- .replace("<", "<")
- .replace(">", ">");
- }
- /**
- * Replace dangerous text that would go inside an HTML attribute.
- * See {@link #safeHtml(String)}
- * <br><br>
- * If we get a null string, just return an empty string
- * <br><br>
- * <pre>{@code
- * example:
- * Given
- * alert('XSS Attack')
- * Get
- * alert('XSS Attack')
- * }</pre>
- */
- public static String safeAttr(String input) {
- if (input == null) {
- return "";
- }
- return input.replace("&", "&")
- .replace("<", "<")
- .replace("\"", """)
- .replace("'", "'");
- }
- /**
- * Encodes UTF-8 text using URL-encoding
- */
- public static String encode(String str) {
- if (str == null) {
- return "%NULL%";
- }
- return URLEncoder.encode(str, UTF_8);
- }
- /**
- * Decodes URL-encoded UTF-8 text, except that we
- * first check if the string value is the token %NULL%,
- * which is our way to signify null.
- */
- public static String decode(String str) {
- mustNotBeNull(str);
- if (str.equals("%NULL%")) {
- return null;
- }
- return URLDecoder.decode(str, UTF_8);
- }
- public static String generateSecureRandomString(int length) {
- final var allowedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
- final var sr = new SecureRandom();
- return IntStream.range(1, length+1)
- .mapToObj (x -> allowedChars.charAt(sr.nextInt(allowedChars.length())))
- .map(Object::toString)
- .collect(Collectors.joining());
- }
- /**
- * Converts a list of bytes to a string. Returns null if the input is null.
- */
- public static String byteListToString(List<Byte> byteList) {
- if (byteList == null) return null;
- final int size = byteList.size();
- final var buf = new byte[size];
- for (int i = 0; i < size; i++) {
- buf[i] = byteList.get(i);
- }
- return new String(buf, UTF_8);
- }
- /**
- * Converts an array of bytes to a string. Returns null if the input is null.
- */
- public static String byteArrayToString(byte[] byteArray) {
- if (byteArray == null) return null;
- return new String(byteArray, UTF_8);
- }
- }