Minor touches.

This commit is contained in:
Aaron D. Lee
2025-12-28 03:09:02 -05:00
parent ffc311c93d
commit 8b9c288780
5 changed files with 145 additions and 25 deletions

View File

@@ -14,11 +14,19 @@
<div class="alert alert-success"> <div class="alert alert-success">
<h6><i class="bi bi-check-circle me-2"></i>Message Decrypted Successfully!</h6> <h6><i class="bi bi-check-circle me-2"></i>Message Decrypted Successfully!</h6>
</div> </div>
<div class="mb-4"> <label class="form-label text-muted">Decoded Message:</label>
<div class="position-relative">
<div class="alert-message p-3 rounded bg-dark border border-secondary" id="decodedContent" style="white-space: pre-wrap;">{{ decoded_message }}</div>
<button class="btn btn-sm btn-outline-light position-absolute top-0 end-0 m-2" onclick="navigator.clipboard.writeText(document.getElementById('decodedContent').innerText).then(() => this.innerHTML = '<i class=\'bi bi-check\'></i>').catch(() => alert('Failed to copy'))">
<i class="bi bi-clipboard"></i> Copy
</button>
</div>
i<!--then<div class="mb-4">
<label class="form-label text-muted">Decoded Message:</label> <label class="form-label text-muted">Decoded Message:</label>
<div class="alert-message">{{ decoded_message }}</div> <div class="alert-message">{{ decoded_message }}</div>
</div> </div>-->
<a href="/decode" class="btn btn-outline-light w-100"> <a href="/decode" class="btn btn-outline-light w-100">
<i class="bi bi-arrow-repeat me-2"></i>Decode Another Message <i class="bi bi-arrow-repeat me-2"></i>Decode Another Message
@@ -83,14 +91,18 @@
<div class="row"> <div class="row">
<div class="col-md-6 mb-3"> <div class="col-md-6 mb-3">
<label class="form-label">
<i class="bi bi-123 me-1"></i> PIN <label class="form-label"><i class="bi bi-123 me-1"></i> PIN</label>
</label> <div class="input-group">
<input type="password" name="pin" class="form-control" id="pinInput" <input type="password" name="pin" class="form-control" id="pinInput" placeholder="6-9 digits" maxlength="9">
placeholder="6-9 digits" maxlength="9"> <button class="btn btn-outline-secondary" type="button" id="togglePin">
<i class="bi bi-eye"></i>
</button>
</div>
<div class="form-text"> <div class="form-text">
If PIN was used during encoding If PIN was used during encoding
</div> </div>
</div> </div>
<div class="col-md-6 mb-3"> <div class="col-md-6 mb-3">
@@ -197,6 +209,45 @@ function updateDayLabel(dayName) {
} }
} }
// 1. PIN Toggle
document.getElementById('togglePin')?.addEventListener('click', function() {
const input = document.getElementById('pinInput');
const icon = this.querySelector('i');
if (input.type === 'password') {
input.type = 'text';
icon.classList.replace('bi-eye', 'bi-eye-slash');
} else {
input.type = 'password';
icon.classList.replace('bi-eye-slash', 'bi-eye');
}
});
// 2. Paste from Clipboard
document.addEventListener('paste', function(e) {
// Only run if the form exists (we are not on the success page)
if (!document.getElementById('decodeForm')) return;
const items = e.clipboardData.items;
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") !== -1) {
const blob = items[i].getAsFile();
// Priority for Decode: Fill Stego Image first (most common), then Reference
const stegoInput = document.querySelector('input[name="stego_image"]');
const refInput = document.querySelector('input[name="reference_photo"]');
const targetInput = (!stegoInput.files.length) ? stegoInput : refInput;
const container = new DataTransfer();
container.items.add(blob);
targetInput.files = container.files;
targetInput.dispatchEvent(new Event('change'));
break;
}
}
});
// Drag & drop with preview // Drag & drop with preview
document.querySelectorAll('.drop-zone').forEach(zone => { document.querySelectorAll('.drop-zone').forEach(zone => {
const input = zone.querySelector('input[type="file"]'); const input = zone.querySelector('input[type="file"]');

View File

@@ -86,14 +86,14 @@
<div class="row"> <div class="row">
<div class="col-md-6 mb-3"> <div class="col-md-6 mb-3">
<label class="form-label"> <label class="form-label"><i class="bi bi-123 me-1"></i> PIN</label>
<i class="bi bi-123 me-1"></i> PIN <div class="input-group">
</label> <input type="password" name="pin" class="form-control" id="pinInput" placeholder="6-9 digits" maxlength="9">
<input type="password" name="pin" class="form-control" id="pinInput" <button class="btn btn-outline-secondary" type="button" id="togglePin">
placeholder="6-9 digits" maxlength="9"> <i class="bi bi-eye"></i>
<div class="form-text"> </button>
Your static 6-9 digit PIN (if configured) </div>
</div> <div class="form-text">Your static 6-9 digit PIN (if configured)</div>
</div> </div>
<div class="col-md-6 mb-3"> <div class="col-md-6 mb-3">
@@ -255,5 +255,61 @@ document.querySelectorAll('.drop-zone').forEach(zone => {
reader.readAsDataURL(file); reader.readAsDataURL(file);
} }
}); });
// 1. PIN Toggle Logic
document.getElementById('togglePin').addEventListener('click', function() {
const input = document.getElementById('pinInput');
const icon = this.querySelector('i');
if (input.type === 'password') {
input.type = 'text';
icon.classList.replace('bi-eye', 'bi-eye-slash');
} else {
input.type = 'password';
icon.classList.replace('bi-eye-slash', 'bi-eye');
}
});
// 2. Prevent Same File Selection
function checkDuplicateFiles() {
const refInput = document.querySelector('input[name="reference_photo"]');
const carInput = document.querySelector('input[name="carrier"]');
if (refInput.files[0] && carInput.files[0]) {
// Compare name and size as a proxy for identical files
if (refInput.files[0].name === carInput.files[0].name &&
refInput.files[0].size === carInput.files[0].size) {
alert("Security Warning: You cannot use the same image for both Reference and Carrier!");
carInput.value = ''; // Clear carrier
document.getElementById('carrierPreview').classList.add('d-none');
document.querySelector('#carrierDropZone .drop-zone-label').innerHTML =
'<i class="bi bi-cloud-arrow-up fs-3 d-block mb-2 text-muted"></i>' +
'<span class="text-muted">Drop image or click to browse</span>';
}
}
}
document.querySelector('input[name="reference_photo"]').addEventListener('change', checkDuplicateFiles);
document.querySelector('input[name="carrier"]').addEventListener('change', checkDuplicateFiles);
// 3. Paste from Clipboard
document.addEventListener('paste', function(e) {
const items = e.clipboardData.items;
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") !== -1) {
const blob = items[i].getAsFile();
// Priority: Fill Carrier first, if empty. Else fill Reference.
const carrierInput = document.querySelector('input[name="carrier"]');
const refInput = document.querySelector('input[name="reference_photo"]');
const targetInput = (!carrierInput.files.length) ? carrierInput : refInput;
const container = new DataTransfer();
container.items.add(blob);
targetInput.files = container.files;
targetInput.dispatchEvent(new Event('change'));
break; // Only paste one image at a time
}
}
});
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -3,6 +3,18 @@
{% block title %}Generate Credentials - Stegasoo{% endblock %} {% block title %}Generate Credentials - Stegasoo{% endblock %}
{% block content %} {% block content %}
<style>
@media print {
body * { visibility: hidden; }
.card-body, .card-body * { visibility: visible; color: black !important; }
.card-body { position: absolute; left: 0; top: 0; width: 100%; margin: 0; border: none; }
.btn, .alert, form, .card-header { display: none !important; }
.table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #000 !important; padding: 8px; }
/* Hide the inputs, show the results */
#generateForm { display: none; }
}
</style>
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-lg-8"> <div class="col-lg-8">
<div class="card"> <div class="card">
@@ -120,16 +132,16 @@
</div> </div>
{% if pin %} {% if pin %}
<hr class="my-4">
<div class="text-center mb-4"> <div class="text-center mb-4">
<h6 class="text-muted mb-2">YOUR STATIC PIN</h6> <h6 class="text-muted mb-2">YOUR STATIC PIN</h6>
<div class="pin-container"> <div class="pin-container p-3 bg-dark border rounded fs-1 font-monospace text-white">
<div class="pin-display">{{ pin }}</div> {{ pin }}
</div> </div>
<div class="mt-2"> <div class="mt-2 d-print-none"> <small class="text-muted">Use this {{ pin_length }}-digit PIN every day</small>
<small class="text-muted">Use this {{ pin_length }}-digit PIN every day</small> </div>
</div>
</div> </div>
{% endif %} {% endif %}
{% if rsa_key_pem %} {% if rsa_key_pem %}

View File

@@ -79,7 +79,8 @@ def get_data_dir() -> Path:
"""Get the data directory path.""" """Get the data directory path."""
# Check multiple locations # Check multiple locations
candidates = [ candidates = [
Path(__file__).parent.parent.parent.parent / 'data', # Development Path(__file__).parent.parent.parent.parent / 'data', # Development
Path(__file__).parent.parent / 'data', # Development
Path(__file__).parent / 'data', # Installed package Path(__file__).parent / 'data', # Installed package
Path('/app/data'), # Docker Path('/app/data'), # Docker
Path.cwd() / 'data', # Current directory Path.cwd() / 'data', # Current directory

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB