mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-06-06 18:30:57 +00: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
|
blank_issues_enabled: true
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: 💬 Discord Server
|
- 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
|
about: You can join our Discord server for real time discussion and support
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<h1 align="center">Stirling-PDF</h1>
|
<h1 align="center">Stirling-PDF</h1>
|
||||||
|
|
||||||
[](https://hub.docker.com/r/frooodle/s-pdf)
|
[](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://github.com/Stirling-Tools/stirling-pdf)
|
[](https://github.com/Stirling-Tools/stirling-pdf)
|
||||||
[](https://www.paypal.com/donate/?hosted_button_id=MN7JPG5G6G3JL)
|
[](https://www.paypal.com/donate/?hosted_button_id=MN7JPG5G6G3JL)
|
||||||
|
@ -68,7 +68,7 @@ public class PasswordController {
|
|||||||
boolean canModifyAnnotations = request.isCanModifyAnnotations();
|
boolean canModifyAnnotations = request.isCanModifyAnnotations();
|
||||||
boolean canPrint = request.isCanPrint();
|
boolean canPrint = request.isCanPrint();
|
||||||
boolean canPrintFaithful = request.isCanPrintFaithful();
|
boolean canPrintFaithful = request.isCanPrintFaithful();
|
||||||
|
System.out.println(fileInput.getOriginalFilename());
|
||||||
PDDocument document = Loader.loadPDF(fileInput.getBytes());
|
PDDocument document = Loader.loadPDF(fileInput.getBytes());
|
||||||
AccessPermission ap = new AccessPermission();
|
AccessPermission ap = new AccessPermission();
|
||||||
ap.setCanAssembleDocument(!canAssembleDocument);
|
ap.setCanAssembleDocument(!canAssembleDocument);
|
||||||
|
@ -12,7 +12,7 @@ $(document).ready(function () {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
firstErrorOccurred = false;
|
firstErrorOccurred = false;
|
||||||
const url = this.action;
|
const url = this.action;
|
||||||
const files = $("#fileInput-input")[0].files;
|
var files = $("#fileInput-input")[0].files;
|
||||||
const formData = new FormData(this);
|
const formData = new FormData(this);
|
||||||
|
|
||||||
// Remove empty file entries
|
// Remove empty file entries
|
||||||
@ -36,6 +36,17 @@ $(document).ready(function () {
|
|||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
try {
|
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 (remoteCall === true) {
|
||||||
if (override === "multi" || (!multiple && files.length > 1 && override !== "single")) {
|
if (override === "multi" || (!multiple && files.length > 1 && override !== "single")) {
|
||||||
await submitMultiPdfForm(url, files);
|
await submitMultiPdfForm(url, files);
|
||||||
@ -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) {
|
async function handleSingleDownload(url, formData, isMulti = false, isZip = false) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, { method: "POST", body: formData });
|
const response = await fetch(url, { method: "POST", body: formData });
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label th:text="#{PDFToPresentation.selectText.1}"></label>
|
<label th:text="#{PDFToPresentation.selectText.1}"></label>
|
||||||
<select class="form-control" name="outputFormat">
|
<select class="form-control" name="outputFormat">
|
||||||
<option value="ppt">PPT</option>
|
|
||||||
<option value="pptx">PPTX</option>
|
<option value="pptx">PPTX</option>
|
||||||
|
<option value="ppt">PPT</option>
|
||||||
<option value="odp">ODP</option>
|
<option value="odp">ODP</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label th:text="#{PDFToWord.selectText.1}"></label>
|
<label th:text="#{PDFToWord.selectText.1}"></label>
|
||||||
<select class="form-control" name="outputFormat">
|
<select class="form-control" name="outputFormat">
|
||||||
<option value="doc">Doc</option>
|
|
||||||
<option value="docx">DocX</option>
|
<option value="docx">DocX</option>
|
||||||
|
<option value="doc">Doc</option>
|
||||||
<option value="odt">Odt</option>
|
<option value="odt">Odt</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<p th:text="#{error.contactTip}"></p>
|
<p th:text="#{error.contactTip}"></p>
|
||||||
<div id="button-group">
|
<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://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>
|
</div>
|
||||||
<a th:href="@{'/'}" id="home-button" class="home-button btn btn-primary" th:text="#{goHomepage}"></a>
|
<a th:href="@{'/'}" id="home-button" class="home-button btn btn-primary" th:text="#{goHomepage}"></a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- Buttons to submit a ticket on GitHub and join Discord server -->
|
<!-- 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://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>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
<p th:text="#{error.contactTip}"></p>
|
<p th:text="#{error.contactTip}"></p>
|
||||||
<div id="button-group">
|
<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://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>
|
</div>
|
||||||
<a th:href="@{'/'}" class="home-button" th:text="#{goHomepage}"></a>
|
<a th:href="@{'/'}" class="home-button" th:text="#{goHomepage}"></a>
|
||||||
<a data-bs-dismiss="modal" class="home-button" th:text="#{close}"></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}">
|
<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">
|
<img th:src="@{'/images/docker.svg'}" alt="docker">
|
||||||
</a>
|
</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">
|
<img th:src="@{'/images/discord.svg'}" alt="discord">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/sponsors/Frooodle" class="mx-1" role="button" th:title="#{donate}">
|
<a href="https://github.com/sponsors/Frooodle" class="mx-1" role="button" th:title="#{donate}">
|
||||||
|
@ -265,7 +265,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
const surveyVersion = "1.1";
|
<!-- const surveyVersion = "1.1";
|
||||||
const modal = new bootstrap.Modal(document.getElementById('surveyModal'));
|
const modal = new bootstrap.Modal(document.getElementById('surveyModal'));
|
||||||
const dontShowAgain = document.getElementById('dontShowAgain');
|
const dontShowAgain = document.getElementById('dontShowAgain');
|
||||||
const takeSurveyButton = document.getElementById('takeSurvey');
|
const takeSurveyButton = document.getElementById('takeSurvey');
|
||||||
@ -293,7 +293,7 @@
|
|||||||
|
|
||||||
if (localStorage.getItem('dontShowSurvey')) {
|
if (localStorage.getItem('dontShowSurvey')) {
|
||||||
modal.hide();
|
modal.hide();
|
||||||
}
|
} -->
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
/>
|
/>
|
||||||
<script th:inline="javascript">
|
<script th:inline="javascript">
|
||||||
const saveSettings = /*[[#{pipelineOptions.saveSettings}]]*/ "";
|
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>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="fileInput" th:text="#{pageRemover.pagesToDelete}"></label>
|
<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>
|
</div>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pageRemover.submit}"></button>
|
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pageRemover.submit}"></button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -20,9 +20,7 @@
|
|||||||
<form method="post" enctype="multipart/form-data" action="api/v1/security/add-watermark">
|
<form method="post" enctype="multipart/form-data" action="api/v1/security/add-watermark">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label th:text="#{watermark.selectText.1}"></label>
|
<label th:text="#{watermark.selectText.1}"></label>
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}">
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<input type="file" id="fileInput" name="fileInput" class="form-control-file" accept="application/pdf" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
@ -17,9 +17,7 @@
|
|||||||
<span class="tool-header-text" th:text="#{autoRedact.header}"></span>
|
<span class="tool-header-text" th:text="#{autoRedact.header}"></span>
|
||||||
</div>
|
</div>
|
||||||
<form action="api/v1/security/auto-redact" method="post" enctype="multipart/form-data">
|
<form action="api/v1/security/auto-redact" method="post" enctype="multipart/form-data">
|
||||||
<div class="mb-3">
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||||
<input type="file" class="form-control" id="fileInput" name="fileInput" required accept="application/pdf">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="listOfText" class="form-label" th:text="#{autoRedact.textsToRedactLabel}"></label>
|
<label for="listOfText" class="form-label" th:text="#{autoRedact.textsToRedactLabel}"></label>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user