mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-03-11 00:19:03 +01:00
auto decrypt, update discord, fix multi file support for some inputs
This commit is contained in:
parent
3576c32c52
commit
75e10efcbd
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,5 +1,5 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: 💬 Discord Server
|
||||
url: https://discord.gg/Cn8pWhQRxZ
|
||||
url: https://discord.gg/HYmhKj45pU
|
||||
about: You can join our Discord server for real time discussion and support
|
||||
|
@ -2,7 +2,7 @@
|
||||
<h1 align="center">Stirling-PDF</h1>
|
||||
|
||||
[](https://hub.docker.com/r/frooodle/s-pdf)
|
||||
[](https://discord.gg/Cn8pWhQRxZ)
|
||||
[](https://discord.gg/HYmhKj45pU)
|
||||
[](https://github.com/Stirling-Tools/Stirling-PDF/)
|
||||
[](https://github.com/Stirling-Tools/stirling-pdf)
|
||||
[](https://www.paypal.com/donate/?hosted_button_id=MN7JPG5G6G3JL)
|
||||
|
@ -68,7 +68,7 @@ public class PasswordController {
|
||||
boolean canModifyAnnotations = request.isCanModifyAnnotations();
|
||||
boolean canPrint = request.isCanPrint();
|
||||
boolean canPrintFaithful = request.isCanPrintFaithful();
|
||||
|
||||
System.out.println(fileInput.getOriginalFilename());
|
||||
PDDocument document = Loader.loadPDF(fileInput.getBytes());
|
||||
AccessPermission ap = new AccessPermission();
|
||||
ap.setCanAssembleDocument(!canAssembleDocument);
|
||||
|
@ -12,7 +12,7 @@ $(document).ready(function () {
|
||||
event.preventDefault();
|
||||
firstErrorOccurred = false;
|
||||
const url = this.action;
|
||||
const files = $("#fileInput-input")[0].files;
|
||||
var files = $("#fileInput-input")[0].files;
|
||||
const formData = new FormData(this);
|
||||
|
||||
// Remove empty file entries
|
||||
@ -36,6 +36,17 @@ $(document).ready(function () {
|
||||
}, 5000);
|
||||
|
||||
try {
|
||||
|
||||
if (!url.includes("remove-password")) {
|
||||
// Check if any PDF files are encrypted and handle decryption if necessary
|
||||
const decryptedFiles = await checkAndDecryptFiles(url ,files);
|
||||
files = decryptedFiles
|
||||
// Append decrypted files to formData
|
||||
decryptedFiles.forEach((file, index) => {
|
||||
formData.set(`fileInput`, file);
|
||||
});
|
||||
}
|
||||
|
||||
if (remoteCall === true) {
|
||||
if (override === "multi" || (!multiple && files.length > 1 && override !== "single")) {
|
||||
await submitMultiPdfForm(url, files);
|
||||
@ -45,24 +56,24 @@ $(document).ready(function () {
|
||||
}
|
||||
clearTimeout(timeoutId);
|
||||
$("#submitBtn").text(originalButtonText);
|
||||
|
||||
|
||||
// After process finishes, check for boredWaiting and gameDialog open status
|
||||
const boredWaiting = localStorage.getItem("boredWaiting") || "disabled";
|
||||
const gameDialog = document.getElementById('game-container-wrapper');
|
||||
if (boredWaiting === "enabled" && gameDialog && gameDialog.open) {
|
||||
// Display a green banner at the bottom of the screen saying "Download complete"
|
||||
let downloadCompleteText = "Download Complete";
|
||||
if(window.downloadCompleteText){
|
||||
if (window.downloadCompleteText) {
|
||||
downloadCompleteText = window.downloadCompleteText;
|
||||
}
|
||||
$("body").append('<div id="download-complete-banner" style="position:fixed;bottom:0;left:0;width:100%;background-color:green;color:white;text-align:center;padding:10px;font-size:16px;z-index:1000;">'+ downloadCompleteText + '</div>');
|
||||
setTimeout(function() {
|
||||
$("#download-complete-banner").fadeOut("slow", function() {
|
||||
$("body").append('<div id="download-complete-banner" style="position:fixed;bottom:0;left:0;width:100%;background-color:green;color:white;text-align:center;padding:10px;font-size:16px;z-index:1000;">' + downloadCompleteText + '</div>');
|
||||
setTimeout(function () {
|
||||
$("#download-complete-banner").fadeOut("slow", function () {
|
||||
$(this).remove(); // Remove the banner after fading out
|
||||
});
|
||||
}, 5000); // Banner will fade out after 5 seconds
|
||||
}
|
||||
|
||||
|
||||
} catch (error) {
|
||||
clearTimeout(timeoutId);
|
||||
handleDownloadError(error);
|
||||
@ -72,6 +83,97 @@ $(document).ready(function () {
|
||||
});
|
||||
});
|
||||
|
||||
async function checkAndDecryptFiles(url, files) {
|
||||
const decryptedFiles = [];
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs';
|
||||
|
||||
// Extract the base URL
|
||||
const baseUrl = new URL(url);
|
||||
let removePasswordUrl = `${baseUrl.origin}`;
|
||||
|
||||
// Check if there's a path before /api/
|
||||
const apiIndex = baseUrl.pathname.indexOf('/api/');
|
||||
if (apiIndex > 0) {
|
||||
removePasswordUrl += baseUrl.pathname.substring(0, apiIndex);
|
||||
}
|
||||
|
||||
// Append the new endpoint
|
||||
removePasswordUrl += '/api/v1/security/remove-password';
|
||||
|
||||
console.log(`Remove password URL: ${removePasswordUrl}`);
|
||||
|
||||
|
||||
for (const file of files) {
|
||||
console.log(`Processing file: ${file.name}`);
|
||||
if (file.type !== 'application/pdf') {
|
||||
console.log(`Skipping non-PDF file: ${file.name}`);
|
||||
decryptedFiles.push(file);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const arrayBuffer = await file.arrayBuffer();
|
||||
const loadingTask = pdfjsLib.getDocument({ data: arrayBuffer });
|
||||
|
||||
console.log(`Attempting to load PDF: ${file.name}`);
|
||||
const pdf = await loadingTask.promise;
|
||||
console.log(`File is not encrypted: ${file.name}`);
|
||||
decryptedFiles.push(file); // If no error, file is not encrypted
|
||||
} catch (error) {
|
||||
if (error.name === 'PasswordException' && error.code === 1) {
|
||||
console.log(`PDF requires password: ${file.name}`, error);
|
||||
console.log(`Attempting to remove password from PDF: ${file.name} with password.`);
|
||||
const password = prompt(`This PDF (${file.name}) is encrypted. Please enter the password:`);
|
||||
|
||||
if (!password) {
|
||||
console.error(`No password provided for encrypted PDF: ${file.name}`);
|
||||
showErrorBanner(`No password provided for encrypted PDF: ${file.name}`, 'Please enter a valid password.');
|
||||
throw error;
|
||||
}
|
||||
|
||||
try {
|
||||
// Prepare FormData for the decryption request
|
||||
const formData = new FormData();
|
||||
formData.append('fileInput', file);
|
||||
formData.append('password', password);
|
||||
|
||||
// Use handleSingleDownload to send the request
|
||||
const decryptionResult = await fetch(removePasswordUrl, { method: "POST", body: formData });
|
||||
|
||||
if (decryptionResult && decryptionResult.blob) {
|
||||
const decryptedBlob = await decryptionResult.blob();
|
||||
const decryptedFile = new File([decryptedBlob], file.name, { type: 'application/pdf' });
|
||||
|
||||
/* // Create a link element to download the file
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(decryptedBlob);
|
||||
link.download = 'test.pdf';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
*/
|
||||
decryptedFiles.push(decryptedFile);
|
||||
console.log(`Successfully decrypted PDF: ${file.name}`);
|
||||
} else {
|
||||
throw new Error('Decryption failed: No valid response from server');
|
||||
}
|
||||
} catch (decryptError) {
|
||||
console.error(`Failed to decrypt PDF: ${file.name}`, decryptError);
|
||||
showErrorBanner(`Failed to decrypt PDF: ${file.name}`, 'Incorrect password or unsupported encryption.');
|
||||
throw decryptError;
|
||||
}
|
||||
} else {
|
||||
console.log(`Error loading PDF: ${file.name}`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
return decryptedFiles;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
async function handleSingleDownload(url, formData, isMulti = false, isZip = false) {
|
||||
try {
|
||||
const response = await fetch(url, { method: "POST", body: formData });
|
||||
|
@ -22,8 +22,8 @@
|
||||
<div class="mb-3">
|
||||
<label th:text="#{PDFToPresentation.selectText.1}"></label>
|
||||
<select class="form-control" name="outputFormat">
|
||||
<option value="ppt">PPT</option>
|
||||
<option value="pptx">PPTX</option>
|
||||
<option value="ppt">PPT</option>
|
||||
<option value="odp">ODP</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -22,8 +22,8 @@
|
||||
<div class="mb-3">
|
||||
<label th:text="#{PDFToWord.selectText.1}"></label>
|
||||
<select class="form-control" name="outputFormat">
|
||||
<option value="docx">DocX</option>
|
||||
<option value="doc">Doc</option>
|
||||
<option value="docx">DocX</option>
|
||||
<option value="odt">Odt</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<p th:text="#{error.contactTip}"></p>
|
||||
<div id="button-group">
|
||||
<a href="https://github.com/Stirling-Tools/Stirling-PDF/issues" id="github-button" class="btn btn-primary" target="_blank" th:text="#{error.github}"></a>
|
||||
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" class="btn btn-primary" target="_blank" th:text="#{joinDiscord}"></a>
|
||||
<a href="https://discord.gg/HYmhKj45pU" id="discord-button" class="btn btn-primary" target="_blank" th:text="#{joinDiscord}"></a>
|
||||
</div>
|
||||
<a th:href="@{'/'}" id="home-button" class="home-button btn btn-primary" th:text="#{goHomepage}"></a>
|
||||
</div>
|
||||
|
@ -20,7 +20,7 @@
|
||||
</div>
|
||||
<!-- Buttons to submit a ticket on GitHub and join Discord server -->
|
||||
<a href="https://github.com/Stirling-Tools/Stirling-PDF/issues" id="github-button" target="_blank" th:text="#{error.github}"></a>
|
||||
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" target="_blank" th:text="#{joinDiscord}"></a>
|
||||
<a href="https://discord.gg/HYmhKj45pU" id="discord-button" target="_blank" th:text="#{joinDiscord}"></a>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
|
@ -39,7 +39,7 @@
|
||||
<p th:text="#{error.contactTip}"></p>
|
||||
<div id="button-group">
|
||||
<a href="https://github.com/Stirling-Tools/Stirling-PDF/issues" id="github-button" target="_blank" th:text="#{error.githubSubmit}"></a>
|
||||
<a href="https://discord.gg/Cn8pWhQRxZ" id="discord-button" target="_blank" th:text="#{error.discordSubmit}"></a>
|
||||
<a href="https://discord.gg/HYmhKj45pU" id="discord-button" target="_blank" th:text="#{error.discordSubmit}"></a>
|
||||
</div>
|
||||
<a th:href="@{'/'}" class="home-button" th:text="#{goHomepage}"></a>
|
||||
<a data-bs-dismiss="modal" class="home-button" th:text="#{close}"></a>
|
||||
|
@ -391,7 +391,7 @@
|
||||
<a href="https://hub.docker.com/r/frooodle/s-pdf" class="mx-1" role="button" th:title="#{seeDockerHub}">
|
||||
<img th:src="@{'/images/docker.svg'}" alt="docker">
|
||||
</a>
|
||||
<a href="https://discord.gg/Cn8pWhQRxZ" class="mx-1" role="button" th:title="#{joinDiscord}">
|
||||
<a href="https://discord.gg/HYmhKj45pU" class="mx-1" role="button" th:title="#{joinDiscord}">
|
||||
<img th:src="@{'/images/discord.svg'}" alt="discord">
|
||||
</a>
|
||||
<a href="https://github.com/sponsors/Frooodle" class="mx-1" role="button" th:title="#{donate}">
|
||||
|
@ -265,7 +265,7 @@
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const surveyVersion = "1.1";
|
||||
<!-- const surveyVersion = "1.1";
|
||||
const modal = new bootstrap.Modal(document.getElementById('surveyModal'));
|
||||
const dontShowAgain = document.getElementById('dontShowAgain');
|
||||
const takeSurveyButton = document.getElementById('takeSurvey');
|
||||
@ -293,7 +293,7 @@
|
||||
|
||||
if (localStorage.getItem('dontShowSurvey')) {
|
||||
modal.hide();
|
||||
}
|
||||
} -->
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
/>
|
||||
<script th:inline="javascript">
|
||||
const saveSettings = /*[[#{pipelineOptions.saveSettings}]]*/ "";
|
||||
const deletePipelineText = /*[[#{pipeline.pipeline.deletePrompt}]]*/ "Are you sure you want to delete pipeline";
|
||||
const deletePipelineText = /*[[#{pipeline.deletePrompt}]]*/ "Are you sure you want to delete pipeline";
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||
<div class="mb-3">
|
||||
<label for="fileInput" th:text="#{pageRemover.pagesToDelete}"></label>
|
||||
<input type="text" class="form-control" id="fileInput" name="pageNumbers" th:placeholder="#{pageRemover.placeholder}" required>
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||
</div>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pageRemover.submit}"></button>
|
||||
</form>
|
||||
|
@ -20,9 +20,7 @@
|
||||
<form method="post" enctype="multipart/form-data" action="api/v1/security/add-watermark">
|
||||
<div class="mb-3">
|
||||
<label th:text="#{watermark.selectText.1}"></label>
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}">
|
||||
<input type="file" id="fileInput" name="fileInput" class="form-control-file" accept="application/pdf" required>
|
||||
</div>
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
|
@ -17,10 +17,8 @@
|
||||
<span class="tool-header-text" th:text="#{autoRedact.header}"></span>
|
||||
</div>
|
||||
<form action="api/v1/security/auto-redact" method="post" enctype="multipart/form-data">
|
||||
<div class="mb-3">
|
||||
<input type="file" class="form-control" id="fileInput" name="fileInput" required accept="application/pdf">
|
||||
</div>
|
||||
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="listOfText" class="form-label" th:text="#{autoRedact.textsToRedactLabel}"></label>
|
||||
<textarea class="form-control" id="listOfText" name="listOfText" rows="4" required th:placeholder="#{autoRedact.textsToRedactPlaceholder}"></textarea>
|
||||
|
Loading…
Reference in New Issue
Block a user