Skip to content

Commit

Permalink
Number fxes (#898)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
Frooodle and pixeebot[bot] committed Mar 10, 2024
1 parent a7bcdd0 commit 1e4134c
Show file tree
Hide file tree
Showing 10 changed files with 227 additions and 93 deletions.
5 changes: 4 additions & 1 deletion build.gradle
Expand Up @@ -12,7 +12,8 @@ plugins {
import com.github.jk1.license.render.*

group = 'stirling.software'
version = '0.22.1'

version = '0.22.2'
sourceCompatibility = '17'

repositories {
Expand Down Expand Up @@ -158,6 +159,8 @@ dependencies {
// https://mvnrepository.com/artifact/com.github.vladimir-bukhtoyarov/bucket4j-core
implementation 'com.github.vladimir-bukhtoyarov:bucket4j-core:7.6.0'

implementation 'com.fathzer:javaluator:3.0.3'

developmentOnly("org.springframework.boot:spring-boot-devtools:3.2.2")
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.28'
Expand Down
4 changes: 2 additions & 2 deletions scripts/download-security-jar.sh
Expand Up @@ -14,8 +14,8 @@ if [ "$DOCKER_ENABLE_SECURITY" = "true" ] && [ "$VERSION_TAG" != "alpha" ]; then
if [ $? -eq 0 ]; then # checks if curl was successful
rm -f app.jar
ln -s app-security.jar app.jar
chown stirlingpdfuser:stirlingpdfgroup app.jar
chmod 755 app.jar
chown stirlingpdfuser:stirlingpdfgroup app.jar || true
chmod 755 app.jar || true
fi
fi
fi
10 changes: 5 additions & 5 deletions scripts/init-without-ocr.sh
Expand Up @@ -2,17 +2,17 @@

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

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

echo "Setting permissions and ownership for necessary directories..."
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" ]]; then
apk add --no-cache calibre@testing
fi
Expand Down
10 changes: 5 additions & 5 deletions scripts/init.sh
Expand Up @@ -15,18 +15,18 @@ fi

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


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

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



Expand Down
Expand Up @@ -51,7 +51,7 @@ public ResponseEntity<byte[]> deletePages(@ModelAttribute PDFWithPageNums reques
String[] pageOrderArr = pagesToDelete.split(",");

List<Integer> pagesToRemove =
GeneralUtils.parsePageList(pageOrderArr, document.getNumberOfPages(), true);
GeneralUtils.parsePageList(pageOrderArr, document.getNumberOfPages(), false);

Collections.sort(pagesToRemove);

Expand Down Expand Up @@ -195,7 +195,7 @@ public ResponseEntity<byte[]> rearrangePages(@ModelAttribute RearrangePagesReque
if (sortType != null && sortType.length() > 0) {
newPageOrder = processSortTypes(sortType, totalPages);
} else {
newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages, true);
newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages, false);
}
logger.info("newPageOrder = " + newPageOrder);
logger.info("totalPages = " + totalPages);
Expand Down
Expand Up @@ -49,12 +49,14 @@ public ResponseEntity<byte[]> splitPdf(@ModelAttribute PDFWithPageNums request)
// open the pdf document

PDDocument document = Loader.loadPDF(file.getBytes());

List<Integer> pageNumbers = request.getPageNumbersList(document, true);
if (!pageNumbers.contains(document.getNumberOfPages() - 1)) {
int totalPages = document.getNumberOfPages();
List<Integer> pageNumbers = request.getPageNumbersList(document, false);
System.out.println(
pageNumbers.stream().map(String::valueOf).collect(Collectors.joining(",")));
if (!pageNumbers.contains(totalPages - 1)) {
// Create a mutable ArrayList so we can add to it
pageNumbers = new ArrayList<>(pageNumbers);
pageNumbers.add(document.getNumberOfPages() - 1);
pageNumbers.add(totalPages - 1);
}

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

Expand Down
Expand Up @@ -88,7 +88,7 @@ public ResponseEntity<byte[]> addStamp(@ModelAttribute AddStampRequest request)
// Load the input PDF
PDDocument document = Loader.loadPDF(pdfFile.getBytes());

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

for (int pageIndex : pageNumbers) {
int zeroBasedIndex = pageIndex - 1;
Expand Down
Expand Up @@ -33,13 +33,13 @@ public List<Integer> getPageNumbersList(boolean zeroCount) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return GeneralUtils.parsePageString(pageNumbers, pageCount, zeroCount);
return GeneralUtils.parsePageList(pageNumbers, pageCount, zeroCount);
}

@Hidden
public List<Integer> getPageNumbersList(PDDocument doc, boolean zeroCount) {
int pageCount = 0;
pageCount = doc.getNumberOfPages();
return GeneralUtils.parsePageString(pageNumbers, pageCount, zeroCount);
return GeneralUtils.parsePageList(pageNumbers, pageCount, zeroCount);
}
}
164 changes: 94 additions & 70 deletions src/main/java/stirling/software/SPDF/utils/GeneralUtils.java
Expand Up @@ -12,11 +12,12 @@
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.web.multipart.MultipartFile;

import com.fathzer.soft.javaluator.DoubleEvaluator;

import io.github.pixee.security.HostValidator;
import io.github.pixee.security.Urls;

Expand Down Expand Up @@ -115,91 +116,114 @@ public static Long convertSizeToBytes(String sizeStr) {
return null;
}

public static List<Integer> parsePageString(String pageOrder, int totalPages) {
return parsePageString(pageOrder, totalPages, false);
}

public static List<Integer> parsePageString(
String pageOrder, int totalPages, boolean isOneBased) {
if (pageOrder == null || pageOrder.isEmpty()) {
return Collections.singletonList(1);
public static List<Integer> parsePageList(String pages, int totalPages, boolean oneBased) {
if (pages == null) {
return List.of(1); // Default to first page if input is null
}
if (pageOrder.matches("\\d+")) {
// Convert the single number string to an integer and return it in a list
return Collections.singletonList(Integer.parseInt(pageOrder));
try {
return parsePageList(pages.split(","), totalPages, oneBased);
} catch (NumberFormatException e) {
return List.of(1); // Default to first page if input is invalid
}
return parsePageList(pageOrder.split(","), totalPages, isOneBased);
}

public static List<Integer> parsePageList(String[] pageOrderArr, int totalPages) {
return parsePageList(pageOrderArr, totalPages, false);
public static List<Integer> parsePageList(String[] pages, int totalPages) {
return parsePageList(pages, totalPages, false);
}

public static List<Integer> parsePageList(
String[] pageOrderArr, int totalPages, boolean isOneBased) {
List<Integer> newPageOrder = new ArrayList<>();

int adjustmentFactor = isOneBased ? 1 : 0;

// loop through the page order array
for (String element : pageOrderArr) {
if ("all".equalsIgnoreCase(element)) {
public static List<Integer> parsePageList(String[] pages, int totalPages, boolean oneBased) {
List<Integer> result = new ArrayList<>();
int offset = oneBased ? 1 : 0;
for (String page : pages) {
if ("all".equalsIgnoreCase(page)) {
for (int i = 0; i < totalPages; i++) {
newPageOrder.add(i + adjustmentFactor);
result.add(i + offset);
}
// As all pages are already added, no need to check further
break;
} else if (element.matches("\\d*n\\+?-?\\d*|\\d*\\+?n")) {
// Handle page order as a function
int coefficient = 0;
int constant = 0;
boolean coefficientExists = false;
boolean constantExists = false;

if (element.contains("n")) {
String[] parts = element.split("n");
if (!"".equals(parts[0]) && parts[0] != null) {
coefficient = Integer.parseInt(parts[0]);
coefficientExists = true;
}
if (parts.length > 1 && !"".equals(parts[1]) && parts[1] != null) {
constant = Integer.parseInt(parts[1]);
constantExists = true;
}
} else if (element.contains("+")) {
constant = Integer.parseInt(element.replace("+", ""));
constantExists = true;
} else if (page.contains(",")) {
// Split the string into parts, could be single pages or ranges
String[] parts = page.split(",");
for (String part : parts) {
result.addAll(handlePart(part, totalPages, offset));
}
} else {
result.addAll(handlePart(page, totalPages, offset));
}
}
return new ArrayList<>(
new java.util.LinkedHashSet<>(result)); // Remove duplicates and maintain order
}

public static List<Integer> evaluateNFunc(String expression, int maxValue) {
List<Integer> results = new ArrayList<>();
DoubleEvaluator evaluator = new DoubleEvaluator();

// Validate the expression
if (!expression.matches("[0-9n+\\-*/() ]+")) {
throw new IllegalArgumentException("Invalid expression");
}

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

if (pageNum <= totalPages && pageNum > 0) {
newPageOrder.add(pageNum - adjustmentFactor);
// Check if the result is null or not within bounds
if (result == null || result <= 0 || result.intValue() > maxValue) {
if (n != 0) break;
} else {
results.add(result.intValue());
}
n++;
}

return results;
}

private static String insertMultiplicationBeforeN(String expression, int nValue) {
// Insert multiplication between a number and 'n' (e.g., "4n" becomes "4*n")
String withMultiplication = expression.replaceAll("(\\d)n", "$1*n");
// Now replace 'n' with its current value
return withMultiplication.replaceAll("n", String.valueOf(nValue));
}

private static List<Integer> handlePart(String part, int totalPages, int offset) {
List<Integer> partResult = new ArrayList<>();

// First check for n-syntax because it should not be processed as a range
if (part.contains("n")) {
partResult = evaluateNFunc(part, totalPages);
// Adjust the results according to the offset
for (int i = 0; i < partResult.size(); i++) {
int adjustedValue = partResult.get(i) - 1 + offset;
partResult.set(i, adjustedValue);
}
} else if (part.contains("-")) {
// Process ranges only if it's not n-syntax
String[] rangeParts = part.split("-");
try {
int start = Integer.parseInt(rangeParts[0]);
int end = Integer.parseInt(rangeParts[1]);
for (int i = start; i <= end; i++) {
if (i >= 1 && i <= totalPages) {
partResult.add(i - 1 + offset);
}
}
} else if (element.contains("-")) {
// split the range into start and end page
String[] range = element.split("-");
int start = Integer.parseInt(range[0]);
int end = Integer.parseInt(range[1]);
// check if the end page is greater than total pages
if (end > totalPages) {
end = totalPages;
}
// loop through the range of pages
for (int j = start; j <= end; j++) {
// print the current index
newPageOrder.add(j - adjustmentFactor);
} catch (NumberFormatException e) {
// Range is invalid, ignore this part
}
} else {
// This is a single page number
try {
int pageNum = Integer.parseInt(part.trim());
if (pageNum >= 1 && pageNum <= totalPages) {
partResult.add(pageNum - 1 + offset);
}
} else {
// if the element is a single page
newPageOrder.add(Integer.parseInt(element) - adjustmentFactor);
} catch (NumberFormatException ignored) {
// Ignore invalid numbers
}
}

return newPageOrder;
return partResult;
}

public static boolean createDir(String path) {
Expand Down

0 comments on commit 1e4134c

Please sign in to comment.