Add main application page, key generation and download is working
This commit is contained in:
700
static/script.js
Normal file
700
static/script.js
Normal file
@@ -0,0 +1,700 @@
|
||||
// Application State
|
||||
let currentTab = "generate"
|
||||
let selectedFiles = []
|
||||
let isProcessing = false
|
||||
|
||||
// DOM Elements
|
||||
const elements = {
|
||||
// Tabs
|
||||
tabGenerate: document.getElementById("tab-generate"),
|
||||
tabDecrypt: document.getElementById("tab-decrypt"),
|
||||
generateSection: document.getElementById("generate-section"),
|
||||
decryptSection: document.getElementById("decrypt-section"),
|
||||
|
||||
// Key Generation Form
|
||||
keyGenerationForm: document.getElementById("key-generation-form"),
|
||||
nameInput: document.getElementById("name"),
|
||||
emailInput: document.getElementById("email"),
|
||||
passphraseInput: document.getElementById("passphrase"),
|
||||
confirmPassphraseInput: document.getElementById("confirm-passphrase"),
|
||||
commentInput: document.getElementById("comment"),
|
||||
generateBtn: document.getElementById("generate-btn"),
|
||||
generationStatus: document.getElementById("generation-status"),
|
||||
loadingStatus: document.getElementById("loading-status"),
|
||||
successStatus: document.getElementById("success-status"),
|
||||
errorStatus: document.getElementById("error-status"),
|
||||
errorMessage: document.getElementById("error-message"),
|
||||
|
||||
// File Decryption
|
||||
dropZone: document.getElementById("drop-zone"),
|
||||
fileInput: document.getElementById("file-input"),
|
||||
selectFilesBtn: document.getElementById("select-files-btn"),
|
||||
fileList: document.getElementById("file-list"),
|
||||
filesContainer: document.getElementById("files-container"),
|
||||
decryptionForm: document.getElementById("decryption-form"),
|
||||
privateKeyInput: document.getElementById("private-key"),
|
||||
keyPassphraseInput: document.getElementById("key-passphrase"),
|
||||
decryptBtn: document.getElementById("decrypt-btn"),
|
||||
decryptionStatus: document.getElementById("decryption-status"),
|
||||
progressBar: document.getElementById("progress-bar"),
|
||||
decryptionMessage: document.getElementById("decryption-message"),
|
||||
decryptionResults: document.getElementById("decryption-results"),
|
||||
}
|
||||
|
||||
// Initialize Application
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
initializeEventListeners()
|
||||
setupFormValidation()
|
||||
setupFileHandling()
|
||||
})
|
||||
|
||||
// Event Listeners
|
||||
function initializeEventListeners() {
|
||||
// Tab Navigation
|
||||
elements.tabGenerate.addEventListener("click", () => switchTab("generate"))
|
||||
elements.tabDecrypt.addEventListener("click", () => switchTab("decrypt"))
|
||||
|
||||
// Key Generation Form
|
||||
elements.keyGenerationForm.addEventListener("submit", handleKeyGeneration)
|
||||
|
||||
// File Upload
|
||||
elements.selectFilesBtn.addEventListener("click", () =>
|
||||
elements.fileInput.click()
|
||||
)
|
||||
elements.fileInput.addEventListener("change", handleFileSelection)
|
||||
|
||||
// Drag and Drop
|
||||
elements.dropZone.addEventListener("dragover", handleDragOver)
|
||||
elements.dropZone.addEventListener("dragleave", handleDragLeave)
|
||||
elements.dropZone.addEventListener("drop", handleFileDrop)
|
||||
|
||||
// Decryption Form
|
||||
elements.decryptionForm.addEventListener("submit", handleFileDecryption)
|
||||
|
||||
// Keyboard accessibility for drop zone
|
||||
elements.dropZone.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault()
|
||||
elements.fileInput.click()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Tab Management
|
||||
function switchTab(tabName) {
|
||||
currentTab = tabName
|
||||
|
||||
// Update tab buttons
|
||||
document.querySelectorAll(".tab-button").forEach((btn) => {
|
||||
btn.classList.remove("active")
|
||||
btn.classList.add("text-white/70")
|
||||
})
|
||||
|
||||
const activeTab = document.getElementById(`tab-${tabName}`)
|
||||
activeTab.classList.add("active")
|
||||
activeTab.classList.remove("text-white/70")
|
||||
activeTab.classList.add("text-white")
|
||||
|
||||
// Update tab content
|
||||
elements.generateSection.classList.toggle("hidden", tabName !== "generate")
|
||||
elements.decryptSection.classList.toggle("hidden", tabName !== "decrypt")
|
||||
|
||||
// Reset states when switching tabs
|
||||
resetFormStates()
|
||||
}
|
||||
|
||||
// Form Validation
|
||||
function setupFormValidation() {
|
||||
// Real-time validation
|
||||
elements.nameInput.addEventListener("input", () => validateField("name"))
|
||||
elements.emailInput.addEventListener("input", () => validateField("email"))
|
||||
elements.passphraseInput.addEventListener("input", () =>
|
||||
validateField("passphrase")
|
||||
)
|
||||
elements.confirmPassphraseInput.addEventListener("input", () =>
|
||||
validateField("confirm-passphrase")
|
||||
)
|
||||
elements.privateKeyInput.addEventListener("input", () =>
|
||||
validateField("private-key")
|
||||
)
|
||||
elements.keyPassphraseInput.addEventListener("input", () =>
|
||||
validateField("key-passphrase")
|
||||
)
|
||||
}
|
||||
|
||||
function validateField(fieldName) {
|
||||
const field = document.getElementById(fieldName)
|
||||
const errorElement = document.getElementById(`${fieldName}-error`)
|
||||
let isValid = true
|
||||
let errorMessage = ""
|
||||
|
||||
switch (fieldName) {
|
||||
case "name":
|
||||
if (!field.value.trim()) {
|
||||
isValid = false
|
||||
errorMessage = "Full name is required"
|
||||
}
|
||||
break
|
||||
|
||||
case "email":
|
||||
if (!field.value.trim()) {
|
||||
isValid = false
|
||||
errorMessage = "Email address is required"
|
||||
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(field.value)) {
|
||||
isValid = false
|
||||
errorMessage = "Please enter a valid email address"
|
||||
}
|
||||
break
|
||||
|
||||
case "passphrase":
|
||||
if (!field.value) {
|
||||
isValid = false
|
||||
errorMessage = "Passphrase is required"
|
||||
} else if (field.value.length < 8) {
|
||||
isValid = false
|
||||
errorMessage = "Passphrase must be at least 8 characters long"
|
||||
}
|
||||
break
|
||||
|
||||
case "confirm-passphrase":
|
||||
if (field.value !== elements.passphraseInput.value) {
|
||||
isValid = false
|
||||
errorMessage = "Passphrases do not match"
|
||||
}
|
||||
break
|
||||
|
||||
case "private-key":
|
||||
if (!field.value.trim()) {
|
||||
isValid = false
|
||||
errorMessage = "Private key is required"
|
||||
} else if (
|
||||
!field.value.includes("-----BEGIN PGP PRIVATE KEY BLOCK-----")
|
||||
) {
|
||||
isValid = false
|
||||
errorMessage = "Please enter a valid PGP private key"
|
||||
}
|
||||
break
|
||||
|
||||
case "key-passphrase":
|
||||
if (!field.value) {
|
||||
isValid = false
|
||||
errorMessage = "Key passphrase is required"
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// Update field styling and error message
|
||||
if (isValid) {
|
||||
field.classList.remove("border-red-500")
|
||||
field.classList.add("border-gray-300")
|
||||
errorElement.classList.add("hidden")
|
||||
errorElement.textContent = ""
|
||||
} else {
|
||||
field.classList.add("border-red-500")
|
||||
field.classList.remove("border-gray-300")
|
||||
errorElement.classList.remove("hidden")
|
||||
errorElement.textContent = errorMessage
|
||||
}
|
||||
|
||||
return isValid
|
||||
}
|
||||
|
||||
function validateForm(formType) {
|
||||
let isValid = true
|
||||
|
||||
if (formType === "generation") {
|
||||
isValid = validateField("name") && isValid
|
||||
isValid = validateField("email") && isValid
|
||||
isValid = validateField("passphrase") && isValid
|
||||
isValid = validateField("confirm-passphrase") && isValid
|
||||
} else if (formType === "decryption") {
|
||||
isValid = validateField("private-key") && isValid
|
||||
isValid = validateField("key-passphrase") && isValid
|
||||
}
|
||||
|
||||
return isValid
|
||||
}
|
||||
|
||||
// Key Generation
|
||||
async function handleKeyGeneration(e) {
|
||||
e.preventDefault()
|
||||
|
||||
if (isProcessing || !validateForm("generation")) {
|
||||
return
|
||||
}
|
||||
|
||||
isProcessing = true
|
||||
showGenerationStatus("loading")
|
||||
|
||||
const formData = {
|
||||
name: elements.nameInput.value.trim(),
|
||||
email: elements.emailInput.value.trim(),
|
||||
passphrase: elements.passphraseInput.value,
|
||||
comment: elements.commentInput.value.trim() || undefined,
|
||||
}
|
||||
|
||||
try {
|
||||
// Simulate API call (replace with actual API endpoint)
|
||||
const responseKeyGeneration = await keyGenerationAPI(formData)
|
||||
|
||||
if (!responseKeyGeneration.success) {
|
||||
console.error("Key generation failed:", responseKeyGeneration.error)
|
||||
throw new Error("Key generation failed")
|
||||
}
|
||||
// Auto-download public key
|
||||
const responsePublicKey = await publicKeyDownloadAPI(formData.email)
|
||||
if (!responsePublicKey.ok) {
|
||||
const errorData = await response.json()
|
||||
console.error("Failed to download public key:", errorData)
|
||||
throw new Error("Failed to download public key")
|
||||
}
|
||||
downloadFile(
|
||||
await responsePublicKey.blob(),
|
||||
responsePublicKey.filename,
|
||||
responsePublicKey.mimetype
|
||||
)
|
||||
|
||||
showGenerationStatus("success")
|
||||
|
||||
// Reset form after successful generation
|
||||
setTimeout(() => {
|
||||
elements.keyGenerationForm.reset()
|
||||
showGenerationStatus("hidden")
|
||||
}, 3000)
|
||||
} catch (error) {
|
||||
console.error("Key generation error:", error)
|
||||
showGenerationStatus("error", error.message)
|
||||
} finally {
|
||||
isProcessing = false
|
||||
}
|
||||
}
|
||||
|
||||
function showGenerationStatus(type, message = "") {
|
||||
elements.generationStatus.classList.remove("hidden")
|
||||
elements.loadingStatus.classList.add("hidden")
|
||||
elements.successStatus.classList.add("hidden")
|
||||
elements.errorStatus.classList.add("hidden")
|
||||
|
||||
if (type === "loading") {
|
||||
elements.loadingStatus.classList.remove("hidden")
|
||||
elements.generateBtn.disabled = true
|
||||
elements.generateBtn.innerHTML =
|
||||
'<i class="fas fa-spinner loading-spinner mr-2"></i>Generating...'
|
||||
} else if (type === "success") {
|
||||
elements.successStatus.classList.remove("hidden")
|
||||
elements.generateBtn.disabled = false
|
||||
elements.generateBtn.innerHTML =
|
||||
'<i class="fas fa-key mr-2"></i>Generate Key Pair'
|
||||
} else if (type === "error") {
|
||||
elements.errorStatus.classList.remove("hidden")
|
||||
elements.errorMessage.textContent = message
|
||||
elements.generateBtn.disabled = false
|
||||
elements.generateBtn.innerHTML =
|
||||
'<i class="fas fa-key mr-2"></i>Generate Key Pair'
|
||||
} else {
|
||||
elements.generationStatus.classList.add("hidden")
|
||||
elements.generateBtn.disabled = false
|
||||
elements.generateBtn.innerHTML =
|
||||
'<i class="fas fa-key mr-2"></i>Generate Key Pair'
|
||||
}
|
||||
}
|
||||
|
||||
// File Handling
|
||||
function setupFileHandling() {
|
||||
// Prevent default drag behaviors
|
||||
;["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => {
|
||||
document.addEventListener(eventName, preventDefaults, false)
|
||||
})
|
||||
|
||||
function preventDefaults(e) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}
|
||||
}
|
||||
|
||||
function handleDragOver(e) {
|
||||
e.preventDefault()
|
||||
elements.dropZone.classList.add("drag-over")
|
||||
}
|
||||
|
||||
function handleDragLeave(e) {
|
||||
e.preventDefault()
|
||||
elements.dropZone.classList.remove("drag-over")
|
||||
}
|
||||
|
||||
function handleFileDrop(e) {
|
||||
e.preventDefault()
|
||||
elements.dropZone.classList.remove("drag-over")
|
||||
|
||||
const files = Array.from(e.dataTransfer.files)
|
||||
processFiles(files)
|
||||
}
|
||||
|
||||
function handleFileSelection(e) {
|
||||
const files = Array.from(e.target.files)
|
||||
processFiles(files)
|
||||
}
|
||||
|
||||
function processFiles(files) {
|
||||
const validFiles = []
|
||||
const allowedTypes = [".asc", ".gpg", ".pgp", ".txt"]
|
||||
const maxSize = 10 * 1024 * 1024 // 10MB
|
||||
|
||||
files.forEach((file) => {
|
||||
const extension = "." + file.name.split(".").pop().toLowerCase()
|
||||
|
||||
if (!allowedTypes.includes(extension)) {
|
||||
showNotification(
|
||||
`File "${file.name}" has an unsupported format.`,
|
||||
"error"
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (file.size > maxSize) {
|
||||
showNotification(`File "${file.name}" is too large (max 10MB).`, "error")
|
||||
return
|
||||
}
|
||||
|
||||
validFiles.push(file)
|
||||
})
|
||||
|
||||
if (validFiles.length > 0) {
|
||||
selectedFiles = validFiles
|
||||
displaySelectedFiles()
|
||||
elements.decryptionForm.classList.remove("hidden")
|
||||
}
|
||||
}
|
||||
|
||||
function displaySelectedFiles() {
|
||||
elements.fileList.classList.remove("hidden")
|
||||
elements.filesContainer.innerHTML = ""
|
||||
|
||||
selectedFiles.forEach((file, index) => {
|
||||
const fileElement = document.createElement("div")
|
||||
fileElement.className =
|
||||
"flex items-center justify-between p-3 bg-gray-50 rounded-lg"
|
||||
fileElement.innerHTML = `
|
||||
<div class="flex items-center gap-3">
|
||||
<i class="fas fa-file-alt text-gray-500"></i>
|
||||
<div>
|
||||
<div class="font-medium text-gray-900">${file.name}</div>
|
||||
<div class="text-sm text-gray-500">${formatFileSize(
|
||||
file.size
|
||||
)}</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="text-red-500 hover:text-red-700 transition-colors"
|
||||
onclick="removeFile(${index})"
|
||||
aria-label="Remove file"
|
||||
>
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
`
|
||||
elements.filesContainer.appendChild(fileElement)
|
||||
})
|
||||
}
|
||||
|
||||
function removeFile(index) {
|
||||
selectedFiles.splice(index, 1)
|
||||
|
||||
if (selectedFiles.length === 0) {
|
||||
elements.fileList.classList.add("hidden")
|
||||
elements.decryptionForm.classList.add("hidden")
|
||||
} else {
|
||||
displaySelectedFiles()
|
||||
}
|
||||
}
|
||||
|
||||
function formatFileSize(bytes) {
|
||||
if (bytes === 0) return "0 Bytes"
|
||||
const k = 1024
|
||||
const sizes = ["Bytes", "KB", "MB", "GB"]
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]
|
||||
}
|
||||
|
||||
// File Decryption
|
||||
async function handleFileDecryption(e) {
|
||||
e.preventDefault()
|
||||
|
||||
if (
|
||||
isProcessing ||
|
||||
!validateForm("decryption") ||
|
||||
selectedFiles.length === 0
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
isProcessing = true
|
||||
showDecryptionStatus(true)
|
||||
|
||||
const privateKey = elements.privateKeyInput.value.trim()
|
||||
const passphrase = elements.keyPassphraseInput.value
|
||||
|
||||
try {
|
||||
const results = []
|
||||
|
||||
for (let i = 0; i < selectedFiles.length; i++) {
|
||||
const file = selectedFiles[i]
|
||||
const progress = ((i + 1) / selectedFiles.length) * 100
|
||||
|
||||
updateProgress(progress, `Decrypting ${file.name}...`)
|
||||
|
||||
// Read file content
|
||||
const fileContent = await readFileAsText(file)
|
||||
|
||||
// Simulate API call for decryption
|
||||
const result = await simulateDecryptionAPI({
|
||||
encryptedContent: fileContent,
|
||||
privateKey: privateKey,
|
||||
passphrase: passphrase,
|
||||
filename: file.name,
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
results.push({
|
||||
filename: file.name,
|
||||
decryptedContent: result.decryptedContent,
|
||||
success: true,
|
||||
})
|
||||
|
||||
// Auto-download decrypted file
|
||||
const decryptedFilename = file.name.replace(
|
||||
/\.(asc|gpg|pgp)$/,
|
||||
"_decrypted.txt"
|
||||
)
|
||||
downloadFile(result.decryptedContent, decryptedFilename, "text/plain")
|
||||
} else {
|
||||
results.push({
|
||||
filename: file.name,
|
||||
error: result.error,
|
||||
success: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
displayDecryptionResults(results)
|
||||
} catch (error) {
|
||||
console.error("Decryption error:", error)
|
||||
showNotification("Decryption failed: " + error.message, "error")
|
||||
} finally {
|
||||
isProcessing = false
|
||||
setTimeout(() => {
|
||||
showDecryptionStatus(false)
|
||||
elements.decryptionForm.reset()
|
||||
selectedFiles = []
|
||||
elements.fileList.classList.add("hidden")
|
||||
elements.decryptionForm.classList.add("hidden")
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
|
||||
function showDecryptionStatus(show) {
|
||||
elements.decryptionStatus.classList.toggle("hidden", !show)
|
||||
elements.decryptBtn.disabled = show
|
||||
|
||||
if (show) {
|
||||
elements.decryptBtn.innerHTML =
|
||||
'<i class="fas fa-spinner loading-spinner mr-2"></i>Decrypting...'
|
||||
updateProgress(0, "Preparing decryption...")
|
||||
} else {
|
||||
elements.decryptBtn.innerHTML =
|
||||
'<i class="fas fa-unlock mr-2"></i>Decrypt Files'
|
||||
}
|
||||
}
|
||||
|
||||
function updateProgress(percentage, message) {
|
||||
elements.progressBar.style.width = percentage + "%"
|
||||
elements.decryptionMessage.textContent = message
|
||||
}
|
||||
|
||||
function displayDecryptionResults(results) {
|
||||
elements.decryptionResults.innerHTML = ""
|
||||
|
||||
results.forEach((result) => {
|
||||
const resultElement = document.createElement("div")
|
||||
resultElement.className = `p-3 rounded-lg ${
|
||||
result.success
|
||||
? "bg-green-50 border border-green-200"
|
||||
: "bg-red-50 border border-red-200"
|
||||
}`
|
||||
|
||||
if (result.success) {
|
||||
resultElement.innerHTML = `
|
||||
<div class="flex items-center gap-2 text-green-700">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span class="font-medium">${result.filename}</span>
|
||||
<span class="text-sm">- Decrypted successfully</span>
|
||||
</div>
|
||||
`
|
||||
} else {
|
||||
resultElement.innerHTML = `
|
||||
<div class="flex items-center gap-2 text-red-700">
|
||||
<i class="fas fa-exclamation-circle"></i>
|
||||
<span class="font-medium">${result.filename}</span>
|
||||
<span class="text-sm">- ${result.error}</span>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
elements.decryptionResults.appendChild(resultElement)
|
||||
})
|
||||
}
|
||||
|
||||
// Utility Functions
|
||||
async function downloadFile(content, filename, mimeType) {
|
||||
// Create download link
|
||||
const url = URL.createObjectURL(content)
|
||||
const a = document.createElement("a")
|
||||
a.href = url
|
||||
a.download = filename
|
||||
|
||||
// Trigger download
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
|
||||
function readFileAsText(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
reader.onload = (e) => resolve(e.target.result)
|
||||
reader.onerror = () => reject(new Error("Failed to read file"))
|
||||
reader.readAsText(file)
|
||||
})
|
||||
}
|
||||
|
||||
function showNotification(message, type = "info") {
|
||||
// Create notification element
|
||||
const notification = document.createElement("div")
|
||||
notification.className = `fixed top-4 right-4 p-4 rounded-lg shadow-lg z-50 ${
|
||||
type === "error"
|
||||
? "bg-red-500 text-white"
|
||||
: type === "success"
|
||||
? "bg-green-500 text-white"
|
||||
: "bg-blue-500 text-white"
|
||||
}`
|
||||
notification.innerHTML = `
|
||||
<div class="flex items-center gap-2">
|
||||
<i class="fas ${
|
||||
type === "error"
|
||||
? "fa-exclamation-circle"
|
||||
: type === "success"
|
||||
? "fa-check-circle"
|
||||
: "fa-info-circle"
|
||||
}"></i>
|
||||
<span>${message}</span>
|
||||
</div>
|
||||
`
|
||||
|
||||
document.body.appendChild(notification)
|
||||
|
||||
// Remove notification after 5 seconds
|
||||
setTimeout(() => {
|
||||
notification.remove()
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
function resetFormStates() {
|
||||
// Reset generation form
|
||||
elements.keyGenerationForm.reset()
|
||||
showGenerationStatus("hidden")
|
||||
|
||||
// Reset decryption form
|
||||
elements.decryptionForm.reset()
|
||||
selectedFiles = []
|
||||
elements.fileList.classList.add("hidden")
|
||||
elements.decryptionForm.classList.add("hidden")
|
||||
showDecryptionStatus(false)
|
||||
|
||||
// Clear validation errors
|
||||
document.querySelectorAll(".text-red-500").forEach((error) => {
|
||||
error.classList.add("hidden")
|
||||
})
|
||||
|
||||
// Reset field styling
|
||||
document.querySelectorAll(".border-red-500").forEach((field) => {
|
||||
field.classList.remove("border-red-500")
|
||||
field.classList.add("border-gray-300")
|
||||
})
|
||||
|
||||
isProcessing = false
|
||||
}
|
||||
|
||||
// API Simulation Functions (Replace with actual API calls)
|
||||
async function keyGenerationAPI(data) {
|
||||
const response = await fetch("/api/generate-key", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
|
||||
return await response.json().then((result) => {
|
||||
return {
|
||||
...result,
|
||||
success: true,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function publicKeyDownloadAPI(email) {
|
||||
const response = await fetch("/api/download/public-key", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ email: email }),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to download public key")
|
||||
}
|
||||
|
||||
return {
|
||||
ok: response.ok,
|
||||
blob: () => response.blob(),
|
||||
mimetype: response.headers.get("content-type"),
|
||||
filename:
|
||||
response.headers
|
||||
.get("content-disposition")
|
||||
?.split("filename=")[1]
|
||||
?.replace(/"/g, "") || "public.asc",
|
||||
}
|
||||
}
|
||||
|
||||
async function simulateDecryptionAPI(data) {
|
||||
// Simulate API delay
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||
|
||||
// Simulate API response
|
||||
return {
|
||||
success: true,
|
||||
decryptedContent: `Decrypted content from ${data.filename}
|
||||
|
||||
This is a simulated decryption result.
|
||||
Original file: ${data.filename}
|
||||
Decrypted at: ${new Date().toISOString()}
|
||||
|
||||
Your encrypted content would appear here in a real implementation.`,
|
||||
message: "File decrypted successfully",
|
||||
}
|
||||
|
||||
// Uncomment for actual API call:
|
||||
/*
|
||||
const response = await fetch('/api/decrypt-file', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
return await response.json();
|
||||
*/
|
||||
}
|
||||
Reference in New Issue
Block a user