Denial of service:regular expression : fortify pointed out a issue - java

Hi i am getting denial of service:regular expressioon warning on the below line
billingApplicationAcctId = billingApplicationAcctId.replaceAll("\" + s, "");
you can see below code for further reference
if (null != formatBillingAcctIdInd && formatBillingAcctIdInd.equals("Y")
&& billingApplicationCode.equalsIgnoreCase(EPWFReferenceDataConstants.BILLING_APPICATION_ID.KENAN.name())) {
Pattern pt = Pattern.compile("[^a-zA-Z0-9]");
Matcher match = pt.matcher(payment.getBillingApplicationAccntId());
while (match.find()) {
String s = match.group();
billingApplicationAcctId = billingApplicationAcctId.replaceAll("\\" + s, "");
}
}
what should i do instead of above code , so i will not get fortify DOS warning

If you want to go away from your regex code, you can compare the input character-wise. Just replace
Pattern pt = Pattern.compile("[^a-zA-Z0-9]");
Matcher match = pt.matcher(payment.getBillingApplicationAccntId());
while (match.find()) {
String s = match.group();
billingApplicationAcctId = billingApplicationAcctId.replaceAll("\\" + s, "");
}
with:
String rawInput = payment.getBillingApplicationAccntId();
StringBuilder sb = new StringBuilder();
for (char c : rawInput.toCharArray()) {
// any char that is an english letter or 0-9 is included. The rest is thrown away...
if ((c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')) {
sb.append(c);
}
}
billingApplicationAcctId = sb.toString();

Related

Why does Java function return 1 when given ""

I am new to Java. The purpose of the function is to get a word's vowel count. But when given "" as input it returns 1 instead of 0.
Please explain like i am five why this is happening.
public static int getCount(String str) {
String vowels = "aeiou";
int answer = 0;
String strArray[] = str.split("");
for(String chr : strArray) {
if ((vowels.contains(chr)) & (chr != "")) {
answer += 1;
}
}
return answer;
}
I fixed the code by adding if ((vowels.contains(chr)) & (chr != ""))
But this feels ugly
"".split("") returns {""}. If you want to go over the characters, use one of these:
for (char c : str.toCharArray()) {
if (vowels.indexOf(c) != -1) { ... }
}
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (vowels.indexOf(c) != -1) { ... }
}
I prefer the second, it doesn't create a copy of the string.

Android Matcher.replaceAll/replaceFirst problem with groups count > 9

I've found some problem with Matcher.replaceFirst/replaceAll when subgroup count in regex is more than 9...
simple example:
String res = "abcdefghij".replaceFirst("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)", "$1 $2 $3 $4 $5 $6 $7 $8 $9 $10");
Expected result is "a b c d e f g h i j" but got "a b c d e f g h i a0" string.
This problem can reproduced in Android runtime, but on local unit tests with desktop java it works well.
When I tried to debug it step by step, I've found following ugly code in Android sources of Matcher class:
private void appendEvaluated(StringBuffer buffer, String s) {
boolean escape = false;
boolean dollar = false;
boolean escapeNamedGroup = false;
int escapeNamedGroupStart = -1;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '\\' && !escape) {
escape = true;
} else if (c == '$' && !escape) {
dollar = true;
} else if (c >= '0' && c <= '9' && dollar) { //<<<<------ WHAT IS IT?!
buffer.append(group(c - '0'));
dollar = false;
} else if (c == '{' && dollar) {
escapeNamedGroup = true;
escapeNamedGroupStart = i;
} else if (c == '}' && dollar && escapeNamedGroup) {
String namedGroupName =
s.substring(escapeNamedGroupStart + 1, i);
buffer.append(group(namedGroupName));
dollar = false;
escapeNamedGroup = false;
} else if (c != '}' && dollar && escapeNamedGroup) {
continue;
} else {
buffer.append(c);
dollar = false;
escape = false;
escapeNamedGroup = false;
}
}
if (escape) {
throw new IllegalArgumentException("character to be escaped is missing");
}
if (dollar) {
throw new IllegalArgumentException("Illegal group reference: group index is missing");
}
if (escapeNamedGroup) {
throw new IllegalArgumentException("Missing ending brace '}' from replacement string");
}
}
this is part of SDK API 29... I've checked API 30 level, it has same code.
maybe someone already solve this problem?
I think it needs to create custom replacer with more correct logic...

Splitting String by comma and ignore comma in multiple double quotes

I have a String like
value 1, value 2, " value 3," value 4, value 5 " ", value 6
I want to split this by comma and ignoring commas found in an expression enclosed by multiple double quotes
My desired output should be
value 1
value 2
" value 3," value 4, value 5 " "
value 6
I tried this Splitting on comma outside quotes but it doesn't work
Thanks in advance........Elsayed
Well first I would recommend to escape inner double quotes, e. g. value 1, value 2, " value 3,\" value 4, value 5 \" ", value 6. With this sort of syntax a method I use for this purpose is below. It is a little bit more complex than the first proposal, because it ignores blanks and line breaks between a comma and the next element in the list.
public static String[] splitSet(String inStr, char delimiter) {
if (inStr == null)
return null;
if (inStr.isEmpty())
return new String[]{};
/*
* add an empty element here and remove it at the end to simplify
* algorithm
*/
String delimiterStr = String.valueOf(delimiter);
String parseStr = inStr + delimiterStr + " ";
/*
* prepare parsing.
*/
Vector<String> list = new Vector<>();
String element = "";
int lc = 0;
char b = ' ';
char c;
boolean inBetweenQuotes = false;
/*
* parsing loop.
*/
while (lc < parseStr.length()) {
c = parseStr.charAt(lc);
/*
* add current entry and all following empty entries to list vector.
* Ignore space and new line characters following the delimiter.
*/
if ((c == delimiter) && !inBetweenQuotes) {
// flag to avoid adding empty elements for delimiter being blank
// or new line
boolean added = false;
while ((lc < parseStr.length())
&& ((c == delimiter) || (c == ' ') || (c == '\n'))) {
if ((c == delimiter)
&& !(added && ((c == ' ') || (c == '\n')))) {
list.add((String) UFormatter.parseElement(element,
DataType.STRING, delimiterStr));
element = "";
added = true;
}
lc++;
if (lc < parseStr.length())
c = parseStr.charAt(lc);
if (lc > 0)
b = parseStr.charAt(lc - 1);
}
}
/*
* add character to tmpList. Close String literal or Vector literal
*/
else {
element = element + c;
// toggle inBetweenQuotes at not escaped '"'
if ((c == '"') && (b != '\\'))
inBetweenQuotes = !inBetweenQuotes;
lc++;
b = c;
}
}
if (!element.isEmpty() && inBetweenQuotes)
list.add(element.substring(0, element.length() - 1) + "\"");
else if (!element.isEmpty())
list.add(element.substring(0, element.length() - 1));
// put Vector to array.
String[] ret = new String[list.size()];
for (int i = 0; i < list.size(); i++)
ret[i] = list.elementAt(i);
return ret;
}
I don't know how to use regex to solve it.
Is the double quotes included now? I haven't tried this code yet.
public static List<String> splitByComma(String text) {
ArrayList<String> ret = new ArrayList<>();
char[] chars = text.toCharArray();
boolean inQuote = false;
StringBuilder tmp = new StringBuilder();
for (char ch : chars) {
if (ch == ',') {
if (inQuote) tmp.append(ch);
else {
ret.add(tmp.toString());
tmp.setLength(0);
}
} else if (ch == '"') {
tmp.append(ch); // I just add this code
inQuote = !inQuote;
} else tmp.append(ch);
}
ret.add(tmp.toString());
return ret;
}
Please tell me if my code has any problem.

TitleCaps program will not translate first character in a String correctly (why?)

See if you guys can solve this. I wrote a title caps program in Java, that is a program which can take a string of ASCII characters and make all words (substrings made up of only letters A-Z or a-z) into title case. So the string "##hello!_world$" becomes "##Hello!_World$". But this program refuses to correctly translate non letters at the first indice of the string despite my best efforts to correct it.
public static String LetterCapitalize(String str) {
String newStr = "";
System.out.println(newStr);
for (int i = 0; i < str.length(); i++) {
// if first character is a letter and not uppercase
if (i == 0 && (!isUpperCase(str.charAt(i)))) {
Character m = (char) ((int) str.charAt(i) - 32);
newStr = newStr + m;
} // if first character is a letter and uppercase
else if (i == 0 && (isUpperCase(str.charAt(i)))) {
Character m = str.charAt(i);
newStr = newStr + m;
} // if first character is not a letter
else if (i == 0 && (!isLetter(str.charAt(i)))) {
Character m = str.charAt(i);
newStr = newStr + m + m;
} // if character is first letter in a word
else if (!isLetter(str.charAt(i - 1)) && isLetter(str.charAt(i)) && !isUpperCase(str.charAt(i))) {
Character m = (char) ((int) str.charAt(i) - 32);
newStr = newStr + m;
} // all other
else {
Character m = str.charAt(i);
newStr = newStr + m;
}
}
return newStr;
}
public static boolean isUpperCase(char c) {
boolean isCap;
if (c >= 'A' && c <= 'Z') {
isCap = true;
} else {
isCap = false;
}
return isCap;
}
public static boolean isLetter(char c) {
boolean isLetter;
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
isLetter = true;
} else {
isLetter = false;
}
return isLetter;
}
this line is wrong: if (i == 0 && (!isUpperCase(str.charAt(i)))) { - it assumes it's a lowercase letter. You need to see if it's a lowercase letter. Not all characters that aren't uppercase are letters. So you should have some thing like
if (i==0 && isLetter() && !isUpperCase())
The other way to do it is have the check for it being a letter come first.

How to use PropertyResourceBundle with keys containing whitespaces

I want to use properties files through PropertyResourceBundle for i18n. My current issue is that keys on the files I have can include white spaces, e.g. :
key number 1 = value number 1
key2 = value2
So, when I load the corresponding property file the first white space is used as the key-value delimiter instead of the '=' sign.
Then, my questions are: how can I use a key with white spaces in it without modifying the properties file (I'd like to avoid adding any slash or unicode character code)? Is there any way to override the default properties file delimiter so I can set '=' as the only one to be considered?
you will have to write your own Properties class, the one in the jdk considers white space as a separator, here is it's code. you'll find out that as soon as it encounter a white space it stop the key & start the value.
private void load0 (LineReader lr) throws IOException {
char[] convtBuf = new char[1024];
int limit;
int keyLen;
int valueStart;
char c;
boolean hasSep;
boolean precedingBackslash;
while ((limit = lr.readLine()) >= 0) {
c = 0;
keyLen = 0;
valueStart = limit;
hasSep = false;
//System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
precedingBackslash = false;
while (keyLen < limit) {
c = lr.lineBuf[keyLen];
//need check if escaped.
if ((c == '=' || c == ':') && !precedingBackslash) {
valueStart = keyLen + 1;
hasSep = true;
break;
} else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) {
valueStart = keyLen + 1;
break;
}
if (c == '\\') {
precedingBackslash = !precedingBackslash;
} else {
precedingBackslash = false;
}
keyLen++;
}
while (valueStart < limit) {
c = lr.lineBuf[valueStart];
if (c != ' ' && c != '\t' && c != '\f') {
if (!hasSep && (c == '=' || c == ':')) {
hasSep = true;
} else {
break;
}
}
valueStart++;
}
String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
put(key, value);
}
}

Categories

Resources