Skip to content

Feature2.6.1 #297

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

Merged
merged 4 commits into from
Aug 16, 2025
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
4 changes: 2 additions & 2 deletions .github/workflows/codacy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ on:
branches: [ main, develop, main1, release* ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
branches: [ main, feature/*, bugfix/*, hotfix/* ]
schedule:
- cron: '42 10 * * 3'
- cron: '0 11,23 * * *'

permissions:
contents: read
Expand Down
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
-- release 2.6.1
- enhanced security: replace secpr5121 with secp256r1 for default ECGenParameterSpec
- enhanced security: Use of a cryptographic algorithm with insufficient key size - Throw InvalidAlgorithmParameterException when use of a cryptographic algorithm with insufficient key size to call EncryptorUtil.generateKeyPair()
- enhanced security: fixed polynomial regular expression used on uncontrolled data (FormatterUtil)
- enhanced logging: log detailed information and stack trace health check failure
- enhanced logging: Netty channel handler exception will be logged only when:
1. run with -debug
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/org/summerboot/jexpress/security/EncryptorUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -489,14 +489,27 @@ public static KeyPair generateKeyPair(String keyfactoryAlgorithm, int size) thro
KeyPairGenerator kpg;
switch (keyfactoryAlgorithm.toUpperCase()) {
case "RSA" -> {
if (size < 2048) {
throw new InvalidAlgorithmParameterException("RSA key size must be at least 2048 bits.");
}
kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(size);
}
case "EC" -> {
if (size < 256) {
throw new InvalidAlgorithmParameterException("EC key size must be at least 256 bits.");
}
kpg = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec spec = getECCurveName(size);
kpg.initialize(spec);
}
case "DSA", "DH" -> {
if (size < 2048) {
throw new InvalidAlgorithmParameterException(keyfactoryAlgorithm + " key size must be at least 2048 bits.");
}
kpg = KeyPairGenerator.getInstance(keyfactoryAlgorithm.toUpperCase());
kpg.initialize(size);
}
default -> throw new NoSuchAlgorithmException(keyfactoryAlgorithm);
}

Expand Down
93 changes: 71 additions & 22 deletions src/main/java/org/summerboot/jexpress/util/FormatterUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,29 +73,72 @@
return StringUtils.isBlank(txt) ? EMPTY_STR_ARRAY : txt.split("\\r?\\n");
}

public static String[] parseDsv(String csv, String delimiter) {
if (StringUtils.isBlank(delimiter) || ",".equals(delimiter)) {
return parseCsv(csv);
public static String[] parseDsv(String dsv, String delimiter) {
return parseDsv(dsv, delimiter, true);
}

public static String[] parseDsv(String dsv, String delimiter, boolean trim) {
if (StringUtils.isBlank(dsv)) {
return EMPTY_STR_ARRAY;
}
return StringUtils.isBlank(csv) ? EMPTY_STR_ARRAY : csv.trim().split("\\s*" + delimiter + "\\s*");

if (trim) {
// Replace all consecutive spaces or delimiter characters with a single delimiter character
dsv = dsv.trim().replaceAll("\\s*" + delimiter + "\\s*", delimiter);
}
// Use StringUtils.split, which does not use regular expressions
return StringUtils.split(dsv, delimiter);
}

public static String[] parsePsv(String psv) {
return parsePsv(psv, true);
}

public static String[] parsePsv(String csv) {
return StringUtils.isBlank(csv) ? EMPTY_STR_ARRAY : csv.trim().split(REGEX_PSV);
public static String[] parsePsv(String psv, boolean trim) {
//return StringUtils.isBlank(csv) ? EMPTY_STR_ARRAY : csv.trim().split(REGEX_PSV);
if (StringUtils.isBlank(psv)) {
return EMPTY_STR_ARRAY;
}
if (trim) {
// Replace all consecutive spaces or delimiter characters with a single delimiter character
psv = psv.trim().replaceAll("[\\s|]+", "|");
}
// Use StringUtils.split, which does not use regular expressions
return StringUtils.split(psv, '|');
}

public static String[] parseCsv(String csv) {
return StringUtils.isBlank(csv) ? EMPTY_STR_ARRAY : csv.trim().split(REGEX_CSV);
return parseCsv(csv, true);
}

public static String[] parseCsv(String csv, boolean trim) {
//return StringUtils.isBlank(csv) ? EMPTY_STR_ARRAY : csv.trim().split(REGEX_CSV);
if (StringUtils.isBlank(csv)) {
return EMPTY_STR_ARRAY;
}
//return StringUtils.isBlank(csv) ? EMPTY_STR_ARRAY : StringUtils.split(csv);
if (trim) {
// Replace all consecutive spaces or delimiter characters with a single delimiter character
csv = csv.trim().replaceAll("\\s*,\\s*", ",");

Check failure

Code scanning / CodeQL

Polynomial regular expression used on uncontrolled data High

This
regular expression
that depends on a
user-provided value
may run slow on strings with many repetitions of ' '.
}
// Use StringUtils.split, which does not use regular expressions
return StringUtils.split(csv, ',');
}

public static String[] parseURL(String url) {
return StringUtils.isBlank(url) ? EMPTY_STR_ARRAY : url.trim().split(REGEX_URL);
return parseURL(url, true);
}

public static String[] parseURL(String url, boolean trim) {
return StringUtils.isBlank(url)
? EMPTY_STR_ARRAY
: trim ? url.trim().split(REGEX_URL) : url.split(REGEX_URL);
//return StringUtils.isBlank(url) ? EMPTY_STR_ARRAY : url.trim().split(REGEX_URL);
if (StringUtils.isBlank(url)) {
return EMPTY_STR_ARRAY;
}
if (trim) {
// Replace all consecutive spaces or delimiter characters with a single delimiter character
url = url.trim().replaceAll("\\s*/\\s*", "/");

Check failure

Code scanning / CodeQL

Polynomial regular expression used on uncontrolled data High

This
regular expression
that depends on a
user-provided value
may run slow on strings with many repetitions of ' '.
}
return StringUtils.split(url, '/');
}

public static String parseUrlQueryParam(String url, Map<String, String> queryParam) {
Expand Down Expand Up @@ -239,22 +282,28 @@
* BindAddresses = 192.168.1.10:8445, 127.0.0.1:8446, 0.0.0.0:8447
*/
public static Map<String, Integer> parseBindingAddresss(String bindAddresses) {
//int[] ports = Arrays.stream(portsStr).mapToInt(Integer::parseInt).toArray();
Map<String, Integer> ret = new HashMap<>();
String[] addrs = parseCsv(bindAddresses);
for (String addr : addrs) {
String[] ap = addr.trim().split(REGEX_BINDING_MAP);
ret.put(ap[0], Integer.parseInt(ap[1]));
}
return ret;
Map<String, String> stringMap = parseMap(bindAddresses, true);
Map<String, Integer> integerMap = stringMap.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey, // key remains the same
entry -> Integer.valueOf(entry.getValue()) // convert value to Integer
));
return integerMap;
}

public static Map<String, String> parseMap(String mapCVS) {
//int[] ports = Arrays.stream(portsStr).mapToInt(Integer::parseInt).toArray();
return parseMap(mapCVS, true);
}

public static Map<String, String> parseMap(String mapCVS, boolean trim) {
Map<String, String> ret = new HashMap<>();
String[] mapKeyValues = parseCsv(mapCVS);
String[] mapKeyValues = parseCsv(mapCVS, true);
for (String mapKeyValue : mapKeyValues) {
String[] ap = mapKeyValue.trim().split(REGEX_BINDING_MAP);
//String[] ap = mapKeyValue.trim().split(REGEX_BINDING_MAP);
if (trim) {
mapKeyValue = mapKeyValue.trim().replaceAll("\\s*:\\s*", ":");

Check failure

Code scanning / CodeQL

Polynomial regular expression used on uncontrolled data High

This
regular expression
that depends on a
user-provided value
may run slow on strings with many repetitions of ' '.
}
String[] ap = StringUtils.split(mapKeyValue, ':');
ret.put(ap[0], ap[1]);
}
return ret;
Expand Down