Compare commits
7 Commits
oauth2-red
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c7b83ee87 | ||
|
|
9152e64b9f | ||
|
|
96655f7cac | ||
|
|
8f7153b30a | ||
|
|
366bec602d | ||
|
|
c9c8378fe0 | ||
|
|
7a7338c6de |
23
.github/scripts/check_language_properties.py
vendored
23
.github/scripts/check_language_properties.py
vendored
@@ -164,7 +164,7 @@ def update_missing_keys(reference_file, file_list, branch=""):
|
|||||||
if current_entry["type"] == "entry":
|
if current_entry["type"] == "entry":
|
||||||
if ref_entry_copy["type"] != "entry":
|
if ref_entry_copy["type"] != "entry":
|
||||||
continue
|
continue
|
||||||
if ref_entry_copy["key"] == current_entry["key"]:
|
if ref_entry_copy["key"].lower() == current_entry["key"].lower():
|
||||||
ref_entry_copy["value"] = current_entry["value"]
|
ref_entry_copy["value"] = current_entry["value"]
|
||||||
updated_properties.append(ref_entry_copy)
|
updated_properties.append(ref_entry_copy)
|
||||||
write_json_file(os.path.join(branch, file_path), updated_properties)
|
write_json_file(os.path.join(branch, file_path), updated_properties)
|
||||||
@@ -199,29 +199,30 @@ def check_for_differences(reference_file, file_list, branch, actor):
|
|||||||
base_dir = os.path.abspath(os.path.join(os.getcwd(), "src", "main", "resources"))
|
base_dir = os.path.abspath(os.path.join(os.getcwd(), "src", "main", "resources"))
|
||||||
|
|
||||||
for file_path in file_arr:
|
for file_path in file_arr:
|
||||||
absolute_path = os.path.abspath(file_path)
|
file_normpath = os.path.normpath(file_path)
|
||||||
|
absolute_path = os.path.abspath(file_normpath)
|
||||||
# Verify that file is within the expected directory
|
# Verify that file is within the expected directory
|
||||||
if not absolute_path.startswith(base_dir):
|
if not absolute_path.startswith(base_dir):
|
||||||
raise ValueError(f"Unsafe file found: {file_path}")
|
raise ValueError(f"Unsafe file found: {file_normpath}")
|
||||||
# Verify file size before processing
|
# Verify file size before processing
|
||||||
if os.path.getsize(os.path.join(branch, file_path)) > MAX_FILE_SIZE:
|
if os.path.getsize(os.path.join(branch, file_normpath)) > MAX_FILE_SIZE:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"The file {file_path} is too large and could pose a security risk."
|
f"The file {file_normpath} is too large and could pose a security risk."
|
||||||
)
|
)
|
||||||
|
|
||||||
basename_current_file = os.path.basename(os.path.join(branch, file_path))
|
basename_current_file = os.path.basename(os.path.join(branch, file_normpath))
|
||||||
if (
|
if (
|
||||||
basename_current_file == basename_reference_file
|
basename_current_file == basename_reference_file
|
||||||
or (
|
or (
|
||||||
# only local windows command
|
# only local windows command
|
||||||
not file_path.startswith(
|
not file_normpath.startswith(
|
||||||
os.path.join("", "src", "main", "resources", "messages_")
|
os.path.join("", "src", "main", "resources", "messages_")
|
||||||
)
|
)
|
||||||
and not file_path.startswith(
|
and not file_normpath.startswith(
|
||||||
os.path.join(os.getcwd(), "src", "main", "resources", "messages_")
|
os.path.join(os.getcwd(), "src", "main", "resources", "messages_")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or not file_path.endswith(".properties")
|
or not file_normpath.endswith(".properties")
|
||||||
or not basename_current_file.startswith("messages_")
|
or not basename_current_file.startswith("messages_")
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
@@ -292,13 +293,13 @@ def check_for_differences(reference_file, file_list, branch, actor):
|
|||||||
else:
|
else:
|
||||||
report.append("2. **Test Status:** ✅ **_Passed_**")
|
report.append("2. **Test Status:** ✅ **_Passed_**")
|
||||||
|
|
||||||
if find_duplicate_keys(os.path.join(branch, file_path)):
|
if find_duplicate_keys(os.path.join(branch, file_normpath)):
|
||||||
has_differences = True
|
has_differences = True
|
||||||
output = "\n".join(
|
output = "\n".join(
|
||||||
[
|
[
|
||||||
f" - `{key}`: first at line {first}, duplicate at `line {duplicate}`"
|
f" - `{key}`: first at line {first}, duplicate at `line {duplicate}`"
|
||||||
for key, first, duplicate in find_duplicate_keys(
|
for key, first, duplicate in find_duplicate_keys(
|
||||||
os.path.join(branch, file_path)
|
os.path.join(branch, file_normpath)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -294,8 +294,8 @@ configurations.all {
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
//tmp for security bumps
|
//tmp for security bumps
|
||||||
implementation 'ch.qos.logback:logback-core:1.5.16'
|
implementation 'ch.qos.logback:logback-core:1.5.17'
|
||||||
implementation 'ch.qos.logback:logback-classic:1.5.16'
|
implementation 'ch.qos.logback:logback-classic:1.5.17'
|
||||||
|
|
||||||
|
|
||||||
// Exclude vulnerable BouncyCastle version used in tableau
|
// Exclude vulnerable BouncyCastle version used in tableau
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ public class SecurityConfiguration {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.info("SAML 2 login is not enabled. Using default.");
|
log.debug("SAML 2 login is not enabled. Using default.");
|
||||||
http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
|
http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
|
||||||
}
|
}
|
||||||
return http.build();
|
return http.build();
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ public class OAuth2Configuration {
|
|||||||
.scope(oidcProvider.getScopes())
|
.scope(oidcProvider.getScopes())
|
||||||
.userNameAttributeName(oidcProvider.getUseAsUsername().getName())
|
.userNameAttributeName(oidcProvider.getUseAsUsername().getName())
|
||||||
.clientName(clientName)
|
.clientName(clientName)
|
||||||
.redirectUri(REDIRECT_URI_PATH + name)
|
.redirectUri(REDIRECT_URI_PATH + "oidc")
|
||||||
.authorizationGrantType(AUTHORIZATION_CODE)
|
.authorizationGrantType(AUTHORIZATION_CODE)
|
||||||
.build())
|
.build())
|
||||||
: Optional.empty();
|
: Optional.empty();
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ public class FileToPdf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// search for the main HTML file.
|
// Search for the main HTML file.
|
||||||
try (Stream<Path> walk = Files.walk(tempDirectory)) {
|
try (Stream<Path> walk = Files.walk(tempDirectory)) {
|
||||||
List<Path> htmlFiles =
|
List<Path> htmlFiles =
|
||||||
walk.filter(file -> file.toString().endsWith(".html"))
|
walk.filter(file -> file.toString().endsWith(".html"))
|
||||||
@@ -190,46 +190,20 @@ public class FileToPdf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] convertBookTypeToPdf(byte[] bytes, String originalFilename)
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
if (originalFilename == null || originalFilename.lastIndexOf('.') == -1) {
|
|
||||||
throw new IllegalArgumentException("Invalid original filename.");
|
|
||||||
}
|
|
||||||
|
|
||||||
String fileExtension = originalFilename.substring(originalFilename.lastIndexOf('.'));
|
|
||||||
List<String> command = new ArrayList<>();
|
|
||||||
Path tempOutputFile = Files.createTempFile("output_", ".pdf");
|
|
||||||
Path tempInputFile = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Create temp file with appropriate extension
|
|
||||||
tempInputFile = Files.createTempFile("input_", fileExtension);
|
|
||||||
Files.write(tempInputFile, bytes);
|
|
||||||
|
|
||||||
command.add("ebook-convert");
|
|
||||||
command.add(tempInputFile.toString());
|
|
||||||
command.add(tempOutputFile.toString());
|
|
||||||
ProcessExecutorResult returnCode =
|
|
||||||
ProcessExecutor.getInstance(ProcessExecutor.Processes.CALIBRE)
|
|
||||||
.runCommandWithOutputHandling(command);
|
|
||||||
|
|
||||||
return Files.readAllBytes(tempOutputFile);
|
|
||||||
} finally {
|
|
||||||
// Clean up temporary files
|
|
||||||
if (tempInputFile != null) {
|
|
||||||
Files.deleteIfExists(tempInputFile);
|
|
||||||
}
|
|
||||||
Files.deleteIfExists(tempOutputFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static String sanitizeZipFilename(String entryName) {
|
static String sanitizeZipFilename(String entryName) {
|
||||||
if (entryName == null || entryName.trim().isEmpty()) {
|
if (entryName == null || entryName.trim().isEmpty()) {
|
||||||
return entryName;
|
return "";
|
||||||
}
|
}
|
||||||
|
// Remove any drive letters (e.g., "C:\") and leading forward/backslashes
|
||||||
|
entryName = entryName.replaceAll("^[a-zA-Z]:[\\\\/]+", "");
|
||||||
|
entryName = entryName.replaceAll("^[\\\\/]+", "");
|
||||||
|
|
||||||
|
// Recursively remove path traversal sequences
|
||||||
while (entryName.contains("../") || entryName.contains("..\\")) {
|
while (entryName.contains("../") || entryName.contains("..\\")) {
|
||||||
entryName = entryName.replace("../", "").replace("..\\", "");
|
entryName = entryName.replace("../", "").replace("..\\", "");
|
||||||
}
|
}
|
||||||
|
// Normalize all backslashes to forward slashes
|
||||||
|
entryName = entryName.replaceAll("\\\\", "/");
|
||||||
return entryName;
|
return entryName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package stirling.software.SPDF.utils;
|
package stirling.software.SPDF.utils;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -222,7 +226,7 @@ public class ProcessExecutor {
|
|||||||
boolean isQpdf =
|
boolean isQpdf =
|
||||||
command != null && !command.isEmpty() && command.get(0).contains("qpdf");
|
command != null && !command.isEmpty() && command.get(0).contains("qpdf");
|
||||||
|
|
||||||
if (outputLines.size() > 0) {
|
if (!outputLines.isEmpty()) {
|
||||||
String outputMessage = String.join("\n", outputLines);
|
String outputMessage = String.join("\n", outputLines);
|
||||||
messages += outputMessage;
|
messages += outputMessage;
|
||||||
if (!liveUpdates) {
|
if (!liveUpdates) {
|
||||||
@@ -230,7 +234,7 @@ public class ProcessExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorLines.size() > 0) {
|
if (!errorLines.isEmpty()) {
|
||||||
String errorMessage = String.join("\n", errorLines);
|
String errorMessage = String.join("\n", errorLines);
|
||||||
messages += errorMessage;
|
messages += errorMessage;
|
||||||
if (!liveUpdates) {
|
if (!liveUpdates) {
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
{
|
{
|
||||||
"moduleName": "ch.qos.logback:logback-classic",
|
"moduleName": "ch.qos.logback:logback-classic",
|
||||||
"moduleUrl": "http://www.qos.ch",
|
"moduleUrl": "http://www.qos.ch",
|
||||||
"moduleVersion": "1.5.16",
|
"moduleVersion": "1.5.17",
|
||||||
"moduleLicense": "GNU Lesser General Public License",
|
"moduleLicense": "GNU Lesser General Public License",
|
||||||
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleName": "ch.qos.logback:logback-core",
|
"moduleName": "ch.qos.logback:logback-core",
|
||||||
"moduleUrl": "http://www.qos.ch",
|
"moduleUrl": "http://www.qos.ch",
|
||||||
"moduleVersion": "1.5.16",
|
"moduleVersion": "1.5.17",
|
||||||
"moduleLicense": "GNU Lesser General Public License",
|
"moduleLicense": "GNU Lesser General Public License",
|
||||||
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
const storedVersion = localStorage.getItem('surveyVersion');
|
const storedVersion = localStorage.getItem('surveyVersion');
|
||||||
if (storedVersion && storedVersion !== surveyVersion) {
|
if (storedVersion && storedVersion !== surveyVersion) {
|
||||||
localStorage.setItem('pageViews', '0');
|
localStorage.setItem('pageViews', '0');
|
||||||
|
localStorage.setItem('surveyVersion', surveyVersion));
|
||||||
}
|
}
|
||||||
|
|
||||||
let pageViews = parseInt(localStorage.getItem('pageViews') || '0');
|
let pageViews = parseInt(localStorage.getItem('pageViews') || '0');
|
||||||
|
|||||||
@@ -5,31 +5,79 @@ import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
public class FileToPdfTest {
|
public class FileToPdfTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the HTML to PDF conversion.
|
||||||
|
* This test expects an IOException when an empty HTML input is provided.
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testConvertHtmlToPdf() {
|
public void testConvertHtmlToPdf() {
|
||||||
HTMLToPdfRequest request = new HTMLToPdfRequest();
|
HTMLToPdfRequest request = new HTMLToPdfRequest();
|
||||||
byte[] fileBytes = new byte[0]; // Sample file bytes
|
byte[] fileBytes = new byte[0]; // Sample file bytes (empty input)
|
||||||
String fileName = "test.html"; // Sample file name
|
String fileName = "test.html"; // Sample file name indicating an HTML file
|
||||||
boolean disableSanitize = false; // Sample boolean value
|
boolean disableSanitize = false; // Flag to control sanitization
|
||||||
|
|
||||||
// Check if the method throws IOException
|
// Expect an IOException to be thrown due to empty input
|
||||||
assertThrows(IOException.class, () -> {
|
Throwable thrown =
|
||||||
FileToPdf.convertHtmlToPdf("/path/",request, fileBytes, fileName, disableSanitize);
|
assertThrows(
|
||||||
});
|
IOException.class,
|
||||||
|
() ->
|
||||||
|
FileToPdf.convertHtmlToPdf(
|
||||||
|
"/path/", request, fileBytes, fileName, disableSanitize));
|
||||||
|
assertNotNull(thrown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test sanitizeZipFilename with null or empty input.
|
||||||
|
* It should return an empty string in these cases.
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testConvertBookTypeToPdf() {
|
public void testSanitizeZipFilename_NullOrEmpty() {
|
||||||
byte[] bytes = new byte[10]; // Sample bytes
|
assertEquals("", FileToPdf.sanitizeZipFilename(null));
|
||||||
String originalFilename = "test.epub"; // Sample original filename
|
assertEquals("", FileToPdf.sanitizeZipFilename(" "));
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the method throws IOException
|
/**
|
||||||
assertThrows(IOException.class, () -> {
|
* Test sanitizeZipFilename to ensure it removes path traversal sequences.
|
||||||
FileToPdf.convertBookTypeToPdf(bytes, originalFilename);
|
* This includes removing both forward and backward slash sequences.
|
||||||
});
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSanitizeZipFilename_RemovesTraversalSequences() {
|
||||||
|
String input = "../some/../path/..\\to\\file.txt";
|
||||||
|
String expected = "some/path/to/file.txt";
|
||||||
|
|
||||||
|
// Print output for debugging purposes
|
||||||
|
System.out.println("sanitizeZipFilename " + FileToPdf.sanitizeZipFilename(input));
|
||||||
|
System.out.flush();
|
||||||
|
|
||||||
|
// Expect that the method replaces backslashes with forward slashes
|
||||||
|
// and removes path traversal sequences
|
||||||
|
assertEquals(expected, FileToPdf.sanitizeZipFilename(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test sanitizeZipFilename to ensure that it removes leading drive letters and slashes.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSanitizeZipFilename_RemovesLeadingDriveAndSlashes() {
|
||||||
|
String input = "C:\\folder\\file.txt";
|
||||||
|
String expected = "folder/file.txt";
|
||||||
|
assertEquals(expected, FileToPdf.sanitizeZipFilename(input));
|
||||||
|
|
||||||
|
input = "/folder/file.txt";
|
||||||
|
expected = "folder/file.txt";
|
||||||
|
assertEquals(expected, FileToPdf.sanitizeZipFilename(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test sanitizeZipFilename to verify that safe filenames remain unchanged.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSanitizeZipFilename_NoChangeForSafeNames() {
|
||||||
|
String input = "folder/subfolder/file.txt";
|
||||||
|
assertEquals(input, FileToPdf.sanitizeZipFilename(input));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user