diff --git a/.github/workflows/file_hash_generation.yml b/.github/workflows/file_hash_generation.yml index a6093bb53..dce072b5b 100644 --- a/.github/workflows/file_hash_generation.yml +++ b/.github/workflows/file_hash_generation.yml @@ -36,8 +36,11 @@ jobs: import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; + import java.util.Arrays; import java.util.Collections; + import java.util.HashSet; import java.util.List; + import java.util.Set; import java.util.zip.CRC32; public class HashGenerator { @@ -46,9 +49,9 @@ jobs: private static final String OUTPUT_FILE = "src/main/resources/reference-hash.json"; // Text file extensions that need normalization - private static final List TEXT_EXTENSIONS = List.of( + private static final Set TEXT_EXTENSIONS = new HashSet<>(Arrays.asList( "html", "htm", "css", "js", "txt", "md", "xml", "json", "csv", "properties" - ); + )); public static void main(String[] args) throws IOException { List entries = new ArrayList<>(); @@ -92,21 +95,22 @@ jobs: String fullPath = basePath + "/" + relativePath; // Calculate hash - String hash = calculateFileHash(file); + String hash = calculateFileHash(file.toPath()); entries.add(new FileEntry(fullPath, hash)); + System.out.println("Processed: " + fullPath + " => " + hash); } } } - private static String calculateFileHash(File file) throws IOException { - String extension = getFileExtension(file.getName()).toLowerCase(); + private static String calculateFileHash(Path filePath) throws IOException { + String extension = getFileExtension(filePath.toString()).toLowerCase(); boolean isTextFile = TEXT_EXTENSIONS.contains(extension); if (isTextFile) { - return calculateNormalizedTextFileHash(file.toPath()); + return calculateNormalizedTextFileHash(filePath); } else { - return calculateBinaryFileHash(file.toPath()); + return calculateBinaryFileHash(filePath); } } @@ -123,7 +127,7 @@ jobs: checksum.update(normalizedBytes, 0, normalizedBytes.length); return String.valueOf(checksum.getValue()); } - + private static String calculateBinaryFileHash(Path filePath) throws IOException { byte[] content = Files.readAllBytes(filePath); diff --git a/src/main/java/stirling/software/SPDF/config/TemplateIntegrityConfig.java b/src/main/java/stirling/software/SPDF/config/TemplateIntegrityConfig.java index d1f30d081..5230f0091 100644 --- a/src/main/java/stirling/software/SPDF/config/TemplateIntegrityConfig.java +++ b/src/main/java/stirling/software/SPDF/config/TemplateIntegrityConfig.java @@ -19,7 +19,6 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.zip.CRC32; -import java.util.zip.Checksum; @Configuration public class TemplateIntegrityConfig { @@ -39,6 +38,9 @@ public class TemplateIntegrityConfig { @Value("${template.normalize.line.endings:true}") private boolean normalizeLineEndings; + + @Value("${template.integrity.enabled:true}") + private boolean integrityCheckEnabled; public TemplateIntegrityConfig(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; @@ -46,6 +48,11 @@ public class TemplateIntegrityConfig { @Bean public boolean templatesModified() { + if (!integrityCheckEnabled) { + logger.info("Template integrity checking is disabled"); + return false; + } + try { // Log configuration information logConfiguration(); @@ -84,51 +91,20 @@ public class TemplateIntegrityConfig { } } - private void logHashComparison(String relativePath, String referenceHash, String currentHash) { - logger.info("Hash comparison for {}: reference={}, current={}", - relativePath, referenceHash, currentHash); - - // Try to convert between formats to see if that's the issue - try { - // If currentHash is hex, convert to decimal - if (currentHash.matches("[0-9a-fA-F]+") && !currentHash.matches("[0-9]+")) { - long decimalValue = Long.parseLong(currentHash, 16); - logger.info("Converting current hex hash to decimal: {} -> {}", - currentHash, decimalValue); - - // Check if the decimal conversion matches the reference - if (String.valueOf(decimalValue).equals(referenceHash)) { - logger.warn("Hash format mismatch detected! Current hash is in hex format but reference is decimal."); - } - } - - // If referenceHash could be decimal but currentHash is decimal too - // Check if reference could be hex - if (referenceHash.matches("[0-9]+") && currentHash.matches("[0-9]+")) { - // Try treating reference as hex and converting to decimal - try { - long hexAsDecimal = Long.parseLong(referenceHash, 16); - if (String.valueOf(hexAsDecimal).equals(currentHash)) { - logger.warn("Reference hash might be incorrectly interpreted as decimal when it's hex!"); - } - } catch (NumberFormatException e) { - // Not a valid hex number, which is fine - } - } - } catch (Exception e) { - logger.info("Error during hash format conversion check", e); - } - } - private void logReferenceHashes(Map hashes) { logger.info("Loaded {} reference hashes", hashes.size()); - // Log a few example HTML files for infoging + // Log a few example files for debugging logger.info("Sample of reference hashes:"); hashes.entrySet().stream() - .filter(e -> e.getKey().endsWith(".html")) .limit(5) .forEach(e -> logger.info(" - {}: {}", e.getKey(), e.getValue())); + + // Also log sample PDF files if any + hashes.entrySet().stream() + .filter(e -> e.getKey().endsWith(".pdf")) + .limit(3) + .forEach(e -> logger.info(" - PDF file: {}: {}", e.getKey(), e.getValue())); } private Map parseHashJson(String json) { @@ -144,7 +120,7 @@ public class TemplateIntegrityConfig { result.put(parts[0], parts[1]); } } - logger.info("Loaded {} reference hashes", result.size()); + logger.debug("Loaded {} reference hashes", result.size()); return result; } @@ -172,7 +148,7 @@ public class TemplateIntegrityConfig { Path directory = Paths.get(resource.getURI()); if (Files.exists(directory) && Files.isDirectory(directory)) { - // Walk the directory tree + // Walk the directory tree - process ALL files, not just text files Files.walk(directory) .filter(Files::isRegularFile) .forEach(path -> { @@ -182,8 +158,8 @@ public class TemplateIntegrityConfig { String basePath = dirPath.replace("/", ""); String relativePath = basePath + "/" + directory.relativize(path).toString().replace("\\", "/"); - // info log the path normalization - logger.info("Processing file: {} -> {}", path, relativePath); + // Debug log the path normalization + logger.debug("Processing file: {} -> {}", path, relativePath); // Check if this file is in our reference String referenceHash = referenceHashes.get(relativePath); @@ -208,9 +184,10 @@ public class TemplateIntegrityConfig { // Check if the hash matches String currentHash = computeFileHash(path); + // Log hash comparison for debugging logger.info("Hash comparison for {}: reference={}, current={}", relativePath, referenceHash, currentHash); - logHashComparison(relativePath, referenceHash, currentHash); + if (!currentHash.equals(referenceHash)) { logger.warn("Modified file detected: {} (expected hash: {}, actual hash: {})", relativePath, referenceHash, currentHash); @@ -232,7 +209,7 @@ public class TemplateIntegrityConfig { if (!modified.get()) { for (Map.Entry entry : foundFiles.entrySet()) { if (!entry.getValue()) { - // File was in reference but not found + // File was in reference but not found - report ALL missing files logger.warn("Missing file detected: {} (expected hash: {})", entry.getKey(), referenceHashes.get(entry.getKey())); return true; @@ -247,15 +224,14 @@ public class TemplateIntegrityConfig { // For text files like HTML, normalize content before hashing String extension = getFileExtension(filePath.toString()).toLowerCase(); if (normalizeLineEndings && isTextFile(extension)) { - return computeNormalizedTextFileHash(filePath, extension); + return computeNormalizedTextFileHash(filePath); } else { // Binary files use direct CRC32 return computeBinaryFileHash(filePath); } } - - private String computeNormalizedTextFileHash(Path filePath, String extension) throws IOException { + private String computeNormalizedTextFileHash(Path filePath) throws IOException { byte[] content = Files.readAllBytes(filePath); String text = new String(content, StandardCharsets.UTF_8); @@ -264,25 +240,19 @@ public class TemplateIntegrityConfig { byte[] normalizedBytes = text.getBytes(StandardCharsets.UTF_8); - Checksum checksum = new CRC32(); + CRC32 checksum = new CRC32(); checksum.update(normalizedBytes, 0, normalizedBytes.length); return String.valueOf(checksum.getValue()); } -private String computeBinaryFileHash(Path filePath) throws IOException { - Checksum checksum = new CRC32(); - - try (InputStream is = Files.newInputStream(filePath)) { - byte[] buffer = new byte[BUFFER_SIZE]; - int bytesRead; - while ((bytesRead = is.read(buffer)) != -1) { - checksum.update(buffer, 0, bytesRead); - } + private String computeBinaryFileHash(Path filePath) throws IOException { + byte[] content = Files.readAllBytes(filePath); + + CRC32 checksum = new CRC32(); + checksum.update(content, 0, content.length); + return String.valueOf(checksum.getValue()); } - // Return decimal representation to match GitHub workflow - return String.valueOf(checksum.getValue()); -} private String getFileExtension(String filename) { int lastDot = filename.lastIndexOf('.'); if (lastDot == -1 || lastDot == filename.length() - 1) { @@ -299,5 +269,4 @@ private String computeBinaryFileHash(Path filePath) throws IOException { extension.equals("xml") || extension.equals("json") || extension.equals("csv") || extension.equals("properties"); } - } \ No newline at end of file diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index c529fff81..ce141422b 100644 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -9,7 +9,6 @@
-