diff --git a/frontends/web/templates/decode.html b/frontends/web/templates/decode.html index 226d6fd..237c83c 100644 --- a/frontends/web/templates/decode.html +++ b/frontends/web/templates/decode.html @@ -14,11 +14,19 @@
Message Decrypted Successfully!
- -
+ + +
+
{{ decoded_message }}
+ +
+ + i Decode Another Message @@ -83,14 +91,18 @@
- - + + +
+ + +
If PIN was used during encoding
+
@@ -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 document.querySelectorAll('.drop-zone').forEach(zone => { const input = zone.querySelector('input[type="file"]'); diff --git a/frontends/web/templates/encode.html b/frontends/web/templates/encode.html index 8498c19..5790eaa 100644 --- a/frontends/web/templates/encode.html +++ b/frontends/web/templates/encode.html @@ -86,14 +86,14 @@
- - -
- Your static 6-9 digit PIN (if configured) -
+ +
+ + +
+
Your static 6-9 digit PIN (if configured)
@@ -255,5 +255,61 @@ document.querySelectorAll('.drop-zone').forEach(zone => { 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 = + '' + + 'Drop image or click to browse'; + } + } +} +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 + } + } +}); {% endblock %} diff --git a/frontends/web/templates/generate.html b/frontends/web/templates/generate.html index 5d6af8d..494415b 100644 --- a/frontends/web/templates/generate.html +++ b/frontends/web/templates/generate.html @@ -3,6 +3,18 @@ {% block title %}Generate Credentials - Stegasoo{% endblock %} {% block content %} +
@@ -120,16 +132,16 @@
{% if pin %} -
+
-
YOUR STATIC PIN
-
-
{{ pin }}
-
-
- Use this {{ pin_length }}-digit PIN every day -
+
YOUR STATIC PIN
+
+ {{ pin }} +
+
Use this {{ pin_length }}-digit PIN every day +
+ {% endif %} {% if rsa_key_pem %} diff --git a/src/stegasoo/constants.py b/src/stegasoo/constants.py index 5570c28..166de03 100644 --- a/src/stegasoo/constants.py +++ b/src/stegasoo/constants.py @@ -79,7 +79,8 @@ def get_data_dir() -> Path: """Get the data directory path.""" # Check multiple locations 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('/app/data'), # Docker Path.cwd() / 'data', # Current directory diff --git a/test_data/c643e6b9_20251228.png b/test_data/c643e6b9_20251228.png new file mode 100644 index 0000000..c24ff84 Binary files /dev/null and b/test_data/c643e6b9_20251228.png differ