-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2412 from reecebrowne/feature/1856/decrypt
Feature/1856/decrypt
- Loading branch information
Showing
33 changed files
with
1,408 additions
and
1,067 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
export class DecryptFile { | ||
async decryptFile(file, requiresPassword) { | ||
try { | ||
const formData = new FormData(); | ||
formData.append('fileInput', file); | ||
if (requiresPassword) { | ||
const password = prompt(`${window.decrypt.passwordPrompt}`); | ||
|
||
if (password === null) { | ||
// User cancelled | ||
console.error(`Password prompt cancelled for PDF: ${file.name}`); | ||
return null; // No file to return | ||
} | ||
|
||
if (!password) { | ||
// No password provided | ||
console.error(`No password provided for encrypted PDF: ${file.name}`); | ||
this.showErrorBanner( | ||
`${window.decrypt.noPassword.replace('{0}', file.name)}`, | ||
'', | ||
`${window.decrypt.unexpectedError}` | ||
); | ||
return null; // No file to return | ||
} | ||
|
||
formData.append('password', password); | ||
} | ||
// Send decryption request | ||
const response = await fetch('/api/v1/security/remove-password', { | ||
method: 'POST', | ||
body: formData, | ||
}); | ||
|
||
if (response.ok) { | ||
const decryptedBlob = await response.blob(); | ||
this.removeErrorBanner(); | ||
return new File([decryptedBlob], file.name, {type: 'application/pdf'}); | ||
} else { | ||
const errorText = await response.text(); | ||
console.error(`${window.decrypt.invalidPassword} ${errorText}`); | ||
this.showErrorBanner( | ||
`${window.decrypt.invalidPassword}`, | ||
errorText, | ||
`${window.decrypt.invalidPasswordHeader.replace('{0}', file.name)}` | ||
); | ||
return null; // No file to return | ||
} | ||
} catch (error) { | ||
// Handle network or unexpected errors | ||
console.error(`Failed to decrypt PDF: ${file.name}`, error); | ||
this.showErrorBanner( | ||
`${window.decrypt.unexpectedError.replace('{0}', file.name)}`, | ||
`${error.message || window.decrypt.unexpectedError}`, | ||
error | ||
); | ||
return null; // No file to return | ||
} | ||
} | ||
|
||
async checkFileEncrypted(file) { | ||
try { | ||
if (file.type !== 'application/pdf') { | ||
return {isEncrypted: false, requiresPassword: false}; | ||
} | ||
|
||
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs'; | ||
const arrayBuffer = await file.arrayBuffer(); | ||
const arrayBufferForPdfLib = arrayBuffer.slice(0); | ||
|
||
const loadingTask = pdfjsLib.getDocument({ | ||
data: arrayBuffer, | ||
}); | ||
|
||
await loadingTask.promise; | ||
|
||
try { | ||
//Uses PDFLib.PDFDocument to check if unpassworded but encrypted | ||
const pdfDoc = await PDFLib.PDFDocument.load(arrayBufferForPdfLib); | ||
return {isEncrypted: false, requiresPassword: false}; | ||
} catch (error) { | ||
if (error.message.includes('Input document to `PDFDocument.load` is encrypted')) { | ||
return {isEncrypted: true, requiresPassword: false}; | ||
} | ||
console.error('Error checking encryption:', error); | ||
throw new Error('Failed to determine if the file is encrypted.'); | ||
} | ||
} catch (error) { | ||
if (error.name === 'PasswordException') { | ||
if (error.code === pdfjsLib.PasswordResponses.NEED_PASSWORD) { | ||
return {isEncrypted: true, requiresPassword: true}; | ||
} else if (error.code === pdfjsLib.PasswordResponses.INCORRECT_PASSWORD) { | ||
return {isEncrypted: true, requiresPassword: false}; | ||
} | ||
} | ||
|
||
console.error('Error checking encryption:', error); | ||
throw new Error('Failed to determine if the file is encrypted.'); | ||
} | ||
} | ||
|
||
showErrorBanner(message, stackTrace, error) { | ||
const errorContainer = document.getElementById('errorContainer'); | ||
errorContainer.style.display = 'block'; // Display the banner | ||
errorContainer.querySelector('.alert-heading').textContent = error; | ||
errorContainer.querySelector('p').textContent = message; | ||
document.querySelector('#traceContent').textContent = stackTrace; | ||
} | ||
|
||
removeErrorBanner() { | ||
const errorContainer = document.getElementById('errorContainer'); | ||
errorContainer.style.display = 'none'; // Hide the banner | ||
errorContainer.querySelector('.alert-heading').textContent = ''; | ||
errorContainer.querySelector('p').textContent = ''; | ||
document.querySelector('#traceContent').textContent = ''; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
document.getElementById('download-pdf').addEventListener('click', async () => { | ||
const modifiedPdf = await DraggableUtils.getOverlayedPdfDocument(); | ||
let decryptedFile = modifiedPdf; | ||
let isEncrypted = false; | ||
let requiresPassword = false; | ||
await this.decryptFile | ||
.checkFileEncrypted(decryptedFile) | ||
.then((result) => { | ||
isEncrypted = result.isEncrypted; | ||
requiresPassword = result.requiresPassword; | ||
}) | ||
.catch((error) => { | ||
console.error(error); | ||
}); | ||
if (decryptedFile.type === 'application/pdf' && isEncrypted) { | ||
decryptedFile = await this.decryptFile.decryptFile(decryptedFile, requiresPassword); | ||
if (!decryptedFile) { | ||
throw new Error('File decryption failed.'); | ||
} | ||
} | ||
const modifiedPdfBytes = await modifiedPdf.save(); | ||
const blob = new Blob([modifiedPdfBytes], {type: 'application/pdf'}); | ||
const link = document.createElement('a'); | ||
link.href = URL.createObjectURL(blob); | ||
link.download = originalFileName + '_signed.pdf'; | ||
link.click(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.