Skip to content

Commit 1e4134c

Browse files
Number fxes (#898)
* init * user and pass to just pass lang update * session management fixes and avoid demo user locking * fix for UMASK and extract cleanups * fixes for user #889 and #332 * increase session count for demo site * fix * gcc * formatting * number fixes init * || true test * version bump * Hardening suggestions for Stirling-PDF / numberFxes (#899) Switch order of literals to prevent NullPointerException Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com> --------- Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>
1 parent a7bcdd0 commit 1e4134c

File tree

10 files changed

+227
-93
lines changed

10 files changed

+227
-93
lines changed

build.gradle

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ plugins {
1212
import com.github.jk1.license.render.*
1313

1414
group = 'stirling.software'
15-
version = '0.22.1'
15+
16+
version = '0.22.2'
1617
sourceCompatibility = '17'
1718

1819
repositories {
@@ -158,6 +159,8 @@ dependencies {
158159
// https://mvnrepository.com/artifact/com.github.vladimir-bukhtoyarov/bucket4j-core
159160
implementation 'com.github.vladimir-bukhtoyarov:bucket4j-core:7.6.0'
160161

162+
implementation 'com.fathzer:javaluator:3.0.3'
163+
161164
developmentOnly("org.springframework.boot:spring-boot-devtools:3.2.2")
162165
compileOnly 'org.projectlombok:lombok:1.18.30'
163166
annotationProcessor 'org.projectlombok:lombok:1.18.28'

scripts/download-security-jar.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ if [ "$DOCKER_ENABLE_SECURITY" = "true" ] && [ "$VERSION_TAG" != "alpha" ]; then
1414
if [ $? -eq 0 ]; then # checks if curl was successful
1515
rm -f app.jar
1616
ln -s app-security.jar app.jar
17-
chown stirlingpdfuser:stirlingpdfgroup app.jar
18-
chmod 755 app.jar
17+
chown stirlingpdfuser:stirlingpdfgroup app.jar || true
18+
chmod 755 app.jar || true
1919
fi
2020
fi
2121
fi

scripts/init-without-ocr.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22

33
# Update the user and group IDs as per environment variables
44
if [ ! -z "$PUID" ] && [ "$PUID" != "$(id -u stirlingpdfuser)" ]; then
5-
usermod -o -u "$PUID" stirlingpdfuser
5+
usermod -o -u "$PUID" stirlingpdfuser || true
66
fi
77

88
if [ ! -z "$PGID" ] && [ "$PGID" != "$(getent group stirlingpdfgroup | cut -d: -f3)" ]; then
9-
groupmod -o -g "$PGID" stirlingpdfgroup
9+
groupmod -o -g "$PGID" stirlingpdfgroup || true
1010
fi
11-
umask "$UMASK"
11+
umask "$UMASK" || true
1212

1313
echo "Setting permissions and ownership for necessary directories..."
14-
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar
15-
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar
14+
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true
15+
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true
1616
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" ]]; then
1717
apk add --no-cache calibre@testing
1818
fi

scripts/init.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,18 @@ fi
1515

1616
# Update the user and group IDs as per environment variables
1717
if [ ! -z "$PUID" ] && [ "$PUID" != "$(id -u stirlingpdfuser)" ]; then
18-
usermod -o -u "$PUID" stirlingpdfuser
18+
usermod -o -u "$PUID" stirlingpdfuser || true
1919
fi
2020

2121

2222
if [ ! -z "$PGID" ] && [ "$PGID" != "$(getent group stirlingpdfgroup | cut -d: -f3)" ]; then
23-
groupmod -o -g "$PGID" stirlingpdfgroup
23+
groupmod -o -g "$PGID" stirlingpdfgroup || true
2424
fi
25-
umask "$UMASK"
25+
umask "$UMASK" || true
2626

2727
echo "Setting permissions and ownership for necessary directories..."
28-
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar
29-
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar
28+
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true
29+
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true
3030

3131

3232

src/main/java/stirling/software/SPDF/controller/api/RearrangePagesPDFController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public ResponseEntity<byte[]> deletePages(@ModelAttribute PDFWithPageNums reques
5151
String[] pageOrderArr = pagesToDelete.split(",");
5252

5353
List<Integer> pagesToRemove =
54-
GeneralUtils.parsePageList(pageOrderArr, document.getNumberOfPages(), true);
54+
GeneralUtils.parsePageList(pageOrderArr, document.getNumberOfPages(), false);
5555

5656
Collections.sort(pagesToRemove);
5757

@@ -195,7 +195,7 @@ public ResponseEntity<byte[]> rearrangePages(@ModelAttribute RearrangePagesReque
195195
if (sortType != null && sortType.length() > 0) {
196196
newPageOrder = processSortTypes(sortType, totalPages);
197197
} else {
198-
newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages, true);
198+
newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages, false);
199199
}
200200
logger.info("newPageOrder = " + newPageOrder);
201201
logger.info("totalPages = " + totalPages);

src/main/java/stirling/software/SPDF/controller/api/SplitPDFController.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,14 @@ public ResponseEntity<byte[]> splitPdf(@ModelAttribute PDFWithPageNums request)
4949
// open the pdf document
5050

5151
PDDocument document = Loader.loadPDF(file.getBytes());
52-
53-
List<Integer> pageNumbers = request.getPageNumbersList(document, true);
54-
if (!pageNumbers.contains(document.getNumberOfPages() - 1)) {
52+
int totalPages = document.getNumberOfPages();
53+
List<Integer> pageNumbers = request.getPageNumbersList(document, false);
54+
System.out.println(
55+
pageNumbers.stream().map(String::valueOf).collect(Collectors.joining(",")));
56+
if (!pageNumbers.contains(totalPages - 1)) {
5557
// Create a mutable ArrayList so we can add to it
5658
pageNumbers = new ArrayList<>(pageNumbers);
57-
pageNumbers.add(document.getNumberOfPages() - 1);
59+
pageNumbers.add(totalPages - 1);
5860
}
5961

6062
logger.info(
@@ -69,7 +71,7 @@ public ResponseEntity<byte[]> splitPdf(@ModelAttribute PDFWithPageNums request)
6971
for (int i = previousPageNumber; i <= splitPoint; i++) {
7072
PDPage page = document.getPage(i);
7173
splitDocument.addPage(page);
72-
logger.debug("Adding page {} to split document", i);
74+
logger.info("Adding page {} to split document", i);
7375
}
7476
previousPageNumber = splitPoint + 1;
7577

src/main/java/stirling/software/SPDF/controller/api/misc/StampController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public ResponseEntity<byte[]> addStamp(@ModelAttribute AddStampRequest request)
8888
// Load the input PDF
8989
PDDocument document = Loader.loadPDF(pdfFile.getBytes());
9090

91-
List<Integer> pageNumbers = request.getPageNumbersList(document, false);
91+
List<Integer> pageNumbers = request.getPageNumbersList(document, true);
9292

9393
for (int pageIndex : pageNumbers) {
9494
int zeroBasedIndex = pageIndex - 1;

src/main/java/stirling/software/SPDF/model/api/PDFWithPageNums.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ public List<Integer> getPageNumbersList(boolean zeroCount) {
3333
// TODO Auto-generated catch block
3434
e.printStackTrace();
3535
}
36-
return GeneralUtils.parsePageString(pageNumbers, pageCount, zeroCount);
36+
return GeneralUtils.parsePageList(pageNumbers, pageCount, zeroCount);
3737
}
3838

3939
@Hidden
4040
public List<Integer> getPageNumbersList(PDDocument doc, boolean zeroCount) {
4141
int pageCount = 0;
4242
pageCount = doc.getNumberOfPages();
43-
return GeneralUtils.parsePageString(pageNumbers, pageCount, zeroCount);
43+
return GeneralUtils.parsePageList(pageNumbers, pageCount, zeroCount);
4444
}
4545
}

src/main/java/stirling/software/SPDF/utils/GeneralUtils.java

Lines changed: 94 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
import java.nio.file.SimpleFileVisitor;
1313
import java.nio.file.attribute.BasicFileAttributes;
1414
import java.util.ArrayList;
15-
import java.util.Collections;
1615
import java.util.List;
1716

1817
import org.springframework.web.multipart.MultipartFile;
1918

19+
import com.fathzer.soft.javaluator.DoubleEvaluator;
20+
2021
import io.github.pixee.security.HostValidator;
2122
import io.github.pixee.security.Urls;
2223

@@ -115,91 +116,114 @@ public static Long convertSizeToBytes(String sizeStr) {
115116
return null;
116117
}
117118

118-
public static List<Integer> parsePageString(String pageOrder, int totalPages) {
119-
return parsePageString(pageOrder, totalPages, false);
120-
}
121-
122-
public static List<Integer> parsePageString(
123-
String pageOrder, int totalPages, boolean isOneBased) {
124-
if (pageOrder == null || pageOrder.isEmpty()) {
125-
return Collections.singletonList(1);
119+
public static List<Integer> parsePageList(String pages, int totalPages, boolean oneBased) {
120+
if (pages == null) {
121+
return List.of(1); // Default to first page if input is null
126122
}
127-
if (pageOrder.matches("\\d+")) {
128-
// Convert the single number string to an integer and return it in a list
129-
return Collections.singletonList(Integer.parseInt(pageOrder));
123+
try {
124+
return parsePageList(pages.split(","), totalPages, oneBased);
125+
} catch (NumberFormatException e) {
126+
return List.of(1); // Default to first page if input is invalid
130127
}
131-
return parsePageList(pageOrder.split(","), totalPages, isOneBased);
132128
}
133129

134-
public static List<Integer> parsePageList(String[] pageOrderArr, int totalPages) {
135-
return parsePageList(pageOrderArr, totalPages, false);
130+
public static List<Integer> parsePageList(String[] pages, int totalPages) {
131+
return parsePageList(pages, totalPages, false);
136132
}
137133

138-
public static List<Integer> parsePageList(
139-
String[] pageOrderArr, int totalPages, boolean isOneBased) {
140-
List<Integer> newPageOrder = new ArrayList<>();
141-
142-
int adjustmentFactor = isOneBased ? 1 : 0;
143-
144-
// loop through the page order array
145-
for (String element : pageOrderArr) {
146-
if ("all".equalsIgnoreCase(element)) {
134+
public static List<Integer> parsePageList(String[] pages, int totalPages, boolean oneBased) {
135+
List<Integer> result = new ArrayList<>();
136+
int offset = oneBased ? 1 : 0;
137+
for (String page : pages) {
138+
if ("all".equalsIgnoreCase(page)) {
147139
for (int i = 0; i < totalPages; i++) {
148-
newPageOrder.add(i + adjustmentFactor);
140+
result.add(i + offset);
149141
}
150-
// As all pages are already added, no need to check further
151-
break;
152-
} else if (element.matches("\\d*n\\+?-?\\d*|\\d*\\+?n")) {
153-
// Handle page order as a function
154-
int coefficient = 0;
155-
int constant = 0;
156-
boolean coefficientExists = false;
157-
boolean constantExists = false;
158-
159-
if (element.contains("n")) {
160-
String[] parts = element.split("n");
161-
if (!"".equals(parts[0]) && parts[0] != null) {
162-
coefficient = Integer.parseInt(parts[0]);
163-
coefficientExists = true;
164-
}
165-
if (parts.length > 1 && !"".equals(parts[1]) && parts[1] != null) {
166-
constant = Integer.parseInt(parts[1]);
167-
constantExists = true;
168-
}
169-
} else if (element.contains("+")) {
170-
constant = Integer.parseInt(element.replace("+", ""));
171-
constantExists = true;
142+
} else if (page.contains(",")) {
143+
// Split the string into parts, could be single pages or ranges
144+
String[] parts = page.split(",");
145+
for (String part : parts) {
146+
result.addAll(handlePart(part, totalPages, offset));
172147
}
148+
} else {
149+
result.addAll(handlePart(page, totalPages, offset));
150+
}
151+
}
152+
return new ArrayList<>(
153+
new java.util.LinkedHashSet<>(result)); // Remove duplicates and maintain order
154+
}
155+
156+
public static List<Integer> evaluateNFunc(String expression, int maxValue) {
157+
List<Integer> results = new ArrayList<>();
158+
DoubleEvaluator evaluator = new DoubleEvaluator();
159+
160+
// Validate the expression
161+
if (!expression.matches("[0-9n+\\-*/() ]+")) {
162+
throw new IllegalArgumentException("Invalid expression");
163+
}
173164

174-
for (int i = 1; i <= totalPages; i++) {
175-
int pageNum = coefficientExists ? coefficient * i : i;
176-
pageNum += constantExists ? constant : 0;
165+
int n = 0;
166+
while (true) {
167+
// Replace 'n' with the current value of n, correctly handling numbers before 'n'
168+
String sanitizedExpression = insertMultiplicationBeforeN(expression, n);
169+
Double result = evaluator.evaluate(sanitizedExpression);
177170

178-
if (pageNum <= totalPages && pageNum > 0) {
179-
newPageOrder.add(pageNum - adjustmentFactor);
171+
// Check if the result is null or not within bounds
172+
if (result == null || result <= 0 || result.intValue() > maxValue) {
173+
if (n != 0) break;
174+
} else {
175+
results.add(result.intValue());
176+
}
177+
n++;
178+
}
179+
180+
return results;
181+
}
182+
183+
private static String insertMultiplicationBeforeN(String expression, int nValue) {
184+
// Insert multiplication between a number and 'n' (e.g., "4n" becomes "4*n")
185+
String withMultiplication = expression.replaceAll("(\\d)n", "$1*n");
186+
// Now replace 'n' with its current value
187+
return withMultiplication.replaceAll("n", String.valueOf(nValue));
188+
}
189+
190+
private static List<Integer> handlePart(String part, int totalPages, int offset) {
191+
List<Integer> partResult = new ArrayList<>();
192+
193+
// First check for n-syntax because it should not be processed as a range
194+
if (part.contains("n")) {
195+
partResult = evaluateNFunc(part, totalPages);
196+
// Adjust the results according to the offset
197+
for (int i = 0; i < partResult.size(); i++) {
198+
int adjustedValue = partResult.get(i) - 1 + offset;
199+
partResult.set(i, adjustedValue);
200+
}
201+
} else if (part.contains("-")) {
202+
// Process ranges only if it's not n-syntax
203+
String[] rangeParts = part.split("-");
204+
try {
205+
int start = Integer.parseInt(rangeParts[0]);
206+
int end = Integer.parseInt(rangeParts[1]);
207+
for (int i = start; i <= end; i++) {
208+
if (i >= 1 && i <= totalPages) {
209+
partResult.add(i - 1 + offset);
180210
}
181211
}
182-
} else if (element.contains("-")) {
183-
// split the range into start and end page
184-
String[] range = element.split("-");
185-
int start = Integer.parseInt(range[0]);
186-
int end = Integer.parseInt(range[1]);
187-
// check if the end page is greater than total pages
188-
if (end > totalPages) {
189-
end = totalPages;
190-
}
191-
// loop through the range of pages
192-
for (int j = start; j <= end; j++) {
193-
// print the current index
194-
newPageOrder.add(j - adjustmentFactor);
212+
} catch (NumberFormatException e) {
213+
// Range is invalid, ignore this part
214+
}
215+
} else {
216+
// This is a single page number
217+
try {
218+
int pageNum = Integer.parseInt(part.trim());
219+
if (pageNum >= 1 && pageNum <= totalPages) {
220+
partResult.add(pageNum - 1 + offset);
195221
}
196-
} else {
197-
// if the element is a single page
198-
newPageOrder.add(Integer.parseInt(element) - adjustmentFactor);
222+
} catch (NumberFormatException ignored) {
223+
// Ignore invalid numbers
199224
}
200225
}
201-
202-
return newPageOrder;
226+
return partResult;
203227
}
204228

205229
public static boolean createDir(String path) {

0 commit comments

Comments
 (0)