broadfield-dev commited on
Commit
055da99
·
verified ·
1 Parent(s): 8af987e

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +265 -19
index.html CHANGED
@@ -1,19 +1,265 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>KeyLock.js - JavaScript Steganography & Crypto Plugin</title>
7
+ <style>
8
+ :root {
9
+ --bg-color: #0d1117;
10
+ --border-color: #30363d;
11
+ --text-color: #c9d1d9;
12
+ --accent-color: #58a6ff;
13
+ --error-color: #f85149;
14
+ --success-color: #3fb950;
15
+ --card-bg: #161b22;
16
+ }
17
+ body {
18
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
19
+ background-color: var(--bg-color);
20
+ color: var(--text-color);
21
+ margin: 0;
22
+ padding: 2rem;
23
+ display: flex;
24
+ justify-content: center;
25
+ }
26
+ main {
27
+ display: grid;
28
+ grid-template-columns: 1fr 1fr;
29
+ gap: 2rem;
30
+ max-width: 1200px;
31
+ width: 100%;
32
+ }
33
+ .card {
34
+ background-color: var(--card-bg);
35
+ border: 1px solid var(--border-color);
36
+ border-radius: 8px;
37
+ padding: 1.5rem;
38
+ }
39
+ h1, h2 {
40
+ border-bottom: 1px solid var(--border-color);
41
+ padding-bottom: 0.5rem;
42
+ margin-top: 0;
43
+ }
44
+ textarea, input[type="text"] {
45
+ width: 100%;
46
+ box-sizing: border-box;
47
+ background-color: var(--bg-color);
48
+ border: 1px solid var(--border-color);
49
+ color: var(--text-color);
50
+ padding: 8px;
51
+ border-radius: 6px;
52
+ font-family: monospace;
53
+ }
54
+ textarea {
55
+ min-height: 120px;
56
+ resize: vertical;
57
+ }
58
+ button {
59
+ background-color: var(--accent-color);
60
+ color: white;
61
+ border: none;
62
+ padding: 10px 15px;
63
+ border-radius: 6px;
64
+ cursor: pointer;
65
+ font-weight: bold;
66
+ transition: background-color 0.2s;
67
+ }
68
+ button:hover {
69
+ background-color: #79b8ff;
70
+ }
71
+ .key-pair { display: flex; gap: 1rem; }
72
+ .key-pair > div { flex: 1; }
73
+ #image-upload-box {
74
+ border: 2px dashed var(--border-color);
75
+ border-radius: 8px;
76
+ padding: 1rem;
77
+ text-align: center;
78
+ cursor: pointer;
79
+ min-height: 150px;
80
+ display: flex;
81
+ align-items: center;
82
+ justify-content: center;
83
+ transition: border-color 0.2s;
84
+ }
85
+ #image-upload-box:hover { border-color: var(--accent-color); }
86
+ #generated-image-preview {
87
+ max-width: 100%;
88
+ border-radius: 6px;
89
+ margin-top: 1rem;
90
+ border: 1px solid var(--border-color);
91
+ }
92
+ #status-display {
93
+ margin-top: 1rem;
94
+ padding: 1rem;
95
+ border: 1px solid var(--border-color);
96
+ border-radius: 6px;
97
+ min-height: 50px;
98
+ white-space: pre-wrap;
99
+ word-break: break-word;
100
+ }
101
+ .status-success { color: var(--success-color); }
102
+ .status-error { color: var(--error-color); }
103
+ .hidden { display: none; }
104
+ </style>
105
+ </head>
106
+ <body>
107
+
108
+ <main>
109
+ <div class="card">
110
+ <h2>Encoder</h2>
111
+ <p>Generate a new RSA key pair, then use the public key to encrypt a payload into an image.</p>
112
+
113
+ <button id="generate-keys-btn">1. Generate New Key Pair</button>
114
+ <div class="key-pair">
115
+ <div>
116
+ <label for="public-key">Public Key (for Encryption)</label>
117
+ <textarea id="public-key" rows="7"></textarea>
118
+ </div>
119
+ <div>
120
+ <label for="private-key">Private Key (for Decryption)</label>
121
+ <textarea id="private-key" rows="7"></textarea>
122
+ </div>
123
+ </div>
124
+
125
+ <hr style="border-color: var(--border-color); margin: 1.5rem 0;">
126
+
127
+ <label for="payload-input">Data to Encrypt (Key=Value format)</label>
128
+ <textarea id="payload-input" placeholder="USER=demo-user
129
+ PASS:super_secret_password
130
+ "API_KEY" = "..."">USER = "TestUser"
131
+ PASS: TestPass
132
+ "GROQ_API_KEY" = "ALKSDFJASHFKSFH"</textarea>
133
+
134
+ <button id="generate-image-btn" style="margin-top: 1rem;">2. Generate Encrypted Image</button>
135
+
136
+ <img id="generated-image-preview" class="hidden" alt="Generated Encrypted Image">
137
+ <a id="download-link" class="hidden" style="display: block; margin-top: 0.5rem;">Download PNG</a>
138
+ </div>
139
+
140
+ <div class="card">
141
+ <h2>Decoder</h2>
142
+ <p>Upload an image generated by the encoder and use the corresponding private key to decode the hidden payload.</p>
143
+
144
+ <label for="private-key-input">Private Key for Decryption</label>
145
+ <textarea id="private-key-input" rows="7" placeholder="Paste the private key here..."></textarea>
146
+
147
+ <input type="file" id="image-upload-input" accept="image/png" class="hidden">
148
+ <div id="image-upload-box" onclick="document.getElementById('image-upload-input').click();">
149
+ Click or Drop KeyLock PNG here
150
+ </div>
151
+
152
+ <div id="status-display">Awaiting KeyLock image...</div>
153
+ </div>
154
+ </main>
155
+
156
+ <script src="keylock.js"></script>
157
+ <script>
158
+ document.addEventListener('DOMContentLoaded', () => {
159
+ const keylock = new KeyLock();
160
+
161
+ // --- UI Elements ---
162
+ const generateKeysBtn = document.getElementById('generate-keys-btn');
163
+ const publicKeyText = document.getElementById('public-key');
164
+ const privateKeyText = document.getElementById('private-key');
165
+ const privateKeyInput = document.getElementById('private-key-input');
166
+
167
+ const payloadInput = document.getElementById('payload-input');
168
+ const generateImageBtn = document.getElementById('generate-image-btn');
169
+ const imagePreview = document.getElementById('generated-image-preview');
170
+ const downloadLink = document.getElementById('download-link');
171
+
172
+ const imageUploadInput = document.getElementById('image-upload-input');
173
+ const statusDisplay = document.getElementById('status-display');
174
+
175
+ // --- Event Listeners ---
176
+
177
+ // Key Generation
178
+ generateKeysBtn.addEventListener('click', async () => {
179
+ try {
180
+ const { privateKeyPem, publicKeyPem } = await keylock.generatePemKeys();
181
+ publicKeyText.value = publicKeyPem;
182
+ privateKeyText.value = privateKeyPem;
183
+ privateKeyInput.value = privateKeyPem; // Auto-fill for convenience
184
+ } catch (e) {
185
+ alert(`Key generation failed: ${e.message}`);
186
+ }
187
+ });
188
+
189
+ // Image Generation (Encoding)
190
+ generateImageBtn.addEventListener('click', async () => {
191
+ const payload = payloadInput.value;
192
+ const pubKey = publicKeyText.value;
193
+
194
+ if (!pubKey || !payload) {
195
+ alert('Please generate a key pair and provide a payload first.');
196
+ return;
197
+ }
198
+
199
+ try {
200
+ generateImageBtn.textContent = 'Generating...';
201
+ generateImageBtn.disabled = true;
202
+
203
+ const imageDataUrl = await keylock.generateEncryptedImage(payload, pubKey);
204
+ imagePreview.src = imageDataUrl;
205
+ imagePreview.classList.remove('hidden');
206
+ downloadLink.href = imageDataUrl;
207
+ downloadLink.download = `keylock_${Date.now()}.png`;
208
+ downloadLink.classList.remove('hidden');
209
+
210
+ } catch (e) {
211
+ alert(`Image generation failed: ${e.message}`);
212
+ } finally {
213
+ generateImageBtn.textContent = '2. Generate Encrypted Image';
214
+ generateImageBtn.disabled = false;
215
+ }
216
+ });
217
+
218
+ // Image Upload (Decoding)
219
+ imageUploadInput.addEventListener('change', async (event) => {
220
+ const file = event.target.files[0];
221
+ const privKey = privateKeyInput.value;
222
+
223
+ if (!file) return;
224
+ if (!privKey) {
225
+ statusDisplay.textContent = 'Error: Please provide the private key for decryption.';
226
+ statusDisplay.className = 'status-display status-error';
227
+ return;
228
+ }
229
+
230
+ statusDisplay.textContent = 'Decoding...';
231
+ statusDisplay.className = 'status-display';
232
+
233
+ const reader = new FileReader();
234
+ reader.onload = (e) => {
235
+ const img = new Image();
236
+ img.onload = async () => {
237
+ const result = await keylock.decodePayload(img, privKey);
238
+ if (result.status === 'Success') {
239
+ let output = '✅ Success! Decoded Payload:\n\n';
240
+ for(const [key, value] of Object.entries(result.payload)) {
241
+ const valueDisplay = key.toLowerCase().includes('pass') ? '•'.repeat(String(value).length) : value;
242
+ output += `${key}: ${valueDisplay}\n`;
243
+ }
244
+ statusDisplay.textContent = output;
245
+ statusDisplay.className = 'status-display status-success';
246
+ } else {
247
+ statusDisplay.textContent = `❌ Error: ${result.message}`;
248
+ statusDisplay.className = 'status-display status-error';
249
+ }
250
+ };
251
+ img.onerror = () => {
252
+ statusDisplay.textContent = 'Error: Could not load the selected file as an image.';
253
+ statusDisplay.className = 'status-display status-error';
254
+ };
255
+ img.src = e.target.result;
256
+ };
257
+ reader.readAsDataURL(file);
258
+ });
259
+
260
+ // Auto-generate keys on load for quick demo
261
+ generateKeysBtn.click();
262
+ });
263
+ </script>
264
+ </body>
265
+ </html>