/*
* Password Management Servlets (PWM)
* http://www.pwm-project.org
*
* Copyright (c) 2006-2009 Novell, Inc.
* Copyright (c) 2009-2017 The PWM Project
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package password.pwm.util.java;
import net.iharder.Base64;
import org.apache.commons.codec.binary.Base32;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import password.pwm.PwmConstants;
import password.pwm.util.logging.PwmLogger;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
public abstract class StringUtil {
private static final PwmLogger LOGGER = PwmLogger.forClass(StringUtil.class);
/**
* Based on http://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java.
*
* @param input string to have escaped
* @return ldap escaped script
*
*/
public static String escapeLdapFilter(final String input) {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
final char curChar = input.charAt(i);
switch (curChar) {
case '\\':
sb.append("\\5c");
break;
case '*':
sb.append("\\2a");
break;
case '(':
sb.append("\\28");
break;
case ')':
sb.append("\\29");
break;
case '\u0000':
sb.append("\\00");
break;
default:
sb.append(curChar);
}
}
return sb.toString();
}
/**
* Based on http://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java.
*
* @param input string to have escaped
* @return ldap escaped script
*
*/
public static String escapeLdapDN(final String input) {
final StringBuilder sb = new StringBuilder(); // If using JDK >= 1.5 consider using StringBuilder
if ((input.length() > 0) && ((input.charAt(0) == ' ') || (input.charAt(0) == '#'))) {
sb.append('\\'); // add the leading backslash if needed
}
for (int i = 0; i < input.length(); i++) {
final char curChar = input.charAt(i);
switch (curChar) {
case '\\':
sb.append("\\\\");
break;
case ',':
sb.append("\\,");
break;
case '+':
sb.append("\\+");
break;
case '"':
sb.append("\\\"");
break;
case '<':
sb.append("\\<");
break;
case '>':
sb.append("\\>");
break;
case ';':
sb.append("\\;");
break;
default:
sb.append(curChar);
}
}
if ((input.length() > 1) && (input.charAt(input.length() - 1) == ' ')) {
sb.insert(sb.length() - 1, '\\'); // add the trailing backslash if needed
}
return sb.toString();
}
public static Map<String, String> convertStringListToNameValuePair(final Collection<String> input, final String separator) {
if (input == null || input.isEmpty()) {
return Collections.emptyMap();
}
final Map<String, String> returnMap = new LinkedHashMap<>();
for (final String loopStr : input) {
if (loopStr != null && separator != null && loopStr.contains(separator)) {
final int separatorLocation = loopStr.indexOf(separator);
final String key = loopStr.substring(0, separatorLocation);
if (!key.trim().isEmpty()) {
final String value = loopStr.substring(separatorLocation + separator.length(), loopStr.length());
returnMap.put(key, value);
}
} else {
if (loopStr != null && !loopStr.trim().isEmpty()) {
returnMap.put(loopStr, "");
}
}
}
return returnMap;
}
public static String join(final Object[] inputs, final String separator) {
return StringUtils.join(inputs, separator);
}
public static String join(final Collection inputs, final String separator) {
return StringUtils.join(inputs == null ? new String[]{} : inputs.toArray(), separator);
}
public static String formatDiskSize(final long diskSize) {
final float COUNT = 1000;
if (diskSize < 1) {
return "n/a";
}
if (diskSize == 0) {
return "0";
}
final NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(2);
if (diskSize > COUNT * COUNT * COUNT) {
final StringBuilder sb = new StringBuilder();
sb.append(nf.format(diskSize / COUNT / COUNT / COUNT));
sb.append(" GB");
return sb.toString();
}
if (diskSize > COUNT * COUNT) {
final StringBuilder sb = new StringBuilder();
sb.append(nf.format(diskSize / COUNT / COUNT));
sb.append(" MB");
return sb.toString();
}
return NumberFormat.getInstance().format(diskSize) + " bytes";
}
public enum Base64Options {
GZIP,
URL_SAFE,
;
private static int asBase64UtilOptions(final Base64Options... options) {
int b64UtilOptions = 0;
if (JavaHelper.enumArrayContainsValue(options, Base64Options.GZIP)) {
b64UtilOptions = b64UtilOptions | Base64.GZIP;
}
if (JavaHelper.enumArrayContainsValue(options, Base64Options.URL_SAFE)) {
b64UtilOptions = b64UtilOptions | Base64.URL_SAFE;
}
return b64UtilOptions;
}
}
public static String escapeJS(final String input) {
return StringEscapeUtils.escapeEcmaScript(input);
}
public static String escapeHtml(final String input)
{
return StringEscapeUtils.escapeHtml4(input);
}
public static String escapeCsv(final String input)
{
return StringEscapeUtils.escapeCsv(input);
}
public static String escapeJava(final String input)
{
return StringEscapeUtils.escapeJava(input);
}
public static String escapeXml(final String input)
{
return StringEscapeUtils.escapeXml11(input);
}
public static String urlEncode(final String input) {
try {
return URLEncoder.encode(input, PwmConstants.DEFAULT_CHARSET.toString());
} catch (UnsupportedEncodingException e) {
LOGGER.error("unexpected error during url encoding: " + e.getMessage());
return input;
}
}
public static String urlDecode(final String input) {
try {
return URLDecoder.decode(input, PwmConstants.DEFAULT_CHARSET.toString());
} catch (UnsupportedEncodingException e) {
LOGGER.error("unexpected error during url decoding: " + e.getMessage());
return input;
}
}
public static byte[] base64Decode(final String input)
throws IOException
{
return Base64.decode(input);
}
public static String base32Encode(final byte[] input)
throws IOException
{
final Base32 base32 = new Base32();
return new String(base32.encode(input));
}
public static byte[] base64Decode(final String input, final StringUtil.Base64Options... options)
throws IOException
{
final int b64UtilOptions = Base64Options.asBase64UtilOptions(options);
return Base64.decode(input, b64UtilOptions);
}
public static String base64Encode(final byte[] input)
{
return Base64.encodeBytes(input);
}
public static String base64Encode(final byte[] input, final StringUtil.Base64Options... options)
throws IOException
{
final int b64UtilOptions = Base64Options.asBase64UtilOptions(options);
if (b64UtilOptions > 0) {
return Base64.encodeBytes(input, b64UtilOptions);
} else {
return Base64.encodeBytes(input);
}
}
public static String padEndToLength(final String input, final int length, final char appendChar) {
if (input == null) {
return null;
}
if (input.length() >= length) {
return input;
}
final StringBuilder sb = new StringBuilder(input);
while (sb.length() < length) {
sb.append(appendChar);
}
return sb.toString();
}
public static Collection<String> whitespaceSplit(final String input) {
if (input == null) {
return Collections.emptyList();
}
final String[] splitValues = input.trim().split("\\s+");
return Arrays.asList(splitValues);
}
public static String[] createStringChunks(final String str, final int size) {
if (size <= 0 || str == null || str.length() <= size) {
return new String[] { str };
}
final int numOfChunks = str.length() - size + 1;
final Set<String> chunks = new HashSet<>(numOfChunks);
for (int i=0; i<numOfChunks; i++) {
chunks.add(StringUtils.substring(str, i, i+size));
}
return chunks.toArray(new String[numOfChunks]);
}
public static String collectionToString(final Collection collection, final String recordSeparator) {
final StringBuilder sb = new StringBuilder();
if (collection != null) {
for (final Iterator iterator = collection.iterator(); iterator.hasNext(); ) {
final Object obj = iterator.next();
if (obj != null) {
sb.append(obj.toString());
if (iterator.hasNext()) {
sb.append(recordSeparator);
}
}
}
}
return sb.toString();
}
public static String mapToString(final Map map) {
return mapToString(map, "=", ",");
}
public static String mapToString(final Map map, final String keyValueSeparator, final String recordSeparator) {
final StringBuilder sb = new StringBuilder();
for (final Iterator iterator = map.keySet().iterator(); iterator.hasNext(); ) {
final String key = iterator.next().toString();
final String value = map.get(key) == null ? "" : map.get(key).toString();
if (key != null && value != null && !key.trim().isEmpty() && !value.trim().isEmpty()) {
sb.append(key.trim());
sb.append(keyValueSeparator);
sb.append(value.trim());
if (iterator.hasNext()) {
sb.append(recordSeparator);
}
}
}
return sb.toString();
}
public static int[] toCodePointArray(final String str) {
if (str != null) {
final int len = str.length();
final int[] acp = new int[str.codePointCount(0, len)];
for (int i = 0, j = 0; i < len; i = str.offsetByCodePoints(i, 1)) {
acp[j++] = str.codePointAt(i);
}
return acp;
}
return new int[0];
}
public static boolean isEmpty(final CharSequence input) {
return StringUtils.isEmpty(input);
}
public static String defaultString(final String input, final String defaultStr) {
return StringUtils.defaultString(input, defaultStr);
}
public static boolean equals(final String input1, final String input2) {
return StringUtils.equals(input1, input2);
}
}